/*
* JBoss, Home of Professional Open Source.
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.resource.adapter.jms;
import java.util.HashSet;
import java.util.Iterator;
import javax.jms.ConnectionConsumer;
import javax.jms.ConnectionMetaData;
import javax.jms.Destination;
import javax.jms.ExceptionListener;
import javax.jms.IllegalStateException;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueSession;
import javax.jms.ServerSessionPool;
import javax.jms.Session;
import javax.jms.TemporaryQueue;
import javax.jms.TemporaryTopic;
import javax.jms.Topic;
import javax.jms.TopicSession;
import javax.naming.Reference;
import javax.resource.Referenceable;
import javax.resource.ResourceException;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ManagedConnectionFactory;
import org.jboss.logging.Logger;
import org.jboss.resource.connectionmanager.JTATransactionChecker;
/**
* Implements the JMS Connection API and produces {@link JmsSession} objects.
*
* @author <a href="mailto:peter.antman@tim.se">Peter Antman</a>.
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @author <a href="mailto:adrian@jboss.com">Adrian Brock</a>
* @version <tt>$Revision: 85245 $</tt>
*/
public class JmsSessionFactoryImpl
implements JmsSessionFactory, Referenceable
{
private static final Logger log = Logger.getLogger(JmsSessionFactoryImpl.class);
/** Are we closed? */
private boolean closed = false;
/** Whether trace is enabled */
private boolean trace = log.isTraceEnabled();
private Reference reference;
// Used from JmsConnectionFactory
private String userName;
private String password;
private String clientID;
private int type;
/* Whether we are started */
private boolean started = false;
/** JmsRa own factory */
private JmsManagedConnectionFactory mcf;
/** Hook to the appserver */
private ConnectionManager cm;
/** The sessions */
private HashSet sessions = new HashSet();
/** The temporary queues */
private HashSet tempQueues = new HashSet();
/** The temporary topics */
private HashSet tempTopics = new HashSet();
public JmsSessionFactoryImpl(final ManagedConnectionFactory mcf,
final ConnectionManager cm,
final int type)
{
this.mcf = (JmsManagedConnectionFactory) mcf;
this.cm = cm;
if (cm == null)
// This is standalone usage, no appserver
this.cm = new JmsConnectionManager();
else
this.cm = cm;
this.type = type;
if (trace)
log.trace("mcf=" + mcf + ", cm=" + cm + ", type=" + type);
}
public void setReference(final Reference reference)
{
this.reference = reference;
}
public Reference getReference()
{
return reference;
}
// --- API for JmsConnectionFactoryImpl
public void setUserName(final String name)
{
userName = name;
}
public void setPassword(final String password)
{
this.password = password;
}
//---- QueueConnection ---
public QueueSession createQueueSession(final boolean transacted,
final int acknowledgeMode)
throws JMSException
{
checkClosed();
if (type == JmsConnectionFactory.TOPIC)
throw new IllegalStateException("Can not get a queue session from a topic connection");
return allocateConnection(transacted, acknowledgeMode, type);
}
public ConnectionConsumer createConnectionConsumer
(Queue queue,
String messageSelector,
ServerSessionPool sessionPool,
int maxMessages)
throws JMSException
{
throw new IllegalStateException(ISE);
}
//--- TopicConnection ---
public TopicSession createTopicSession(final boolean transacted,
final int acknowledgeMode)
throws JMSException
{
checkClosed();
if (type == JmsConnectionFactory.QUEUE)
throw new IllegalStateException("Can not get a topic session from a queue connection");
return allocateConnection(transacted, acknowledgeMode, type);
}
public ConnectionConsumer createConnectionConsumer
(Topic topic,
String messageSelector,
ServerSessionPool sessionPool,
int maxMessages)
throws JMSException
{
throw new IllegalStateException(ISE);
}
public ConnectionConsumer createDurableConnectionConsumer(
Topic topic,
String subscriptionName,
String messageSelector,
ServerSessionPool sessionPool,
int maxMessages)
throws JMSException
{
throw new IllegalStateException(ISE);
}
//--- All the Connection methods
public String getClientID() throws JMSException
{
checkClosed();
if (clientID == null)
return mcf.getClientID();
return clientID;
}
public void setClientID(String cID) throws JMSException
{
if (mcf.isStrict())
throw new IllegalStateException(ISE);
checkClosed();
if (clientID != null)
throw new IllegalStateException("Cannot change client id");
clientID = cID;
}
public ConnectionMetaData getMetaData() throws JMSException
{
checkClosed();
return mcf.getMetaData();
}
public ExceptionListener getExceptionListener() throws JMSException
{
throw new IllegalStateException(ISE);
}
public void setExceptionListener(ExceptionListener listener)
throws JMSException
{
throw new IllegalStateException(ISE);
}
public void start() throws JMSException
{
checkClosed();
if (trace)
log.trace("start() " + this);
synchronized (sessions)
{
if (started)
return;
started = true;
for (Iterator i = sessions.iterator(); i.hasNext();)
{
JmsSession session = (JmsSession) i.next();
session.start();
}
}
}
public void stop() throws JMSException
{
if (mcf.isStrict())
throw new IllegalStateException(ISE);
checkClosed();
if (trace)
log.trace("stop() " + this);
synchronized (sessions)
{
if (started == false)
return;
started = true;
for (Iterator i = sessions.iterator(); i.hasNext();)
{
JmsSession session = (JmsSession) i.next();
session.stop();
}
}
}
public void close() throws JMSException
{
if (closed)
return;
closed = true;
if (trace)
log.trace("close() " + this);
synchronized (sessions)
{
for (Iterator i = sessions.iterator(); i.hasNext();)
{
JmsSession session = (JmsSession) i.next();
try
{
session.closeSession();
}
catch (Throwable t)
{
log.trace("Error closing session", t);
}
i.remove();
}
}
synchronized (tempQueues)
{
for (Iterator i = tempQueues.iterator(); i.hasNext();)
{
TemporaryQueue temp = (TemporaryQueue) i.next();
try
{
if (trace)
log.trace("Closing temporary queue " + temp + " for " + this);
temp.delete();
}
catch (Throwable t)
{
log.trace("Error deleting temporary queue", t);
}
i.remove();
}
}
synchronized (tempTopics)
{
for (Iterator i = tempTopics.iterator(); i.hasNext();)
{
TemporaryTopic temp = (TemporaryTopic) i.next();
try
{
if (trace)
log.trace("Closing temporary topic " + temp + " for " + this);
temp.delete();
}
catch (Throwable t)
{
log.trace("Error deleting temporary queue", t);
}
i.remove();
}
}
}
public void closeSession(JmsSession session) throws JMSException
{
synchronized (sessions)
{
sessions.remove(session);
}
}
public void addTemporaryQueue(TemporaryQueue temp)
{
synchronized(tempQueues)
{
tempQueues.add(temp);
}
}
public void addTemporaryTopic(TemporaryTopic temp)
{
synchronized(tempTopics)
{
tempTopics.add(temp);
}
}
// -- JMS 1.1
public ConnectionConsumer createConnectionConsumer(Destination destination, ServerSessionPool pool, int maxMessages) throws JMSException
{
throw new IllegalStateException(ISE);
}
public ConnectionConsumer createConnectionConsumer(Destination destination, String name, ServerSessionPool pool, int maxMessages) throws JMSException
{
throw new IllegalStateException(ISE);
}
public Session createSession(boolean transacted, int acknowledgeMode)
throws JMSException
{
checkClosed();
return allocateConnection(transacted, acknowledgeMode, type);
}
protected JmsSession allocateConnection(boolean transacted, int acknowledgeMode, int sessionType) throws JMSException
{
try
{
synchronized (sessions)
{
if (mcf.isStrict() && sessions.isEmpty() == false)
throw new IllegalStateException("Only allowed one session per connection. See the J2EE spec, e.g. J2EE1.4 Section 6.6");
if (transacted)
acknowledgeMode = Session.SESSION_TRANSACTED;
JmsConnectionRequestInfo info = new JmsConnectionRequestInfo(transacted, acknowledgeMode, sessionType);
info.setUserName(userName);
info.setPassword(password);
info.setClientID(clientID);
info.setDefaults(mcf.getProperties());
if (trace)
log.trace("Allocating session for " + this + " with request info=" + info);
JmsSession session = (JmsSession) cm.allocateConnection(mcf, info);
try
{
if (trace)
log.trace("Allocated " + this + " session=" + session);
session.setJmsSessionFactory(this);
if (started)
session.start();
sessions.add(session);
return session;
}
catch (Throwable t)
{
try
{
session.close();
}
catch (Throwable ignored)
{
}
if (t instanceof Exception)
throw (Exception) t;
else
throw new RuntimeException("Unexpected error: ", t);
}
}
}
catch (Exception e)
{
log.error("could not create session", e);
JMSException je = new JMSException
("Could not create a session: " + e);
je.setLinkedException(e);
throw je;
}
}
protected void checkClosed() throws IllegalStateException
{
if (closed)
throw new IllegalStateException("The connection is closed");
checkTransactionActive();
}
/**
* Check whether a tranasction is active
*
* @throws IllegalStateException if the transaction is not active, preparing, prepared or committing or for any error in the transaction manager
*/
protected void checkTransactionActive() throws IllegalStateException
{
if (cm == null)
throw new IllegalStateException("No connection manager");
try
{
if (cm instanceof JTATransactionChecker)
((JTATransactionChecker) cm).checkTransactionActive();
}
catch (Exception e)
{
IllegalStateException ex = new IllegalStateException("Transaction not active");
ex.initCause(e);
ex.setLinkedException(e);
throw ex;
}
}
}