/*
* Copyright 2003,2004 Colin Crist
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package hermes.impl.jms;
import hermes.Domain;
import hermes.Hermes;
import hermes.HermesException;
import hermes.JNDIQueueConnectionFactory;
import hermes.browser.HermesBrowser;
import hermes.config.DestinationConfig;
import hermes.config.FactoryConfig;
import hermes.config.SessionConfig;
import hermes.impl.ConnectionFactoryManagerImpl;
import hermes.impl.ConnectionManager;
import hermes.impl.DestinationManager;
import hermes.impl.JMSManagerImpl;
import hermes.impl.LoaderSupport;
import hermes.impl.SessionManager;
import hermes.impl.TopicBrowser;
import hermes.util.JMSUtils;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.IllegalStateException;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.QueueBrowser;
import javax.jms.QueueConnection;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TopicConnection;
import javax.jms.TopicSession;
import javax.naming.NamingException;
import org.apache.log4j.Logger;
/**
* Generic session management helper.
*
* @author colincrist@hermesjms.com
* @version $Id: AbstractSessionManager.java,v 1.1 2004/07/21 20:25:40
* colincrist Exp $
*/
public abstract class AbstractSessionManager extends JMSManagerImpl implements SessionManager {
private static final Logger log = Logger.getLogger(AbstractSessionManager.class);
private FactoryConfig factoryConfig;
private boolean transacted = true;
private String id;
private int reconnects = -1;
private long reconnectTimeout = 30 * 1000;
private boolean audit = false;
private String auditDirectory = ".";
private ConnectionFactoryManagerImpl myCFManager;
private int acknowledgeMode = Session.CLIENT_ACKNOWLEDGE;
private DestinationManager destinationManager;
private Map destinationToConfigMap = new HashMap();
private SessionConfig config;
public AbstractSessionManager(DestinationManager destinationManager, SessionConfig config) {
this.destinationManager = destinationManager;
this.config = config;
}
public SessionConfig getConfig() {
return config;
}
/**
* Get the session, creating is as needed.
*
* @return
* @throws JMSException
*/
public abstract Session getSession() throws JMSException;
/**
* Get a consumer for a destination. The consumer is cached thread local.
*/
public abstract MessageConsumer getConsumer(Destination d) throws JMSException;
/**
* Get a consumer for a destination and a selector. The consumer is cached
* thread local.
*/
public abstract MessageConsumer getConsumer(Destination d, String selector) throws JMSException;
protected Session createSession() throws JMSException {
try {
return doCreateSession();
} catch (IllegalStateException ex) {
try {
close();
} catch (JMSException e) {
log.error("closing session: " + e.getMessage(), e);
}
try {
getConnectionManager().close();
} catch (JMSException e) {
log.error("closing connection: " + e.getMessage(), e);
}
return doCreateSession();
}
}
/**
* Create a session based on configured options.
*/
private Session doCreateSession() throws JMSException {
Session session = null;
Connection conn = (Connection) parent.getObject();
try {
ConnectionFactory connectionFactory = getConnectionFactoryManager().getConnectionFactory();
/**
* Hack so that although the interface seems to be JMS 1.1, if its
* WebMethods only use the JMS 1.0.2b methods.
*/
boolean isWebMethodsHack = false;
if (connectionFactory instanceof JNDIQueueConnectionFactory) {
JNDIQueueConnectionFactory jndiCF = (JNDIQueueConnectionFactory) connectionFactory;
if (jndiCF.getInitialContextFactory() != null && jndiCF.getInitialContextFactory().equals("hermes.ext.wme.WMEInitialContextFactory")) {
isWebMethodsHack = true;
}
}
if (!isWebMethodsHack) {
session = conn.createSession(isTransacted(), getAcknowledgeMode());
log.debug("session created using JMS 1.1 interface");
}
} catch (NoSuchMethodError ex) {
// NOP
} catch (AbstractMethodError ex) {
// NOP
}
if (session == null) {
if (JMSUtils.isQueue(conn)) {
session = ((QueueConnection) conn).createQueueSession(isTransacted(), getAcknowledgeMode());
} else {
session = ((TopicConnection) conn).createTopicSession(isTransacted(), getAcknowledgeMode());
}
log.debug("session created using JMS 1.0.2b interface");
}
return session;
}
public int getAcknowledgeMode() {
log.debug("acknowledgeMode = " + (isTransacted() ? "Session.CLIENT_ACKNOWLEDGE" : "Session.AUTO_ACKNOWLEDGE"));
return isTransacted() ? Session.CLIENT_ACKNOWLEDGE : Session.AUTO_ACKNOWLEDGE;
}
/**
* Get some identifier for this session manager
*/
public String getId() {
return id;
}
/**
* Returned the managed object, in this case the session.
*/
public Object getObject() throws JMSException {
return getSession();
}
/**
* Set the transaction policy
*/
public void setTransacted(boolean transacted) {
this.transacted = transacted;
}
public boolean isTransacted() {
return transacted;
}
/**
* Set the ID.
*/
public void setId(String id) {
this.id = id;
}
/**
* Set the parent
*/
public void setParent(JMSManagerImpl parent) {
super.setParent(parent);
}
/**
* Set the number of times we want to try and reconnect
*/
public void setReconnects(int reconnects) {
this.reconnects = reconnects;
}
/**
* Set the period to try reconnects
*/
public void setReconnectTimeout(Long reconnectTimeout) {
this.reconnectTimeout = reconnectTimeout.longValue();
}
/**
* Get the connection factory manager, that is the parent.
*/
public ConnectionFactoryManagerImpl getConnectionFactoryManager() {
if (myCFManager == null) {
synchronized (this) {
if (myCFManager == null && parent != null) {
myCFManager = (ConnectionFactoryManagerImpl) parent.getParent();
}
}
}
return myCFManager;
}
/**
* @return
*/
public boolean isAudit() {
return audit;
}
/**
* @return
*/
public String getAuditDirectory() {
return auditDirectory;
}
/**
* @param b
*/
public void setAudit(boolean b) {
audit = b;
}
/**
* @param string
*/
public void setAuditDirectory(String string) {
auditDirectory = string;
}
/**
* When reconnects is set > 1 this timeout is used between reconnet attempts
*/
public long getReconnectTimeout() {
return reconnectTimeout;
}
/**
* When reconnects is set > 1 this timeout is used between reconnet attempts
*/
public void setReconnectTimeout(long reconnectTimeout) {
this.reconnectTimeout = reconnectTimeout;
}
public int getReconnects() {
return reconnects;
}
public void setFactoryConfig(FactoryConfig factoryConfig) {
this.factoryConfig = factoryConfig;
}
public FactoryConfig getFactoryConfig() {
return factoryConfig;
}
/**
* Get the connection factory.
*/
public ConnectionFactory getConnectionFactory() throws JMSException {
return getConnectionFactoryManager().getConnectionFactory();
}
/**
* Get the connection.
*/
public Connection getConnection() throws JMSException {
return (Connection) parent.getObject();
}
public QueueBrowser createBrowser(Hermes hermes, DestinationConfig config) throws JMSException {
if (config.getDomain() == Domain.QUEUE.getId()) {
final Queue queue = (Queue) destinationManager.getDestination(getSession(), config.getName(), Domain.QUEUE);
try {
if (config.getSelector() != null) {
return getSession().createBrowser(queue, config.getSelector());
} else {
return getSession().createBrowser(queue);
}
} catch (NoSuchMethodError ex) {
// NOP
} catch (AbstractMethodError ex) {
// NOP
}
if (!(getSession() instanceof QueueSession)) {
throw new HermesException("Session is 1.0.2 and not in the queue domain");
}
if (config.getSelector() != null) {
return ((QueueSession) getSession()).createBrowser(queue, config.getSelector());
} else {
return ((QueueSession) getSession()).createBrowser(queue);
}
} else if (config.getDomain() == Domain.TOPIC.getId()) {
return new TopicBrowser(hermes.getSession(), destinationManager, config);
} else {
throw new HermesException("The domain for " + config.getName() + " is not defined, configure it as a queue or a topic");
}
}
/**
* Create browser, can be used with topics too.
*/
public QueueBrowser createBrowser(Hermes hermes, Destination destination, String selector) throws JMSException {
final DestinationConfig dConfig = HermesBrowser.getConfigDAO().duplicate(getDestinationConfig(destination));
if (dConfig.getSelector() == null) {
dConfig.setSelector(selector);
}
return createBrowser(hermes, dConfig);
}
/**
* Get an iterator over all the <i>statically configured </i> destinations.
*/
public Collection getDestinations() {
return getConnectionFactoryManager().getDestinationConfigs();
}
/**
* Get the destination specific configuration
*/
public DestinationConfig getDestinationConfig(String d, Domain domain) throws JMSException {
return getConnectionFactoryManager().getDestinationConfig(d, domain);
}
/*
* (non-Javadoc)
*
* @see hermes.impl.SessionManager#getDestination(java.lang.String)
*/
public Destination getDestination(String named, Domain domain) throws JMSException, NamingException {
Destination rval = destinationManager.getDestination(getSession(), named, domain);
DestinationConfig config = getDestinationConfig(named, domain);
if (config != null) {
destinationToConfigMap.put(rval, getDestinationConfig(named, domain));
if (config.getProperties() != null) {
try {
LoaderSupport.populateBean(rval, config.getProperties());
} catch (Exception ex) {
throw new HermesException(ex);
}
}
}
return rval;
}
public DestinationConfig getDestinationConfig(Destination d) {
return (DestinationConfig) destinationToConfigMap.get(d);
}
/*
* (non-Javadoc)
*
* @see hermes.impl.SessionManager#getConnectionManager()
*/
public ConnectionManager getConnectionManager() throws JMSException {
return (ConnectionManager) parent;
}
/**
* Get a producer, producers are cached on thread local.
*/
protected MessageProducer createQueueProducer() throws JMSException {
return ((QueueSession) getSession()).createSender(null);
}
/**
* Get a producer, producers are cached on thread local.
*/
protected MessageProducer createTopicProducer() throws JMSException {
return ((TopicSession) getSession()).createPublisher(null);
}
public DestinationManager getDestinationManager() {
return destinationManager;
}
/**
* Return a verbose description of this session.
*/
public String toString() {
return (getConnectionFactoryManager() == null) ? super.toString() : getConnectionFactoryManager().toString();
}
}