001 /* 002 * Copyright (C) The Apache Software Foundation. All rights reserved. 003 * 004 * This software is published under the terms of the Apache Software License 005 * version 1.1, a copy of which has been included with this distribution in 006 * the LICENSE file. 007 * 008 * $Id: SessionFactory.java 155459 2005-02-26 13:24:44Z dirkv $ 009 */ 010 package org.apache.commons.messenger; 011 012 import java.util.Properties; 013 014 import javax.jms.Connection; 015 import javax.jms.ConnectionFactory; 016 import javax.jms.JMSException; 017 import javax.jms.MessageListener; 018 import javax.jms.QueueConnection; 019 import javax.jms.QueueConnectionFactory; 020 import javax.jms.ServerSessionPool; 021 import javax.jms.Session; 022 import javax.jms.TopicConnection; 023 import javax.jms.TopicConnectionFactory; 024 025 import org.apache.commons.logging.Log; 026 import org.apache.commons.logging.LogFactory; 027 028 /** <p><code>SessionFactory</code> is a Factory of JMS Session objects. 029 * It can be configured with a JMS Connection object to use or can use 030 * a JMS ConnectionFactory instance to create the JMS Connection lazily</p> 031 * 032 * @author <a href="mailto:jstrachan@apache.org">James Strachan</a> 033 * @version $Revision: 155459 $ 034 */ 035 public class SessionFactory { 036 037 /** Logger */ 038 private static final Log log = LogFactory.getLog(SessionFactory.class); 039 040 /** The JMS connection used to create JMS sessions */ 041 private Connection connection; 042 043 /** The JMS ConnectionFactory used to create JMS Connection instances */ 044 private ConnectionFactory connectionFactory; 045 046 /** JMS acknowlege mode used on each session */ 047 private int acknowlegeMode = Session.AUTO_ACKNOWLEDGE; 048 049 /** whether JMS sessions should be transacted */ 050 private boolean transacted; 051 052 /** the optional username used when creating a new JMS connection via a JMS ConnectionFactory */ 053 private String username; 054 055 /** the optional password used when creating a new JMS connection via a JMS ConnectionFactory */ 056 private String password; 057 058 /** the properties used to create the connection */ 059 protected Properties properties; 060 061 /** Whether to use a Topic or Queue connection/session */ 062 private boolean topic = true; 063 064 /** The client ID for the connection */ 065 private String clientID; 066 067 /** Creates a new Session instance */ 068 public Session createSession(Connection connection) throws JMSException { 069 if ( log.isDebugEnabled() ) { 070 log.debug( 071 "Creating a JMS session in transacted mode: " 072 + isTransacted() + " with ack mode: " + getAcknowledgeMode() 073 ); 074 } 075 076 if (topic) { 077 TopicConnection topicConnection = (TopicConnection) connection; 078 return topicConnection.createTopicSession(isTransacted(), getAcknowledgeMode()); 079 } 080 else { 081 QueueConnection queueConnection = (QueueConnection) connection; 082 return queueConnection.createQueueSession(isTransacted(), getAcknowledgeMode()); 083 } 084 } 085 086 /** Creates a new Session instance */ 087 public Session createSession() throws JMSException { 088 Connection connection = getConnection(); 089 if (topic) { 090 TopicConnection topicConnection = (TopicConnection) connection; 091 return topicConnection.createTopicSession(isTransacted(), getAcknowledgeMode()); 092 } 093 else { 094 QueueConnection queueConnection = (QueueConnection) connection; 095 return queueConnection.createQueueSession(isTransacted(), getAcknowledgeMode()); 096 } 097 } 098 099 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 }