View Javadoc

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         // iterate through the list of connection and call
184         // notifyExceptionListener
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         // all properties are strings so add them to the reference
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 }