AMQConnectionFactory.java
001 /*
002  *
003  * Licensed to the Apache Software Foundation (ASF) under one
004  * or more contributor license agreements.  See the NOTICE file
005  * distributed with this work for additional information
006  * regarding copyright ownership.  The ASF licenses this file
007  * to you under the Apache License, Version 2.0 (the
008  * "License"); you may not use this file except in compliance
009  * with the License.  You may obtain a copy of the License at
010  
011  *   http://www.apache.org/licenses/LICENSE-2.0
012  
013  * Unless required by applicable law or agreed to in writing,
014  * software distributed under the License is distributed on an
015  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016  * KIND, either express or implied.  See the License for the
017  * specific language governing permissions and limitations
018  * under the License.
019  *
020  */
021 package org.apache.qpid.client;
022 
023 import java.net.InetAddress;
024 import java.net.UnknownHostException;
025 import java.util.Hashtable;
026 import java.util.UUID;
027 
028 import javax.jms.*;
029 import javax.naming.Context;
030 import javax.naming.Name;
031 import javax.naming.NamingException;
032 import javax.naming.RefAddr;
033 import javax.naming.Reference;
034 import javax.naming.Referenceable;
035 import javax.naming.StringRefAddr;
036 import javax.naming.spi.ObjectFactory;
037 
038 import org.apache.qpid.jms.ConnectionURL;
039 import org.apache.qpid.url.AMQBindingURL;
040 import org.apache.qpid.url.URLSyntaxException;
041 
042 
043 public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory,
044                                              ObjectFactory, Referenceable, XATopicConnectionFactory,
045                                              XAQueueConnectionFactory, XAConnectionFactory
046 {
047     private String _host;
048     private int _port;
049     private String _defaultUsername;
050     private String _defaultPassword;
051     private String _virtualPath;
052 
053     private ConnectionURL _connectionDetails;
054     private SSLConfiguration _sslConfig;
055 
056     public AMQConnectionFactory()
057     {
058     }
059 
060     /**
061      * This is the Only constructor used!
062      * It is used form the context and from the JNDI objects.
063      */
064     public AMQConnectionFactory(String urlthrows URLSyntaxException
065     {
066         _connectionDetails = new AMQConnectionURL(url);
067     }
068 
069     /**
070      * This constructor is never used!
071      */
072     public AMQConnectionFactory(ConnectionURL url)
073     {
074         _connectionDetails = url;
075     }
076 
077     /**
078      * This constructor is never used!
079      */
080     public AMQConnectionFactory(String broker, String username, String password, String clientName, String virtualHost)
081             throws URLSyntaxException
082     {
083         this(new AMQConnectionURL(
084                 ConnectionURL.AMQ_PROTOCOL + "://" + username + ":" + password + "@" + clientName + "/" + virtualHost + "?brokerlist='" + broker + "'"));
085     }
086 
087     /**
088      * This constructor is never used!
089      */
090     public AMQConnectionFactory(String host, int port, String virtualPath)
091     {
092         this(host, port, "guest""guest", virtualPath);
093     }
094 
095     /**
096      * This constructor is never used!
097      */
098     public AMQConnectionFactory(String host, int port, String defaultUsername, String defaultPassword,
099                                 String virtualPath)
100     {
101         _host = host;
102         _port = port;
103         _defaultUsername = defaultUsername;
104         _defaultPassword = defaultPassword;
105         _virtualPath = virtualPath;
106 
107 //todo when setting Host/Port has been resolved then we can use this otherwise those methods won't work with the following line.
108 //        _connectionDetails = new AMQConnectionURL(
109 //                ConnectionURL.AMQ_PROTOCOL + "://" +
110 //                        _defaultUsername + ":" + _defaultPassword + "@" +
111 //                        virtualPath + "?brokerlist='tcp://" + host + ":" + port + "'");
112     }
113 
114     /**
115      @return The _defaultPassword.
116      */
117     public final String getDefaultPassword(String password)
118     {
119         if (_connectionDetails != null)
120         {
121             return _connectionDetails.getPassword();
122         }
123         else
124         {
125             return _defaultPassword;
126         }
127     }
128 
129     /**
130      @param password The _defaultPassword to set.
131      */
132     public final void setDefaultPassword(String password)
133     {
134         if (_connectionDetails != null)
135         {
136             _connectionDetails.setPassword(password);
137         }
138         _defaultPassword = password;
139     }
140 
141     /**
142      * Getter for SSLConfiguration
143      *
144      @return SSLConfiguration if set, otherwise null
145      */
146     public final SSLConfiguration getSSLConfiguration()
147     {
148         return _sslConfig;
149     }
150 
151     /**
152      * Setter for SSLConfiguration
153      *
154      @param sslConfig config to store
155      */
156     public final void setSSLConfiguration(SSLConfiguration sslConfig)
157     {
158         _sslConfig = sslConfig;
159     }
160 
161     /**
162      @return The _defaultPassword.
163      */
164     public final String getDefaultUsername(String password)
165     {
166         if (_connectionDetails != null)
167         {
168             return _connectionDetails.getUsername();
169         }
170         else
171         {
172             return _defaultUsername;
173         }
174     }
175 
176     /**
177      @param username The _defaultUsername to set.
178      */
179     public final void setDefaultUsername(String username)
180     {
181         if (_connectionDetails != null)
182         {
183             _connectionDetails.setUsername(username);
184         }
185         _defaultUsername = username;
186     }
187 
188     /**
189      @return The _host .
190      */
191     public final String getHost()
192     {
193         //todo this doesn't make sense in a multi broker URL as we have no current as that is done by AMQConnection
194         return _host;
195     }
196 
197     /**
198      @param host The _host to set.
199      */
200     public final void setHost(String host)
201     {
202         //todo if _connectionDetails is set then run _connectionDetails.addBrokerDetails()
203         // Should perhaps have this method changed to setBroker(host,port)
204         _host = host;
205     }
206 
207     /**
208      @return _port The _port to set.
209      */
210     public final int getPort()
211     {
212         //todo see getHost
213         return _port;
214     }
215 
216     /**
217      @param port The port to set.
218      */
219     public final void setPort(int port)
220     {
221         //todo see setHost
222         _port = port;
223     }
224 
225     /**
226      @return he _virtualPath.
227      */
228     public final String getVirtualPath()
229     {
230         if (_connectionDetails != null)
231         {
232             return _connectionDetails.getVirtualHost();
233         }
234         else
235         {
236             return _virtualPath;
237         }
238     }
239 
240     /**
241      @param path The _virtualPath to set.
242      */
243     public final void setVirtualPath(String path)
244     {
245         if (_connectionDetails != null)
246         {
247             _connectionDetails.setVirtualHost(path);
248         }
249 
250         _virtualPath = path;
251     }
252 
253     public static String getUniqueClientID()
254     {
255         try
256         {
257             InetAddress addr = InetAddress.getLocalHost();
258             return addr.getHostName() + System.currentTimeMillis();
259         }
260         catch (UnknownHostException e)
261         {
262             return "UnknownHost" + UUID.randomUUID();
263         }
264     }
265 
266     public Connection createConnection() throws JMSException
267     {
268         try
269         {
270             if (_connectionDetails != null)
271             {
272                 if (_connectionDetails.getClientName() == null || _connectionDetails.getClientName().equals(""))
273                 {
274                     _connectionDetails.setClientName(getUniqueClientID());
275                 }
276                 return new AMQConnection(_connectionDetails, _sslConfig);
277             }
278             else
279             {
280                 return new AMQConnection(_host, _port, _defaultUsername, _defaultPassword, getUniqueClientID(),
281                                          _virtualPath);
282             }
283         }
284         catch (Exception e)
285         {
286             JMSException jmse = new JMSException("Error creating connection: " + e.getMessage());
287             jmse.setLinkedException(e);
288             throw jmse;
289         }
290 
291 
292     }
293 
294     public Connection createConnection(String userName, String passwordthrows JMSException
295     {
296         return createConnection(userName, password, null);
297     }
298     
299     public Connection createConnection(String userName, String password, String idthrows JMSException
300     {
301         try
302         {
303             if (_connectionDetails != null)
304             {
305                 _connectionDetails.setUsername(userName);
306                 _connectionDetails.setPassword(password);
307                 
308                 if (id != null && !id.equals(""))
309                 {
310                     _connectionDetails.setClientName(id);
311                 
312                 else if (_connectionDetails.getClientName() == null || _connectionDetails.getClientName().equals(""))
313                 {
314                     _connectionDetails.setClientName(getUniqueClientID());
315                 }
316                 return new AMQConnection(_connectionDetails, _sslConfig);
317             }
318             else
319             {
320                 return new AMQConnection(_host, _port, userName, password, (id != null ? id : getUniqueClientID()), _virtualPath);
321             }
322         }
323         catch (Exception e)
324         {
325             JMSException jmse = new JMSException("Error creating connection: " + e.getMessage());
326             jmse.setLinkedException(e);
327             throw jmse;
328         }
329     }
330 
331     public QueueConnection createQueueConnection() throws JMSException
332     {
333         return (QueueConnectioncreateConnection();
334     }
335 
336     public QueueConnection createQueueConnection(String username, String passwordthrows JMSException
337     {
338         return (QueueConnectioncreateConnection(username, password);
339     }
340 
341     public TopicConnection createTopicConnection() throws JMSException
342     {
343         return (TopicConnectioncreateConnection();
344     }
345 
346     public TopicConnection createTopicConnection(String username, String passwordthrows JMSException
347     {
348         return (TopicConnectioncreateConnection(username, password);
349     }
350 
351 
352     public ConnectionURL getConnectionURL()
353     {
354         return _connectionDetails;
355     }
356 
357     /**
358      * JNDI interface to create objects from References.
359      *
360      @param obj  The Reference from JNDI
361      @param name
362      @param ctx
363      @param env
364      *
365      @return AMQConnection,AMQTopic,AMQQueue, or AMQConnectionFactory.
366      *
367      @throws Exception
368      */
369     public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable envthrows Exception
370     {
371         if (obj instanceof Reference)
372         {
373             Reference ref = (Referenceobj;
374 
375             if (ref.getClassName().equals(AMQConnection.class.getName()))
376             {
377                 RefAddr addr = ref.get(AMQConnection.class.getName());
378 
379                 if (addr != null)
380                 {
381                     return new AMQConnection((Stringaddr.getContent());
382                 }
383             }
384 
385             if (ref.getClassName().equals(AMQQueue.class.getName()))
386             {
387                 RefAddr addr = ref.get(AMQQueue.class.getName());
388 
389                 if (addr != null)
390                 {
391                     return new AMQQueue(new AMQBindingURL((Stringaddr.getContent()));
392                 }
393             }
394 
395             if (ref.getClassName().equals(AMQTopic.class.getName()))
396             {
397                 RefAddr addr = ref.get(AMQTopic.class.getName());
398 
399                 if (addr != null)
400                 {
401                     return new AMQTopic(new AMQBindingURL((Stringaddr.getContent()));
402                 }
403             }
404 
405             if (ref.getClassName().equals(AMQConnectionFactory.class.getName()))
406             {
407                 RefAddr addr = ref.get(AMQConnectionFactory.class.getName());
408 
409                 if (addr != null)
410                 {
411                     return new AMQConnectionFactory((Stringaddr.getContent());
412                 }
413             }
414 
415         }
416         return null;
417     }
418 
419 
420     public Reference getReference() throws NamingException
421     {
422         return new Reference(
423                 AMQConnectionFactory.class.getName(),
424                 new StringRefAddr(AMQConnectionFactory.class.getName(), _connectionDetails.getURL()),
425                              AMQConnectionFactory.class.getName()null);          // factory location
426     }
427 
428     // ---------------------------------------------------------------------------------------------------
429     // the following methods are provided for XA compatibility
430     // Those methods are only supported by 0_10 and above 
431     // ---------------------------------------------------------------------------------------------------
432 
433     /**
434      * Creates a XAConnection with the default user identity.
435      <p> The XAConnection is created in stopped mode. No messages
436      * will be delivered until the <code>Connection.start</code> method
437      * is explicitly called.
438      *
439      @return A newly created XAConnection
440      @throws JMSException         If creating the XAConnection fails due to some internal error.
441      @throws JMSSecurityException If client authentication fails due to an invalid user name or password.
442      */
443     public XAConnection createXAConnection() throws JMSException
444     {
445         try
446         {
447             return new XAConnectionImpl(_connectionDetails, _sslConfig);
448         }
449         catch (Exception e)
450         {
451             JMSException jmse = new JMSException("Error creating connection: " + e.getMessage());
452             jmse.setLinkedException(e);
453             throw jmse;
454         }
455     }
456 
457     /**
458      * Creates a XAConnection with the specified user identity.
459      <p> The XAConnection is created in stopped mode. No messages
460      * will be delivered until the <code>Connection.start</code> method
461      * is explicitly called.
462      *
463      @param username the caller's user name
464      @param password the caller's password
465      @return A newly created XAConnection.
466      @throws JMSException         If creating the XAConnection fails due to some internal error.
467      @throws JMSSecurityException If client authentication fails due to an invalid user name or password.
468      */
469     public XAConnection createXAConnection(String username, String passwordthrows JMSException
470     {
471         if (_connectionDetails != null)
472         {
473             _connectionDetails.setUsername(username);
474             _connectionDetails.setPassword(password);
475 
476             if (_connectionDetails.getClientName() == null || _connectionDetails.getClientName().equals(""))
477             {
478                 _connectionDetails.setClientName(getUniqueClientID());
479             }
480         }
481         else
482         {
483             throw new JMSException("A URL must be specified to access XA connections");
484         }
485         return createXAConnection();
486     }
487 
488 
489     /**
490      * Creates a XATopicConnection with the default user identity.
491      <p> The XATopicConnection is created in stopped mode. No messages
492      * will be delivered until the <code>Connection.start</code> method
493      * is explicitly called.
494      *
495      @return A newly created XATopicConnection
496      @throws JMSException         If creating the XATopicConnection fails due to some internal error.
497      @throws JMSSecurityException If client authentication fails due to an invalid user name or password.
498      */
499     public XATopicConnection createXATopicConnection() throws JMSException
500     {
501         return (XATopicConnectioncreateXAConnection();
502     }
503 
504     /**
505      * Creates a XATopicConnection with the specified user identity.
506      <p> The XATopicConnection is created in stopped mode. No messages
507      * will be delivered until the <code>Connection.start</code> method
508      * is explicitly called.
509      *
510      @param username the caller's user name
511      @param password the caller's password
512      @return A newly created XATopicConnection.
513      @throws JMSException         If creating the XATopicConnection fails due to some internal error.
514      @throws JMSSecurityException If client authentication fails due to an invalid user name or password.
515      */
516     public XATopicConnection createXATopicConnection(String username, String passwordthrows JMSException
517     {
518          return (XATopicConnectioncreateXAConnection(username, password);
519     }
520 
521     /**
522      * Creates a XAQueueConnection with the default user identity.
523      <p> The XAQueueConnection is created in stopped mode. No messages
524      * will be delivered until the <code>Connection.start</code> method
525      * is explicitly called.
526      *
527      @return A newly created XAQueueConnection
528      @throws JMSException         If creating the XAQueueConnection fails due to some internal error.
529      @throws JMSSecurityException If client authentication fails due to an invalid user name or password.
530      */
531     public XAQueueConnection createXAQueueConnection() throws JMSException
532     {
533        return (XAQueueConnectioncreateXAConnection();
534     }
535 
536     /**
537      * Creates a XAQueueConnection with the specified user identity.
538      <p> The XAQueueConnection is created in stopped mode. No messages
539      * will be delivered until the <code>Connection.start</code> method
540      * is explicitly called.
541      *
542      @param username the caller's user name
543      @param password the caller's password
544      @return A newly created XAQueueConnection.
545      @throws JMSException         If creating the XAQueueConnection fails due to some internal error.
546      @throws JMSSecurityException If client authentication fails due to an invalid user name or password.
547      */
548     public XAQueueConnection createXAQueueConnection(String username, String passwordthrows JMSException
549     {
550         return (XAQueueConnectioncreateXAConnection(username, password);
551     }
552 }