1 /***
2 * Redistribution and use of this software and associated documentation
3 * ("Software"), with or without modification, are permitted provided
4 * that the following conditions are met:
5 *
6 * 1. Redistributions of source code must retain copyright
7 * statements and notices. Redistributions must also contain a
8 * copy of this document.
9 *
10 * 2. Redistributions in binary form must reproduce the
11 * above copyright notice, this list of conditions and the
12 * following disclaimer in the documentation and/or other
13 * materials provided with the distribution.
14 *
15 * 3. The name "Exolab" must not be used to endorse or promote
16 * products derived from this Software without prior written
17 * permission of Exoffice Technologies. For written permission,
18 * please contact info@exolab.org.
19 *
20 * 4. Products derived from this Software may not be called "Exolab"
21 * nor may "Exolab" appear in their names without prior written
22 * permission of Exoffice Technologies. Exolab is a registered
23 * trademark of Exoffice Technologies.
24 *
25 * 5. Due credit should be given to the Exolab Project
26 * (http://www.exolab.org/).
27 *
28 * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32 * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39 * OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Copyright 2000-2005 (C) Exoffice Technologies Inc. All Rights Reserved.
42 *
43 * $Id: JmsConnectionFactory.java,v 1.2 2005/03/18 03:36:37 tanderson Exp $
44 */
45 package org.exolab.jms.client;
46
47 import java.io.Externalizable;
48 import java.io.IOException;
49 import java.io.ObjectInput;
50 import java.io.ObjectOutput;
51 import java.lang.reflect.Constructor;
52 import java.lang.reflect.InvocationTargetException;
53 import java.util.ArrayList;
54 import java.util.Iterator;
55 import java.util.List;
56 import java.util.Map;
57 import javax.jms.Connection;
58 import javax.jms.ConnectionFactory;
59 import javax.jms.ExceptionListener;
60 import javax.jms.JMSException;
61 import javax.jms.JMSSecurityException;
62 import javax.jms.QueueConnection;
63 import javax.jms.QueueConnectionFactory;
64 import javax.jms.TopicConnectionFactory;
65 import javax.jms.TopicConnection;
66 import javax.naming.Reference;
67 import javax.naming.Referenceable;
68 import javax.naming.StringRefAddr;
69
70
71 /***
72 * Client implementation of the <code>javax.jms.ConnectionFactory</code>
73 * interface.
74 *
75 * @author <a href="mailto:jima@exoffice.com">Jim Alateras</a>
76 * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a>
77 * @version $Revision: 1.2 $ $Date: 2005/03/18 03:36:37 $
78 */
79 public class JmsConnectionFactory
80 implements ConnectionFactory, QueueConnectionFactory,
81 TopicConnectionFactory, ExceptionListener, Externalizable,
82 Referenceable {
83
84 /***
85 * The class name of the server proxy.
86 */
87 private String _className;
88
89 /***
90 * Properties to initialise the server proxy with.
91 */
92 private Map _properties;
93
94 /***
95 * The environment to use when creating the server proxy. May be
96 * <code>null</code>
97 */
98 private Map _environment;
99
100 /***
101 * The server proxy.
102 */
103 private JmsServerStubIfc _proxy;
104
105 /***
106 * The set of connections created via this factory
107 */
108 private List _connections = new ArrayList();
109
110 /***
111 * Object version no. for serialization
112 */
113 private static final long serialVersionUID = 3;
114
115
116 /***
117 * Default constructor required for serialization
118 */
119 public JmsConnectionFactory() {
120 }
121
122 /***
123 * Construct a new <code>JmsConnectionFactory</code>
124 *
125 * @param className the class name of the server proxy
126 * @param properties properties to initialise the server proxy with
127 * @param environment the environment to use when creating the server proxy.
128 * May be <code>null</code>
129 */
130 public JmsConnectionFactory(String className, Map properties,
131 Map environment) {
132 if (className == null) {
133 throw new IllegalArgumentException("Argument 'className' is null");
134 }
135 if (properties == null) {
136 throw new IllegalArgumentException("Argument 'properties' is null");
137 }
138 _className = className;
139 _properties = properties;
140 _environment = environment;
141 }
142
143 /***
144 * Returns the server proxy
145 *
146 * @return the server proxy
147 * @throws JMSException if the proxy cannot be created
148 */
149 public synchronized JmsServerStubIfc getProxy() throws JMSException {
150 if (_proxy == null) {
151 try {
152 Class[] argTypes = {Map.class, Map.class};
153 Object[] args = {_properties, _environment};
154
155 Class factoryClass = Class.forName(_className);
156 Constructor constructor =
157 factoryClass.getDeclaredConstructor(argTypes);
158 _proxy = (JmsServerStubIfc) constructor.newInstance(args);
159 _proxy.setExceptionListener(this);
160 } catch (InvocationTargetException exception) {
161 if (exception.getTargetException() != null) {
162 throw new JMSException("Failed to create proxy: "
163 + exception.getTargetException());
164 } else {
165 throw new JMSException("Failed to create proxy: "
166 + exception);
167 }
168 } catch (Exception exception) {
169 throw new JMSException("Failed to create proxy: "
170 + exception);
171 }
172 }
173
174 return _proxy;
175 }
176
177 /***
178 * Notifies user of a JMS exception.
179 *
180 * @param exception the JMS exception
181 */
182 public void onException(JMSException exception) {
183
184
185 JmsConnection[] connections = getConnections();
186 for (int i = 0; i < connections.length; ++i) {
187 JmsConnection connection = connections[i];
188 connection.notifyExceptionListener(exception);
189 }
190
191 synchronized (this) {
192 _connections.clear();
193 _proxy = null;
194 }
195 }
196
197 /***
198 * Retrieves the reference of this object.
199 *
200 * @return the reference of this object
201 */
202 public Reference getReference() {
203 Reference reference = new Reference(getClass().getName(),
204 new StringRefAddr("serverClass",
205 _className),
206 JmsConnectionFactoryBuilder.class.getName(),
207 null);
208
209
210 Iterator iterator = _properties.entrySet().iterator();
211 while (iterator.hasNext()) {
212 Map.Entry entry = (Map.Entry) iterator.next();
213 String key = (String) entry.getKey();
214 String value = (String) entry.getValue();
215 reference.add(new StringRefAddr(key, value));
216 }
217
218 return reference;
219 }
220
221 /***
222 * Writes the object state to a stream.
223 *
224 * @param stream the stream to write the state to
225 * @throws IOException for any I/O error
226 */
227 public void writeExternal(ObjectOutput stream) throws IOException {
228 stream.writeLong(serialVersionUID);
229 stream.writeObject(_className);
230 stream.writeObject(_properties);
231 }
232
233 /***
234 * Reads the object state from a stream.
235 *
236 * @param stream the stream to read the state from
237 * @throws IOException for any I/O error
238 * @throws ClassNotFoundException if the class for an object being restored
239 * cannot be found
240 */
241 public void readExternal(ObjectInput stream)
242 throws IOException, ClassNotFoundException {
243 long version = stream.readLong();
244 if (version == serialVersionUID) {
245 _className = (String) stream.readObject();
246 _properties = (Map) stream.readObject();
247 } else {
248 throw new IOException(JmsConnectionFactory.class.getName()
249 + " with version " + version
250 + " is not supported.");
251 }
252 }
253
254 /***
255 * Creates a connection with the default user identity. The connection is
256 * created in stopped mode. No messages will be delivered until the
257 * <code>Connection.start</code> method is explicitly called.
258 *
259 * @return a newly created connection
260 * @throws JMSException if the JMS provider fails to create the
261 * connection due to some internal error.
262 * @throws JMSSecurityException if client authentication fails due to an
263 * invalid user name or password.
264 */
265 public Connection createConnection() throws JMSException {
266 return createConnection(null, null);
267 }
268
269 /***
270 * Creates a connection with the specified user identity. The connection is
271 * created in stopped mode. No messages will be delivered until the
272 * <code>Connection.start</code> method is explicitly called.
273 *
274 * @param userName the caller's user name
275 * @param password the caller's password
276 * @return a newly created connection
277 * @throws JMSException if the JMS provider fails to create the
278 * connection due to some internal error.
279 * @throws JMSSecurityException if client authentication fails due to an
280 * invalid user name or password.
281 */
282 public Connection createConnection(String userName, String password)
283 throws JMSException {
284 JmsConnection connection = new JmsConnection(this, null, userName,
285 password);
286 addConnection(connection);
287 return connection;
288 }
289
290 /***
291 * Create a queue connection with the default user identity.
292 *
293 * @return a newly created queue connection
294 * @throws JMSException if the connection can't be created due to
295 * some internal error
296 * @throws JMSSecurityException if client authentication fails due to
297 * invalid user name or password
298 */
299 public QueueConnection createQueueConnection() throws JMSException {
300 return createQueueConnection(null, null);
301 }
302
303 /***
304 * Create a queue connection with the specified user identity.
305 *
306 * @param userName the caller's user name
307 * @param password tghe caller's password
308 * @return a newly created queue connection
309 * @throws JMSException if the connection can't be created due to
310 * some internal error
311 * @throws JMSSecurityException if client authentication fails due to
312 * invalid user name or password
313 */
314 public QueueConnection createQueueConnection(String userName,
315 String password)
316 throws JMSException {
317
318 JmsQueueConnection connection = new JmsQueueConnection(this, null,
319 userName,
320 password);
321 addConnection(connection);
322 return connection;
323 }
324
325 /***
326 * Create a topic connection with the default user identity.
327 *
328 * @return a newly created topic connection
329 * @throws JMSException if the connection can't be created due to some
330 * internal error
331 * @throws JMSSecurityException if client authentication fails due to
332 * invalid user name or password
333 */
334 public TopicConnection createTopicConnection() throws JMSException {
335 return createTopicConnection(null, null);
336 }
337
338 /***
339 * Create a topic connection with the specified user identity.
340 *
341 * @param userName the caller's user name
342 * @param password tghe caller's password
343 * @return a newly created topic connection
344 * @throws JMSException if the connection can't be created due to some
345 * internal error
346 * @throws JMSSecurityException if client authentication fails due to
347 * invalid user name or password
348 */
349 public TopicConnection createTopicConnection(String userName,
350 String password)
351 throws JMSException {
352
353 JmsTopicConnection connection = new JmsTopicConnection(
354 this, null, userName, password);
355 addConnection(connection);
356 return connection;
357 }
358
359 /***
360 * Add a connection.
361 *
362 * @param connection the connection to add
363 */
364 protected synchronized void addConnection(JmsConnection connection) {
365 _connections.add(connection);
366 }
367
368 /***
369 * Remove a connection.
370 *
371 * @param connection the connection to remove
372 */
373 protected synchronized void removeConnection(JmsConnection connection) {
374 _connections.remove(connection);
375 }
376
377 /***
378 * Returns the set of active connections.
379 *
380 * @return the set of active connections
381 */
382 protected synchronized JmsConnection[] getConnections() {
383 return (JmsConnection[]) _connections.toArray(new JmsConnection[0]);
384 }
385
386 }