View Javadoc

1   /*
2    * Copyright (C) The Apache Software Foundation. All rights reserved.
3    *
4    * This software is published under the terms of the Apache Software License
5    * version 1.1, a copy of which has been included with this distribution in
6    * the LICENSE file.
7    * 
8    * $Id: SessionFactory.java 155459 2005-02-26 13:24:44Z dirkv $
9    */
10  package org.apache.commons.messenger;
11  
12  import java.util.Properties;
13  
14  import javax.jms.Connection;
15  import javax.jms.ConnectionFactory;
16  import javax.jms.JMSException;
17  import javax.jms.MessageListener;
18  import javax.jms.QueueConnection;
19  import javax.jms.QueueConnectionFactory;
20  import javax.jms.ServerSessionPool;
21  import javax.jms.Session;
22  import javax.jms.TopicConnection;
23  import javax.jms.TopicConnectionFactory;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  
28  /** <p><code>SessionFactory</code> is a Factory of JMS Session objects.
29    * It can be configured with a JMS Connection object to use or can use 
30    * a JMS ConnectionFactory instance to create the JMS Connection lazily</p>
31    *
32    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
33    * @version $Revision: 155459 $
34    */
35  public class SessionFactory {
36  
37      /** Logger */
38      private static final Log log = LogFactory.getLog(SessionFactory.class);
39  
40      /** The JMS connection used to create JMS sessions */
41      private Connection connection;
42  
43      /** The JMS ConnectionFactory used to create JMS Connection instances */
44      private ConnectionFactory connectionFactory;
45  
46      /** JMS acknowlege mode used on each session */
47      private int acknowlegeMode = Session.AUTO_ACKNOWLEDGE;
48  
49      /** whether JMS sessions should be transacted */
50      private boolean transacted;
51  
52      /** the optional username used when creating a new JMS connection via a JMS ConnectionFactory */
53      private String username;
54  
55      /** the optional password used when creating a new JMS connection via a JMS ConnectionFactory */
56      private String password;
57  
58      /** the properties used to create the connection */
59      protected Properties properties;
60  
61      /** Whether to use a Topic or Queue connection/session */
62      private boolean topic = true;
63  
64      /** The client ID for the connection */
65      private String clientID;
66      
67      /** Creates a new Session instance */
68      public Session createSession(Connection connection) throws JMSException {
69          if ( log.isDebugEnabled() ) {
70              log.debug( 
71                  "Creating a JMS session in transacted mode: " 
72                  + isTransacted() + " with ack mode: " + getAcknowledgeMode() 
73              );
74          }
75          
76          if (topic) {
77              TopicConnection topicConnection = (TopicConnection) connection;
78              return topicConnection.createTopicSession(isTransacted(), getAcknowledgeMode());
79          }
80          else {
81              QueueConnection queueConnection = (QueueConnection) connection;
82              return queueConnection.createQueueSession(isTransacted(), getAcknowledgeMode());
83          }
84      }
85  
86      /** Creates a new Session instance */
87      public Session createSession() throws JMSException {
88          Connection connection = getConnection();
89          if (topic) {
90              TopicConnection topicConnection = (TopicConnection) connection;
91              return topicConnection.createTopicSession(isTransacted(), getAcknowledgeMode());
92          }
93          else {
94              QueueConnection queueConnection = (QueueConnection) connection;
95              return queueConnection.createQueueSession(isTransacted(), getAcknowledgeMode());
96          }
97      }
98  
99      public ServerSessionPool createServerSessionPool(
100         MessageListener messageListener,
101         int maxThreads)
102         throws JMSException {
103         return new DefaultServerSessionPool(this, messageListener, maxThreads);
104     }
105 
106     /** Factory method used to create a connection */
107     public Connection createConnection() throws JMSException {
108         ConnectionFactory factory = getConnectionFactory();
109         if (factory == null) {
110             throw new JMSException("No ConnectionFactory configured. Cannot create a JMS Session");
111         }
112         if (log.isDebugEnabled()) {
113             log.debug("About to create a connection from: " + factory);
114         }
115         if (topic) {
116             return createTopicConnection((TopicConnectionFactory) factory);
117         }
118         else {
119             return createQueueConnection((QueueConnectionFactory) factory);
120         }
121     }
122 
123     /** Closes the JMS Connection that this object is using, if any */
124     public synchronized void close() throws JMSException {
125         if (connection != null) {
126             Connection tmp = connection;
127             connection = null;
128             tmp.close();
129         }
130     }
131 
132 
133     // Properties
134     //-------------------------------------------------------------------------    
135     /** Returns the JMS connection used to create new sessions */
136     public Connection getConnection() throws JMSException {
137         if (connection == null) {
138             setConnection(createConnection());
139             connection.start();
140         }
141         return connection;
142     }
143 
144     public void setConnection(Connection connection) throws JMSException {
145         this.connection = connection;
146         // change the topic flag if the wrong topic/queue type
147         if (topic) {
148             if (!(connection instanceof TopicConnection)) {
149                 setTopic(false);
150             }
151         }
152         else {
153             if (!(connection instanceof QueueConnection)) {
154                 setTopic(true);
155             }
156         }
157         
158         // assign a clientID if one is set
159         if (clientID != null) {
160             connection.setClientID(clientID);                
161         }
162     }
163 
164     /** Returns the JMS ConnectionFactory used to create a new connection */
165     public ConnectionFactory getConnectionFactory() throws JMSException {
166         if (connectionFactory == null) {
167             setConnectionFactory(createConnectionFactory());
168         }
169         return connectionFactory;
170     }
171 
172     public void setConnectionFactory(ConnectionFactory connectionFactory) {
173         this.connectionFactory = connectionFactory;
174         // change the topic flag if the wrong topic/queue type
175         if (topic) {
176             if (!(connectionFactory instanceof TopicConnectionFactory)) {
177                 setTopic(false);
178             }
179         }
180         else {
181             if (!(connectionFactory instanceof QueueConnectionFactory)) {
182                 setTopic(true);
183             }
184         }
185     }
186 
187     /** Returns true if sessions created by this factory should be transacted */
188     public boolean isTransacted() {
189         return transacted;
190     }
191 
192     public void setTransacted(boolean transacted) {
193         this.transacted = transacted;
194     }
195 
196     /** Returns the JMS acknowledge mode used by the JMS sessions created by this session */
197     public int getAcknowledgeMode() {
198         return acknowlegeMode;
199     }
200 
201     public void setAcknowledgeMode(int acknowlegeMode) {
202         this.acknowlegeMode = acknowlegeMode;
203     }
204     
205     /**
206      * A String based setter method to allow this property to be defined
207      * easily from within the digester XML file.
208      * 
209      * @param value is either "auto", "client" or "dups_ok"
210      * @throws IllegalArgumentException if the value is not one of the correct values 
211      */
212     public void setAcknowledge(String value) {
213     	if (value != null) {
214     		if (value.equalsIgnoreCase("auto")) {
215     			setAcknowledgeMode(Session.AUTO_ACKNOWLEDGE);
216     		}
217     		else if (value.equalsIgnoreCase("client")) {
218     			setAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
219     		}
220     		else if (value.equalsIgnoreCase("dups_ok")) {
221     			setAcknowledgeMode(Session.DUPS_OK_ACKNOWLEDGE);
222     		}
223     		else {
224     			throw new IllegalArgumentException(
225 					"Value: " + value 
226 					+ " is invalid. Must be 'auto', 'client' or 'dups_ok'"
227 				);
228     		}
229     	}
230     }
231 
232     /** Returns the optional username used when creating a new JMS connection via a JMS ConnectionFactory */
233     public String getUsername() {
234         return username;
235     }
236 
237     public void setUsername(String username) {
238         this.username = username;
239     }
240 
241     /** Returns the optional password used when creating a new JMS connection via a JMS ConnectionFactory */
242     public String getPassword() {
243         return password;
244     }
245 
246     public void setPassword(String password) {
247         this.password = password;
248     }
249 
250     /** Returns the Properties that can be used to configure the connection creation */
251     public Properties getProperties() {
252         if (properties == null) {
253             properties = createProperties();
254         }
255         return properties;
256     }
257 
258     public void setProperties(Properties properties) {
259         this.properties = properties;
260     }
261 
262     public void addProperty(String name, String value) {
263         getProperties().setProperty(name, value);
264     }
265 
266     /** @return whether to use a Topic or Queue connection/session */
267     public boolean isTopic() {
268         return topic;
269     }
270 
271     /** Sets whether to use a Topic or Queue connection/session */
272     public void setTopic(boolean topic) {
273         this.topic = topic;
274     }
275 
276     /**
277      * Returns the clientID used on the current connection.
278      * @return String
279      */
280     public String getClientID() {
281         return clientID;
282     }
283 
284     /**
285      * Sets the clientID used on the current connection.
286      * @param clientID The clientID to set
287      */
288     public void setClientID(String clientID) {
289         this.clientID = clientID;
290     }
291 
292 
293     // Implementation methods
294     //-------------------------------------------------------------------------    
295     protected QueueConnection createQueueConnection(QueueConnectionFactory queueConnectionFactory)
296         throws JMSException {
297         if (username != null || password != null) {
298             return queueConnectionFactory.createQueueConnection(username, password);
299         }
300         else {
301             return queueConnectionFactory.createQueueConnection();
302         }
303     }
304 
305     protected TopicConnection createTopicConnection(TopicConnectionFactory topicConnectionFactory)
306         throws JMSException {
307         if (username != null || password != null) {
308             return topicConnectionFactory.createTopicConnection(username, password);
309         }
310         else {
311             return topicConnectionFactory.createTopicConnection();
312         }
313     }
314 
315     /** Factory method used to create a connection factory. 
316       * Derived classes may wish to use JNDI to load the ConnectionFactory
317       */
318     protected ConnectionFactory createConnectionFactory() throws JMSException {
319         return null;
320     }
321 
322     /** Factory method used to create the initial JNDI context properties.
323       * Derived classes may wish to overload this method to provide different properties
324       */
325     protected Properties createProperties() {
326         try {
327             return new Properties(System.getProperties());
328         }
329         catch (Throwable e) {
330             // security exceptoin
331             return new Properties();
332         }
333     }
334 }