summaryrefslogtreecommitdiff
path: root/java/jca/src
diff options
context:
space:
mode:
authorAndrew Stitcher <astitcher@apache.org>2011-12-18 05:09:07 +0000
committerAndrew Stitcher <astitcher@apache.org>2011-12-18 05:09:07 +0000
commitfb08688252d1043b202e1b88a9cd5b37da67794c (patch)
tree918cb48793f3c686e52f8ccf714b306a65f53852 /java/jca/src
parentd9ff8e43999e4c59d4092064a6e2c80773534864 (diff)
downloadqpid-python-fb08688252d1043b202e1b88a9cd5b37da67794c.tar.gz
QPID-3044: Implement JCA Adapter for Java JMS client
- Large contributions from Weston Price & Kevin Conner git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk/qpid@1220336 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/jca/src')
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryObjectFactory.java62
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryProperties.java215
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRABytesMessage.java462
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactory.java58
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactoryImpl.java442
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionManager.java80
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionMetaData.java208
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionRequestInfo.java361
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRACredential.java245
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAException.java70
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRALocalTransaction.java129
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAMCFProperties.java177
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java880
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnectionFactory.java623
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAMapMessage.java457
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java782
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageConsumer.java353
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageListener.java74
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageProducer.java419
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAMetaData.java116
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAObjectMessage.java85
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAProperties.java186
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueBrowser.java139
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueReceiver.java70
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueSender.java147
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRASession.java33
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactory.java62
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactoryImpl.java911
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java1732
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAStreamMessage.java415
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRATextMessage.java83
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicPublisher.java220
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicSubscriber.java86
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidRAXAResource.java245
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/QpidResourceAdapter.java820
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/Util.java184
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/admin/AdminObjectFactory.java74
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/admin/QpidBindingURL.java52
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxy.java156
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/admin/QpidDestinationProxy.java162
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/admin/QpidQueue.java51
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/admin/QpidTopic.java52
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java593
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivationSpec.java604
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidMessageHandler.java245
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/tm/GeronimoTransactionManagerLocator.java63
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/tm/JBoss7TransactionManagerLocator.java33
-rw-r--r--java/jca/src/main/java/org/apache/qpid/ra/tm/JBossTransactionManagerLocator.java70
-rw-r--r--java/jca/src/main/resources/META-INF/jboss-ra.xml33
-rwxr-xr-xjava/jca/src/main/resources/META-INF/ra.xml220
50 files changed, 14039 insertions, 0 deletions
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryObjectFactory.java b/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryObjectFactory.java
new file mode 100644
index 0000000000..2dc94ed194
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryObjectFactory.java
@@ -0,0 +1,62 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameNotFoundException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.spi.ObjectFactory;
+
+/**
+ *
+ * A ConnectionFactoryObjectFactory.
+ *
+ * Given a reference - reconstructs a QpidRAConnectionFactory
+ *
+ */
+public class ConnectionFactoryObjectFactory implements ObjectFactory
+{
+ static final String QPID_CF = "QPID-CF";
+
+ public Object getObjectInstance(final Object ref, final Name name, final Context ctx, final Hashtable<?,?> props) throws Exception
+ {
+ if (!(ref instanceof Reference))
+ {
+ throw new IllegalArgumentException();
+ }
+
+ RefAddr ra = ((Reference)ref).get(QPID_CF);
+ if (ra == null)
+ {
+ throw new NameNotFoundException();
+ }
+
+ byte[] bytes = (byte[])ra.getContent();
+
+ return Util.deserialize(bytes);
+
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryProperties.java b/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryProperties.java
new file mode 100644
index 0000000000..be129a67cc
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryProperties.java
@@ -0,0 +1,215 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ */
+public class ConnectionFactoryProperties
+{
+ /**
+ * The logger
+ */
+ private static final Logger _log = LoggerFactory.getLogger(ConnectionFactoryProperties.class);
+
+ private boolean _hasBeenUpdated = false;
+
+ private String _clientID;
+
+ private String _connectionURL;
+
+ private String _userName;
+
+ private String _password;
+
+ private String _host;
+
+ private Integer _port;
+
+ private String _path;
+
+ private Boolean _localTx = Boolean.FALSE;
+
+ public String getClientId()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getClientID()");
+ }
+ return _clientID;
+ }
+
+ public void setClientId(final String clientID)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setClientID(" + clientID + ")");
+ }
+ _hasBeenUpdated = true;
+ this._clientID = clientID;
+ }
+
+ public boolean isHasBeenUpdated()
+ {
+ return _hasBeenUpdated;
+ }
+
+ public String getConnectionURL()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getConnectionURL()");
+ }
+ return _connectionURL;
+ }
+
+ public void setConnectionURL(final String connectionURL)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setConnectionURL(" + connectionURL + ")");
+ }
+ _hasBeenUpdated = true;
+ this._connectionURL = connectionURL;
+ }
+
+ public String getPassword()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDefaultPassword()");
+ }
+ return _password;
+ }
+
+ public void setPassword(final String defaultPassword)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDefaultPassword(" + defaultPassword + ")");
+ }
+ _hasBeenUpdated = true;
+ this._password = defaultPassword;
+ }
+
+ public String getUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDefaultUsername()");
+ }
+ return _userName;
+ }
+
+ public void setUserName(final String defaultUsername)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDefaultUsername(" + defaultUsername + ")");
+ }
+ _hasBeenUpdated = true;
+ this._userName = defaultUsername;
+ }
+
+ public String getHost()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getHost()");
+ }
+ return _host;
+ }
+
+ public void setHost(final String host)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setHost(" + host + ")");
+ }
+ _hasBeenUpdated = true;
+ this._host = host;
+ }
+
+ public Integer getPort()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPort()");
+ }
+ return _port;
+ }
+
+ public void setPort(final Integer port)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPort(" + port + ")");
+ }
+ _hasBeenUpdated = true;
+ this._port = port;
+ }
+
+ public String getPath()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPath()");
+ }
+ return _path;
+ }
+
+ public void setPath(final String path)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPath(" + path + ")");
+ }
+ _hasBeenUpdated = true;
+ this._path = path;
+ }
+
+ public Boolean isUseLocalTx()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("isUseLocalTx()");
+ }
+ return _localTx;
+ }
+
+ public void setUseLocalTx(Boolean localTx)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUseLocalTx(" + localTx + ")");
+ }
+
+ if(localTx != null)
+ {
+ _hasBeenUpdated = true;
+ this._localTx = localTx;
+ }
+
+ }
+
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRABytesMessage.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRABytesMessage.java
new file mode 100644
index 0000000000..d30a45c739
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRABytesMessage.java
@@ -0,0 +1,462 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message
+ *
+ */
+public class QpidRABytesMessage extends QpidRAMessage implements BytesMessage
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRABytesMessage.class);
+
+ /**
+ * Create a new wrapper
+ * @param message the message
+ * @param session the session
+ */
+ public QpidRABytesMessage(final BytesMessage message, final QpidRASessionImpl session)
+ {
+ super(message, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(message) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get body length
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long getBodyLength() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getBodyLength()");
+ }
+
+ return ((BytesMessage)_message).getBodyLength();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean readBoolean() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readBoolean()");
+ }
+
+ return ((BytesMessage)_message).readBoolean();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public byte readByte() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readByte()");
+ }
+
+ return ((BytesMessage)_message).readByte();
+ }
+
+ /**
+ * Read
+ * @param value The value
+ * @param length The length
+ * @return The result
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int readBytes(final byte[] value, final int length) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readBytes(" + value + ", " + length + ")");
+ }
+
+ return ((BytesMessage)_message).readBytes(value, length);
+ }
+
+ /**
+ * Read
+ * @param value The value
+ * @return The result
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int readBytes(final byte[] value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readBytes(" + value + ")");
+ }
+
+ return ((BytesMessage)_message).readBytes(value);
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public char readChar() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readChar()");
+ }
+
+ return ((BytesMessage)_message).readChar();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public double readDouble() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readDouble()");
+ }
+
+ return ((BytesMessage)_message).readDouble();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public float readFloat() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readFloat()");
+ }
+
+ return ((BytesMessage)_message).readFloat();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int readInt() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readInt()");
+ }
+
+ return ((BytesMessage)_message).readInt();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long readLong() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readLong()");
+ }
+
+ return ((BytesMessage)_message).readLong();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public short readShort() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readShort()");
+ }
+
+ return ((BytesMessage)_message).readShort();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int readUnsignedByte() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readUnsignedByte()");
+ }
+
+ return ((BytesMessage)_message).readUnsignedByte();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int readUnsignedShort() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readUnsignedShort()");
+ }
+
+ return ((BytesMessage)_message).readUnsignedShort();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String readUTF() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readUTF()");
+ }
+
+ return ((BytesMessage)_message).readUTF();
+ }
+
+ /**
+ * Reset
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void reset() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("reset()");
+ }
+
+ ((BytesMessage)_message).reset();
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeBoolean(final boolean value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeBoolean(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeBoolean(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeByte(final byte value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeByte(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeByte(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @param offset The offset
+ * @param length The length
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeBytes(final byte[] value, final int offset, final int length) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeBytes(" + value + ", " + offset + ", " + length + ")");
+ }
+
+ ((BytesMessage)_message).writeBytes(value, offset, length);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeBytes(final byte[] value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeBytes(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeBytes(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeChar(final char value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeChar(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeChar(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeDouble(final double value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeDouble(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeDouble(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeFloat(final float value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeFloat(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeFloat(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeInt(final int value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeInt(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeInt(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeLong(final long value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeLong(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeLong(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeObject(final Object value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeObject(" + Util.asString(value) + ")");
+ }
+
+ ((BytesMessage)_message).writeObject(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeShort(final short value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeShort(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeShort(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeUTF(final String value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeUTF(" + value + ")");
+ }
+
+ ((BytesMessage)_message).writeUTF(value);
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactory.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactory.java
new file mode 100644
index 0000000000..1e8fb13c79
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactory.java
@@ -0,0 +1,58 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.io.Serializable;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.TopicConnectionFactory;
+import javax.jms.XAConnectionFactory;
+import javax.jms.XAQueueConnectionFactory;
+import javax.jms.XATopicConnectionFactory;
+import javax.resource.Referenceable;
+
+/**
+ * An aggregate interface for the JMS connection factories
+ *
+ */
+public interface QpidRAConnectionFactory extends ConnectionFactory, TopicConnectionFactory, QueueConnectionFactory,
+ XAConnectionFactory, XAQueueConnectionFactory, XATopicConnectionFactory, Serializable, Referenceable
+{
+ /** Connection factory capable of handling connections */
+ public static final int CONNECTION = 0;
+
+ /** Connection factory capable of handling queues */
+ public static final int QUEUE_CONNECTION = 1;
+
+ /** Connection factory capable of handling topics */
+ public static final int TOPIC_CONNECTION = 2;
+
+ /** Connection factory capable of handling XA connections */
+ public static final int XA_CONNECTION = 3;
+
+ /** Connection factory capable of handling XA queues */
+ public static final int XA_QUEUE_CONNECTION = 4;
+
+ /** Connection factory capable of handling XA topics */
+ public static final int XA_TOPIC_CONNECTION = 5;
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactoryImpl.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactoryImpl.java
new file mode 100644
index 0000000000..77a38d5b34
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactoryImpl.java
@@ -0,0 +1,442 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.io.IOException;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.QueueConnection;
+import javax.jms.TopicConnection;
+import javax.jms.XAConnection;
+import javax.jms.XAQueueConnection;
+import javax.jms.XATopicConnection;
+import javax.naming.BinaryRefAddr;
+import javax.naming.Reference;
+import javax.resource.spi.ConnectionManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The connection factory
+ *
+ */
+public class QpidRAConnectionFactoryImpl implements QpidRAConnectionFactory
+{
+ /** Serial version UID */
+ private static final long serialVersionUID = -5306006173783505760L;
+
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAConnectionFactoryImpl.class);
+
+ /** The managed connection factory */
+ private final QpidRAManagedConnectionFactory _mcf;
+
+ /** The connection manager */
+ private ConnectionManager _cm;
+
+ /** Naming reference */
+ private Reference _reference;
+
+ /**
+ * Constructor
+ * @param mcf The managed connection factory
+ * @param cm The connection manager
+ */
+ public QpidRAConnectionFactoryImpl(final QpidRAManagedConnectionFactory mcf, final ConnectionManager cm)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + mcf + ", " + cm + ")");
+ }
+
+ this._mcf = mcf;
+
+ if (cm == null)
+ {
+ // This is standalone usage, no appserver
+ this._cm = new QpidRAConnectionManager();
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created new ConnectionManager=" + this._cm);
+ }
+ }
+ else
+ {
+ this._cm = cm;
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Using ManagedConnectionFactory=" + mcf + ", ConnectionManager=" + this._cm);
+ }
+ }
+
+ /**
+ * Set the reference
+ * @param reference The reference
+ */
+ public void setReference(final Reference reference)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setReference(" + reference + ")");
+ }
+
+ this._reference = reference;
+ }
+
+ /**
+ * Get the reference
+ * @return The reference
+ */
+ public Reference getReference()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getReference()");
+ }
+ if (_reference == null)
+ {
+ try
+ {
+ _reference = new Reference(this.getClass().getCanonicalName(),
+ new BinaryRefAddr(ConnectionFactoryObjectFactory.QPID_CF,
+ Util.serialize(this)),
+ ConnectionFactoryObjectFactory.class.getCanonicalName(),
+ null);
+ }
+ catch (final IOException ioe)
+ {
+ _log.error("Error while giving object Reference.", ioe);
+ }
+ }
+
+ return _reference;
+
+ }
+
+ /**
+ * Create a queue connection
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public QueueConnection createQueueConnection() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createQueueConnection()");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.QUEUE_CONNECTION);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created queue connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a queue connection
+ * @param userName The user name
+ * @param password The password
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public QueueConnection createQueueConnection(final String userName, final String password) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createQueueConnection(" + userName + ", ****)");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.QUEUE_CONNECTION);
+ s.setUserName(userName);
+ s.setPassword(password);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created queue connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a topic connection
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public TopicConnection createTopicConnection() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTopicConnection()");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.TOPIC_CONNECTION);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created topic connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a topic connection
+ * @param userName The user name
+ * @param password The password
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public TopicConnection createTopicConnection(final String userName, final String password) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTopicConnection(" + userName + ", ****)");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.TOPIC_CONNECTION);
+ s.setUserName(userName);
+ s.setPassword(password);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created topic connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a connection
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public Connection createConnection() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnection()");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf, _cm, QpidRAConnectionFactory.CONNECTION);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a connection
+ * @param userName The user name
+ * @param password The password
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public Connection createConnection(final String userName, final String password) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnection(" + userName + ", ****)");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf, _cm, QpidRAConnectionFactory.CONNECTION);
+ s.setUserName(userName);
+ s.setPassword(password);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a XA queue connection
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public XAQueueConnection createXAQueueConnection() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXAQueueConnection()");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.XA_QUEUE_CONNECTION);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created XA queue connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a XA queue connection
+ * @param userName The user name
+ * @param password The password
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public XAQueueConnection createXAQueueConnection(final String userName, final String password) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXAQueueConnection(" + userName + ", ****)");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.XA_QUEUE_CONNECTION);
+ s.setUserName(userName);
+ s.setPassword(password);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created XA queue connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a XA topic connection
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public XATopicConnection createXATopicConnection() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXATopicConnection()");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.XA_TOPIC_CONNECTION);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created XA topic connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a XA topic connection
+ * @param userName The user name
+ * @param password The password
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public XATopicConnection createXATopicConnection(final String userName, final String password) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXATopicConnection(" + userName + ", ****)");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf,
+ _cm,
+ QpidRAConnectionFactory.XA_TOPIC_CONNECTION);
+ s.setUserName(userName);
+ s.setPassword(password);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created XA topic connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a XA connection
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public XAConnection createXAConnection() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXAConnection()");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf, _cm, QpidRAConnectionFactory.XA_CONNECTION);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created XA connection: " + s);
+ }
+
+ return s;
+ }
+
+ /**
+ * Create a XA connection
+ * @param userName The user name
+ * @param password The password
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public XAConnection createXAConnection(final String userName, final String password) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXAConnection(" + userName + ", ****)");
+ }
+
+ QpidRASessionFactoryImpl s = new QpidRASessionFactoryImpl(_mcf, _cm, QpidRAConnectionFactory.XA_CONNECTION);
+ s.setUserName(userName);
+ s.setPassword(password);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created XA connection: " + s);
+ }
+
+ return s;
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionManager.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionManager.java
new file mode 100644
index 0000000000..7ba5dd5374
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionManager.java
@@ -0,0 +1,80 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionManager;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.ManagedConnectionFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The connection manager used in non-managed environments.
+ *
+ */
+public class QpidRAConnectionManager implements ConnectionManager
+{
+ /** Serial version UID */
+ private static final long serialVersionUID = 688529567919039006L;
+
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAConnectionManager.class);
+
+ /**
+ * Constructor
+ */
+ public QpidRAConnectionManager()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+ }
+
+ /**
+ * Allocates a connection
+ * @param mcf The managed connection factory
+ * @param cxRequestInfo The connection request information
+ * @return The connection
+ * @exception ResourceException Thrown if there is a problem obtaining the connection
+ */
+ public Object allocateConnection(final ManagedConnectionFactory mcf, final ConnectionRequestInfo cxRequestInfo) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("allocateConnection(" + mcf + ", " + cxRequestInfo + ")");
+ }
+
+ ManagedConnection mc = mcf.createManagedConnection(null, cxRequestInfo);
+ Object c = mc.getConnection(null, cxRequestInfo);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Allocated connection: " + c + ", with managed connection: " + mc);
+ }
+
+ return c;
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionMetaData.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionMetaData.java
new file mode 100644
index 0000000000..ec14c2a492
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionMetaData.java
@@ -0,0 +1,208 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+
+import javax.jms.ConnectionMetaData;
+
+import org.apache.qpid.client.CustomJMSXProperty;
+import org.apache.qpid.common.QpidProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class implements javax.jms.ConnectionMetaData
+ *
+ */
+public class QpidRAConnectionMetaData implements ConnectionMetaData
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAConnectionMetaData.class);
+
+ private static final String PROVIDER_VERSION ;
+ private static final int PROVIDER_MAJOR ;
+ private static final int PROVIDER_MINOR ;
+ private static final String[] JMSX_PROPERTY_NAMES ;
+
+ /**
+ * Constructor
+ */
+ public QpidRAConnectionMetaData()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+ }
+
+ /**
+ * Get the JMS version
+ * @return The version
+ */
+ public String getJMSVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSVersion()");
+ }
+
+ return "1.1";
+ }
+
+ /**
+ * Get the JMS major version
+ * @return The major version
+ */
+ public int getJMSMajorVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSMajorVersion()");
+ }
+
+ return 1;
+ }
+
+ /**
+ * Get the JMS minor version
+ * @return The minor version
+ */
+ public int getJMSMinorVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSMinorVersion()");
+ }
+
+ return 1;
+ }
+
+ /**
+ * Get the JMS provider name
+ * @return The name
+ */
+ public String getJMSProviderName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSProviderName()");
+ }
+
+ return QpidProperties.getProductName() + " Resource Adapter" ;
+ }
+
+ /**
+ * Get the provider version
+ * @return The version
+ */
+ public String getProviderVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getProviderVersion()");
+ }
+
+ return PROVIDER_VERSION ;
+ }
+
+ /**
+ * Get the provider major version
+ * @return The version
+ */
+ public int getProviderMajorVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getProviderMajorVersion()");
+ }
+
+ return PROVIDER_MAJOR ;
+ }
+
+ /**
+ * Get the provider minor version
+ * @return The version
+ */
+ public int getProviderMinorVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getProviderMinorVersion()");
+ }
+
+ return PROVIDER_MINOR ;
+ }
+
+ /**
+ * Get the JMS XPropertyNames
+ * @return The names
+ */
+ public Enumeration<String> getJMSXPropertyNames()
+ {
+ // Bug in CustomJMSXProperty.asEnumeration() so we handle this here
+ return Collections.enumeration(Arrays.asList(JMSX_PROPERTY_NAMES)) ;
+ }
+
+ static
+ {
+ final String version = QpidProperties.getReleaseVersion() ;
+ int major = -1 ;
+ int minor = -1 ;
+ if (version != null)
+ {
+ final int separator = version.indexOf('.') ;
+ if (separator != -1)
+ {
+ major = parseInt(version.substring(0, separator), "major") ;
+ minor = parseInt(version.substring(separator+1, version.length()), "minor") ;
+ }
+ }
+ PROVIDER_VERSION = version ;
+ PROVIDER_MAJOR = major ;
+ PROVIDER_MINOR = minor ;
+
+ final CustomJMSXProperty[] properties = CustomJMSXProperty.values();
+ final String[] names = new String[properties.length] ;
+ int count = 0 ;
+ for(CustomJMSXProperty property : properties)
+ {
+ names[count++] = property.toString() ;
+ }
+ JMSX_PROPERTY_NAMES = names ;
+ }
+
+ private static int parseInt(final String value, final String name)
+ {
+ try
+ {
+ return Integer.parseInt(value) ;
+ }
+ catch (final NumberFormatException nfe)
+ {
+ _log.warn("Failed to parse " + name + ": " + value) ;
+ return -1 ;
+ }
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionRequestInfo.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionRequestInfo.java
new file mode 100644
index 0000000000..c37a264ebc
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionRequestInfo.java
@@ -0,0 +1,361 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.jms.Session;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionRequestInfo;
+
+import org.apache.qpid.jms.ConnectionURL;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Connection request information
+ *
+ */
+public class QpidRAConnectionRequestInfo implements ConnectionRequestInfo
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAConnectionRequestInfo.class);
+
+ /** The user name */
+ private String _userName;
+
+ /** The password */
+ private String _password;
+
+ /** The client id */
+ private String _clientID;
+
+ /** The type */
+ private final int _type;
+
+ /** Use transactions */
+ private final boolean _transacted;
+
+ /** The acknowledge mode */
+ private final int _acknowledgeMode;
+
+ /**
+ * Constructor
+ * @param ra The resource adapter.
+ * @param type The connection type
+ * @throws ResourceException
+ */
+ public QpidRAConnectionRequestInfo(final QpidResourceAdapter ra, final int type)
+ throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + ra + ")");
+ }
+
+ final QpidRAProperties properties = ra.getProperties() ;
+ if (properties.getConnectionURL() != null)
+ {
+ final ConnectionURL connectionURL = ra.getDefaultAMQConnectionFactory().getConnectionURL() ;
+ _userName = connectionURL.getUsername();
+ _password = connectionURL.getPassword();
+ _clientID = connectionURL.getClientName();
+ }
+ else
+ {
+ _userName = ra.getDefaultUserName();
+ _password = ra.getDefaultPassword();
+ _clientID = ra.getClientId();
+ }
+ this._type = type;
+ _transacted = true;
+ _acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+ }
+
+ /**
+ * Constructor
+ * @param type The connection type
+ */
+ public QpidRAConnectionRequestInfo(final int type)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + type + ")");
+ }
+
+ this._type = type;
+ _transacted = true;
+ _acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+ }
+
+ /**
+ * Constructor
+ * @param transacted Use transactions
+ * @param acknowledgeMode The acknowledge mode
+ * @param type The connection type
+ */
+ public QpidRAConnectionRequestInfo(final boolean transacted, final int acknowledgeMode, final int type)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + transacted +
+ ", " +
+ acknowledgeMode +
+ ", " +
+ type +
+ ")");
+ }
+
+ this._transacted = transacted;
+ this._acknowledgeMode = acknowledgeMode;
+ this._type = type;
+ }
+
+ /**
+ * Fill in default values if they are missing
+ * @param connectionURL The connection URL
+ */
+ public void setDefaults(final ConnectionURL connectionURL)
+ {
+ if (_userName == null)
+ {
+ _userName = connectionURL.getUsername();
+ }
+ if (_password == null)
+ {
+ _password = connectionURL.getPassword();
+ }
+ if (_clientID == null)
+ {
+ _clientID = connectionURL.getClientName();
+ }
+ }
+
+ /**
+ * Fill in default values if they are missing
+ * @param ra The resource adapter
+ * @throws ResourceException
+ */
+ public void setDefaults(final QpidResourceAdapter ra)
+ throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDefaults(" + ra + ")");
+ }
+
+ final QpidRAProperties properties = ra.getProperties() ;
+ if (properties.getConnectionURL() != null)
+ {
+ setDefaults(ra.getDefaultAMQConnectionFactory().getConnectionURL()) ;
+ }
+ else
+ {
+ if (_userName == null)
+ {
+ _userName = ra.getDefaultUserName();
+ }
+ if (_password == null)
+ {
+ _password = ra.getDefaultPassword();
+ }
+ if (_clientID == null)
+ {
+ _clientID = ra.getClientId();
+ }
+ }
+ }
+
+ /**
+ * Get the user name
+ * @return The value
+ */
+ public String getUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUserName()");
+ }
+
+ return _userName;
+ }
+
+ /**
+ * Set the user name
+ * @param userName The value
+ */
+ public void setUserName(final String userName)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUserName(" + userName + ")");
+ }
+
+ this._userName = userName;
+ }
+
+ /**
+ * Get the password
+ * @return The value
+ */
+ public String getPassword()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPassword()");
+ }
+
+ return _password;
+ }
+
+ /**
+ * Set the password
+ * @param password The value
+ */
+ public void setPassword(final String password)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPassword(****)");
+ }
+
+ this._password = password;
+ }
+
+ /**
+ * Get the client id
+ * @return The value
+ */
+ public String getClientID()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getClientID()");
+ }
+
+ return _clientID;
+ }
+
+ /**
+ * Set the client id
+ * @param clientID The value
+ */
+ public void setClientID(final String clientID)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setClientID(" + clientID + ")");
+ }
+
+ this._clientID = clientID;
+ }
+
+ /**
+ * Get the connection type
+ * @return The type
+ */
+ public int getType()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getType()");
+ }
+
+ return _type;
+ }
+
+ /**
+ * Use transactions
+ * @return True if transacted; otherwise false
+ */
+ public boolean isTransacted()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("isTransacted() " + _transacted);
+ }
+
+ return _transacted;
+ }
+
+ /**
+ * Get the acknowledge mode
+ * @return The mode
+ */
+ public int getAcknowledgeMode()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getAcknowledgeMode()");
+ }
+
+ return _acknowledgeMode;
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this one.
+ * @param obj Object with which to compare
+ * @return True if this object is the same as the obj argument; false otherwise.
+ */
+ @Override
+ public boolean equals(final Object obj)
+ {
+ if (obj instanceof QpidRAConnectionRequestInfo)
+ {
+ QpidRAConnectionRequestInfo you = (QpidRAConnectionRequestInfo)obj;
+ return Util.compare(_userName, you.getUserName()) && Util.compare(_password, you.getPassword()) &&
+ Util.compare(_clientID, you.getClientID()) &&
+ _type == you.getType() &&
+ _transacted == you.isTransacted() &&
+ _acknowledgeMode == you.getAcknowledgeMode();
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Return the hash code for the object
+ * @return The hash code
+ */
+ @Override
+ public int hashCode()
+ {
+ int hash = 7;
+
+ hash += 31 * hash + (_userName != null ? _userName.hashCode() : 0);
+ hash += 31 * hash + (_password != null ? _password.hashCode() : 0);
+ hash += 31 * hash + (_clientID != null ? _clientID.hashCode() : 0);
+ hash += 31 * hash + _type;
+ hash += 31 * hash + (_transacted ? 1 : 0);
+ hash += 31 * hash + _acknowledgeMode;
+
+ return hash;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "QpidRAConnectionRequestInfo[type=" + _type +
+ ", transacted=" + _transacted + ", acknowledgeMode=" + _acknowledgeMode +
+ ", clientID=" + _clientID + ", userName=" + _userName + ((_password != null) ? ", password=********]" :"]");
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRACredential.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRACredential.java
new file mode 100644
index 0000000000..2b42f9dc3d
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRACredential.java
@@ -0,0 +1,245 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.io.Serializable;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Set;
+
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.resource.spi.SecurityException;
+import javax.resource.spi.security.PasswordCredential;
+import javax.security.auth.Subject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Credential information
+ *
+ */
+public class QpidRACredential implements Serializable
+{
+ /** Serial version UID */
+ private static final long serialVersionUID = 7040664839205409352L;
+
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRACredential.class);
+
+ /** The user name */
+ private String _userName;
+
+ /** The password */
+ private String _password;
+
+ /**
+ * Private constructor
+ */
+ private QpidRACredential()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+ }
+
+ /**
+ * Get the user name
+ * @return The value
+ */
+ public String getUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUserName()");
+ }
+
+ return _userName;
+ }
+
+ /**
+ * Set the user name
+ * @param userName The value
+ */
+ private void setUserName(final String userName)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUserName(" + userName + ")");
+ }
+
+ this._userName = userName;
+ }
+
+ /**
+ * Get the password
+ * @return The value
+ */
+ public String getPassword()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPassword()");
+ }
+
+ return _password;
+ }
+
+ /**
+ * Set the password
+ * @param password The value
+ */
+ private void setPassword(final String password)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPassword(****)");
+ }
+
+ this._password = password;
+ }
+
+ /**
+ * Get credentials
+ * @param mcf The managed connection factory
+ * @param subject The subject
+ * @param info The connection request info
+ * @return The credentials
+ * @exception SecurityException Thrown if the credentials cant be retrieved
+ */
+ public static QpidRACredential getCredential(final ManagedConnectionFactory mcf,
+ final Subject subject,
+ final ConnectionRequestInfo info) throws SecurityException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getCredential(" + mcf + ", " + subject + ", " + info + ")");
+ }
+
+ QpidRACredential jc = new QpidRACredential();
+ if (subject == null && info != null)
+ {
+ jc.setUserName(((QpidRAConnectionRequestInfo)info).getUserName());
+ jc.setPassword(((QpidRAConnectionRequestInfo)info).getPassword());
+ }
+ else if (subject != null)
+ {
+ PasswordCredential pwdc = GetCredentialAction.getCredential(subject, mcf);
+
+ if (pwdc == null)
+ {
+ throw new SecurityException("No password credentials found");
+ }
+
+ jc.setUserName(pwdc.getUserName());
+ jc.setPassword(new String(pwdc.getPassword()));
+ }
+ else
+ {
+ throw new SecurityException("No Subject or ConnectionRequestInfo set, could not get credentials");
+ }
+
+ return jc;
+ }
+
+ /**
+ * String representation
+ * @return The representation
+ */
+ @Override
+ public String toString()
+ {
+ return super.toString() + "{ username=" + _userName + ", password=**** }";
+ }
+
+ /**
+ * Privileged class to get credentials
+ */
+ private static class GetCredentialAction implements PrivilegedAction<PasswordCredential>
+ {
+ /** The subject */
+ private final Subject subject;
+
+ /** The managed connection factory */
+ private final ManagedConnectionFactory mcf;
+
+ /**
+ * Constructor
+ * @param subject The subject
+ * @param mcf The managed connection factory
+ */
+ GetCredentialAction(final Subject subject, final ManagedConnectionFactory mcf)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + subject + ", " + mcf + ")");
+ }
+
+ this.subject = subject;
+ this.mcf = mcf;
+ }
+
+ /**
+ * Run
+ * @return The credential
+ */
+ public PasswordCredential run()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("run()");
+ }
+
+ Set<PasswordCredential> creds = subject.getPrivateCredentials(PasswordCredential.class);
+ PasswordCredential pwdc = null;
+
+ for (PasswordCredential curCred : creds)
+ {
+ if (curCred.getManagedConnectionFactory().equals(mcf))
+ {
+ pwdc = curCred;
+ break;
+ }
+ }
+ return pwdc;
+ }
+
+ /**
+ * Get credentials
+ * @param subject The subject
+ * @param mcf The managed connection factory
+ * @return The credential
+ */
+ static PasswordCredential getCredential(final Subject subject, final ManagedConnectionFactory mcf)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getCredential(" + subject + ", " + mcf + ")");
+ }
+
+ GetCredentialAction action = new GetCredentialAction(subject, mcf);
+ return AccessController.doPrivileged(action);
+ }
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAException.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAException.java
new file mode 100644
index 0000000000..9c070f6184
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAException.java
@@ -0,0 +1,70 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+
+/**
+ * Qpid Resource Adapter exception.
+ */
+public class QpidRAException extends Exception
+{
+ /**
+ * The serial version uid for this serializable class.
+ */
+ private static final long serialVersionUID = 2921345326731695238L;
+
+ /**
+ * Create a default Qpid ra exception.
+ */
+ public QpidRAException()
+ {
+ super();
+ }
+
+ /**
+ * Create an Qpid ra exception with a specific message.
+ * @param message The message associated with this exception.
+ */
+ public QpidRAException(final String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Create an Qpid ra exception with a specific cause.
+ * @param cause The cause associated with this exception.
+ */
+ public QpidRAException(final Throwable cause)
+ {
+ super(cause);
+ }
+
+ /**
+ * Create an Qpid ra exception with a specific message and cause.
+ * @param message The message associated with this exception.
+ * @param cause The cause associated with this exception.
+ */
+ public QpidRAException(final String message, final Throwable cause)
+ {
+ super(message, cause);
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRALocalTransaction.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRALocalTransaction.java
new file mode 100644
index 0000000000..eeb49b6b52
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRALocalTransaction.java
@@ -0,0 +1,129 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.jms.JMSException;
+import javax.resource.ResourceException;
+import javax.resource.spi.LocalTransaction;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * JMS Local transaction
+ *
+ */
+public class QpidRALocalTransaction implements LocalTransaction
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRALocalTransaction.class);
+
+ /** The managed connection */
+ private final QpidRAManagedConnection _mc;
+
+ /**
+ * Constructor
+ * @param mc The managed connection
+ */
+ public QpidRALocalTransaction(final QpidRAManagedConnection mc)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + mc + ")");
+ }
+
+ this._mc = mc;
+ }
+
+ /**
+ * Begin
+ * @exception ResourceException Thrown if the operation fails
+ */
+ public void begin() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("begin()");
+ }
+ }
+
+ /**
+ * Commit
+ * @exception ResourceException Thrown if the operation fails
+ */
+ public void commit() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("commit()");
+ }
+
+ _mc.lock();
+
+ try
+ {
+ if (_mc.getSession() == null)
+ {
+ throw new ResourceException("Could not commit LocalTransaction: null Session.");
+ }
+
+ _mc.getSession().commit();
+ }
+ catch (JMSException e)
+ {
+ throw new ResourceException("Could not commit LocalTransaction", e);
+ }
+ finally
+ {
+ _mc.unlock();
+ }
+ }
+
+ /**
+ * Rollback
+ * @exception ResourceException Thrown if the operation fails
+ */
+ public void rollback() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("rollback()");
+ }
+
+ _mc.lock();
+ try
+ {
+ if (_mc.getSession() != null && _mc.getSession().getTransacted())
+ {
+ _mc.getSession().rollback();
+ }
+ }
+ catch (JMSException ex)
+ {
+ throw new ResourceException("Could not rollback LocalTransaction", ex);
+ }
+ finally
+ {
+ _mc.unlock();
+ }
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMCFProperties.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMCFProperties.java
new file mode 100644
index 0000000000..dd60c175de
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMCFProperties.java
@@ -0,0 +1,177 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.io.Serializable;
+
+import javax.jms.Queue;
+import javax.jms.Topic;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The MCF default properties
+ *
+ */
+public class QpidRAMCFProperties extends ConnectionFactoryProperties implements Serializable
+{
+ /**
+ * Serial version UID
+ */
+ private static final long serialVersionUID = -1675836810881223064L;
+
+ /**
+ * The logger
+ */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAMCFProperties.class);
+
+ /**
+ * The queue type
+ */
+ private static final String QUEUE_TYPE = Queue.class.getName();
+
+ /**
+ * The topic type
+ */
+ private static final String TOPIC_TYPE = Topic.class.getName();
+
+ /**
+ * The connection type
+ */
+ private int _type = QpidRAConnectionFactory.CONNECTION;
+
+ /**
+ * Use tryLock
+ */
+ private Integer _useTryLock;
+
+ /**
+ * Constructor
+ */
+ public QpidRAMCFProperties()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+
+ _useTryLock = null;
+ }
+
+ /**
+ * Get the connection type
+ *
+ * @return The type
+ */
+ public int getType()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getType()");
+ }
+
+ return _type;
+ }
+
+ /**
+ * Set the default session type.
+ *
+ * @param defaultType either javax.jms.Topic or javax.jms.Queue
+ */
+ public void setSessionDefaultType(final String defaultType)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSessionDefaultType(" + _type + ")");
+ }
+
+ if (defaultType.equals(QpidRAMCFProperties.QUEUE_TYPE))
+ {
+ _type = QpidRAConnectionFactory.QUEUE_CONNECTION;
+ }
+ else if (defaultType.equals(QpidRAMCFProperties.TOPIC_TYPE))
+ {
+ _type = QpidRAConnectionFactory.TOPIC_CONNECTION;
+ }
+ else
+ {
+ _type = QpidRAConnectionFactory.CONNECTION;
+ }
+ }
+
+ /**
+ * Get the default session type.
+ *
+ * @return The default session type
+ */
+ public String getSessionDefaultType()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSessionDefaultType()");
+ }
+
+ if (_type == QpidRAConnectionFactory.CONNECTION)
+ {
+ return "BOTH";
+ }
+ else if (_type == QpidRAConnectionFactory.QUEUE_CONNECTION)
+ {
+ return QpidRAMCFProperties.TOPIC_TYPE;
+ }
+ else
+ {
+ return QpidRAMCFProperties.QUEUE_TYPE;
+ }
+ }
+
+ /**
+ * Get the useTryLock.
+ *
+ * @return the useTryLock.
+ */
+ public Integer getUseTryLock()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUseTryLock()");
+ }
+
+ return _useTryLock;
+ }
+
+ /**
+ * Set the useTryLock.
+ *
+ * @param useTryLock the useTryLock.
+ */
+ public void setUseTryLock(final Integer useTryLock)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUseTryLock(" + useTryLock + ")");
+ }
+
+ this._useTryLock = useTryLock;
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java
new file mode 100644
index 0000000000..fb1b7f060c
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java
@@ -0,0 +1,880 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.jms.Connection;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.ResourceAllocationException;
+import javax.jms.Session;
+import javax.jms.QueueConnection;
+import javax.jms.TopicConnection;
+import javax.jms.XAQueueConnection;
+import javax.jms.XASession;
+import javax.jms.XATopicConnection;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionEvent;
+import javax.resource.spi.ConnectionEventListener;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.IllegalStateException;
+import javax.resource.spi.LocalTransaction;
+import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.ManagedConnectionMetaData;
+import javax.resource.spi.SecurityException;
+import javax.security.auth.Subject;
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAResource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The managed connection
+ *
+ */
+public class QpidRAManagedConnection implements ManagedConnection, ExceptionListener
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAManagedConnection.class);
+
+ /** The managed connection factory */
+ private final QpidRAManagedConnectionFactory _mcf;
+
+ /** The connection request information */
+ private final QpidRAConnectionRequestInfo _cri;
+
+ /** The user name */
+ private final String _userName;
+
+ /** The password */
+ private final String _password;
+
+ /** Has the connection been destroyed */
+ private final AtomicBoolean _isDestroyed = new AtomicBoolean(false);
+
+ /** Event listeners */
+ private final List<ConnectionEventListener> _eventListeners;
+
+ /** Handles */
+ private final Set<QpidRASessionImpl> _handles;
+
+ /** Lock */
+ private ReentrantLock _lock = new ReentrantLock();
+
+ // Physical JMS connection stuff
+ private Connection _connection;
+
+ private XASession _xaSession;
+
+ private XAResource _xaResource;
+
+ private Session _session;
+
+ private final TransactionManager _tm;
+
+ private boolean _inManagedTx;
+
+ /**
+ * Constructor
+ * @param mcf The managed connection factory
+ * @param cri The connection request information
+ * @param userName The user name
+ * @param password The password
+ */
+ public QpidRAManagedConnection(final QpidRAManagedConnectionFactory mcf,
+ final QpidRAConnectionRequestInfo cri,
+ final TransactionManager tm,
+ final String userName,
+ final String password) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + mcf + ", " + cri + ", " + userName + ", ****)");
+ }
+
+ this._mcf = mcf;
+ this._cri = cri;
+ this._tm = tm;
+ this._userName = userName;
+ this._password = password;
+ _eventListeners = Collections.synchronizedList(new ArrayList<ConnectionEventListener>());
+ _handles = Collections.synchronizedSet(new HashSet<QpidRASessionImpl>());
+
+ try
+ {
+ setup();
+ }
+ catch (Throwable t)
+ {
+ try
+ {
+ destroy();
+ }
+ catch (Throwable ignored)
+ {
+ }
+ throw new ResourceException("Error during setup", t);
+ }
+ }
+
+ /**
+ * Get a connection
+ * @param subject The security subject
+ * @param cxRequestInfo The request info
+ * @return The connection
+ * @exception ResourceException Thrown if an error occurs
+ */
+ public synchronized Object getConnection(final Subject subject, final ConnectionRequestInfo cxRequestInfo) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getConnection(" + subject + ", " + cxRequestInfo + ")");
+ }
+
+ // Check user first
+ QpidRACredential credential = QpidRACredential.getCredential(_mcf, subject, cxRequestInfo);
+
+ // Null users are allowed!
+ if (_userName != null && !_userName.equals(credential.getUserName()))
+ {
+ throw new SecurityException("Password credentials not the same, reauthentication not allowed");
+ }
+
+ if (_userName == null && credential.getUserName() != null)
+ {
+ throw new SecurityException("Password credentials not the same, reauthentication not allowed");
+ }
+
+ if (_isDestroyed.get())
+ {
+ throw new IllegalStateException("The managed connection is already destroyed");
+ }
+
+ QpidRASessionImpl session = new QpidRASessionImpl(this, (QpidRAConnectionRequestInfo)cxRequestInfo);
+ _handles.add(session);
+ return session;
+ }
+
+ /**
+ * Destroy all handles.
+ * @exception ResourceException Failed to close one or more handles.
+ */
+ private void destroyHandles() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("destroyHandles()");
+ }
+
+ try
+ {
+ if (_connection != null)
+ {
+ _connection.stop();
+ }
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Ignored error stopping connection", t);
+ }
+
+ for (QpidRASessionImpl session : _handles)
+ {
+ session.destroy();
+ }
+
+ _handles.clear();
+ }
+
+ /**
+ * Destroy the physical connection.
+ * @exception ResourceException Could not property close the session and connection.
+ */
+ public void destroy() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("destroy()");
+ }
+
+ if (_isDestroyed.get() || _connection == null)
+ {
+ return;
+ }
+
+ _isDestroyed.set(true);
+
+ try
+ {
+ _connection.setExceptionListener(null);
+ }
+ catch (JMSException e)
+ {
+ _log.debug("Error unsetting the exception listener " + this, e);
+ }
+
+ destroyHandles();
+
+ try
+ {
+ try
+ {
+ if (_xaSession != null)
+ {
+ _xaSession.close();
+ }
+ }
+ catch (JMSException e)
+ {
+ _log.debug("Error closing session " + this, e);
+ }
+
+ if (_connection != null)
+ {
+ _connection.close();
+ }
+ }
+ catch (Throwable e)
+ {
+ throw new ResourceException("Could not properly close the session and connection", e);
+ }
+ }
+
+ /**
+ * Cleanup
+ * @exception ResourceException Thrown if an error occurs
+ */
+ public void cleanup() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("cleanup()");
+ }
+
+ if (_isDestroyed.get())
+ {
+ throw new IllegalStateException("ManagedConnection already destroyed");
+ }
+
+ destroyHandles();
+
+ _inManagedTx = false;
+
+ // I'm recreating the lock object when we return to the pool
+ // because it looks too nasty to expect the connection handle
+ // to unlock properly in certain race conditions
+ // where the dissociation of the managed connection is "random".
+ _lock = new ReentrantLock();
+ }
+
+ /**
+ * Move a handler from one mc to this one.
+ * @param obj An object of type QpidRASession.
+ * @throws ResourceException Failed to associate connection.
+ * @throws IllegalStateException ManagedConnection in an illegal state.
+ */
+ public void associateConnection(final Object obj) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("associateConnection(" + obj + ")");
+ }
+
+ if (!_isDestroyed.get() && obj instanceof QpidRASessionImpl)
+ {
+ QpidRASessionImpl h = (QpidRASessionImpl)obj;
+ h.setManagedConnection(this);
+ _handles.add(h);
+ }
+ else
+ {
+ throw new IllegalStateException("ManagedConnection in an illegal state");
+ }
+ }
+
+ public void checkTransactionActive() throws JMSException
+ {
+ // don't bother looking at the transaction if there's an active XID
+ if (!_inManagedTx && _tm != null)
+ {
+ try
+ {
+ Transaction tx = _tm.getTransaction();
+ if (tx != null)
+ {
+ int status = tx.getStatus();
+ // Only allow states that will actually succeed
+ if (status != Status.STATUS_ACTIVE && status != Status.STATUS_PREPARING &&
+ status != Status.STATUS_PREPARED &&
+ status != Status.STATUS_COMMITTING)
+ {
+ throw new javax.jms.IllegalStateException("Transaction " + tx + " not active");
+ }
+ }
+ }
+ catch (SystemException e)
+ {
+ JMSException jmsE = new javax.jms.IllegalStateException("Unexpected exception on the Transaction ManagerTransaction");
+ jmsE.initCause(e);
+ throw jmsE;
+ }
+ }
+ }
+
+
+ /**
+ * Aqquire a lock on the managed connection
+ */
+ protected void lock()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("lock()");
+ }
+
+ _lock.lock();
+ }
+
+ /**
+ * Aqquire a lock on the managed connection within the specified period
+ * @exception JMSException Thrown if an error occurs
+ */
+ protected void tryLock() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("tryLock()");
+ }
+
+ Integer tryLock = _mcf.getUseTryLock();
+ if (tryLock == null || tryLock.intValue() <= 0)
+ {
+ lock();
+ return;
+ }
+ try
+ {
+ if (_lock.tryLock(tryLock.intValue(), TimeUnit.SECONDS) == false)
+ {
+ throw new ResourceAllocationException("Unable to obtain lock in " + tryLock + " seconds: " + this);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ throw new ResourceAllocationException("Interrupted attempting lock: " + this);
+ }
+ }
+
+ /**
+ * Unlock the managed connection
+ */
+ protected void unlock()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("unlock()");
+ }
+
+ if (_lock.isHeldByCurrentThread())
+ {
+ _lock.unlock();
+ }
+ }
+
+ /**
+ * Add a connection event listener.
+ * @param l The connection event listener to be added.
+ */
+ public void addConnectionEventListener(final ConnectionEventListener l)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addConnectionEventListener(" + l + ")");
+ }
+
+ _eventListeners.add(l);
+ }
+
+ /**
+ * Remove a connection event listener.
+ * @param l The connection event listener to be removed.
+ */
+ public void removeConnectionEventListener(final ConnectionEventListener l)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("removeConnectionEventListener(" + l + ")");
+ }
+
+ _eventListeners.remove(l);
+ }
+
+ /**
+ * Get the XAResource for the connection.
+ * @return The XAResource for the connection.
+ * @exception ResourceException XA transaction not supported
+ */
+ public XAResource getXAResource() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getXAResource()");
+ }
+
+ //
+ // Spec says a mc must allways return the same XA resource,
+ // so we cache it.
+ //
+ if (_xaResource == null)
+ {
+ _xaResource = new QpidRAXAResource(this, _xaSession.getXAResource());
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("XAResource=" + _xaResource);
+ }
+
+ return _xaResource;
+ }
+
+ /**
+ * Get the location transaction for the connection.
+ * @return The local transaction for the connection.
+ * @exception ResourceException Thrown if operation fails.
+ */
+ public LocalTransaction getLocalTransaction() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getLocalTransaction()");
+ }
+
+ LocalTransaction tx = new QpidRALocalTransaction(this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("LocalTransaction=" + tx);
+ }
+
+ return tx;
+ }
+
+ /**
+ * Get the meta data for the connection.
+ * @return The meta data for the connection.
+ * @exception ResourceException Thrown if the operation fails.
+ * @exception IllegalStateException Thrown if the managed connection already is destroyed.
+ */
+ public ManagedConnectionMetaData getMetaData() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMetaData()");
+ }
+
+ if (_isDestroyed.get())
+ {
+ throw new IllegalStateException("The managed connection is already destroyed");
+ }
+
+ return new QpidRAMetaData(this);
+ }
+
+ /**
+ * Set the log writer -- NOT SUPPORTED
+ * @param out The log writer
+ * @exception ResourceException If operation fails
+ */
+ public void setLogWriter(final PrintWriter out) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setLogWriter(" + out + ")");
+ }
+ }
+
+ /**
+ * Get the log writer -- NOT SUPPORTED
+ * @return Always null
+ * @exception ResourceException If operation fails
+ */
+ public PrintWriter getLogWriter() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getLogWriter()");
+ }
+
+ return null;
+ }
+
+ /**
+ * Notifies user of a JMS exception.
+ * @param exception The JMS exception
+ */
+ public void onException(final JMSException exception)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("onException(" + exception + ")");
+ }
+
+ if (_isDestroyed.get())
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Ignoring error on already destroyed connection " + this, exception);
+ }
+ return;
+ }
+
+ _log.warn("Handling JMS exception failure: " + this, exception);
+
+ try
+ {
+ _connection.setExceptionListener(null);
+ }
+ catch (JMSException e)
+ {
+ _log.debug("Unable to unset exception listener", e);
+ }
+
+ ConnectionEvent event = new ConnectionEvent(this, ConnectionEvent.CONNECTION_ERROR_OCCURRED, exception);
+ sendEvent(event);
+ }
+
+ /**
+ * Get the session for this connection.
+ * @return The session
+ * @throws JMSException
+ */
+ protected Session getSession() throws JMSException
+ {
+ if(_xaSession != null && !_mcf.getUseLocalTx())
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSession() -> XA session " + Util.asString(_xaSession));
+ }
+
+ return _xaSession;
+ }
+ else
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSession() -> session " + Util.asString(_session));
+ }
+
+ return _session;
+ }
+ }
+
+ /**
+ * Send an event.
+ * @param event The event to send.
+ */
+ protected void sendEvent(final ConnectionEvent event)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sendEvent(" + event + ")");
+ }
+
+ int type = event.getId();
+
+ // convert to an array to avoid concurrent modification exceptions
+ ConnectionEventListener[] list = _eventListeners.toArray(new ConnectionEventListener[_eventListeners.size()]);
+
+ for (ConnectionEventListener l : list)
+ {
+ switch (type)
+ {
+ case ConnectionEvent.CONNECTION_CLOSED:
+ l.connectionClosed(event);
+ break;
+
+ case ConnectionEvent.LOCAL_TRANSACTION_STARTED:
+ l.localTransactionStarted(event);
+ break;
+
+ case ConnectionEvent.LOCAL_TRANSACTION_COMMITTED:
+ l.localTransactionCommitted(event);
+ break;
+
+ case ConnectionEvent.LOCAL_TRANSACTION_ROLLEDBACK:
+ l.localTransactionRolledback(event);
+ break;
+
+ case ConnectionEvent.CONNECTION_ERROR_OCCURRED:
+ l.connectionErrorOccurred(event);
+ break;
+
+ default:
+ throw new IllegalArgumentException("Illegal eventType: " + type);
+ }
+ }
+ }
+
+ /**
+ * Remove a handle from the handle map.
+ * @param handle The handle to remove.
+ */
+ protected void removeHandle(final QpidRASessionImpl handle)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("removeHandle(" + handle + ")");
+ }
+
+ _handles.remove(handle);
+ }
+
+ /**
+ * Get the request info for this connection.
+ * @return The connection request info for this connection.
+ */
+ protected QpidRAConnectionRequestInfo getCRI()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getCRI()");
+ }
+
+ return _cri;
+ }
+
+ /**
+ * Get the connection factory for this connection.
+ * @return The connection factory for this connection.
+ */
+ protected QpidRAManagedConnectionFactory getManagedConnectionFactory()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getManagedConnectionFactory()");
+ }
+
+ return _mcf;
+ }
+
+ /**
+ * Start the connection
+ * @exception JMSException Thrown if the connection cant be started
+ */
+ void start() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start()");
+ }
+
+ if (_connection != null)
+ {
+ _connection.start();
+ }
+ }
+
+ /**
+ * Stop the connection
+ * @exception JMSException Thrown if the connection cant be stopped
+ */
+ void stop() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("stop()");
+ }
+
+ if (_connection != null)
+ {
+ _connection.stop();
+ }
+ }
+
+ /**
+ * Get the user name
+ * @return The user name
+ */
+ protected String getUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUserName()");
+ }
+
+ return _userName;
+ }
+
+ /**
+ * Setup the connection.
+ * @exception ResourceException Thrown if a connection couldnt be created
+ */
+ private void setup() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setup()");
+ }
+
+ try
+ {
+ boolean transacted = _cri.isTransacted();
+ int acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+ boolean localTx = _mcf.getUseLocalTx();
+
+ if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
+ {
+ if (_userName != null && _password != null)
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createXATopicConnection(_userName, _password);
+ }
+ else
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createTopicConnection();
+ }
+ }
+ else
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createXATopicConnection();
+ }
+ else
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createTopicConnection();
+ }
+ }
+
+ if(!localTx)
+ {
+ _xaSession = ((XATopicConnection)_connection).createXATopicSession();
+
+ }
+ else
+ {
+ _session = ((TopicConnection)_connection).createTopicSession(localTx, acknowledgeMode);
+ }
+ }
+ else if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION)
+ {
+ if (_userName != null && _password != null)
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createXAQueueConnection(_userName, _password);
+ }
+ else
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createQueueConnection();
+ }
+ }
+ else
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createXAQueueConnection();
+ }
+ else
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createQueueConnection();
+ }
+ }
+
+ if(!localTx)
+ {
+ _xaSession = ((XAQueueConnection)_connection).createXAQueueSession();
+
+ }
+ else
+ {
+ _session = ((QueueConnection)_connection).createQueueSession(localTx, acknowledgeMode);
+
+ }
+ }
+ else
+ {
+ if (_userName != null && _password != null)
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createXAConnection(_userName, _password);
+ }
+ else
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createConnection();
+ }
+ }
+ else
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createXAConnection();
+ }
+ else
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createConnection();
+ }
+ }
+
+ if(!localTx)
+ {
+ _xaSession = ((XAQueueConnection)_connection).createXASession();
+
+ }
+ else
+ {
+ _session = ((QueueConnection)_connection).createSession(localTx, acknowledgeMode);
+
+ }
+ }
+
+ _connection.setExceptionListener(this);
+ }
+ catch (JMSException je)
+ {
+ throw new ResourceException(je.getMessage(), je);
+ }
+ }
+
+ protected void setInManagedTx(boolean inManagedTx)
+ {
+ this._inManagedTx = inManagedTx;
+ }
+
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnectionFactory.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnectionFactory.java
new file mode 100644
index 0000000000..377a0c6253
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnectionFactory.java
@@ -0,0 +1,623 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.io.PrintWriter;
+import java.util.Set;
+
+import javax.jms.ConnectionMetaData;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionManager;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.resource.spi.ResourceAdapter;
+import javax.resource.spi.ResourceAdapterAssociation;
+import javax.security.auth.Subject;
+
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Qpid ManagedConectionFactory
+ *
+ */
+public class QpidRAManagedConnectionFactory implements ManagedConnectionFactory, ResourceAdapterAssociation
+{
+ /**
+ * Serial version UID
+ */
+ private static final long serialVersionUID = -8798804592247643959L;
+
+ /**
+ * The logger
+ */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAManagedConnectionFactory.class);
+
+ /**
+ * The resource adapter
+ */
+ private QpidResourceAdapter _ra;
+
+ /**
+ * Connection manager
+ */
+ private ConnectionManager _cm;
+
+ /**
+ * The managed connection factory properties
+ */
+ private final QpidRAMCFProperties _mcfProperties;
+
+ /**
+ * Connection Factory used if properties are set
+ */
+ private AMQConnectionFactory _connectionFactory;
+
+ /**
+ * Constructor
+ */
+ public QpidRAManagedConnectionFactory()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+
+ _ra = null;
+ _cm = null;
+ _mcfProperties = new QpidRAMCFProperties();
+ }
+
+ /**
+ * Creates a Connection Factory instance
+ *
+ * @return javax.resource.cci.ConnectionFactory instance
+ * @throws ResourceException Thrown if a connection factory cant be created
+ */
+ public Object createConnectionFactory() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionFactory()");
+ }
+
+ return createConnectionFactory(new QpidRAConnectionManager());
+ }
+
+ /**
+ * Creates a Connection Factory instance
+ *
+ * @param cxManager The connection manager
+ * @return javax.resource.cci.ConnectionFactory instance
+ * @throws ResourceException Thrown if a connection factory cant be created
+ */
+ public Object createConnectionFactory(final ConnectionManager cxManager) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionFactory(" + cxManager + ")");
+ }
+
+ _cm = cxManager;
+
+ QpidRAConnectionFactory cf = new QpidRAConnectionFactoryImpl(this, _cm);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created connection factory: " + cf +
+ ", using connection manager: " +
+ _cm);
+ }
+
+ return cf;
+ }
+
+ /**
+ * Creates a new physical connection to the underlying EIS resource manager.
+ *
+ * @param subject Caller's security information
+ * @param cxRequestInfo Additional resource adapter specific connection request information
+ * @return The managed connection
+ * @throws ResourceException Thrown if a managed connection cant be created
+ */
+ public ManagedConnection createManagedConnection(final Subject subject, final ConnectionRequestInfo cxRequestInfo) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createManagedConnection(" + subject + ", " + cxRequestInfo + ")");
+ }
+
+ QpidRAConnectionRequestInfo cri = getCRI((QpidRAConnectionRequestInfo)cxRequestInfo);
+
+ QpidRACredential credential = QpidRACredential.getCredential(this, subject, cri);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("jms credential: " + credential);
+ }
+
+ QpidRAManagedConnection mc = new QpidRAManagedConnection(this,
+ cri,
+ _ra.getTM(),
+ credential.getUserName(),
+ credential.getPassword());
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("created new managed connection: " + mc);
+ }
+
+ return mc;
+ }
+
+ /**
+ * Returns a matched connection from the candidate set of connections.
+ *
+ * @param connectionSet The candidate connection set
+ * @param subject Caller's security information
+ * @param cxRequestInfo Additional resource adapter specific connection request information
+ * @return The managed connection
+ * @throws ResourceException Thrown if no managed connection can be found
+ */
+ @SuppressWarnings("rawtypes")
+ public ManagedConnection matchManagedConnections(final Set connectionSet,
+ final Subject subject,
+ final ConnectionRequestInfo cxRequestInfo) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("matchManagedConnections(" + connectionSet +
+ ", " +
+ subject +
+ ", " +
+ cxRequestInfo +
+ ")");
+ }
+
+ QpidRAConnectionRequestInfo cri = getCRI((QpidRAConnectionRequestInfo)cxRequestInfo);
+ QpidRACredential credential = QpidRACredential.getCredential(this, subject, cri);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Looking for connection matching credentials: " + credential);
+ }
+
+ for (final Object obj : connectionSet)
+ {
+ if (obj instanceof QpidRAManagedConnection)
+ {
+ QpidRAManagedConnection mc = (QpidRAManagedConnection)obj;
+ ManagedConnectionFactory mcf = mc.getManagedConnectionFactory();
+
+ if ((mc.getUserName() == null || mc.getUserName() != null && mc.getUserName()
+ .equals(credential.getUserName())) && mcf.equals(this))
+ {
+ if (cri.equals(mc.getCRI()))
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Found matching connection: " + mc);
+ }
+
+ return mc;
+ }
+ }
+ }
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("No matching connection was found");
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the log writer -- NOT SUPPORTED
+ *
+ * @param out The writer
+ * @throws ResourceException Thrown if the writer cant be set
+ */
+ public void setLogWriter(final PrintWriter out) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setLogWriter(" + out + ")");
+ }
+ }
+
+ /**
+ * Get the log writer -- NOT SUPPORTED
+ *
+ * @return The writer
+ * @throws ResourceException Thrown if the writer cant be retrieved
+ */
+ public PrintWriter getLogWriter() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getLogWriter()");
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the resource adapter
+ *
+ * @return The resource adapter
+ */
+ public ResourceAdapter getResourceAdapter()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getResourceAdapter()");
+ }
+
+ return _ra;
+ }
+
+ /**
+ * Set the resource adapter
+ *
+ * @param ra The resource adapter
+ * @throws ResourceException Thrown if incorrect resource adapter
+ */
+ public void setResourceAdapter(final ResourceAdapter ra) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setResourceAdapter(" + ra + ")");
+ }
+
+ if (!(ra instanceof QpidResourceAdapter))
+ {
+ throw new ResourceException("Resource adapter is " + ra);
+ }
+
+ this._ra = (QpidResourceAdapter)ra;
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this one.
+ *
+ * @param obj Object with which to compare
+ * @return True if this object is the same as the obj argument; false otherwise.
+ */
+ @Override
+ public boolean equals(final Object obj)
+ {
+ if (obj instanceof QpidRAManagedConnectionFactory)
+ {
+ QpidRAManagedConnectionFactory other = (QpidRAManagedConnectionFactory)obj;
+
+ return _mcfProperties.equals(other.getProperties()) && _ra.equals(other.getResourceAdapter());
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Return the hash code for the object
+ *
+ * @return The hash code
+ */
+ @Override
+ public int hashCode()
+ {
+ int hash = _mcfProperties.hashCode();
+ hash += 31 * _ra.hashCode();
+
+ return hash;
+ }
+
+ /**
+ * Get the default session type
+ *
+ * @return The value
+ */
+ public String getSessionDefaultType()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSessionDefaultType()");
+ }
+
+ return _mcfProperties.getSessionDefaultType();
+ }
+
+ /**
+ * Set the default session type
+ *
+ * @param type either javax.jms.Topic or javax.jms.Queue
+ */
+ public void setSessionDefaultType(final String type)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSessionDefaultType(" + type + ")");
+ }
+
+ _mcfProperties.setSessionDefaultType(type);
+ }
+
+ public String getClientID()
+ {
+ return _mcfProperties.getClientId();
+ }
+
+ public void setClientID(final String clientID)
+ {
+ _mcfProperties.setClientId(clientID);
+ }
+
+ public String getConnectionURL()
+ {
+ return _mcfProperties.getConnectionURL() ;
+ }
+
+ public void setConnectionURL(final String connectionURL)
+ {
+ _mcfProperties.setConnectionURL(connectionURL);
+ }
+
+ public String getPassword()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDefaultPassword()");
+ }
+ return _mcfProperties.getPassword();
+ }
+
+ public void setPassword(final String defaultPassword)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDefaultPassword(" + defaultPassword + ")");
+ }
+ _mcfProperties.setPassword(defaultPassword);
+ }
+
+ public String getUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDefaultUsername()");
+ }
+ return _mcfProperties.getUserName();
+ }
+
+ public void setUserName(final String defaultUsername)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDefaultUsername(" + defaultUsername + ")");
+ }
+ _mcfProperties.setUserName(defaultUsername);
+ }
+
+ public String getHost()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getHost()");
+ }
+ return _mcfProperties.getHost();
+ }
+
+ public void setHost(final String host)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setHost(" + host + ")");
+ }
+ _mcfProperties.setHost(host);
+ }
+
+ public Integer getPort()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPort()");
+ }
+ return _mcfProperties.getPort();
+ }
+
+ public void setPort(final Integer port)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPort(" + port + ")");
+ }
+ _mcfProperties.setPort(port);
+ }
+
+ public String getPath()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPath()");
+ }
+ return _mcfProperties.getPath();
+ }
+
+ public void setPath(final String path)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPath(" + path + ")");
+ }
+ _mcfProperties.setPath(path);
+ }
+
+ /**
+ * Get the useTryLock.
+ *
+ * @return the useTryLock.
+ */
+ public Integer getUseTryLock()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUseTryLock()");
+ }
+
+ return _mcfProperties.getUseTryLock();
+ }
+
+ /**
+ * Set the useTryLock.
+ *
+ * @param useTryLock the useTryLock.
+ */
+ public void setUseTryLock(final Integer useTryLock)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUseTryLock(" + useTryLock + ")");
+ }
+
+ _mcfProperties.setUseTryLock(useTryLock);
+ }
+
+ /**
+ * Get the connection metadata
+ *
+ * @return The metadata
+ */
+ public ConnectionMetaData getMetaData()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMetadata()");
+ }
+
+ return new QpidRAConnectionMetaData();
+ }
+
+ /**
+ * Get the default connection factory
+ *
+ * @return The factory
+ */
+ protected synchronized AMQConnectionFactory getDefaultAMQConnectionFactory() throws ResourceException
+ {
+ if (_connectionFactory == null)
+ {
+ try
+ {
+ _connectionFactory = _ra.createAMQConnectionFactory(_mcfProperties);
+ }
+ catch (final QpidRAException qpidrae)
+ {
+ throw new ResourceException("Unexpected exception creating the connection factory", qpidrae) ;
+ }
+ }
+ return _connectionFactory;
+ }
+
+ /**
+ * Get a clean connection factory
+ *
+ * @return The factory
+ */
+ protected AMQConnectionFactory getCleanAMQConnectionFactory() throws ResourceException
+ {
+ try
+ {
+ return _ra.createAMQConnectionFactory(_mcfProperties);
+ }
+ catch (final QpidRAException qpidrae)
+ {
+ throw new ResourceException("Unexpected exception creating the connection factory", qpidrae) ;
+ }
+ }
+
+ /**
+ * Get the managed connection factory properties
+ *
+ * @return The properties
+ */
+ protected QpidRAMCFProperties getProperties()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getProperties()");
+ }
+
+ return _mcfProperties;
+ }
+
+ /**
+ * Get a connection request info instance
+ *
+ * @param info The instance that should be updated; may be <code>null</code>
+ * @return The instance
+ * @throws ResourceException
+ */
+ private QpidRAConnectionRequestInfo getCRI(final QpidRAConnectionRequestInfo info)
+ throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getCRI(" + info + ")");
+ }
+
+ if (info == null)
+ {
+ // Create a default one
+ return new QpidRAConnectionRequestInfo(_ra, _mcfProperties.getType());
+ }
+ else
+ {
+ // Fill the one with any defaults
+ info.setDefaults(_ra);
+ return info;
+ }
+ }
+
+ public Boolean getUseLocalTx()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUseLocalTx()");
+ }
+
+ return _mcfProperties.isUseLocalTx();
+ }
+
+ public void setUseLocalTx(final Boolean localTx)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUseLocalTx(" + localTx + ")");
+ }
+
+ _mcfProperties.setUseLocalTx(localTx);
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMapMessage.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMapMessage.java
new file mode 100644
index 0000000000..797a28a09a
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMapMessage.java
@@ -0,0 +1,457 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.util.Enumeration;
+
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message
+ *
+ */
+public class QpidRAMapMessage extends QpidRAMessage implements MapMessage
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAMapMessage.class);
+
+ /**
+ * Create a new wrapper
+ *
+ * @param message the message
+ * @param session the session
+ */
+ public QpidRAMapMessage(final MapMessage message, final QpidRASessionImpl session)
+ {
+ super(message, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + message + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean getBoolean(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getBoolean(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getBoolean(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public byte getByte(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getByte(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getByte(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public byte[] getBytes(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getBytes(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getBytes(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public char getChar(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getChar(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getChar(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public double getDouble(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDouble(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getDouble(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public float getFloat(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getFloat(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getFloat(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int getInt(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getInt(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getInt(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long getLong(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getLong(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getLong(name);
+ }
+
+ /**
+ * Get the map names
+ * @return The values
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Enumeration<?> getMapNames() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMapNames()");
+ }
+
+ return ((MapMessage)_message).getMapNames();
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Object getObject(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getObject(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getObject(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public short getShort(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getShort(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getShort(name);
+ }
+
+ /**
+ * Get
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getString(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getString(" + name + ")");
+ }
+
+ return ((MapMessage)_message).getString(name);
+ }
+
+ /**
+ * Does the item exist
+ * @param name The name
+ * @return True / false
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean itemExists(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("itemExists(" + name + ")");
+ }
+
+ return ((MapMessage)_message).itemExists(name);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setBoolean(final String name, final boolean value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setBoolean(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setBoolean(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setByte(final String name, final byte value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setByte(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setByte(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @param offset The offset
+ * @param length The length
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setBytes(final String name, final byte[] value, final int offset, final int length) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setBytes(" + name + ", " + value + ", " + offset + ", " + length + ")");
+ }
+
+ ((MapMessage)_message).setBytes(name, value, offset, length);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setBytes(final String name, final byte[] value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setBytes(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setBytes(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setChar(final String name, final char value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setChar(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setChar(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setDouble(final String name, final double value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDouble(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setDouble(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setFloat(final String name, final float value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setFloat(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setFloat(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setInt(final String name, final int value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setInt(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setInt(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setLong(final String name, final long value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setLong(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setLong(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setObject(final String name, final Object value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setObject(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setObject(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setShort(final String name, final short value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setShort(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setShort(name, value);
+ }
+
+ /**
+ * Set
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setString(final String name, final String value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setString(" + name + ", " + value + ")");
+ }
+
+ ((MapMessage)_message).setString(name, value);
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java
new file mode 100644
index 0000000000..691fe8c40a
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java
@@ -0,0 +1,782 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.util.Enumeration;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message
+ */
+public class QpidRAMessage implements Message
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAMessage.class);
+
+ /** The message */
+ protected Message _message;
+
+ /** The session */
+ protected QpidRASessionImpl _session;
+
+ /**
+ * Create a new wrapper
+ * @param message the message
+ * @param session the session
+ */
+ public QpidRAMessage(final Message message, final QpidRASessionImpl session)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(message) + ", " + session + ")");
+ }
+
+ this._message = message;
+ this._session = session;
+ }
+
+ /**
+ * Acknowledge
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void acknowledge() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("acknowledge()");
+ }
+
+ _session.getSession(); // Check for closed
+ _message.acknowledge();
+ }
+
+ /**
+ * Clear body
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void clearBody() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("clearBody()");
+ }
+
+ _message.clearBody();
+ }
+
+ /**
+ * Clear properties
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void clearProperties() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("clearProperties()");
+ }
+
+ _message.clearProperties();
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean getBooleanProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getBooleanProperty(" + name + ")");
+ }
+
+ return _message.getBooleanProperty(name);
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public byte getByteProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getByteProperty(" + name + ")");
+ }
+
+ return _message.getByteProperty(name);
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public double getDoubleProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDoubleProperty(" + name + ")");
+ }
+
+ return _message.getDoubleProperty(name);
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public float getFloatProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getFloatProperty(" + name + ")");
+ }
+
+ return _message.getFloatProperty(name);
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int getIntProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getIntProperty(" + name + ")");
+ }
+
+ return _message.getIntProperty(name);
+ }
+
+ /**
+ * Get correlation id
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getJMSCorrelationID() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSCorrelationID()");
+ }
+
+ return _message.getJMSCorrelationID();
+ }
+
+ /**
+ * Get correlation id
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public byte[] getJMSCorrelationIDAsBytes() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSCorrelationIDAsBytes()");
+ }
+
+ return _message.getJMSCorrelationIDAsBytes();
+ }
+
+ /**
+ * Get delivery mode
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int getJMSDeliveryMode() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSDeliveryMode()");
+ }
+
+ return _message.getJMSDeliveryMode();
+ }
+
+ /**
+ * Get destination
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Destination getJMSDestination() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSDestination()");
+ }
+
+ return _message.getJMSDestination();
+ }
+
+ /**
+ * Get expiration
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long getJMSExpiration() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSExpiration()");
+ }
+
+ return _message.getJMSExpiration();
+ }
+
+ /**
+ * Get message id
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getJMSMessageID() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSMessageID()");
+ }
+
+ return _message.getJMSMessageID();
+ }
+
+ /**
+ * Get priority
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int getJMSPriority() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSPriority()");
+ }
+
+ return _message.getJMSPriority();
+ }
+
+ /**
+ * Get redelivered status
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean getJMSRedelivered() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSRedelivered()");
+ }
+
+ return _message.getJMSRedelivered();
+ }
+
+ /**
+ * Get reply to destination
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Destination getJMSReplyTo() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSReplyTo()");
+ }
+
+ return _message.getJMSReplyTo();
+ }
+
+ /**
+ * Get timestamp
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long getJMSTimestamp() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSTimestamp()");
+ }
+
+ return _message.getJMSTimestamp();
+ }
+
+ /**
+ * Get type
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getJMSType() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSType()");
+ }
+
+ return _message.getJMSType();
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long getLongProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getLongProperty(" + name + ")");
+ }
+
+ return _message.getLongProperty(name);
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Object getObjectProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getObjectProperty(" + name + ")");
+ }
+
+ return _message.getObjectProperty(name);
+ }
+
+ /**
+ * Get property names
+ * @return The values
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Enumeration<?> getPropertyNames() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPropertyNames()");
+ }
+
+ return _message.getPropertyNames();
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public short getShortProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getShortProperty(" + name + ")");
+ }
+
+ return _message.getShortProperty(name);
+ }
+
+ /**
+ * Get property
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getStringProperty(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getStringProperty(" + name + ")");
+ }
+
+ return _message.getStringProperty(name);
+ }
+
+ /**
+ * Do property exist
+ * @param name The name
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean propertyExists(final String name) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("propertyExists(" + name + ")");
+ }
+
+ return _message.propertyExists(name);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setBooleanProperty(final String name, final boolean value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setBooleanProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setBooleanProperty(name, value);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setByteProperty(final String name, final byte value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setByteProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setByteProperty(name, value);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setDoubleProperty(final String name, final double value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDoubleProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setDoubleProperty(name, value);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setFloatProperty(final String name, final float value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setFloatProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setFloatProperty(name, value);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setIntProperty(final String name, final int value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setIntProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setIntProperty(name, value);
+ }
+
+ /**
+ * Set correlation id
+ * @param correlationID The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSCorrelationID(final String correlationID) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSCorrelationID(" + correlationID + ")");
+ }
+
+ _message.setJMSCorrelationID(correlationID);
+ }
+
+ /**
+ * Set correlation id
+ * @param correlationID The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSCorrelationIDAsBytes(final byte[] correlationID) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSCorrelationIDAsBytes(" + correlationID + ")");
+ }
+
+ _message.setJMSCorrelationIDAsBytes(correlationID);
+ }
+
+ /**
+ * Set delivery mode
+ * @param deliveryMode The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSDeliveryMode(final int deliveryMode) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSDeliveryMode(" + deliveryMode + ")");
+ }
+
+ _message.setJMSDeliveryMode(deliveryMode);
+ }
+
+ /**
+ * Set destination
+ * @param destination The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSDestination(final Destination destination) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSDestination(" + destination + ")");
+ }
+
+ _message.setJMSDestination(destination);
+ }
+
+ /**
+ * Set expiration
+ * @param expiration The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSExpiration(final long expiration) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSExpiration(" + expiration + ")");
+ }
+
+ _message.setJMSExpiration(expiration);
+ }
+
+ /**
+ * Set message id
+ * @param id The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSMessageID(final String id) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSMessageID(" + id + ")");
+ }
+
+ _message.setJMSMessageID(id);
+ }
+
+ /**
+ * Set priority
+ * @param priority The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSPriority(final int priority) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSPriority(" + priority + ")");
+ }
+
+ _message.setJMSPriority(priority);
+ }
+
+ /**
+ * Set redelivered status
+ * @param redelivered The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSRedelivered(final boolean redelivered) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSRedelivered(" + redelivered + ")");
+ }
+
+ _message.setJMSRedelivered(redelivered);
+ }
+
+ /**
+ * Set reply to
+ * @param replyTo The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSReplyTo(final Destination replyTo) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSReplyTo(" + replyTo + ")");
+ }
+
+ _message.setJMSReplyTo(replyTo);
+ }
+
+ /**
+ * Set timestamp
+ * @param timestamp The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSTimestamp(final long timestamp) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSTimestamp(" + timestamp + ")");
+ }
+
+ _message.setJMSTimestamp(timestamp);
+ }
+
+ /**
+ * Set type
+ * @param type The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setJMSType(final String type) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setJMSType(" + type + ")");
+ }
+
+ _message.setJMSType(type);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setLongProperty(final String name, final long value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setLongProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setLongProperty(name, value);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setObjectProperty(final String name, final Object value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setObjectProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setObjectProperty(name, value);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setShortProperty(final String name, final short value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setShortProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setShortProperty(name, value);
+ }
+
+ /**
+ * Set property
+ * @param name The name
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setStringProperty(final String name, final String value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setStringProperty(" + name + ", " + value + ")");
+ }
+
+ _message.setStringProperty(name, value);
+ }
+
+ /**
+ * Return the hash code
+ * @return The hash code
+ */
+ @Override
+ public int hashCode()
+ {
+ return _message.hashCode();
+ }
+
+ /**
+ * Check for equality
+ * @param object The other object
+ * @return True / false
+ */
+ @Override
+ public boolean equals(final Object object)
+ {
+ if (object != null && object instanceof QpidRAMessage)
+ {
+ return _message.equals(((QpidRAMessage)object)._message);
+ }
+ else
+ {
+ return _message.equals(object);
+ }
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageConsumer.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageConsumer.java
new file mode 100644
index 0000000000..aa0e6adb0e
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageConsumer.java
@@ -0,0 +1,353 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.ObjectMessage;
+import javax.jms.StreamMessage;
+import javax.jms.TextMessage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message consumer
+ *
+ */
+public class QpidRAMessageConsumer implements MessageConsumer
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAMessageConsumer.class);
+
+ /** The wrapped message consumer */
+ protected MessageConsumer _consumer;
+ /** The closed flag */
+ private AtomicBoolean _closed = new AtomicBoolean();
+
+ /** The session for this consumer */
+ protected QpidRASessionImpl _session;
+
+ /**
+ * Create a new wrapper
+ * @param consumer the consumer
+ * @param session the session
+ */
+ public QpidRAMessageConsumer(final MessageConsumer consumer, final QpidRASessionImpl session)
+ {
+ this._consumer = consumer;
+ this._session = session;
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("new QpidRAMessageConsumer " + this +
+ " consumer=" +
+ Util.asString(consumer) +
+ " session=" +
+ session);
+ }
+ }
+
+ /**
+ * Close
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void close() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("close " + this);
+ }
+ try
+ {
+ closeConsumer();
+ }
+ finally
+ {
+ _session.removeConsumer(this);
+ }
+ }
+
+ /**
+ * Check state
+ * @exception JMSException Thrown if an error occurs
+ */
+ void checkState() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("checkState()");
+ }
+ _session.checkState();
+ }
+
+ /**
+ * Get message listener
+ * @return The listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageListener getMessageListener() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMessageListener()");
+ }
+
+ checkState();
+ _session.checkStrict();
+ return _consumer.getMessageListener();
+ }
+
+ /**
+ * Set message listener
+ * @param listener The listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setMessageListener(final MessageListener listener) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ checkState();
+ _session.checkStrict();
+ if (listener == null)
+ {
+ _consumer.setMessageListener(null);
+ }
+ else
+ {
+ _consumer.setMessageListener(wrapMessageListener(listener));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Get message selector
+ * @return The selector
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getMessageSelector() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMessageSelector()");
+ }
+
+ checkState();
+ return _consumer.getMessageSelector();
+ }
+
+ /**
+ * Receive
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Message receive() throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("receive " + this);
+ }
+
+ checkState();
+ // Make an explicit start check otherwise qpid starts the dispatcher
+ Message message = (_session.isStarted() ? _consumer.receive() : null);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("received " + this + " result=" + Util.asString(message));
+ }
+
+ if (message == null)
+ {
+ return null;
+ }
+ else
+ {
+ return wrapMessage(message);
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Receive
+ * @param timeout The timeout value
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Message receive(final long timeout) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("receive " + this + " timeout=" + timeout);
+ }
+
+ checkState();
+ // Make an explicit start check otherwise qpid starts the dispatcher
+ Message message = (_session.isStarted() ? _consumer.receive(timeout) : null);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("received " + this + " result=" + Util.asString(message));
+ }
+
+ if (message == null)
+ {
+ return null;
+ }
+ else
+ {
+ return wrapMessage(message);
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Receive
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Message receiveNoWait() throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("receiveNoWait " + this);
+ }
+
+ checkState();
+ // Make an explicit start check otherwise qpid starts the dispatcher
+ Message message = (_session.isStarted() ? _consumer.receiveNoWait() : null);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("received " + this + " result=" + Util.asString(message));
+ }
+
+ if (message == null)
+ {
+ return null;
+ }
+ else
+ {
+ return wrapMessage(message);
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Close consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ void closeConsumer() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("closeConsumer()");
+ }
+
+ if (!_closed.getAndSet(true))
+ {
+ _consumer.close();
+ }
+ }
+
+ /**
+ * Wrap message
+ * @param message The message to be wrapped
+ * @return The wrapped message
+ */
+ Message wrapMessage(final Message message)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("wrapMessage(" + Util.asString(message) + ")");
+ }
+
+ if (message instanceof BytesMessage)
+ {
+ return new QpidRABytesMessage((BytesMessage)message, _session);
+ }
+ else if (message instanceof MapMessage)
+ {
+ return new QpidRAMapMessage((MapMessage)message, _session);
+ }
+ else if (message instanceof ObjectMessage)
+ {
+ return new QpidRAObjectMessage((ObjectMessage)message, _session);
+ }
+ else if (message instanceof StreamMessage)
+ {
+ return new QpidRAStreamMessage((StreamMessage)message, _session);
+ }
+ else if (message instanceof TextMessage)
+ {
+ return new QpidRATextMessage((TextMessage)message, _session);
+ }
+ return new QpidRAMessage(message, _session);
+ }
+
+ /**
+ * Wrap message listener
+ * @param listener The listener to be wrapped
+ * @return The wrapped listener
+ */
+ MessageListener wrapMessageListener(final MessageListener listener)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMessageSelector()");
+ }
+
+ return new QpidRAMessageListener(listener, this);
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageListener.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageListener.java
new file mode 100644
index 0000000000..e272df818f
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageListener.java
@@ -0,0 +1,74 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message listener
+ */
+public class QpidRAMessageListener implements MessageListener
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAMessageListener.class);
+
+ /** The message listener */
+ private final MessageListener _listener;
+
+ /** The consumer */
+ private final QpidRAMessageConsumer _consumer;
+
+ /**
+ * Create a new wrapper
+ * @param listener the listener
+ * @param consumer the consumer
+ */
+ public QpidRAMessageListener(final MessageListener listener, final QpidRAMessageConsumer consumer)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + listener + ", " + consumer + ")");
+ }
+
+ this._listener = listener;
+ this._consumer = consumer;
+ }
+
+ /**
+ * On message
+ * @param message The message
+ */
+ public void onMessage(Message message)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("onMessage(" + Util.asString(message) + ")");
+ }
+
+ message = _consumer.wrapMessage(message);
+ _listener.onMessage(message);
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageProducer.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageProducer.java
new file mode 100644
index 0000000000..ce0656e30d
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageProducer.java
@@ -0,0 +1,419 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * QpidRAMessageProducer.
+ *
+ */
+public class QpidRAMessageProducer implements MessageProducer
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAMessageProducer.class);
+
+ /** The wrapped message producer */
+ protected MessageProducer _producer;
+
+ /** The session for this consumer */
+ protected QpidRASessionImpl _session;
+
+ /**
+ * Create a new wrapper
+ * @param producer the producer
+ * @param session the session
+ */
+ public QpidRAMessageProducer(final MessageProducer producer, final QpidRASessionImpl session)
+ {
+ this._producer = producer;
+ this._session = session;
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("new QpidRAMessageProducer " + this +
+ " producer=" +
+ Util.asString(producer) +
+ " session=" +
+ session);
+ }
+ }
+
+ /**
+ * Close
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void close() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("close " + this);
+ }
+ try
+ {
+ closeProducer();
+ }
+ finally
+ {
+ _session.removeProducer(this);
+ }
+ }
+
+ /**
+ * Send message
+ * @param destination The destination
+ * @param message The message
+ * @param deliveryMode The delivery mode
+ * @param priority The priority
+ * @param timeToLive The time to live
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void send(final Destination destination,
+ final Message message,
+ final int deliveryMode,
+ final int priority,
+ final long timeToLive) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this +
+ " destination=" +
+ destination +
+ " message=" +
+ Util.asString(message) +
+ " deliveryMode=" +
+ deliveryMode +
+ " priority=" +
+ priority +
+ " ttl=" +
+ timeToLive);
+ }
+
+ checkState();
+
+ _producer.send(destination, message, deliveryMode, priority, timeToLive);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Send message
+ * @param destination The destination
+ * @param message The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void send(final Destination destination, final Message message) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this + " destination=" + destination + " message=" + Util.asString(message));
+ }
+
+ checkState();
+
+ _producer.send(destination, message);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Send message
+ * @param message The message
+ * @param deliveryMode The delivery mode
+ * @param priority The priority
+ * @param timeToLive The time to live
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void send(final Message message, final int deliveryMode, final int priority, final long timeToLive) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this +
+ " message=" +
+ Util.asString(message) +
+ " deliveryMode=" +
+ deliveryMode +
+ " priority=" +
+ priority +
+ " ttl=" +
+ timeToLive);
+ }
+
+ checkState();
+
+ _producer.send(message, deliveryMode, priority, timeToLive);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Send message
+ * @param message The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void send(final Message message) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this + " message=" + Util.asString(message));
+ }
+
+ checkState();
+
+ _producer.send(message);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Get the delivery mode
+ * @return The mode
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int getDeliveryMode() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDeliveryMode()");
+ }
+
+ return _producer.getDeliveryMode();
+ }
+
+ /**
+ * Get the destination
+ * @return The destination
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Destination getDestination() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDestination()");
+ }
+
+ return _producer.getDestination();
+ }
+
+ /**
+ * Disable message id
+ * @return True if disable
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean getDisableMessageID() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDisableMessageID()");
+ }
+
+ return _producer.getDisableMessageID();
+ }
+
+ /**
+ * Disable message timestamp
+ * @return True if disable
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean getDisableMessageTimestamp() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDisableMessageTimestamp()");
+ }
+
+ return _producer.getDisableMessageTimestamp();
+ }
+
+ /**
+ * Get the priority
+ * @return The priority
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int getPriority() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPriority()");
+ }
+
+ return _producer.getPriority();
+ }
+
+ /**
+ * Get the time to live
+ * @return The ttl
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long getTimeToLive() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTimeToLive()");
+ }
+
+ return _producer.getTimeToLive();
+ }
+
+ /**
+ * Set the delivery mode
+ * @param deliveryMode The mode
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setDeliveryMode(final int deliveryMode) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDeliveryMode(" + deliveryMode + ")");
+ }
+
+ _producer.setDeliveryMode(deliveryMode);
+ }
+
+ /**
+ * Set disable message id
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setDisableMessageID(final boolean value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDisableMessageID(" + value + ")");
+ }
+
+ _producer.setDisableMessageID(value);
+ }
+
+ /**
+ * Set disable message timestamp
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setDisableMessageTimestamp(final boolean value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDisableMessageTimestamp(" + value + ")");
+ }
+
+ _producer.setDisableMessageTimestamp(value);
+ }
+
+ /**
+ * Set the priority
+ * @param defaultPriority The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setPriority(final int defaultPriority) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPriority(" + defaultPriority + ")");
+ }
+
+ _producer.setPriority(defaultPriority);
+ }
+
+ /**
+ * Set the ttl
+ * @param timeToLive The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setTimeToLive(final long timeToLive) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTimeToLive(" + timeToLive + ")");
+ }
+
+ _producer.setTimeToLive(timeToLive);
+ }
+
+ /**
+ * Check state
+ * @exception JMSException Thrown if an error occurs
+ */
+ void checkState() throws JMSException
+ {
+ _session.checkState();
+ }
+
+ /**
+ * Close producer
+ * @exception JMSException Thrown if an error occurs
+ */
+ void closeProducer() throws JMSException
+ {
+ _producer.close();
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMetaData.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMetaData.java
new file mode 100644
index 0000000000..0ad7d089c3
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMetaData.java
@@ -0,0 +1,116 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.resource.ResourceException;
+import javax.resource.spi.ManagedConnectionMetaData;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Managed connection meta data
+ *
+ */
+public class QpidRAMetaData implements ManagedConnectionMetaData
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAMetaData.class);
+
+ /** The managed connection */
+ private final QpidRAManagedConnection _mc;
+
+ /**
+ * Constructor
+ * @param mc The managed connection
+ */
+ public QpidRAMetaData(final QpidRAManagedConnection mc)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + mc + ")");
+ }
+
+ this._mc = mc;
+ }
+
+ /**
+ * Get the EIS product name
+ * @return The name
+ * @exception ResourceException Thrown if operation fails
+ */
+ public String getEISProductName() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getEISProductName()");
+ }
+
+ return "Qpid";
+ }
+
+ /**
+ * Get the EIS product version
+ * @return The version
+ * @exception ResourceException Thrown if operation fails
+ */
+ public String getEISProductVersion() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getEISProductVersion()");
+ }
+
+ return "2.0";
+ }
+
+ /**
+ * Get the user name
+ * @return The user name
+ * @exception ResourceException Thrown if operation fails
+ */
+ public String getUserName() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUserName()");
+ }
+
+ return _mc.getUserName();
+ }
+
+ /**
+ * Get the maximum number of connections -- RETURNS 0
+ * @return The number
+ * @exception ResourceException Thrown if operation fails
+ */
+ public int getMaxConnections() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMaxConnections()");
+ }
+
+ return 0;
+ }
+
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAObjectMessage.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAObjectMessage.java
new file mode 100644
index 0000000000..926319bb85
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAObjectMessage.java
@@ -0,0 +1,85 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+import javax.jms.ObjectMessage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message
+ *
+ */
+public class QpidRAObjectMessage extends QpidRAMessage implements ObjectMessage
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAObjectMessage.class);
+
+ /**
+ * Create a new wrapper
+ * @param message the message
+ * @param session the session
+ */
+ public QpidRAObjectMessage(final ObjectMessage message, final QpidRASessionImpl session)
+ {
+ super(message, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(message) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get the object
+ * @return The object
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Serializable getObject() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getObject()");
+ }
+
+ return ((ObjectMessage)_message).getObject();
+ }
+
+ /**
+ * Set the object
+ * @param object The object
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setObject(final Serializable object) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setObject(" + object + ")");
+ }
+
+ ((ObjectMessage)_message).setObject(object);
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAProperties.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAProperties.java
new file mode 100644
index 0000000000..21f7d2574f
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAProperties.java
@@ -0,0 +1,186 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.io.Serializable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The RA default properties - these are set in the ra.xml file
+ *
+ */
+public class QpidRAProperties extends ConnectionFactoryProperties implements Serializable
+{
+ /** Serial version UID */
+ private static final long serialVersionUID = -4823893873707374791L;
+
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAProperties.class);
+
+ private static final int DEFAULT_SETUP_ATTEMPTS = 10;
+
+ private static final long DEFAULT_SETUP_INTERVAL = 2 * 1000;
+
+ private int _setupAttempts = DEFAULT_SETUP_ATTEMPTS;
+
+ private long _setupInterval = DEFAULT_SETUP_INTERVAL;
+
+ /** Use Local TX instead of XA */
+ private Boolean _localTx = false;
+
+ /** Class used to locate the Transaction Manager. */
+ private String _transactionManagerLocatorClass ;
+
+ /** Method used to locate the TM */
+ private String _transactionManagerLocatorMethod ;
+
+
+ /**
+ * Constructor
+ */
+ public QpidRAProperties()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+ }
+
+ /**
+ * Get the use XA flag
+ * @return The value
+ */
+ public Boolean getUseLocalTx()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUseLocalTx()");
+ }
+
+ return _localTx;
+ }
+
+ /**
+ * Set the use XA flag
+ * @param localTx The value
+ */
+ public void setUseLocalTx(final Boolean localTx)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUseLocalTx(" + localTx + ")");
+ }
+
+ this._localTx = localTx;
+ }
+
+ public void setTransactionManagerLocatorClass(final String transactionManagerLocatorClass)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTransactionManagerLocatorClass(" + transactionManagerLocatorClass + ")");
+ }
+
+ this._transactionManagerLocatorClass = transactionManagerLocatorClass;
+ }
+
+ public String getTransactionManagerLocatorClass()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransactionManagerLocatorClass()");
+ }
+
+ return _transactionManagerLocatorClass;
+ }
+
+ public String getTransactionManagerLocatorMethod()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransactionManagerLocatorMethod()");
+ }
+
+ return _transactionManagerLocatorMethod;
+ }
+
+ public void setTransactionManagerLocatorMethod(final String transactionManagerLocatorMethod)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTransactionManagerLocatorMethod(" + transactionManagerLocatorMethod + ")");
+ }
+
+ this._transactionManagerLocatorMethod = transactionManagerLocatorMethod;
+ }
+
+ public int getSetupAttempts()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSetupAttempts()");
+ }
+
+ return _setupAttempts;
+ }
+
+ public void setSetupAttempts(int setupAttempts)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSetupAttempts(" + setupAttempts + ")");
+ }
+
+ this._setupAttempts = setupAttempts;
+ }
+
+ public long getSetupInterval()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSetupInterval()");
+ }
+
+ return _setupInterval;
+ }
+
+ public void setSetupInterval(long setupInterval)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSetupInterval(" + setupInterval + ")");
+ }
+
+ this._setupInterval = setupInterval;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "QpidRAProperties[localTx=" + _localTx +
+ ", transactionManagerLocatorClass=" + _transactionManagerLocatorClass +
+ ", transactionManagerLocatorMethod=" + _transactionManagerLocatorMethod +
+ ", setupAttempts=" + _setupAttempts +
+ ", setupInterval=" + _setupInterval + "]";
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueBrowser.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueBrowser.java
new file mode 100644
index 0000000000..bcd2d3b63c
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueBrowser.java
@@ -0,0 +1,139 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.util.Enumeration;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * QpidRAQueueBrowser.
+ *
+ */
+public class QpidRAQueueBrowser implements QueueBrowser
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAQueueBrowser.class);
+
+ /** The wrapped queue browser */
+ protected QueueBrowser _browser;
+
+ /** The session for this consumer */
+ protected QpidRASessionImpl _session;
+
+ /** The closed flag */
+ private AtomicBoolean _isClosed = new AtomicBoolean();
+
+ /**
+ * Create a new wrapper
+ * @param browser the browser
+ * @param session the session
+ */
+ public QpidRAQueueBrowser(final QueueBrowser browser, final QpidRASessionImpl session)
+ {
+ _browser = browser;
+ _session = session;
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("new QpidRAQueueBrowser " + this +
+ " browser=" +
+ Util.asString(browser) +
+ " session=" +
+ session);
+ }
+ }
+
+ /**
+ * Close
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void close() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("close " + this);
+ }
+
+ if (!_isClosed.getAndSet(true))
+ {
+ try
+ {
+ _browser.close();
+ }
+ finally
+ {
+ _session.removeQueueBrowser(this);
+ }
+ }
+ }
+
+ /**
+ * Get the queue associated with this browser.
+ * @return the associated queue.
+ */
+ public Queue getQueue()
+ throws JMSException
+ {
+ return _browser.getQueue();
+ }
+
+ /**
+ * Get the message selector associated with this browser.
+ * @return the associated message selector.
+ */
+ public String getMessageSelector()
+ throws JMSException
+ {
+ return _browser.getMessageSelector();
+ }
+
+ /**
+ * Get an enumeration for the current browser.
+ * @return The enumeration.
+ */
+ public Enumeration getEnumeration()
+ throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getEnumeration " + this + " browser=" + Util.asString(_browser));
+ }
+
+ _session.lock();
+ try
+ {
+ _session.checkState();
+ return _browser.getEnumeration();
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueReceiver.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueReceiver.java
new file mode 100644
index 0000000000..ad1f7fc43b
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueReceiver.java
@@ -0,0 +1,70 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.QueueReceiver;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a queue receiver
+ *
+ */
+public class QpidRAQueueReceiver extends QpidRAMessageConsumer implements QueueReceiver
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAQueueReceiver.class);
+
+ /**
+ * Create a new wrapper
+ * @param consumer the queue receiver
+ * @param session the session
+ */
+ public QpidRAQueueReceiver(final QueueReceiver consumer, final QpidRASessionImpl session)
+ {
+ super(consumer, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(consumer) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get queue
+ * @return The queue
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Queue getQueue() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getQueue()");
+ }
+
+ checkState();
+ return ((QueueReceiver)_consumer).getQueue();
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueSender.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueSender.java
new file mode 100644
index 0000000000..7a123618be
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueSender.java
@@ -0,0 +1,147 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Queue;
+import javax.jms.QueueSender;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * QpidRAQueueSender.
+ *
+ */
+public class QpidRAQueueSender extends QpidRAMessageProducer implements QueueSender
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAQueueSender.class);
+
+ /**
+ * Create a new wrapper
+ * @param producer the producer
+ * @param session the session
+ */
+ public QpidRAQueueSender(final QueueSender producer, final QpidRASessionImpl session)
+ {
+ super(producer, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(producer) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get queue
+ * @return The queue
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Queue getQueue() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getQueue()");
+ }
+
+ return ((QueueSender)_producer).getQueue();
+ }
+
+ /**
+ * Send message
+ * @param destination The destination
+ * @param message The message
+ * @param deliveryMode The delivery mode
+ * @param priority The priority
+ * @param timeToLive The time to live
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void send(final Queue destination,
+ final Message message,
+ final int deliveryMode,
+ final int priority,
+ final long timeToLive) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this +
+ " destination=" +
+ destination +
+ " message=" +
+ Util.asString(message) +
+ " deliveryMode=" +
+ deliveryMode +
+ " priority=" +
+ priority +
+ " ttl=" +
+ timeToLive);
+ }
+
+ checkState();
+ _producer.send(destination, message, deliveryMode, priority, timeToLive);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Send message
+ * @param destination The destination
+ * @param message The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void send(final Queue destination, final Message message) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this + " destination=" + destination + " message=" + Util.asString(message));
+ }
+
+ checkState();
+ _producer.send(destination, message);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRASession.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRASession.java
new file mode 100644
index 0000000000..081677ca4b
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRASession.java
@@ -0,0 +1,33 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.jms.JMSException;
+
+public interface QpidRASession
+{
+ public void setQpidSessionFactory(QpidRASessionFactory sf);
+
+ public void start() throws JMSException;
+
+ public void close() throws JMSException;
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactory.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactory.java
new file mode 100644
index 0000000000..cf28d5bba1
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactory.java
@@ -0,0 +1,62 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.QueueConnection;
+import javax.jms.TemporaryQueue;
+import javax.jms.TemporaryTopic;
+import javax.jms.TopicConnection;
+import javax.jms.XAConnection;
+import javax.jms.XAQueueConnection;
+import javax.jms.XATopicConnection;
+
+/**
+ * A joint interface for all connection types
+ *
+ */
+public interface QpidRASessionFactory extends Connection, TopicConnection, QueueConnection, XAConnection,
+ XATopicConnection, XAQueueConnection
+{
+ /** Error message for strict behaviour */
+ String ISE = "This method is not applicable inside the application server. See the J2EE spec, e.g. J2EE1.4 Section 6.6";
+
+ /**
+ * Add a temporary queue
+ * @param temp The temporary queue
+ */
+ void addTemporaryQueue(TemporaryQueue temp);
+
+ /**
+ * Add a temporary topic
+ * @param temp The temporary topic
+ */
+ void addTemporaryTopic(TemporaryTopic temp);
+
+ /**
+ * Notification that a session is closed
+ * @param session The session
+ * @throws JMSException for any error
+ */
+ void closeSession(QpidRASessionImpl session) throws JMSException;
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactoryImpl.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactoryImpl.java
new file mode 100644
index 0000000000..e2bc2d2008
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactoryImpl.java
@@ -0,0 +1,911 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+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.jms.XAQueueSession;
+import javax.jms.XASession;
+import javax.jms.XATopicSession;
+import javax.naming.Reference;
+import javax.resource.Referenceable;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implements the JMS Connection API and produces {@link QpidRASessionImpl} objects.
+ *
+ */
+public class QpidRASessionFactoryImpl implements QpidRASessionFactory, Referenceable
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRASessionFactoryImpl.class);
+
+ /** Are we closed? */
+ private boolean _closed = false;
+
+ /** The naming reference */
+ private Reference _reference;
+
+ /** The user name */
+ private String _userName;
+
+ /** The password */
+ private String _password;
+
+ /** The client ID */
+ private String _clientID;
+
+ /** The connection type */
+ private final int _type;
+
+ /** Whether we are started */
+ private boolean _started = false;
+
+ /** The managed connection factory */
+ private final QpidRAManagedConnectionFactory _mcf;
+
+ /** The connection manager */
+ private ConnectionManager _cm;
+
+ /** The sessions */
+ private final Set<QpidRASession> _sessions = new HashSet<QpidRASession>();
+
+ /** The temporary queues */
+ private final Set<TemporaryQueue> _tempQueues = new HashSet<TemporaryQueue>();
+
+ /** The temporary topics */
+ private final Set<TemporaryTopic> _tempTopics = new HashSet<TemporaryTopic>();
+
+ /**
+ * Constructor
+ * @param mcf The managed connection factory
+ * @param cm The connection manager
+ * @param type The connection type
+ */
+ public QpidRASessionFactoryImpl(final QpidRAManagedConnectionFactory mcf,
+ final ConnectionManager cm,
+ final int type)
+ {
+ this._mcf = mcf;
+
+ if (cm == null)
+ {
+ this._cm = new QpidRAConnectionManager();
+ }
+ else
+ {
+ this._cm = cm;
+ }
+
+ this._type = type;
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + mcf + ", " + cm + ", " + type);
+ }
+ }
+
+ /**
+ * Set the naming reference
+ * @param reference The reference
+ */
+ public void setReference(final Reference reference)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setReference(" + reference + ")");
+ }
+
+ this._reference = reference;
+ }
+
+ /**
+ * Get the naming reference
+ * @return The reference
+ */
+ public Reference getReference()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getReference()");
+ }
+
+ return _reference;
+ }
+
+ /**
+ * Set the user name
+ * @param name The user name
+ */
+ public void setUserName(final String name)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUserName(" + name + ")");
+ }
+
+ _userName = name;
+ }
+
+ /**
+ * Set the password
+ * @param password The password
+ */
+ public void setPassword(final String password)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPassword(****)");
+ }
+
+ this._password = password;
+ }
+
+ /**
+ * Get the client ID
+ * @return The client ID
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getClientID() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getClientID()");
+ }
+
+ checkClosed();
+
+ if (_clientID == null)
+ {
+ try
+ {
+ return _mcf.getDefaultAMQConnectionFactory().getConnectionURL().getClientName() ;
+ }
+ catch (final ResourceException re)
+ {
+ final JMSException jmse = new JMSException("Unexpected exception obtaining resource") ;
+ jmse.initCause(re) ;
+ throw jmse ;
+ }
+ }
+
+ return _clientID;
+ }
+
+ /**
+ * Set the client ID -- throws IllegalStateException
+ * @param cID The client ID
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setClientID(final String cID) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setClientID(" + cID + ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a queue session
+ * @param transacted Use transactions
+ * @param acknowledgeMode The acknowledge mode
+ * @return The queue session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueSession createQueueSession(final boolean transacted, final int acknowledgeMode) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createQueueSession(" + transacted + ", " + acknowledgeMode + ")");
+ }
+
+ checkClosed();
+
+ if (_type == QpidRAConnectionFactory.TOPIC_CONNECTION || _type == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Can not get a queue session from a topic connection");
+ }
+
+ return (QueueSession)allocateConnection(transacted, acknowledgeMode, _type);
+ }
+
+ /**
+ * Create a XA queue session
+ * @return The XA queue session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public XAQueueSession createXAQueueSession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXAQueueSession()");
+ }
+
+ checkClosed();
+
+ if (_type == QpidRAConnectionFactory.CONNECTION || _type == QpidRAConnectionFactory.TOPIC_CONNECTION ||
+ _type == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Can not get a topic session from a queue connection");
+ }
+
+ return (XAQueueSession) allocateConnection(_type);
+ }
+
+ /**
+ * Create a connection consumer -- throws IllegalStateException
+ * @param queue The queue
+ * @param messageSelector The message selector
+ * @param sessionPool The session pool
+ * @param maxMessages The number of max messages
+ * @return The connection consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionConsumer createConnectionConsumer(final Queue queue,
+ final String messageSelector,
+ final ServerSessionPool sessionPool,
+ final int maxMessages) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionConsumer(" + queue +
+ ", " +
+ messageSelector +
+ ", " +
+ sessionPool +
+ ", " +
+ maxMessages +
+ ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a topic session
+ * @param transacted Use transactions
+ * @param acknowledgeMode The acknowledge mode
+ * @return The topic session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSession createTopicSession(final boolean transacted, final int acknowledgeMode) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTopicSession(" + transacted + ", " + acknowledgeMode + ")");
+ }
+
+ checkClosed();
+
+ if (_type == QpidRAConnectionFactory.QUEUE_CONNECTION || _type == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Can not get a topic session from a queue connection");
+ }
+
+ return (TopicSession) allocateConnection(transacted, acknowledgeMode, _type);
+ }
+
+ /**
+ * Create a XA topic session
+ * @return The XA topic session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public XATopicSession createXATopicSession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXATopicSession()");
+ }
+
+ checkClosed();
+
+ if (_type == QpidRAConnectionFactory.CONNECTION || _type == QpidRAConnectionFactory.QUEUE_CONNECTION ||
+ _type == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Can not get a topic session from a queue connection");
+ }
+
+ return (XATopicSession) allocateConnection(_type);
+ }
+
+ /**
+ * Create a connection consumer -- throws IllegalStateException
+ * @param topic The topic
+ * @param messageSelector The message selector
+ * @param sessionPool The session pool
+ * @param maxMessages The number of max messages
+ * @return The connection consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionConsumer createConnectionConsumer(final Topic topic,
+ final String messageSelector,
+ final ServerSessionPool sessionPool,
+ final int maxMessages) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionConsumer(" + topic +
+ ", " +
+ messageSelector +
+ ", " +
+ sessionPool +
+ ", " +
+ maxMessages +
+ ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a durable connection consumer -- throws IllegalStateException
+ * @param topic The topic
+ * @param subscriptionName The subscription name
+ * @param messageSelector The message selector
+ * @param sessionPool The session pool
+ * @param maxMessages The number of max messages
+ * @return The connection consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionConsumer createDurableConnectionConsumer(final Topic topic,
+ final String subscriptionName,
+ final String messageSelector,
+ final ServerSessionPool sessionPool,
+ final int maxMessages) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionConsumer(" + topic +
+ ", " +
+ subscriptionName +
+ ", " +
+ messageSelector +
+ ", " +
+ sessionPool +
+ ", " +
+ maxMessages +
+ ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a connection consumer -- throws IllegalStateException
+ * @param destination The destination
+ * @param pool The session pool
+ * @param maxMessages The number of max messages
+ * @return The connection consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionConsumer createConnectionConsumer(final Destination destination,
+ final ServerSessionPool pool,
+ final int maxMessages) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionConsumer(" + destination +
+ ", " +
+ pool +
+ ", " +
+ maxMessages +
+ ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a connection consumer -- throws IllegalStateException
+ * @param destination The destination
+ * @param name The name
+ * @param pool The session pool
+ * @param maxMessages The number of max messages
+ * @return The connection consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionConsumer createConnectionConsumer(final Destination destination,
+ final String name,
+ final ServerSessionPool pool,
+ final int maxMessages) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionConsumer(" + destination +
+ ", " +
+ name +
+ ", " +
+ pool +
+ ", " +
+ maxMessages +
+ ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a session
+ * @param transacted Use transactions
+ * @param acknowledgeMode The acknowledge mode
+ * @return The session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Session createSession(final boolean transacted, final int acknowledgeMode) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createSession(" + transacted + ", " + acknowledgeMode + ")");
+ }
+
+ checkClosed();
+ return (Session) allocateConnection(transacted, acknowledgeMode, _type);
+ }
+
+ /**
+ * Create a XA session
+ * @return The XA session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public XASession createXASession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXASession()");
+ }
+
+ checkClosed();
+ return (XASession) allocateConnection(_type);
+ }
+
+ /**
+ * Get the connection metadata
+ * @return The connection metadata
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionMetaData getMetaData() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMetaData()");
+ }
+
+ checkClosed();
+ return _mcf.getMetaData();
+ }
+
+ /**
+ * Get the exception listener -- throws IllegalStateException
+ * @return The exception listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ExceptionListener getExceptionListener() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getExceptionListener()");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Set the exception listener -- throws IllegalStateException
+ * @param listener The exception listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setExceptionListener(final ExceptionListener listener) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setExceptionListener(" + listener + ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Start
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void start() throws JMSException
+ {
+ checkClosed();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start() " + this);
+ }
+
+ synchronized (_sessions)
+ {
+ if (_started)
+ {
+ return;
+ }
+ _started = true;
+ for (Iterator<QpidRASession> i = _sessions.iterator(); i.hasNext();)
+ {
+ QpidRASessionImpl session = (QpidRASessionImpl)i.next();
+ session.start();
+ }
+ }
+ }
+
+ /**
+ * Stop -- throws IllegalStateException
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void stop() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("stop() " + this);
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Close
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void close() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("close() " + this);
+ }
+
+ if (_closed)
+ {
+ return;
+ }
+
+ _closed = true;
+
+ synchronized (_sessions)
+ {
+ for (Iterator<QpidRASession> i = _sessions.iterator(); i.hasNext();)
+ {
+ QpidRASessionImpl session = (QpidRASessionImpl)i.next();
+ try
+ {
+ session.closeSession();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error closing session", t);
+ }
+ i.remove();
+ }
+ }
+
+ synchronized (_tempQueues)
+ {
+ for (Iterator<TemporaryQueue> i = _tempQueues.iterator(); i.hasNext();)
+ {
+ TemporaryQueue temp = (TemporaryQueue)i.next();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _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<TemporaryTopic> i = _tempTopics.iterator(); i.hasNext();)
+ {
+ TemporaryTopic temp = (TemporaryTopic)i.next();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Closing temporary topic " + temp + " for " + this);
+ }
+ temp.delete();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error deleting temporary queue", t);
+ }
+ i.remove();
+ }
+ }
+ }
+
+ /**
+ * Close session
+ * @param session The session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void closeSession(final QpidRASessionImpl session) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("closeSession(" + session + ")");
+ }
+
+ synchronized (_sessions)
+ {
+ _sessions.remove(session);
+ }
+ }
+
+ /**
+ * Add temporary queue
+ * @param temp The temporary queue
+ */
+ public void addTemporaryQueue(final TemporaryQueue temp)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addTemporaryQueue(" + temp + ")");
+ }
+
+ synchronized (_tempQueues)
+ {
+ _tempQueues.add(temp);
+ }
+ }
+
+ /**
+ * Add temporary topic
+ * @param temp The temporary topic
+ */
+ public void addTemporaryTopic(final TemporaryTopic temp)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addTemporaryTopic(" + temp + ")");
+ }
+
+ synchronized (_tempTopics)
+ {
+ _tempTopics.add(temp);
+ }
+ }
+
+ /**
+ * Allocation a connection
+ * @param sessionType The session type
+ * @return The session
+ * @exception JMSException Thrown if an error occurs
+ */
+ protected QpidRASession allocateConnection(final int sessionType) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("allocateConnection(" + sessionType + ")");
+ }
+
+ try
+ {
+ synchronized (_sessions)
+ {
+ if (_sessions.isEmpty() == false)
+ {
+ throw new IllegalStateException("Only allowed one session per connection. See the J2EE spec, e.g. J2EE1.4 Section 6.6");
+ }
+
+ QpidRAConnectionRequestInfo info = new QpidRAConnectionRequestInfo(sessionType);
+ info.setUserName(_userName);
+ info.setPassword(_password);
+ info.setClientID(_clientID);
+ info.setDefaults(_mcf.getDefaultAMQConnectionFactory().getConnectionURL());
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Allocating session for " + this + " with request info=" + info);
+ }
+
+ QpidRASession session = (QpidRASession)_cm.allocateConnection(_mcf, info);
+
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Allocated " + this + " session=" + session);
+ }
+
+ session.setQpidSessionFactory(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.getMessage());
+ je.setLinkedException(e);
+ throw je;
+ }
+ }
+
+ /**
+ * Allocation a connection
+ * @param transacted Use transactions
+ * @param acknowledgeMode The acknowledge mode
+ * @param sessionType The session type
+ * @return The session
+ * @exception JMSException Thrown if an error occurs
+ */
+ protected QpidRASession allocateConnection(final boolean transacted, int acknowledgeMode, final int sessionType) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("allocateConnection(" + transacted +
+ ", " +
+ acknowledgeMode +
+ ", " +
+ sessionType +
+ ")");
+ }
+
+ try
+ {
+ synchronized (_sessions)
+ {
+ if (_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;
+ }
+
+ QpidRAConnectionRequestInfo info = new QpidRAConnectionRequestInfo(transacted,
+ acknowledgeMode,
+ sessionType);
+ info.setUserName(_userName);
+ info.setPassword(_password);
+ info.setClientID(_clientID);
+ info.setDefaults(_mcf.getDefaultAMQConnectionFactory().getConnectionURL());
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Allocating session for " + this + " with request info=" + info);
+ }
+
+ QpidRASession session = (QpidRASession)_cm.allocateConnection(_mcf, info);
+
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Allocated " + this + " session=" + session);
+ }
+
+ session.setQpidSessionFactory(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.getMessage());
+ je.setLinkedException(e);
+ throw je;
+ }
+ }
+
+ /**
+ * Check if we are closed
+ * @exception IllegalStateException Thrown if closed
+ */
+ protected void checkClosed() throws IllegalStateException
+ {
+ if (_closed)
+ {
+ throw new IllegalStateException("The connection is closed");
+ }
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java
new file mode 100644
index 0000000000..a270253c13
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java
@@ -0,0 +1,1732 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jms.BytesMessage;
+import javax.jms.Destination;
+import javax.jms.IllegalStateException;
+import javax.jms.InvalidDestinationException;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+import javax.jms.QueueReceiver;
+import javax.jms.QueueSender;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.StreamMessage;
+import javax.jms.TemporaryQueue;
+import javax.jms.TemporaryTopic;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.jms.TopicPublisher;
+import javax.jms.TopicSession;
+import javax.jms.TopicSubscriber;
+import javax.jms.TransactionInProgressException;
+import javax.jms.XAQueueSession;
+import javax.jms.XASession;
+import javax.jms.XATopicSession;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionEvent;
+import javax.resource.spi.ManagedConnection;
+import javax.transaction.xa.XAResource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A joint interface for JMS sessions
+ *
+ */
+public class QpidRASessionImpl implements Session, QueueSession, TopicSession, XASession, XAQueueSession, XATopicSession, QpidRASession
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRASessionImpl.class);
+
+ /** The managed connection */
+ private volatile QpidRAManagedConnection _mc;
+ /** The locked managed connection */
+ private QpidRAManagedConnection _lockedMC;
+
+ /** The connection request info */
+ private final QpidRAConnectionRequestInfo _cri;
+
+ /** The session factory */
+ private QpidRASessionFactory _sf;
+
+ /** The message consumers */
+ private final Set<MessageConsumer> _consumers;
+
+ /** The message producers */
+ private final Set<MessageProducer> _producers;
+
+ /** The queue browsers */
+ private final Set<QueueBrowser> _browsers;
+
+ /** Are we started */
+ private AtomicBoolean _started = new AtomicBoolean(false) ;
+
+ /**
+ * Constructor
+ * @param mc The managed connection
+ * @param cri The connection request info
+ */
+ public QpidRASessionImpl(final QpidRAManagedConnection mc, final QpidRAConnectionRequestInfo cri)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + mc + ", " + cri + ")");
+ }
+
+ this._mc = mc;
+ this._cri = cri;
+ _sf = null;
+ _consumers = new HashSet<MessageConsumer>();
+ _producers = new HashSet<MessageProducer>();
+ _browsers = new HashSet<QueueBrowser>();
+ }
+
+ /**
+ * Set the session factory
+ * @param sf The session factory
+ */
+ public void setQpidSessionFactory(final QpidRASessionFactory sf)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setQpidSessionFactory(" + sf + ")");
+ }
+
+ _started.set(false) ;
+ this._sf = sf;
+ }
+
+ /**
+ * Lock
+ * @exception JMSException Thrown if an error occurs
+ * @exception IllegalStateException The session is closed
+ */
+ protected void lock() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("lock()");
+ }
+
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ mc.tryLock();
+ _lockedMC = mc ;
+ }
+ else
+ {
+ throw new IllegalStateException("Connection is not associated with a managed connection. " + this);
+ }
+ }
+
+ /**
+ * Unlock
+ */
+ protected void unlock()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("unlock()");
+ }
+
+ if (_lockedMC != null)
+ {
+ try
+ {
+ _lockedMC.unlock();
+ }
+ finally
+ {
+ _lockedMC = null ;
+ }
+ }
+
+ // We recreate the lock when returned to the pool
+ // so missing the unlock after disassociation is not important
+ }
+
+ /**
+ * Create a bytes message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public BytesMessage createBytesMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createBytesMessage" + Util.asString(session));
+ }
+
+ return session.createBytesMessage();
+ }
+
+ /**
+ * Create a map message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MapMessage createMapMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createMapMessage" + Util.asString(session));
+ }
+
+ return session.createMapMessage();
+ }
+
+ /**
+ * Create a message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Message createMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createMessage" + Util.asString(session));
+ }
+
+ return session.createMessage();
+ }
+
+ /**
+ * Create an object message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ObjectMessage createObjectMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createObjectMessage" + Util.asString(session));
+ }
+
+ return session.createObjectMessage();
+ }
+
+ /**
+ * Create an object message
+ * @param object The object
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ObjectMessage createObjectMessage(final Serializable object) throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createObjectMessage(" + object + ")" + Util.asString(session));
+ }
+
+ return session.createObjectMessage(object);
+ }
+
+ /**
+ * Create a stream message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public StreamMessage createStreamMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createStreamMessage" + Util.asString(session));
+ }
+
+ return session.createStreamMessage();
+ }
+
+ /**
+ * Create a text message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TextMessage createTextMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTextMessage" + Util.asString(session));
+ }
+
+ return session.createTextMessage();
+ }
+
+ /**
+ * Create a text message
+ * @param string The text
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TextMessage createTextMessage(final String string) throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTextMessage(" + string + ")" + Util.asString(session));
+ }
+
+ return session.createTextMessage(string);
+ }
+
+ /**
+ * Get transacted
+ * @return True if transacted; otherwise false
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean getTransacted() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransacted()");
+ }
+
+ getSessionInternal();
+ return _cri.isTransacted();
+ }
+
+ /**
+ * Get the message listener -- throws IllegalStateException
+ * @return The message listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageListener getMessageListener() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMessageListener()");
+ }
+
+ throw new IllegalStateException("Method not allowed");
+ }
+
+ /**
+ * Set the message listener -- Throws IllegalStateException
+ * @param listener The message listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setMessageListener(final MessageListener listener) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setMessageListener(" + listener + ")");
+ }
+
+ throw new IllegalStateException("Method not allowed");
+ }
+
+ /**
+ * Always throws an Error.
+ * @exception Error Method not allowed.
+ */
+ public void run()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("run()");
+ }
+
+ throw new Error("Method not allowed");
+ }
+
+ /**
+ * Closes the session. Sends a ConnectionEvent.CONNECTION_CLOSED to the
+ * managed connection.
+ * @exception JMSException Failed to close session.
+ */
+ public void close() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("close()");
+ }
+
+ _sf.closeSession(this);
+ closeSession();
+ }
+
+ /**
+ * Commit
+ * @exception JMSException Failed to close session.
+ */
+ public void commit() throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.XA_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new TransactionInProgressException("XA connection");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_cri.isTransacted() == false)
+ {
+ throw new IllegalStateException("Session is not transacted");
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Commit session " + this);
+ }
+
+ session.commit();
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Rollback
+ * @exception JMSException Failed to close session.
+ */
+ public void rollback() throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.XA_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new TransactionInProgressException("XA connection");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_cri.isTransacted() == false)
+ {
+ throw new IllegalStateException("Session is not transacted");
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Rollback session " + this);
+ }
+
+ session.rollback();
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Recover
+ * @exception JMSException Failed to close session.
+ */
+ public void recover() throws JMSException
+ {
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_cri.isTransacted())
+ {
+ throw new IllegalStateException("Session is transacted");
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Recover session " + this);
+ }
+
+ session.recover();
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a topic
+ * @param topicName The topic name
+ * @return The topic
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Topic createTopic(final String topicName) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create topic for javax.jms.QueueSession");
+ }
+
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTopic " + Util.asString(session) + " topicName=" + topicName);
+ }
+
+ Topic result = session.createTopic(topicName);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdTopic " + Util.asString(session) + " topic=" + result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Create a topic subscriber
+ * @param topic The topic
+ * @return The subscriber
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSubscriber createSubscriber(final Topic topic) throws JMSException
+ {
+ lock();
+ try
+ {
+ TopicSession session = getTopicSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createSubscriber " + Util.asString(session) + " topic=" + topic);
+ }
+
+ TopicSubscriber result = session.createSubscriber(topic);
+ result = new QpidRATopicSubscriber(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdSubscriber " + Util.asString(session) + " QpidRATopicSubscriber=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a topic subscriber
+ * @param topic The topic
+ * @param messageSelector The message selector
+ * @param noLocal If true inhibits the delivery of messages published by its own connection
+ * @return The subscriber
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSubscriber createSubscriber(final Topic topic, final String messageSelector, final boolean noLocal) throws JMSException
+ {
+ lock();
+ try
+ {
+ TopicSession session = getTopicSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createSubscriber " + Util.asString(session) +
+ " topic=" +
+ topic +
+ " selector=" +
+ messageSelector +
+ " noLocal=" +
+ noLocal);
+ }
+
+ TopicSubscriber result = session.createSubscriber(topic, messageSelector, noLocal);
+ result = new QpidRATopicSubscriber(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdSubscriber " + Util.asString(session) + " QpidRATopicSubscriber=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a durable topic subscriber
+ * @param topic The topic
+ * @param name The name
+ * @return The subscriber
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSubscriber createDurableSubscriber(final Topic topic, final String name) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create durable subscriber from javax.jms.QueueSession");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createDurableSubscriber " + Util.asString(session) + " topic=" + topic + " name=" + name);
+ }
+
+ TopicSubscriber result = session.createDurableSubscriber(topic, name);
+ result = new QpidRATopicSubscriber(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdDurableSubscriber " + Util.asString(session) + " QpidRATopicSubscriber=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a topic subscriber
+ * @param topic The topic
+ * @param name The name
+ * @param messageSelector The message selector
+ * @param noLocal If true inhibits the delivery of messages published by its own connection
+ * @return The subscriber
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSubscriber createDurableSubscriber(final Topic topic,
+ final String name,
+ final String messageSelector,
+ final boolean noLocal) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create durable subscriber from javax.jms.QueueSession");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createDurableSubscriber " + Util.asString(session) +
+ " topic=" +
+ topic +
+ " name=" +
+ name +
+ " selector=" +
+ messageSelector +
+ " noLocal=" +
+ noLocal);
+ }
+
+ TopicSubscriber result = session.createDurableSubscriber(topic, name, messageSelector, noLocal);
+ result = new QpidRATopicSubscriber(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdDurableSubscriber " + Util.asString(session) + " QpidRATopicSubscriber=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a topic publisher
+ * @param topic The topic
+ * @return The publisher
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicPublisher createPublisher(final Topic topic) throws JMSException
+ {
+ lock();
+ try
+ {
+ TopicSession session = getTopicSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createPublisher " + Util.asString(session) + " topic=" + topic);
+ }
+
+ TopicPublisher result = session.createPublisher(topic);
+ result = new QpidRATopicPublisher(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdPublisher " + Util.asString(session) + " publisher=" + result);
+ }
+
+ addProducer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a temporary topic
+ * @return The temporary topic
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TemporaryTopic createTemporaryTopic() throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create temporary topic for javax.jms.QueueSession");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTemporaryTopic " + Util.asString(session));
+ }
+
+ TemporaryTopic temp = session.createTemporaryTopic();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdTemporaryTopic " + Util.asString(session) + " temp=" + temp);
+ }
+
+ _sf.addTemporaryTopic(temp);
+
+ return temp;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Unsubscribe
+ * @param name The name
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void unsubscribe(final String name) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot unsubscribe for javax.jms.QueueSession");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("unsubscribe " + Util.asString(session) + " name=" + name);
+ }
+
+ session.unsubscribe(name);
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a browser
+ * @param queue The queue
+ * @return The browser
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueBrowser createBrowser(final Queue queue) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create browser for javax.jms.TopicSession");
+ }
+
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createBrowser " + Util.asString(session) + " queue=" + queue);
+ }
+
+ QueueBrowser result = session.createBrowser(queue);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdBrowser " + Util.asString(session) + " browser=" + result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Create a browser
+ * @param queue The queue
+ * @param messageSelector The message selector
+ * @return The browser
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueBrowser createBrowser(final Queue queue, final String messageSelector) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create browser for javax.jms.TopicSession");
+ }
+
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createBrowser " + Util.asString(session) + " queue=" + queue + " selector=" + messageSelector);
+ }
+
+ QueueBrowser result = session.createBrowser(queue, messageSelector);
+ result = new QpidRAQueueBrowser(result, this);
+ addQueueBrowser(result) ;
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdBrowser " + Util.asString(session) + " browser=" + result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Create a queue
+ * @param queueName The queue name
+ * @return The queue
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Queue createQueue(final String queueName) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create browser or javax.jms.TopicSession");
+ }
+
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createQueue " + Util.asString(session) + " queueName=" + queueName);
+ }
+
+ Queue result = session.createQueue(queueName);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdQueue " + Util.asString(session) + " queue=" + result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Create a queue receiver
+ * @param queue The queue
+ * @return The queue receiver
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueReceiver createReceiver(final Queue queue) throws JMSException
+ {
+ lock();
+ try
+ {
+ QueueSession session = getQueueSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createReceiver " + Util.asString(session) + " queue=" + queue);
+ }
+
+ QueueReceiver result = session.createReceiver(queue);
+ result = new QpidRAQueueReceiver(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdReceiver " + Util.asString(session) + " receiver=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a queue receiver
+ * @param queue The queue
+ * @param messageSelector
+ * @return The queue receiver
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueReceiver createReceiver(final Queue queue, final String messageSelector) throws JMSException
+ {
+ lock();
+ try
+ {
+ QueueSession session = getQueueSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createReceiver " + Util.asString(session) + " queue=" + queue + " selector=" + messageSelector);
+ }
+
+ QueueReceiver result = session.createReceiver(queue, messageSelector);
+ result = new QpidRAQueueReceiver(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdReceiver " + Util.asString(session) + " receiver=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a queue sender
+ * @param queue The queue
+ * @return The queue sender
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueSender createSender(final Queue queue) throws JMSException
+ {
+ lock();
+ try
+ {
+ QueueSession session = getQueueSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createSender " + Util.asString(session) + " queue=" + queue);
+ }
+
+ QueueSender result = session.createSender(queue);
+ result = new QpidRAQueueSender(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdSender " + Util.asString(session) + " sender=" + result);
+ }
+
+ addProducer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a temporary queue
+ * @return The temporary queue
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TemporaryQueue createTemporaryQueue() throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create temporary queue for javax.jms.TopicSession");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTemporaryQueue " + Util.asString(session));
+ }
+
+ TemporaryQueue temp = session.createTemporaryQueue();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdTemporaryQueue " + Util.asString(session) + " temp=" + temp);
+ }
+
+ _sf.addTemporaryQueue(temp);
+
+ return temp;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a message consumer
+ * @param destination The destination
+ * @return The message consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageConsumer createConsumer(final Destination destination) throws JMSException
+ {
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConsumer " + Util.asString(session) + " dest=" + destination);
+ }
+
+ MessageConsumer result = session.createConsumer(destination);
+ result = new QpidRAMessageConsumer(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdConsumer " + Util.asString(session) + " consumer=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a message consumer
+ * @param destination The destination
+ * @param messageSelector The message selector
+ * @return The message consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageConsumer createConsumer(final Destination destination, final String messageSelector) throws JMSException
+ {
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConsumer " + Util.asString(session) +
+ " dest=" +
+ destination +
+ " messageSelector=" +
+ messageSelector);
+ }
+
+ MessageConsumer result = session.createConsumer(destination, messageSelector);
+ result = new QpidRAMessageConsumer(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdConsumer " + Util.asString(session) + " consumer=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a message consumer
+ * @param destination The destination
+ * @param messageSelector The message selector
+ * @param noLocal If true inhibits the delivery of messages published by its own connection
+ * @return The message consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageConsumer createConsumer(final Destination destination,
+ final String messageSelector,
+ final boolean noLocal) throws JMSException
+ {
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConsumer " + Util.asString(session) +
+ " dest=" +
+ destination +
+ " messageSelector=" +
+ messageSelector +
+ " noLocal=" +
+ noLocal);
+ }
+
+ MessageConsumer result = session.createConsumer(destination, messageSelector, noLocal);
+ result = new QpidRAMessageConsumer(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdConsumer " + Util.asString(session) + " consumer=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a message producer
+ * @param destination The destination
+ * @return The message producer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageProducer createProducer(final Destination destination) throws JMSException
+ {
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createProducer " + Util.asString(session) + " dest=" + destination);
+ }
+
+ MessageProducer result = session.createProducer(destination);
+ result = new QpidRAMessageProducer(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdProducer " + Util.asString(session) + " producer=" + result);
+ }
+
+ addProducer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Get the acknowledge mode
+ * @return The mode
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int getAcknowledgeMode() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getAcknowledgeMode()");
+ }
+
+ getSessionInternal();
+ return _cri.getAcknowledgeMode();
+ }
+
+ /**
+ * Get the XA resource
+ * @return The XA resource
+ * @exception IllegalStateException If non XA connection
+ */
+ public XAResource getXAResource()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getXAResource()");
+ }
+
+ if (_cri.getType() == QpidRAConnectionFactory.CONNECTION || _cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
+ {
+ return null;
+ }
+
+ try
+ {
+ lock();
+
+ return getXAResourceInternal();
+ }
+ catch (Throwable t)
+ {
+ return null;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Get the session
+ * @return The session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Session getSession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSession()");
+ }
+
+ if (_cri.getType() == QpidRAConnectionFactory.CONNECTION || _cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Non XA connection");
+ }
+
+ lock();
+ try
+ {
+ return this;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Get the queue session
+ * @return The queue session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueSession getQueueSession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getQueueSession()");
+ }
+
+ if (_cri.getType() == QpidRAConnectionFactory.CONNECTION || _cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Non XA connection");
+ }
+
+ lock();
+ try
+ {
+ return this;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Get the topic session
+ * @return The topic session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSession getTopicSession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTopicSession()");
+ }
+
+ if (_cri.getType() == QpidRAConnectionFactory.CONNECTION || _cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Non XA connection");
+ }
+
+ lock();
+ try
+ {
+ return this;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Set the managed connection
+ * @param managedConnection The managed connection
+ */
+ void setManagedConnection(final QpidRAManagedConnection managedConnection)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setManagedConnection(" + managedConnection + ")");
+ }
+
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ mc.removeHandle(this);
+ }
+
+ this._mc = managedConnection;
+ }
+
+ /** for tests only */
+ public ManagedConnection getManagedConnection()
+ {
+ return _mc;
+ }
+
+ /**
+ * Destroy
+ */
+ void destroy()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("destroy()");
+ }
+
+ _mc = null;
+ }
+
+ /**
+ * Start
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void start() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start()");
+ }
+
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ _started.set(true) ;
+ mc.start();
+ }
+ }
+
+ /**
+ * Stop
+ * @exception JMSException Thrown if an error occurs
+ */
+ void stop() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("stop()");
+ }
+
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ mc.stop();
+ _started.set(false) ;
+ }
+ }
+
+ /**
+ * Check strict
+ * @exception JMSException Thrown if an error occurs
+ */
+ void checkStrict() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("checkStrict()");
+ }
+
+ if (_mc != null)
+ {
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+ }
+
+ /**
+ * Close session
+ * @exception JMSException Thrown if an error occurs
+ */
+ void closeSession() throws JMSException
+ {
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ _log.trace("Closing session");
+
+ try
+ {
+ mc.stop();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error stopping managed connection", t);
+ }
+
+ synchronized (_consumers)
+ {
+ for (Iterator<MessageConsumer> i = _consumers.iterator(); i.hasNext();)
+ {
+ QpidRAMessageConsumer consumer = (QpidRAMessageConsumer)i.next();
+ try
+ {
+ consumer.closeConsumer();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error closing consumer", t);
+ }
+ i.remove();
+ }
+ }
+
+ synchronized (_producers)
+ {
+ for (Iterator<MessageProducer> i = _producers.iterator(); i.hasNext();)
+ {
+ QpidRAMessageProducer producer = (QpidRAMessageProducer)i.next();
+ try
+ {
+ producer.closeProducer();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error closing producer", t);
+ }
+ i.remove();
+ }
+ }
+
+ synchronized (_browsers)
+ {
+ for (Iterator<QueueBrowser> i = _browsers.iterator(); i.hasNext();)
+ {
+ QpidRAQueueBrowser browser = (QpidRAQueueBrowser)i.next();
+ try
+ {
+ browser.close();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error closing browser", t);
+ }
+ i.remove();
+ }
+ }
+
+ mc.removeHandle(this);
+ ConnectionEvent ev = new ConnectionEvent(mc, ConnectionEvent.CONNECTION_CLOSED);
+ ev.setConnectionHandle(this);
+ mc.sendEvent(ev);
+ this._mc = null;
+ }
+ }
+
+ /**
+ * Add consumer
+ * @param consumer The consumer
+ */
+ void addConsumer(final MessageConsumer consumer)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addConsumer(" + consumer + ")");
+ }
+
+ synchronized (_consumers)
+ {
+ _consumers.add(consumer);
+ }
+ }
+
+ /**
+ * Remove consumer
+ * @param consumer The consumer
+ */
+ void removeConsumer(final MessageConsumer consumer)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("removeConsumer(" + consumer + ")");
+ }
+
+ synchronized (_consumers)
+ {
+ _consumers.remove(consumer);
+ }
+ }
+
+ /**
+ * Add producer
+ * @param producer The producer
+ */
+ void addProducer(final MessageProducer producer)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addProducer(" + producer + ")");
+ }
+
+ synchronized (_producers)
+ {
+ _producers.add(producer);
+ }
+ }
+
+ /**
+ * Remove producer
+ * @param producer The producer
+ */
+ void removeProducer(final MessageProducer producer)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("removeProducer(" + producer + ")");
+ }
+
+ synchronized (_producers)
+ {
+ _producers.remove(producer);
+ }
+ }
+
+ /**
+ * Add queue browser
+ * @param browser The queue browser
+ */
+ void addQueueBrowser(final QueueBrowser browser)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addQueueBrowser(" + browser + ")");
+ }
+
+ synchronized (_browsers)
+ {
+ _browsers.add(browser);
+ }
+ }
+
+ /**
+ * Remove queue browser
+ * @param browser The queue browser
+ */
+ void removeQueueBrowser(final QueueBrowser browser)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("removeQueueBrowser(" + browser + ")");
+ }
+
+ synchronized (_browsers)
+ {
+ _browsers.remove(browser);
+ }
+ }
+
+ /**
+ * Get the session and ensure that it is open
+ * @return The session
+ * @exception JMSException Thrown if an error occurs
+ * @exception IllegalStateException The session is closed
+ */
+ Session getSessionInternal() throws JMSException
+ {
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc == null)
+ {
+ throw new IllegalStateException("The session is closed");
+ }
+
+ Session session = mc.getSession();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSessionInternal " + Util.asString(session) + " for " + this);
+ }
+
+ return session;
+ }
+
+ /**
+ * Get the XA resource and ensure that it is open
+ * @return The XA Resource
+ * @exception JMSException Thrown if an error occurs
+ * @exception IllegalStateException The session is closed
+ */
+ XAResource getXAResourceInternal() throws JMSException
+ {
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc == null)
+ {
+ throw new IllegalStateException("The session is closed");
+ }
+
+ try
+ {
+ XAResource xares = mc.getXAResource();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getXAResourceInternal " + xares + " for " + this);
+ }
+
+ return xares;
+ }
+ catch (ResourceException e)
+ {
+ JMSException jmse = new JMSException("Unable to get XA Resource");
+ jmse.initCause(e);
+ throw jmse;
+ }
+ }
+
+ /**
+ * Get the queue session
+ * @return The queue session
+ * @exception JMSException Thrown if an error occurs
+ * @exception IllegalStateException The session is closed
+ */
+ QueueSession getQueueSessionInternal() throws JMSException
+ {
+ Session s = getSessionInternal();
+ if (!(s instanceof QueueSession))
+ {
+ throw new InvalidDestinationException("Attempting to use QueueSession methods on: " + this);
+ }
+ return (QueueSession)s;
+ }
+
+ /**
+ * Get the topic session
+ * @return The topic session
+ * @exception JMSException Thrown if an error occurs
+ * @exception IllegalStateException The session is closed
+ */
+ TopicSession getTopicSessionInternal() throws JMSException
+ {
+ Session s = getSessionInternal();
+ if (!(s instanceof TopicSession))
+ {
+ throw new InvalidDestinationException("Attempting to use TopicSession methods on: " + this);
+ }
+ return (TopicSession)s;
+ }
+
+ /**
+ * @throws SystemException
+ * @throws RollbackException
+ *
+ */
+ public void checkState() throws JMSException
+ {
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ mc.checkTransactionActive();
+ }
+ }
+
+ /**
+ * Has this session been started?
+ * @return true if started, false if stopped.
+ */
+ public boolean isStarted()
+ {
+ return _started.get();
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAStreamMessage.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAStreamMessage.java
new file mode 100644
index 0000000000..3c2bee33f2
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAStreamMessage.java
@@ -0,0 +1,415 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.jms.JMSException;
+import javax.jms.StreamMessage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message
+ *
+ */
+public class QpidRAStreamMessage extends QpidRAMessage implements StreamMessage
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAStreamMessage.class);
+
+ /**
+ * Create a new wrapper
+ * @param message the message
+ * @param session the session
+ */
+ public QpidRAStreamMessage(final StreamMessage message, final QpidRASessionImpl session)
+ {
+ super(message, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(message) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean readBoolean() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readBoolean()");
+ }
+
+ return ((StreamMessage)_message).readBoolean();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public byte readByte() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readByte()");
+ }
+
+ return ((StreamMessage)_message).readByte();
+ }
+
+ /**
+ * Read
+ * @param value The value
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int readBytes(final byte[] value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readBytes(" + value + ")");
+ }
+
+ return ((StreamMessage)_message).readBytes(value);
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public char readChar() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readChar()");
+ }
+
+ return ((StreamMessage)_message).readChar();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public double readDouble() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readDouble()");
+ }
+
+ return ((StreamMessage)_message).readDouble();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public float readFloat() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readFloat()");
+ }
+
+ return ((StreamMessage)_message).readFloat();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int readInt() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readInt()");
+ }
+
+ return ((StreamMessage)_message).readInt();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public long readLong() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readLong()");
+ }
+
+ return ((StreamMessage)_message).readLong();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Object readObject() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readObject()");
+ }
+
+ return ((StreamMessage)_message).readObject();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public short readShort() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readShort()");
+ }
+
+ return ((StreamMessage)_message).readShort();
+ }
+
+ /**
+ * Read
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String readString() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("readString()");
+ }
+
+ return ((StreamMessage)_message).readString();
+ }
+
+ /**
+ * Reset
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void reset() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("reset()");
+ }
+
+ ((StreamMessage)_message).reset();
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeBoolean(final boolean value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeBoolean(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeBoolean(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeByte(final byte value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeByte(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeByte(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @param offset The offset
+ * @param length The length
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeBytes(final byte[] value, final int offset, final int length) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeBytes(" + value + ", " + offset + ", " + length + ")");
+ }
+
+ ((StreamMessage)_message).writeBytes(value, offset, length);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeBytes(final byte[] value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeBytes(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeBytes(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeChar(final char value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeChar(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeChar(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeDouble(final double value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeDouble(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeDouble(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeFloat(final float value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeFloat(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeFloat(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeInt(final int value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeInt(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeInt(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeLong(final long value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeLong(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeLong(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeObject(final Object value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeObject(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeObject(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeShort(final short value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeShort(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeShort(value);
+ }
+
+ /**
+ * Write
+ * @param value The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void writeString(final String value) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("writeString(" + value + ")");
+ }
+
+ ((StreamMessage)_message).writeString(value);
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRATextMessage.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRATextMessage.java
new file mode 100644
index 0000000000..d74d006a7f
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRATextMessage.java
@@ -0,0 +1,83 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.jms.JMSException;
+import javax.jms.TextMessage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a message
+ *
+ */
+public class QpidRATextMessage extends QpidRAMessage implements TextMessage
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRATextMessage.class);
+
+ /**
+ * Create a new wrapper
+ * @param message the message
+ * @param session the session
+ */
+ public QpidRATextMessage(final TextMessage message, final QpidRASessionImpl session)
+ {
+ super(message, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(message) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get text
+ * @return The text
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getText() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getText()");
+ }
+
+ return ((TextMessage)_message).getText();
+ }
+
+ /**
+ * Set text
+ * @param string The text
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setText(final String string) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setText(" + string + ")");
+ }
+
+ ((TextMessage)_message).setText(string);
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicPublisher.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicPublisher.java
new file mode 100644
index 0000000000..b753690142
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicPublisher.java
@@ -0,0 +1,220 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Topic;
+import javax.jms.TopicPublisher;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * QpidRATopicPublisher.
+ *
+ */
+public class QpidRATopicPublisher extends QpidRAMessageProducer implements TopicPublisher
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRATopicPublisher.class);
+
+ /**
+ * Create a new wrapper
+ * @param producer the producer
+ * @param session the session
+ */
+ public QpidRATopicPublisher(final TopicPublisher producer, final QpidRASessionImpl session)
+ {
+ super(producer, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(producer) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get the topic
+ * @return The topic
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Topic getTopic() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTopic()");
+ }
+
+ return ((TopicPublisher)_producer).getTopic();
+ }
+
+ /**
+ * Publish message
+ * @param message The message
+ * @param deliveryMode The delivery mode
+ * @param priority The priority
+ * @param timeToLive The time to live
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void publish(final Message message, final int deliveryMode, final int priority, final long timeToLive) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this +
+ " message=" +
+ Util.asString(message) +
+ " deliveryMode=" +
+ deliveryMode +
+ " priority=" +
+ priority +
+ " ttl=" +
+ timeToLive);
+ }
+
+ checkState();
+
+ ((TopicPublisher)_producer).publish(message, deliveryMode, priority, timeToLive);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Publish message
+ * @param message The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void publish(final Message message) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this + " message=" + Util.asString(message));
+ }
+
+ checkState();
+
+ ((TopicPublisher)_producer).publish(message);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Publish message
+ * @param destination The destination
+ * @param message The message
+ * @param deliveryMode The delivery mode
+ * @param priority The priority
+ * @param timeToLive The time to live
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void publish(final Topic destination,
+ final Message message,
+ final int deliveryMode,
+ final int priority,
+ final long timeToLive) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this +
+ " destination=" +
+ destination +
+ " message=" +
+ Util.asString(message) +
+ " deliveryMode=" +
+ deliveryMode +
+ " priority=" +
+ priority +
+ " ttl=" +
+ timeToLive);
+ }
+
+ checkState();
+
+ ((TopicPublisher)_producer).publish(destination, message, deliveryMode, priority, timeToLive);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+
+ /**
+ * Publish message
+ * @param destination The destination
+ * @param message The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void publish(final Topic destination, final Message message) throws JMSException
+ {
+ _session.lock();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("send " + this + " destination=" + destination + " message=" + Util.asString(message));
+ }
+
+ checkState();
+
+ ((TopicPublisher)_producer).publish(destination, message);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sent " + this + " result=" + Util.asString(message));
+ }
+ }
+ finally
+ {
+ _session.unlock();
+ }
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicSubscriber.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicSubscriber.java
new file mode 100644
index 0000000000..e423f468e0
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicSubscriber.java
@@ -0,0 +1,86 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.jms.JMSException;
+import javax.jms.Topic;
+import javax.jms.TopicSubscriber;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper for a topic subscriber
+ *
+ */
+public class QpidRATopicSubscriber extends QpidRAMessageConsumer implements TopicSubscriber
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRATopicSubscriber.class);
+
+ /**
+ * Create a new wrapper
+ * @param consumer the topic subscriber
+ * @param session the session
+ */
+ public QpidRATopicSubscriber(final TopicSubscriber consumer, final QpidRASessionImpl session)
+ {
+ super(consumer, session);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + Util.asString(consumer) + ", " + session + ")");
+ }
+ }
+
+ /**
+ * Get the no local value
+ * @return The value
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean getNoLocal() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getNoLocal()");
+ }
+
+ checkState();
+ return ((TopicSubscriber)_consumer).getNoLocal();
+ }
+
+ /**
+ * Get the topic
+ * @return The topic
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Topic getTopic() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTopic()");
+ }
+
+ checkState();
+ return ((TopicSubscriber)_consumer).getTopic();
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidRAXAResource.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAXAResource.java
new file mode 100644
index 0000000000..22b39792b1
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidRAXAResource.java
@@ -0,0 +1,245 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * QpidRAXAResource.
+ *
+ */
+public class QpidRAXAResource implements XAResource
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAXAResource.class);
+
+ /** The managed connection */
+ private final QpidRAManagedConnection _managedConnection;
+
+ /** The resource */
+ private final XAResource _xaResource;
+
+ /**
+ * Create a new QpidRAXAResource.
+ * @param managedConnection the managed connection
+ * @param xaResource the xa resource
+ */
+ public QpidRAXAResource(final QpidRAManagedConnection managedConnection, final XAResource xaResource)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + managedConnection + ", " + Util.asString(xaResource) + ")");
+ }
+
+ this._managedConnection = managedConnection;
+ this._xaResource = xaResource;
+ }
+
+ /**
+ * Start
+ * @param xid A global transaction identifier
+ * @param flags One of TMNOFLAGS, TMJOIN, or TMRESUME
+ * @exception XAException An error has occurred
+ */
+ public void start(final Xid xid, final int flags) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start(" + xid + ", " + flags + ")");
+ }
+
+ _managedConnection.lock();
+ try
+ {
+ _xaResource.start(xid, flags);
+ }
+ finally
+ {
+ _managedConnection.setInManagedTx(true);
+ _managedConnection.unlock();
+ }
+ }
+
+ /**
+ * End
+ * @param xid A global transaction identifier
+ * @param flags One of TMSUCCESS, TMFAIL, or TMSUSPEND.
+ * @exception XAException An error has occurred
+ */
+ public void end(final Xid xid, final int flags) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("end(" + xid + ", " + flags + ")");
+ }
+
+ _managedConnection.lock();
+ try
+ {
+ _xaResource.end(xid, flags);
+ }
+ finally
+ {
+ _managedConnection.setInManagedTx(false);
+ _managedConnection.unlock();
+ }
+ }
+
+ /**
+ * Prepare
+ * @param xid A global transaction identifier
+ * @return XA_RDONLY or XA_OK
+ * @exception XAException An error has occurred
+ */
+ public int prepare(final Xid xid) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("prepare(" + xid + ")");
+ }
+
+ return _xaResource.prepare(xid);
+ }
+
+ /**
+ * Commit
+ * @param xid A global transaction identifier
+ * @param onePhase If true, the resource manager should use a one-phase commit protocol to commit the work done on behalf of xid.
+ * @exception XAException An error has occurred
+ */
+ public void commit(final Xid xid, final boolean onePhase) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("commit(" + xid + ", " + onePhase + ")");
+ }
+
+ _xaResource.commit(xid, onePhase);
+ }
+
+ /**
+ * Rollback
+ * @param xid A global transaction identifier
+ * @exception XAException An error has occurred
+ */
+ public void rollback(final Xid xid) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("rollback(" + xid + ")");
+ }
+
+ _xaResource.rollback(xid);
+ }
+
+ /**
+ * Forget
+ * @param xid A global transaction identifier
+ * @exception XAException An error has occurred
+ */
+ public void forget(final Xid xid) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("forget(" + xid + ")");
+ }
+
+ _managedConnection.lock();
+ try
+ {
+ _xaResource.forget(xid);
+ }
+ finally
+ {
+ _managedConnection.setInManagedTx(false);
+ _managedConnection.unlock();
+ }
+ }
+
+ /**
+ * IsSameRM
+ * @param xaRes An XAResource object whose resource manager instance is to be compared with the resource manager instance of the target object.
+ * @return True if its the same RM instance; otherwise false.
+ * @exception XAException An error has occurred
+ */
+ public boolean isSameRM(final XAResource xaRes) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("isSameRM(" + xaRes + ")");
+ }
+
+ return _xaResource.isSameRM(xaRes);
+ }
+
+ /**
+ * Recover
+ * @param flag One of TMSTARTRSCAN, TMENDRSCAN, TMNOFLAGS
+ * @return Zero or more XIDs
+ * @exception XAException An error has occurred
+ */
+ public Xid[] recover(final int flag) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("recover(" + flag + ")");
+ }
+
+ return _xaResource.recover(flag);
+ }
+
+ /**
+ * Get the transaction timeout in seconds
+ * @return The transaction timeout
+ * @exception XAException An error has occurred
+ */
+ public int getTransactionTimeout() throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransactionTimeout()");
+ }
+
+ return _xaResource.getTransactionTimeout();
+ }
+
+ /**
+ * Set the transaction timeout
+ * @param seconds The number of seconds
+ * @return True if the transaction timeout value is set successfully; otherwise false.
+ * @exception XAException An error has occurred
+ */
+ public boolean setTransactionTimeout(final int seconds) throws XAException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTransactionTimeout(" + seconds + ")");
+ }
+
+ return _xaResource.setTransactionTimeout(seconds);
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/QpidResourceAdapter.java b/java/jca/src/main/java/org/apache/qpid/ra/QpidResourceAdapter.java
new file mode 100644
index 0000000000..d56f520db4
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/QpidResourceAdapter.java
@@ -0,0 +1,820 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jms.Session;
+import javax.jms.XASession;
+import javax.resource.ResourceException;
+import javax.resource.spi.ActivationSpec;
+import javax.resource.spi.BootstrapContext;
+import javax.resource.spi.ResourceAdapter;
+import javax.resource.spi.ResourceAdapterInternalException;
+import javax.resource.spi.endpoint.MessageEndpointFactory;
+import javax.resource.spi.work.WorkManager;
+import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAResource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.client.XAConnectionImpl;
+import org.apache.qpid.ra.inflow.QpidActivation;
+import org.apache.qpid.ra.inflow.QpidActivationSpec;
+import org.apache.qpid.url.URLSyntaxException;
+
+/**
+ * The resource adapter for Qpid
+ *
+ */
+public class QpidResourceAdapter implements ResourceAdapter, Serializable
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = -2446231446818098726L;
+
+ /**
+ * The logger
+ */
+ private static final Logger _log = LoggerFactory.getLogger(QpidResourceAdapter.class);
+
+ /**
+ * The bootstrap context
+ */
+ private BootstrapContext _ctx;
+
+ /**
+ * The resource adapter properties
+ */
+ private final QpidRAProperties _raProperties;
+
+ /**
+ * Have the factory been configured
+ */
+ private final AtomicBoolean _configured;
+
+ /**
+ * The activations by activation spec
+ */
+ private final Map<ActivationSpec, QpidActivation> _activations;
+
+ private AMQConnectionFactory _defaultAMQConnectionFactory;
+
+ private TransactionManager _tm;
+
+ /**
+ * Constructor
+ */
+ public QpidResourceAdapter()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+
+ _raProperties = new QpidRAProperties();
+ _configured = new AtomicBoolean(false);
+ _activations = new ConcurrentHashMap<ActivationSpec, QpidActivation>();
+ }
+
+ public TransactionManager getTM()
+ {
+ return _tm;
+ }
+
+ /**
+ * Endpoint activation
+ *
+ * @param endpointFactory The endpoint factory
+ * @param spec The activation spec
+ * @throws ResourceException Thrown if an error occurs
+ */
+ public void endpointActivation(final MessageEndpointFactory endpointFactory, final ActivationSpec spec) throws ResourceException
+ {
+ if (!_configured.getAndSet(true))
+ {
+ try
+ {
+ setup();
+ }
+ catch (QpidRAException e)
+ {
+ throw new ResourceException("Unable to create activation", e);
+ }
+ }
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("endpointActivation(" + endpointFactory + ", " + spec + ")");
+ }
+
+ QpidActivation activation = new QpidActivation(this, endpointFactory, (QpidActivationSpec)spec);
+ _activations.put(spec, activation);
+ activation.start();
+ }
+
+ /**
+ * Endpoint deactivation
+ *
+ * @param endpointFactory The endpoint factory
+ * @param spec The activation spec
+ */
+ public void endpointDeactivation(final MessageEndpointFactory endpointFactory, final ActivationSpec spec)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("endpointDeactivation(" + endpointFactory + ", " + spec + ")");
+ }
+
+ QpidActivation activation = _activations.remove(spec);
+ if (activation != null)
+ {
+ activation.stop();
+ }
+ }
+
+ /**
+ * Get XA resources
+ *
+ * @param specs The activation specs
+ * @return The XA resources
+ * @throws ResourceException Thrown if an error occurs or unsupported
+ */
+ public XAResource[] getXAResources(final ActivationSpec[] specs) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getXAResources(" + specs + ")");
+ }
+
+ return null;
+ }
+
+ /**
+ * Start
+ *
+ * @param ctx The bootstrap context
+ * @throws ResourceAdapterInternalException
+ * Thrown if an error occurs
+ */
+ public void start(final BootstrapContext ctx) throws ResourceAdapterInternalException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start(" + ctx + ")");
+ }
+
+ locateTM();
+
+ this._ctx = ctx;
+
+ _log.info("Qpid resource adapter started");
+ }
+
+ /**
+ * Stop
+ */
+ public void stop()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("stop()");
+ }
+
+ for (Map.Entry<ActivationSpec, QpidActivation> entry : _activations.entrySet())
+ {
+ try
+ {
+ entry.getValue().stop();
+ }
+ catch (Exception ignored)
+ {
+ _log.debug("Ignored", ignored);
+ }
+ }
+
+ _activations.clear();
+
+ _log.info("Qpid resource adapter stopped");
+ }
+
+ /**
+ * Get the user name
+ *
+ * @return The value
+ */
+ public String getDefaultUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUserName()");
+ }
+
+ return _raProperties.getUserName();
+ }
+
+ /**
+ * Set the user name
+ *
+ * @param userName The value
+ */
+ public void setDefaultUserName(final String userName)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUserName(" + userName + ")");
+ }
+
+ _raProperties.setUserName(userName);
+ }
+
+ /**
+ * Get the password
+ *
+ * @return The value
+ */
+ public String getDefaultPassword()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPassword()");
+ }
+
+ return _raProperties.getPassword();
+ }
+
+ /**
+ * Set the password
+ *
+ * @param password The value
+ */
+ public void setDefaultPassword(final String password)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPassword(****)");
+ }
+
+ _raProperties.setPassword(password);
+ }
+
+ /**
+ * Get the client ID
+ *
+ * @return The value
+ */
+ public String getClientId()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getClientID()");
+ }
+
+ return _raProperties.getClientId();
+ }
+
+ /**
+ * Set the client ID
+ *
+ * @param clientID The client id
+ */
+ public void setClientId(final String clientID)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setClientID(" + clientID + ")");
+ }
+
+ _raProperties.setClientId(clientID);
+ }
+
+ /**
+ * Get the host
+ *
+ * @return The value
+ */
+ public String getHost()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getHost()");
+ }
+
+ return _raProperties.getHost();
+ }
+
+ /**
+ * Set the host
+ *
+ * @param host The host
+ */
+ public void setHost(final String host)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setHost(" + host + ")");
+ }
+
+ _raProperties.setHost(host);
+ }
+
+ /**
+ * Get the port
+ *
+ * @return The value
+ */
+ public Integer getPort()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPort()");
+ }
+
+ return _raProperties.getPort();
+ }
+
+ /**
+ * Set the client ID
+ *
+ * @param port The port
+ */
+ public void setPort(final Integer port)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPort(" + port + ")");
+ }
+
+ _raProperties.setPort(port);
+ }
+
+ /**
+ * Get the connection url
+ *
+ * @return The value
+ */
+ public String getPath()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPath()");
+ }
+
+ return _raProperties.getPath();
+ }
+
+ /**
+ * Set the client ID
+ *
+ * @param path The path
+ */
+ public void setPath(final String path)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPath(" + path + ")");
+ }
+
+ _raProperties.setPath(path);
+ }
+
+ /**
+ * Get the connection url
+ *
+ * @return The value
+ */
+ public String getConnectionURL()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getConnectionURL()");
+ }
+
+ return _raProperties.getConnectionURL();
+ }
+
+ /**
+ * Set the client ID
+ *
+ * @param connectionURL The connection url
+ */
+ public void setConnectionURL(final String connectionURL)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setConnectionURL(" + connectionURL + ")");
+ }
+
+ _raProperties.setConnectionURL(connectionURL);
+ }
+
+ /**
+ * Get the transaction manager locator class
+ *
+ * @return The value
+ */
+ public String getTransactionManagerLocatorClass()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransactionManagerLocatorClass()");
+ }
+
+ return _raProperties.getTransactionManagerLocatorClass();
+ }
+
+ /**
+ * Set the transaction manager locator class
+ *
+ * @param locator The transaction manager locator class
+ */
+ public void setTransactionManagerLocatorClass(final String locator)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTransactionManagerLocatorClass(" + locator + ")");
+ }
+
+ _raProperties.setTransactionManagerLocatorClass(locator);
+ }
+
+ /**
+ * Get the transaction manager locator method
+ *
+ * @return The value
+ */
+ public String getTransactionManagerLocatorMethod()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransactionManagerLocatorMethod()");
+ }
+
+ return _raProperties.getTransactionManagerLocatorMethod();
+ }
+
+ /**
+ * Set the transaction manager locator method
+ *
+ * @param method The transaction manager locator method
+ */
+ public void setTransactionManagerLocatorMethod(final String method)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTransactionManagerLocatorMethod(" + method + ")");
+ }
+
+ _raProperties.setTransactionManagerLocatorMethod(method);
+ }
+
+ /**
+ * Get the use XA flag
+ *
+ * @return The value
+ */
+ public Boolean getUseLocalTx()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUseLocalTx()");
+ }
+
+ return _raProperties.getUseLocalTx();
+ }
+
+ /**
+ * Set the use XA flag
+ *
+ * @param localTx The value
+ */
+ public void setUseLocalTx(final Boolean localTx)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUseLocalTx(" + localTx + ")");
+ }
+
+ _raProperties.setUseLocalTx(localTx);
+ }
+
+ public Integer getSetupAttempts()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSetupAttempts()");
+ }
+ return _raProperties.getSetupAttempts();
+ }
+
+ public void setSetupAttempts(Integer setupAttempts)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSetupAttempts(" + setupAttempts + ")");
+ }
+ _raProperties.setSetupAttempts(setupAttempts);
+ }
+
+ public Long getSetupInterval()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSetupInterval()");
+ }
+ return _raProperties.getSetupInterval();
+ }
+
+ public void setSetupInterval(Long interval)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSetupInterval(" + interval + ")");
+ }
+ _raProperties.setSetupInterval(interval);
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this one.
+ *
+ * @param obj Object with which to compare
+ * @return True if this object is the same as the obj argument; false otherwise.
+ */
+ public boolean equals(final Object obj)
+ {
+ if (obj == null)
+ {
+ return false;
+ }
+
+ if (obj instanceof QpidResourceAdapter)
+ {
+ return _raProperties.equals(((QpidResourceAdapter)obj).getProperties());
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Return the hash code for the object
+ *
+ * @return The hash code
+ */
+ public int hashCode()
+ {
+ return _raProperties.hashCode();
+ }
+
+ /**
+ * Get the work manager
+ *
+ * @return The manager
+ */
+ public WorkManager getWorkManager()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getWorkManager()");
+ }
+
+ if (_ctx == null)
+ {
+ return null;
+ }
+
+ return _ctx.getWorkManager();
+ }
+
+ public XASession createXASession(final XAConnectionImpl connection)
+ throws Exception
+ {
+ final XASession result = connection.createXASession() ;
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Using session " + Util.asString(result));
+ }
+ return result ;
+ }
+
+ public Session createSession(final AMQConnection connection,
+ final int ackMode,
+ final boolean useLocalTx,
+ final Integer prefetchLow,
+ final Integer prefetchHigh) throws Exception
+ {
+ Session result;
+
+ if (prefetchLow == null)
+ {
+ result = connection.createSession(useLocalTx, ackMode) ;
+ }
+ else if (prefetchHigh == null)
+ {
+ result = connection.createSession(useLocalTx, ackMode, prefetchLow) ;
+ }
+ else
+ {
+ result = connection.createSession(useLocalTx, ackMode, prefetchHigh, prefetchLow) ;
+ }
+
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Using session " + Util.asString(result));
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Get the resource adapter properties
+ *
+ * @return The properties
+ */
+ protected QpidRAProperties getProperties()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getProperties()");
+ }
+
+ return _raProperties;
+ }
+
+ /**
+ * Setup the factory
+ */
+ protected void setup() throws QpidRAException
+ {
+ _defaultAMQConnectionFactory = createAMQConnectionFactory(_raProperties);
+ }
+
+
+ public AMQConnectionFactory getDefaultAMQConnectionFactory() throws ResourceException
+ {
+ if (!_configured.getAndSet(true))
+ {
+ try
+ {
+ setup();
+ }
+ catch (QpidRAException e)
+ {
+ throw new ResourceException("Unable to create activation", e);
+ }
+ }
+ return _defaultAMQConnectionFactory;
+ }
+
+ public AMQConnectionFactory createAMQConnectionFactory(final ConnectionFactoryProperties overrideProperties)
+ throws QpidRAException
+ {
+ try
+ {
+ return createFactory(overrideProperties);
+ }
+ catch (final URLSyntaxException urlse)
+ {
+ throw new QpidRAException("Unexpected exception creating connection factory", urlse) ;
+ }
+ }
+
+ public Map<String, Object> overrideConnectionParameters(final Map<String, Object> connectionParams,
+ final Map<String, Object> overrideConnectionParams)
+ {
+ Map<String, Object> map = new HashMap<String, Object>();
+
+ if(connectionParams != null)
+ {
+ map.putAll(connectionParams);
+ }
+ if(overrideConnectionParams != null)
+ {
+ for (Map.Entry<String, Object> stringObjectEntry : overrideConnectionParams.entrySet())
+ {
+ map.put(stringObjectEntry.getKey(), stringObjectEntry.getValue());
+ }
+ }
+ return map;
+ }
+
+ private void locateTM()
+ {
+ if(_raProperties.getTransactionManagerLocatorClass() != null && _raProperties.getTransactionManagerLocatorMethod() != null)
+ {
+
+ String locatorClasses[] = _raProperties.getTransactionManagerLocatorClass().split(";");
+ String locatorMethods[] = _raProperties.getTransactionManagerLocatorMethod().split(";");
+
+ for (int i = 0 ; i < locatorClasses.length; i++)
+ {
+ _tm = Util.locateTM(locatorClasses[i], locatorMethods[i]);
+ if (_tm != null)
+ {
+ break;
+ }
+ }
+
+
+ }
+
+ if (_tm == null)
+ {
+ _log.warn("It wasn't possible to lookup a Transaction Manager through the configured properties TransactionManagerLocatorClass and TransactionManagerLocatorMethod");
+ _log.warn("Qpid Resource Adapter won't be able to set and verify transaction timeouts in certain cases.");
+ }
+ else
+ {
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("TM located = " + _tm);
+ }
+ }
+ }
+
+
+ private AMQConnectionFactory createFactory(final ConnectionFactoryProperties overrideProperties)
+ throws URLSyntaxException, QpidRAException
+ {
+ final String overrideURL = overrideProperties.getConnectionURL() ;
+ final String url = overrideURL != null ? overrideURL : _raProperties.getConnectionURL() ;
+
+ final String overrideClientID = overrideProperties.getClientId() ;
+ final String clientID = (overrideClientID != null ? overrideClientID : _raProperties.getClientId()) ;
+
+ final String overrideDefaultPassword = overrideProperties.getPassword() ;
+ final String defaultPassword = (overrideDefaultPassword != null ? overrideDefaultPassword : _raProperties.getPassword()) ;
+
+ final String overrideDefaultUsername = overrideProperties.getUserName() ;
+ final String defaultUsername = (overrideDefaultUsername != null ? overrideDefaultUsername : _raProperties.getUserName()) ;
+
+ final String overrideHost = overrideProperties.getHost() ;
+ final String host = (overrideHost != null ? overrideHost : _raProperties.getHost()) ;
+
+ final Integer overridePort = overrideProperties.getPort() ;
+ final Integer port = (overridePort != null ? overridePort : _raProperties.getPort()) ;
+
+ final String overridePath = overrideProperties.getPath() ;
+ final String path = (overridePath != null ? overridePath : _raProperties.getPath()) ;
+
+ final AMQConnectionFactory cf ;
+
+ if (url != null)
+ {
+ cf = new AMQConnectionFactory(url) ;
+
+ if (clientID != null)
+ {
+ cf.getConnectionURL().setClientName(clientID) ;
+ }
+ }
+ else
+ {
+ // create a URL to force the connection details
+ if ((host == null) || (port == null) || (path == null))
+ {
+ throw new QpidRAException("Configuration requires host/port/path if connectionURL is not specified") ;
+ }
+ final String username = (defaultUsername != null ? defaultUsername : "") ;
+ final String password = (defaultPassword != null ? defaultPassword : "") ;
+ final String client = (clientID != null ? clientID : "") ;
+
+ final String newurl = AMQConnectionURL.AMQ_PROTOCOL + "://" + username +":" + password + "@" + client + "/" + path + '?' + AMQConnectionURL.OPTIONS_BROKERLIST + "='tcp://" + host + ':' + port + '\'' ;
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Initialising connectionURL to " + newurl) ;
+ }
+
+ cf = new AMQConnectionFactory(newurl) ;
+ }
+
+ return cf ;
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/Util.java b/java/jca/src/main/java/org/apache/qpid/ra/Util.java
new file mode 100644
index 0000000000..b927aaa0be
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/Util.java
@@ -0,0 +1,184 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+import javax.naming.Context;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.transaction.TransactionManager;
+
+import org.apache.qpid.ra.admin.QpidQueue;
+import org.apache.qpid.ra.admin.QpidTopic;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Various utility functions
+ *
+ */
+public class Util
+{
+
+ private static final Logger _log = LoggerFactory.getLogger(Util.class);
+
+ /**
+ * Compare two strings.
+ * @param me First value
+ * @param you Second value
+ * @return True if object equals else false.
+ */
+ public static boolean compare(final String me, final String you)
+ {
+ // If both null or intern equals
+ if (me == you)
+ {
+ return true;
+ }
+
+ // if me null and you are not
+ if (me == null && you != null)
+ {
+ return false;
+ }
+
+ // me will not be null, test for equality
+ return me.equals(you);
+ }
+
+ /**
+ * Lookup an object in the default initial context
+ * @param context The context to use
+ * @param name the name to lookup
+ * @param clazz the expected type
+ * @return the object
+ * @throws Exception for any error
+ */
+ public static <T> T lookup(final Context context, final String name, final Class<T> clazz) throws Exception
+ {
+ Object object = context.lookup(name);
+
+ if (object instanceof Reference)
+ {
+
+ Reference ref = (Reference) object;
+ String addressContent = null;
+
+ if (ref.getClassName().equals(QpidQueue.class.getName()))
+ {
+ RefAddr addr = ref.get(QpidQueue.class.getName());
+ addressContent = (String) addr.getContent();
+
+ if (addr != null)
+ {
+ return (T)new QpidQueue(addressContent);
+ }
+ }
+
+ if (ref.getClassName().equals(QpidTopic.class.getName()))
+ {
+ RefAddr addr = ref.get(QpidTopic.class.getName());
+ addressContent = (String) addr.getContent();
+
+ if (addr != null)
+ {
+ return (T)new QpidTopic(addressContent);
+ }
+ }
+ }
+
+ return clazz.cast(object);
+
+ }
+
+ /** The Resource adapter can't depend on any provider's specific library. Because of that we use reflection to locate the
+ * transaction manager during startup.
+ *
+ *
+ * TODO: We should use a proper SPI instead of reflection
+ * We would need to define a proper SPI package for this.
+ **/
+ public static TransactionManager locateTM(final String locatorClass, final String locatorMethod)
+ {
+ try
+ {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ Class<?> aClass = loader.loadClass(locatorClass);
+ Object o = aClass.newInstance();
+ Method m = aClass.getMethod(locatorMethod);
+ return (TransactionManager)m.invoke(o);
+ }
+ catch (Throwable e)
+ {
+ _log.debug(e.getMessage(), e);
+ return null;
+ }
+ }
+
+ /**
+ * Serialize the object into a byte array.
+ * @param serializable The serializable object
+ * @return The generated byte array
+ * @throws IOException For errors during serialization.
+ */
+ public static byte[] serialize(final Serializable serializable)
+ throws IOException
+ {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
+ final ObjectOutputStream oos = new ObjectOutputStream(baos) ;
+ oos.writeObject(serializable) ;
+ oos.close() ;
+ return baos.toByteArray() ;
+ }
+
+ /**
+ * Deserialize the byte array into an object.
+ * @param data The serialized object as a byte array
+ * @return The serializable object.
+ * @throws IOException For errors during deserialization
+ * @throws ClassNotFoundException If the deserialized class cannot be found.
+ */
+ public static Object deserialize(final byte[] data)
+ throws IOException, ClassNotFoundException
+ {
+ final ByteArrayInputStream bais = new ByteArrayInputStream(data) ;
+ final ObjectInputStream ois = new ObjectInputStream(bais) ;
+ return ois.readObject() ;
+ }
+
+ /**
+ * Return a string identification for the specified object.
+ * @param object The object value.
+ * @return The string identification.
+ */
+ public static String asString(final Object object)
+ {
+ return (object == null ? "null" : object.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(object))) ;
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/admin/AdminObjectFactory.java b/java/jca/src/main/java/org/apache/qpid/ra/admin/AdminObjectFactory.java
new file mode 100644
index 0000000000..11f2903c72
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/admin/AdminObjectFactory.java
@@ -0,0 +1,74 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra.admin;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.spi.ObjectFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AdminObjectFactory implements ObjectFactory
+{
+ private static final Logger _log = LoggerFactory.getLogger(AdminObjectFactory.class);
+
+ @Override
+ public Object getObjectInstance(Object object, Name name, Context context, Hashtable<?, ?> env) throws Exception
+ {
+
+ Object instance = null;
+
+ if (object instanceof Reference)
+ {
+ Reference ref = (Reference) object;
+ String bindingURLString;
+
+ if (ref.getClassName().equals(QpidQueue.class.getName()))
+ {
+ RefAddr addr = ref.get(QpidQueue.class.getName());
+ bindingURLString = (String) addr.getContent();
+
+ if (addr != null)
+ {
+ return new QpidQueue(bindingURLString);
+ }
+
+ }
+
+ if (ref.getClassName().equals(QpidTopic.class.getName()))
+ {
+ RefAddr addr = ref.get(QpidTopic.class.getName());
+ bindingURLString = (String) addr.getContent();
+
+ if (addr != null)
+ {
+ return new QpidTopic(bindingURLString);
+ }
+ }
+ }
+ return instance;
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidBindingURL.java b/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidBindingURL.java
new file mode 100644
index 0000000000..503f59eecc
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidBindingURL.java
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra.admin;
+
+import java.net.URISyntaxException;
+
+import org.apache.qpid.url.AMQBindingURL;
+import org.apache.qpid.url.BindingURL;
+
+public class QpidBindingURL extends AMQBindingURL {
+
+ private String _url;
+
+ public QpidBindingURL(String url) throws URISyntaxException {
+ super(url);
+
+ if (!url.contains(BindingURL.OPTION_ROUTING_KEY) || getRoutingKey() == null) {
+ setOption(BindingURL.OPTION_ROUTING_KEY, null);
+ }
+
+ this._url = url;
+ }
+
+ @Override
+ public String getURL() {
+ return _url;
+ }
+
+ @Override
+ public String toString() {
+ return _url;
+ }
+
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxy.java b/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxy.java
new file mode 100644
index 0000000000..41242fefae
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxy.java
@@ -0,0 +1,156 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra.admin;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.naming.spi.ObjectFactory;
+
+import org.apache.qpid.client.AMQConnectionFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ *
+ */
+public class QpidConnectionFactoryProxy implements Externalizable, Referenceable, ConnectionFactory, Serializable
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidDestinationProxy.class);
+
+ private String _connectionURL;
+
+ private ConnectionFactory _delegate;
+
+ /**
+ * This constructor should not only be used be de-serialisation code. Create
+ * original object with the other constructor.
+ */
+ public QpidConnectionFactoryProxy()
+ {
+ }
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+ {
+ Reference ref = (Reference) in.readObject();
+
+ try
+ {
+ _delegate = (ConnectionFactory) dereference(ref);
+
+ } catch (Exception e)
+ {
+ _log.error("Failed to dereference ConnectionFactory " + e.getMessage(), e);
+ throw new IOException("Failed to dereference ConnectionFactory: " + e.getMessage());
+ }
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ if (_delegate == null)
+ {
+ _log.error("Null Destination ");
+ throw new IOException("Null ConnectionFactory!");
+ }
+
+ try
+ {
+ out.writeObject(((Referenceable) _delegate).getReference());
+ }
+ catch (NamingException e)
+ {
+ _log.error("Failed to dereference ConnectionFactory " + e.getMessage(), e);
+ throw new IOException("Failed to dereference ConnectionFactory: " + e.getMessage());
+ }
+ }
+
+ @Override
+ public Reference getReference() throws NamingException
+ {
+ try
+ {
+ _delegate = new AMQConnectionFactory(getConnectionURL());
+ /*
+ QpidResourceAdapter ra = new QpidResourceAdapter();
+ QpidRAManagedConnectionFactory mcf = new QpidRAManagedConnectionFactory();
+ mcf.setResourceAdapter(ra);
+ mcf.setConnectionURL(getConnectionURL());
+ delegate = new QpidRAConnectionFactoryImpl(mcf, null);
+ */
+ return ((Referenceable) _delegate).getReference();
+ }
+ catch(Exception e)
+ {
+ throw new NamingException(e.getMessage());
+ }
+ }
+ private Object dereference(Reference ref) throws Exception
+ {
+ ObjectFactory objFactory = (ObjectFactory) Class.forName(
+ ref.getFactoryClassName()).newInstance();
+ return objFactory.getObjectInstance(ref, null, null, null);
+ }
+
+ public void setConnectionURL(final String connectionURL)
+ {
+ this._connectionURL = connectionURL;
+ }
+ public String getConnectionURL()
+ {
+ return this._connectionURL;
+ }
+
+ /**
+ * Create a connection
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public Connection createConnection() throws JMSException
+ {
+ return _delegate.createConnection();
+ }
+
+ /**
+ * Create a connection
+ * @param userName The user name
+ * @param password The password
+ * @return The connection
+ * @exception JMSException Thrown if the operation fails
+ */
+ public Connection createConnection(final String userName, final String password) throws JMSException
+ {
+ return _delegate.createConnection(userName, password);
+ }
+
+}
+
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidDestinationProxy.java b/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidDestinationProxy.java
new file mode 100644
index 0000000000..738ce4be0d
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidDestinationProxy.java
@@ -0,0 +1,162 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra.admin;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+
+import javax.jms.Destination;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.naming.spi.ObjectFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The QpidDestinationProxy provides for allowing an administrator/developer to
+ * create and bind QPID destinations into a JNDI tree. AdminObjects are used as
+ * an generic integration point rather than relying on the EE server specific
+ * API's to create destinations (queues, topics). AdminObjects and associated
+ * properties are defined in the ra.xml file for a particular JCA adapter.
+ * Please see the ra.xml file for the QPID JCA resource adapter as well as the
+ * README.txt for the adapter for more details.
+ *
+ */
+public class QpidDestinationProxy implements Externalizable, Referenceable, Destination, Serializable
+{
+ private static final long serialVersionUID = -1137413782643796461L;
+
+ private static final Logger _log = LoggerFactory.getLogger(QpidDestinationProxy.class);
+
+ private static final String DEFAULT_QUEUE_TYPE = "QUEUE";
+
+ private static final String DEFAULT_TOPIC_TYPE = "TOPIC";
+
+ private String _destinationAddress;
+
+ private String _destinationType;
+
+ private Destination _delegate;
+
+ /**
+ * This constructor should not only be used be de-serialisation code. Create
+ * original object with the other constructor.
+ */
+ public QpidDestinationProxy()
+ {
+ }
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+ {
+ Reference ref = (Reference) in.readObject();
+
+ try
+ {
+ _delegate = (Destination) dereference(ref);
+
+ } catch (Exception e)
+ {
+ _log.error("Failed to dereference Destination " + e.getMessage(), e);
+ throw new IOException("Failed to dereference Destination: " + e.getMessage());
+ }
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ if (_delegate == null)
+ {
+ _log.error("Null Destination ");
+ throw new IOException("Null destination!");
+ }
+
+ try
+ {
+ out.writeObject(((Referenceable) _delegate).getReference());
+ }
+ catch (NamingException e)
+ {
+ _log.error("Failed to dereference Destination " + e.getMessage(), e);
+ throw new IOException("Failed to dereference Destination: " + e.getMessage());
+ }
+ }
+
+ @Override
+ public Reference getReference() throws NamingException
+ {
+ try
+ {
+ if(getDestinationType().equalsIgnoreCase(DEFAULT_QUEUE_TYPE))
+ {
+ _delegate = new QpidQueue(getDestinationAddress());
+ }
+ else if(getDestinationType().equalsIgnoreCase(DEFAULT_TOPIC_TYPE))
+ {
+ _delegate = new QpidTopic(getDestinationAddress());
+ }
+ else
+ {
+ throw new IllegalStateException("Unknown destination type " + getDestinationType());
+ }
+
+ return ((Referenceable) _delegate).getReference();
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(),e);
+ throw new NamingException("Failed to create destination " + e.getMessage());
+ }
+
+ }
+
+ private Object dereference(Reference ref) throws Exception
+ {
+ ObjectFactory objFactory = (ObjectFactory) Class.forName(
+ ref.getFactoryClassName()).newInstance();
+ return objFactory.getObjectInstance(ref, null, null, null);
+ }
+
+ public void setDestinationAddress(String destinationAddress) throws Exception
+ {
+ this._destinationAddress = destinationAddress;
+ }
+
+ public String getDestinationAddress()
+ {
+ return this._destinationAddress;
+ }
+
+ public void setDestinationType(String destinationType)
+ {
+ this._destinationType = destinationType;
+ }
+
+ public String getDestinationType()
+ {
+ return this._destinationType;
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidQueue.java b/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidQueue.java
new file mode 100644
index 0000000000..caef0c8ffd
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidQueue.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra.admin;
+
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+
+import org.apache.qpid.client.AMQQueue;
+
+public class QpidQueue extends AMQQueue
+{
+ private String _url;
+
+ public QpidQueue(final String address) throws Exception
+ {
+ super(address);
+ this._url = address;
+ }
+
+ @Override
+ public Reference getReference() throws NamingException
+ {
+ return new Reference(this.getClass().getName(), new StringRefAddr(this.getClass().getName(), toURL()),
+ AdminObjectFactory.class.getName(), null);
+ }
+
+ @Override
+ public String toURL()
+ {
+ return _url;
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidTopic.java b/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidTopic.java
new file mode 100644
index 0000000000..3f181b93eb
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidTopic.java
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra.admin;
+
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+
+import org.apache.qpid.client.AMQTopic;
+
+public class QpidTopic extends AMQTopic
+{
+ private String _url;
+
+ public QpidTopic(final String address) throws Exception
+ {
+ super(address);
+ this._url = address;
+ }
+
+ @Override
+ public Reference getReference() throws NamingException
+ {
+ return new Reference(this.getClass().getName(), new StringRefAddr(this.getClass().getName(), toURL()),
+ AdminObjectFactory.class.getName(), null);
+ }
+
+ @Override
+ public String toURL()
+ {
+ return _url;
+ }
+
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java b/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java
new file mode 100644
index 0000000000..98427d7f9d
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java
@@ -0,0 +1,593 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra.inflow;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.resource.ResourceException;
+import javax.resource.spi.endpoint.MessageEndpointFactory;
+import javax.resource.spi.work.Work;
+import javax.resource.spi.work.WorkManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.XAConnectionImpl;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.ra.QpidResourceAdapter;
+import org.apache.qpid.ra.Util;
+
+/**
+ * The activation.
+ *
+ */
+public class QpidActivation implements ExceptionListener
+{
+ /**
+ * The logger
+ */
+ private static final Logger _log = LoggerFactory.getLogger(QpidActivation.class);
+
+ /**
+ * The onMessage method
+ */
+ public static final Method ONMESSAGE;
+
+ /**
+ * The resource adapter
+ */
+ private final QpidResourceAdapter _ra;
+
+ /**
+ * The activation spec
+ */
+ private final QpidActivationSpec _spec;
+
+ /**
+ * The message endpoint factory
+ */
+ private final MessageEndpointFactory _endpointFactory;
+
+ /**
+ * Whether delivery is active
+ */
+ private final AtomicBoolean _deliveryActive = new AtomicBoolean(false);
+
+ /**
+ * The destination type
+ */
+ private boolean _isTopic = false;
+
+ /**
+ * Is the delivery transacted
+ */
+ private boolean _isDeliveryTransacted;
+
+ private Destination _destination;
+
+ /**
+ * The connection
+ */
+ private Connection _connection;
+
+ private final List<QpidMessageHandler> _handlers = new ArrayList<QpidMessageHandler>();
+
+ private AMQConnectionFactory _factory;
+
+ // Whether we are in the failure recovery loop
+ private AtomicBoolean _inFailure = new AtomicBoolean(false);
+
+ static
+ {
+ try
+ {
+ ONMESSAGE = MessageListener.class.getMethod("onMessage", new Class[] { Message.class });
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ * @param ra The resource adapter
+ * @param endpointFactory The endpoint factory
+ * @param spec The activation spec
+ * @throws ResourceException Thrown if an error occurs
+ */
+ public QpidActivation(final QpidResourceAdapter ra,
+ final MessageEndpointFactory endpointFactory,
+ final QpidActivationSpec spec) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + ra + ", " + endpointFactory + ", " + spec + ")");
+ }
+
+ this._ra = ra;
+ this._endpointFactory = endpointFactory;
+ this._spec = spec;
+ try
+ {
+ _isDeliveryTransacted = endpointFactory.isDeliveryTransacted(QpidActivation.ONMESSAGE);
+ }
+ catch (Exception e)
+ {
+ throw new ResourceException(e);
+ }
+ }
+
+ /**
+ * Get the activation spec
+ *
+ * @return The value
+ */
+ public QpidActivationSpec getActivationSpec()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getActivationSpec()");
+ }
+
+ return _spec;
+ }
+
+ /**
+ * Get the message endpoint factory
+ *
+ * @return The value
+ */
+ public MessageEndpointFactory getMessageEndpointFactory()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMessageEndpointFactory()");
+ }
+
+ return _endpointFactory;
+ }
+
+ /**
+ * Get whether delivery is transacted
+ *
+ * @return The value
+ */
+ public boolean isDeliveryTransacted()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("isDeliveryTransacted()");
+ }
+
+ return _isDeliveryTransacted;
+ }
+
+ /**
+ * Get the work manager
+ *
+ * @return The value
+ */
+ public WorkManager getWorkManager()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getWorkManager()");
+ }
+
+ return _ra.getWorkManager();
+ }
+
+ /**
+ * Is the destination a topic
+ *
+ * @return The value
+ */
+ public boolean isTopic()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("isTopic()");
+ }
+
+ return _isTopic;
+ }
+
+ /**
+ * Start the activation
+ *
+ * @throws ResourceException Thrown if an error occurs
+ */
+ public void start() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start()");
+ }
+ _deliveryActive.set(true);
+ _ra.getWorkManager().scheduleWork(new SetupActivation());
+ }
+
+ /**
+ * Stop the activation
+ */
+ public void stop()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("stop()");
+ }
+
+ _deliveryActive.set(false);
+ teardown();
+ }
+
+ /**
+ * Setup the activation
+ *
+ * @throws Exception Thrown if an error occurs
+ */
+ protected synchronized void setup() throws Exception
+ {
+ _log.debug("Setting up " + _spec);
+ setupCF();
+
+ setupDestination();
+ final AMQConnection amqConnection ;
+ final boolean useLocalTx = _spec.isUseLocalTx() ;
+ final boolean isXA = _isDeliveryTransacted && !useLocalTx ;
+
+ if (isXA)
+ {
+ amqConnection = (XAConnectionImpl)_factory.createXAConnection() ;
+ }
+ else
+ {
+ amqConnection = (AMQConnection)_factory.createConnection() ;
+ }
+
+ amqConnection.setExceptionListener(this) ;
+
+ for (int i = 0; i < _spec.getMaxSession(); i++)
+ {
+ Session session = null;
+
+ try
+ {
+ if (isXA)
+ {
+ session = _ra.createXASession((XAConnectionImpl)amqConnection) ;
+ }
+ else
+ {
+ session = _ra.createSession((AMQConnection)amqConnection,
+ _spec.getAcknowledgeModeInt(),
+ useLocalTx,
+ _spec.getPrefetchLow(),
+ _spec.getPrefetchHigh());
+ }
+
+ _log.debug("Using session " + Util.asString(session));
+ QpidMessageHandler handler = new QpidMessageHandler(this, _ra.getTM(), session);
+ handler.setup();
+ _handlers.add(handler);
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ amqConnection.close() ;
+ }
+ catch (Exception e2)
+ {
+ _log.trace("Ignored error closing connection", e2);
+ }
+
+ throw e;
+ }
+ }
+ amqConnection.start() ;
+ this._connection = amqConnection ;
+
+ _log.debug("Setup complete " + this);
+ }
+
+ /**
+ * Teardown the activation
+ */
+ protected synchronized void teardown()
+ {
+ _log.debug("Tearing down " + _spec);
+
+ try
+ {
+ if (_connection != null)
+ {
+ _connection.stop();
+ }
+ }
+ catch (Throwable t)
+ {
+ _log.debug("Error stopping connection " + Util.asString(_connection), t);
+ }
+
+ for (QpidMessageHandler handler : _handlers)
+ {
+ handler.teardown();
+ }
+
+ try
+ {
+ if (_connection != null)
+ {
+ _connection.close();
+ }
+ }
+ catch (Throwable t)
+ {
+ _log.debug("Error closing connection " + Util.asString(_connection), t);
+ }
+ if (_spec.isHasBeenUpdated())
+ {
+ _factory = null;
+ }
+ _log.debug("Tearing down complete " + this);
+ }
+
+ protected void setupCF() throws Exception
+ {
+ if (_spec.isHasBeenUpdated())
+ {
+ _factory = _ra.createAMQConnectionFactory(_spec);
+ }
+ else
+ {
+ _factory = _ra.getDefaultAMQConnectionFactory();
+ }
+ }
+
+ public Destination getDestination()
+ {
+ return _destination;
+ }
+
+ protected void setupDestination() throws Exception
+ {
+
+ String destinationName = _spec.getDestination();
+ String destinationTypeString = _spec.getDestinationType();
+
+ if (_spec.isUseJNDI())
+ {
+ Context ctx = new InitialContext();
+ _log.debug("Using context " + ctx.getEnvironment() + " for " + _spec);
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setupDestination(" + ctx + ")");
+ }
+
+ if (destinationTypeString != null && !destinationTypeString.trim().equals(""))
+ {
+ _log.debug("Destination type defined as " + destinationTypeString);
+
+ Class<? extends Destination> destinationType;
+ if (Topic.class.getName().equals(destinationTypeString))
+ {
+ destinationType = Topic.class;
+ _isTopic = true;
+ }
+ else
+ {
+ destinationType = Queue.class;
+ }
+
+ _log.debug("Retrieving destination " + destinationName +
+ " of type " +
+ destinationType.getName());
+ _destination = Util.lookup(ctx, destinationName, destinationType);
+ //_destination = (Destination)ctx.lookup(destinationName);
+
+ }
+ else
+ {
+ _log.debug("Destination type not defined");
+ _log.debug("Retrieving destination " + destinationName +
+ " of type " +
+ Destination.class.getName());
+
+ _destination = Util.lookup(ctx, destinationName, AMQDestination.class);
+ _isTopic = !(_destination instanceof Queue) ;
+ }
+ }
+ else
+ {
+ _destination = (AMQDestination)AMQDestination.createDestination(_spec.getDestination());
+ if (destinationTypeString != null && !destinationTypeString.trim().equals(""))
+ {
+ _log.debug("Destination type defined as " + destinationTypeString);
+ final boolean match ;
+ if (Topic.class.getName().equals(destinationTypeString))
+ {
+ match = (_destination instanceof Topic) ;
+ _isTopic = true;
+ }
+ else
+ {
+ match = (_destination instanceof Queue) ;
+ }
+ if (!match)
+ {
+ throw new ClassCastException("Expected destination of type " + destinationTypeString + " but created destination " + _destination) ;
+ }
+ }
+ else
+ {
+ _isTopic = !(_destination instanceof Queue) ;
+ }
+ }
+
+ _log.debug("Got destination " + _destination + " from " + destinationName);
+ }
+
+ /**
+ * Get a string representation
+ *
+ * @return The value
+ */
+ @Override
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(QpidActivation.class.getName()).append('(');
+ buffer.append("spec=").append(_spec.getClass().getName());
+ buffer.append(" mepf=").append(_endpointFactory.getClass().getName());
+ buffer.append(" active=").append(_deliveryActive.get());
+ if (_spec.getDestination() != null)
+ {
+ buffer.append(" destination=").append(_spec.getDestination());
+ }
+ buffer.append(" transacted=").append(_isDeliveryTransacted);
+ buffer.append(')');
+ return buffer.toString();
+ }
+
+ public void onException(final JMSException jmse)
+ {
+ handleFailure(jmse) ;
+ }
+
+ /**
+ * Handles any failure by trying to reconnect
+ *
+ * @param failure the reason for the failure
+ */
+ public void handleFailure(Throwable failure)
+ {
+ if(doesNotExist(failure))
+ {
+ _log.info("awaiting topic/queue creation " + getActivationSpec().getDestination());
+ }
+ else
+ {
+ _log.warn("Failure in Qpid activation " + _spec, failure);
+ }
+ int reconnectCount = 0;
+ int setupAttempts = _spec.getSetupAttempts();
+ long setupInterval = _spec.getSetupInterval();
+
+ // Only enter the failure loop once
+ if (_inFailure.getAndSet(true))
+ return;
+ try
+ {
+ while (_deliveryActive.get() && (setupAttempts == -1 || reconnectCount < setupAttempts))
+ {
+ teardown();
+
+ try
+ {
+ Thread.sleep(setupInterval);
+ }
+ catch (InterruptedException e)
+ {
+ _log.debug("Interrupted trying to reconnect " + _spec, e);
+ break;
+ }
+
+ _log.info("Attempting to reconnect " + _spec);
+ try
+ {
+ setup();
+ _log.info("Reconnected with Qpid");
+ break;
+ }
+ catch (Throwable t)
+ {
+ if(doesNotExist(failure))
+ {
+ _log.info("awaiting topic/queue creation " + getActivationSpec().getDestination());
+ }
+ else
+ {
+ _log.error("Unable to reconnect " + _spec, t);
+ }
+ }
+ ++reconnectCount;
+ }
+ }
+ finally
+ {
+ // Leaving failure recovery loop
+ _inFailure.set(false);
+ }
+ }
+
+ /**
+ * Check to see if the failure represents a missing endpoint
+ * @param failure The failure.
+ * @return true if it represents a missing endpoint, false otherwise
+ */
+ private boolean doesNotExist(final Throwable failure)
+ {
+ return (failure instanceof AMQException) && (((AMQException)failure).getErrorCode() == AMQConstant.NOT_FOUND) ;
+ }
+
+ /**
+ * Handles the setup
+ */
+ private class SetupActivation implements Work
+ {
+ public void run()
+ {
+ try
+ {
+ setup();
+ }
+ catch (Throwable t)
+ {
+ handleFailure(t);
+ }
+ }
+
+ public void release()
+ {
+ }
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivationSpec.java b/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivationSpec.java
new file mode 100644
index 0000000000..5f4e2dcf6b
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivationSpec.java
@@ -0,0 +1,604 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra.inflow;
+
+import java.io.Serializable;
+
+import javax.jms.Session;
+import javax.resource.ResourceException;
+import javax.resource.spi.ActivationSpec;
+import javax.resource.spi.InvalidPropertyException;
+import javax.resource.spi.ResourceAdapter;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.qpid.ra.ConnectionFactoryProperties;
+import org.apache.qpid.ra.QpidResourceAdapter;
+
+/**
+ * The activation spec
+ * These properties are set on the MDB ActivactionProperties
+ *
+ */
+public class QpidActivationSpec extends ConnectionFactoryProperties implements ActivationSpec, Serializable
+{
+ private static final long serialVersionUID = 7379131936083146158L;
+
+ private static final int DEFAULT_MAX_SESSION = 15;
+
+ /** The logger */
+ private static final transient Logger _log = LoggerFactory.getLogger(QpidActivationSpec.class);
+
+ /** The resource adapter */
+ private QpidResourceAdapter _ra;
+
+ /** The destination */
+ private String _destination;
+
+ /** The destination type */
+ private String _destinationType;
+
+ /** The message selector */
+ private String _messageSelector;
+
+ /** The acknowledgement mode */
+ private int _acknowledgeMode;
+
+ /** The subscription durability */
+ private boolean _subscriptionDurability;
+
+ /** The subscription name */
+ private String _subscriptionName;
+
+ /** The maximum number of sessions */
+ private Integer _maxSession;
+
+ /** Transaction timeout */
+ private Integer _transactionTimeout;
+
+ /** prefetch low */
+ private Integer _prefetchLow;
+
+ /** prefetch high */
+ private Integer _prefetchHigh;
+
+ private boolean _useJNDI = true;
+
+ // undefined by default, default is specified at the RA level in QpidRAProperties
+ private Integer _setupAttempts;
+
+ // undefined by default, default is specified at the RA level in QpidRAProperties
+ private Long _setupInterval;
+
+ /**
+ * Constructor
+ */
+ public QpidActivationSpec()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+
+ _acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+ _maxSession = DEFAULT_MAX_SESSION;
+ _transactionTimeout = 0;
+ }
+
+ /**
+ * Get the resource adapter
+ * @return The resource adapter
+ */
+ public ResourceAdapter getResourceAdapter()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getResourceAdapter()");
+ }
+
+ return _ra;
+ }
+
+ /**
+ * @return the useJNDI
+ */
+ public boolean isUseJNDI()
+ {
+ return _useJNDI;
+ }
+
+ /**
+ * @param value the useJNDI to set
+ */
+ public void setUseJNDI(final boolean value)
+ {
+ _useJNDI = value;
+ }
+
+ /**
+ * Set the resource adapter
+ * @param ra The resource adapter
+ * @exception ResourceException Thrown if incorrect resource adapter
+ */
+ public void setResourceAdapter(final ResourceAdapter ra) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setResourceAdapter(" + ra + ")");
+ }
+
+ if (ra == null || !(ra instanceof QpidResourceAdapter))
+ {
+ throw new ResourceException("Resource adapter is " + ra);
+ }
+
+ this._ra = (QpidResourceAdapter)ra;
+ }
+
+ /**
+ * Get the destination
+ * @return The value
+ */
+ public String getDestination()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDestination()");
+ }
+
+ return _destination;
+ }
+
+ /**
+ * Set the destination
+ * @param value The value
+ */
+ public void setDestination(final String value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDestination(" + value + ")");
+ }
+
+ _destination = value;
+ }
+
+ /**
+ * Get the destination type
+ * @return The value
+ */
+ public String getDestinationType()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDestinationType()");
+ }
+
+ return _destinationType;
+ }
+
+ /**
+ * Set the destination type
+ * @param value The value
+ */
+ public void setDestinationType(final String value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDestinationType(" + value + ")");
+ }
+
+ _destinationType = value;
+ }
+
+ /**
+ * Get the message selector
+ * @return The value
+ */
+ public String getMessageSelector()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMessageSelector()");
+ }
+
+ return _messageSelector;
+ }
+
+ /**
+ * Set the message selector
+ * @param value The value
+ */
+ public void setMessageSelector(final String value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setMessageSelector(" + value + ")");
+ }
+
+ _messageSelector = value;
+ }
+
+ /**
+ * Get the acknowledge mode
+ * @return The value
+ */
+ public String getAcknowledgeMode()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getAcknowledgeMode()");
+ }
+
+ if (Session.DUPS_OK_ACKNOWLEDGE == _acknowledgeMode)
+ {
+ return "Dups-ok-acknowledge";
+ }
+ else
+ {
+ return "Auto-acknowledge";
+ }
+ }
+
+ /**
+ * Set the acknowledge mode
+ * @param value The value
+ */
+ public void setAcknowledgeMode(final String value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setAcknowledgeMode(" + value + ")");
+ }
+
+ if ("DUPS_OK_ACKNOWLEDGE".equalsIgnoreCase(value) || "Dups-ok-acknowledge".equalsIgnoreCase(value))
+ {
+ _acknowledgeMode = Session.DUPS_OK_ACKNOWLEDGE;
+ }
+ else if ("AUTO_ACKNOWLEDGE".equalsIgnoreCase(value) || "Auto-acknowledge".equalsIgnoreCase(value))
+ {
+ _acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+ }
+ else
+ {
+ throw new IllegalArgumentException("Unsupported acknowledgement mode " + value);
+ }
+ }
+
+ /**
+ * @return the acknowledgement mode
+ */
+ public int getAcknowledgeModeInt()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getAcknowledgeMode()");
+ }
+
+ return _acknowledgeMode;
+ }
+
+ /**
+ * Get the subscription durability
+ * @return The value
+ */
+ public String getSubscriptionDurability()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSubscriptionDurability()");
+ }
+
+ if (_subscriptionDurability)
+ {
+ return "Durable";
+ }
+ else
+ {
+ return "NonDurable";
+ }
+ }
+
+ /**
+ * Set the subscription durability
+ * @param value The value
+ */
+ public void setSubscriptionDurability(final String value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSubscriptionDurability(" + value + ")");
+ }
+
+ _subscriptionDurability = "Durable".equals(value);
+ }
+
+ /**
+ * Get the status of subscription durability
+ * @return The value
+ */
+ public boolean isSubscriptionDurable()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("isSubscriptionDurable()");
+ }
+
+ return _subscriptionDurability;
+ }
+
+ /**
+ * Get the subscription name
+ * @return The value
+ */
+ public String getSubscriptionName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSubscriptionName()");
+ }
+
+ return _subscriptionName;
+ }
+
+ /**
+ * Set the subscription name
+ * @param value The value
+ */
+ public void setSubscriptionName(final String value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSubscriptionName(" + value + ")");
+ }
+
+ _subscriptionName = value;
+ }
+
+ /**
+ * Get the number of max session
+ * @return The value
+ */
+ public Integer getMaxSession()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMaxSession()");
+ }
+
+ if (_maxSession == null)
+ {
+ return DEFAULT_MAX_SESSION;
+ }
+
+ return _maxSession;
+ }
+
+ /**
+ * Set the number of max session
+ * @param value The value
+ */
+ public void setMaxSession(final Integer value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setMaxSession(" + value + ")");
+ }
+
+ _maxSession = value;
+ }
+
+ /**
+ * Get the transaction timeout
+ * @return The value
+ */
+ public Integer getTransactionTimeout()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransactionTimeout()");
+ }
+
+ return _transactionTimeout;
+ }
+
+ /**
+ * Set the transaction timeout
+ * @param value The value
+ */
+ public void setTransactionTimeout(final Integer value)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTransactionTimeout(" + value + ")");
+ }
+
+ _transactionTimeout = value;
+ }
+
+ /**
+ * Get the prefetch low
+ * @return The value
+ */
+ public Integer getPrefetchLow()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPrefetchLow()");
+ }
+
+ return _prefetchLow;
+ }
+
+ /**
+ * Set the prefetch low
+ * @param value The value
+ */
+ public void setPrefetchLow(final Integer prefetchLow)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPrefetchLow(" + prefetchLow + ")");
+ }
+
+ this._prefetchLow = prefetchLow;
+ }
+
+ /**
+ * Get the prefetch high
+ * @return The value
+ */
+ public Integer getPrefetchHigh()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPrefetchHigh()");
+ }
+
+ return _prefetchHigh;
+ }
+
+ /**
+ * Set the prefetch high
+ * @param value The value
+ */
+ public void setPrefetchHigh(final Integer prefetchHigh)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPrefetchHigh(" + prefetchHigh + ")");
+ }
+
+ this._prefetchHigh = prefetchHigh;
+ }
+
+ public int getSetupAttempts()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSetupAttempts()");
+ }
+
+ if (_setupAttempts == null)
+ {
+ return _ra.getSetupAttempts();
+ }
+ else
+ {
+ return _setupAttempts;
+ }
+ }
+
+ public void setSetupAttempts(int setupAttempts)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSetupAttempts(" + setupAttempts + ")");
+ }
+
+ this._setupAttempts = setupAttempts;
+ }
+
+ public long getSetupInterval()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSetupInterval()");
+ }
+
+ if (_setupInterval == null)
+ {
+ return _ra.getSetupInterval();
+ }
+ else
+ {
+ return _setupInterval;
+ }
+ }
+
+ public void setSetupInterval(long setupInterval)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSetupInterval(" + setupInterval + ")");
+ }
+
+ this._setupInterval = setupInterval;
+ }
+
+ /**
+ * Validate
+ * @exception InvalidPropertyException Thrown if a validation exception occurs
+ */
+ public void validate() throws InvalidPropertyException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("validate()");
+ }
+
+ if (_destination == null || _destination.trim().equals(""))
+ {
+ throw new InvalidPropertyException("Destination is mandatory");
+ }
+ }
+
+ /**
+ * Get a string representation
+ * @return The value
+ */
+ @Override
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(QpidActivationSpec.class.getName()).append('(');
+ buffer.append("ra=").append(_ra);
+ buffer.append(" destination=").append(_destination);
+ buffer.append(" destinationType=").append(_destinationType);
+ if (_messageSelector != null)
+ {
+ buffer.append(" selector=").append(_messageSelector);
+ }
+ buffer.append(" ack=").append(getAcknowledgeMode());
+ buffer.append(" durable=").append(_subscriptionDurability);
+ buffer.append(" clientID=").append(getClientId());
+ if (_subscriptionName != null)
+ {
+ buffer.append(" subscription=").append(_subscriptionName);
+ }
+ buffer.append(" user=").append(getUserName());
+ if (getPassword() != null)
+ {
+ buffer.append(" password=").append("****");
+ }
+ buffer.append(" maxSession=").append(_maxSession);
+ if (_prefetchLow != null)
+ {
+ buffer.append(" prefetchLow=").append(_prefetchLow);
+ }
+ if (_prefetchHigh != null)
+ {
+ buffer.append(" prefetchHigh=").append(_prefetchHigh);
+ }
+ buffer.append(')');
+ return buffer.toString();
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidMessageHandler.java b/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidMessageHandler.java
new file mode 100644
index 0000000000..473efab31f
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidMessageHandler.java
@@ -0,0 +1,245 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra.inflow;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.XASession;
+import javax.resource.ResourceException;
+import javax.resource.spi.endpoint.MessageEndpoint;
+import javax.resource.spi.endpoint.MessageEndpointFactory;
+import javax.transaction.Status;
+import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAResource;
+
+import org.apache.qpid.ra.Util;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The message handler
+ *
+ */
+public class QpidMessageHandler implements MessageListener
+{
+ /**
+ * The logger
+ */
+ private static final Logger _log = LoggerFactory.getLogger(QpidMessageHandler.class);
+
+ /**
+ * The session
+ */
+ private final Session _session;
+
+ private MessageConsumer _consumer;
+
+ /**
+ * The endpoint
+ */
+ private MessageEndpoint _endpoint;
+
+ private final QpidActivation _activation;
+
+ private boolean _useLocalTx;
+
+ private boolean _transacted;
+
+ private final TransactionManager _tm;
+
+ public QpidMessageHandler(final QpidActivation activation,
+ final TransactionManager tm,
+ final Session session)
+ {
+ this._activation = activation;
+ this._session = session;
+ this._tm = tm;
+ }
+
+ public void setup() throws Exception
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setup()");
+ }
+
+ QpidActivationSpec spec = _activation.getActivationSpec();
+ String selector = spec.getMessageSelector();
+
+ // Create the message consumer
+ if (_activation.isTopic())
+ {
+ final Topic topic = (Topic) _activation.getDestination();
+ final String subscriptionName = spec.getSubscriptionName();
+ if (spec.isSubscriptionDurable())
+ _consumer = _session.createDurableSubscriber(topic, subscriptionName, selector, false);
+ else
+ _consumer = _session.createConsumer(topic, selector) ;
+ }
+ else
+ {
+ final Queue queue = (Queue) _activation.getDestination();
+ _consumer = _session.createConsumer(queue, selector);
+ }
+
+ // Create the endpoint, if we are transacted pass the session so it is enlisted, unless using Local TX
+ MessageEndpointFactory endpointFactory = _activation.getMessageEndpointFactory();
+ _useLocalTx = _activation.getActivationSpec().isUseLocalTx();
+ _transacted = _activation.isDeliveryTransacted() || _useLocalTx ;
+ if (_activation.isDeliveryTransacted() && !_activation.getActivationSpec().isUseLocalTx())
+ {
+ final XAResource xaResource = ((XASession)_session).getXAResource() ;
+ _endpoint = endpointFactory.createEndpoint(xaResource);
+ }
+ else
+ {
+ _endpoint = endpointFactory.createEndpoint(null);
+ }
+ _consumer.setMessageListener(this);
+ }
+
+ /**
+ * Stop the handler
+ */
+ public void teardown()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("teardown()");
+ }
+
+ try
+ {
+ if (_endpoint != null)
+ {
+ _endpoint.release();
+ _endpoint = null;
+ }
+ }
+ catch (Throwable t)
+ {
+ _log.debug("Error releasing endpoint " + _endpoint, t);
+ }
+ }
+
+ public void onMessage(final Message message)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("onMessage(" + Util.asString(message) + ")");
+ }
+
+ boolean beforeDelivery = false;
+
+ try
+ {
+ if (_activation.getActivationSpec().getTransactionTimeout() > 0 && _tm != null)
+ {
+ _tm.setTransactionTimeout(_activation.getActivationSpec().getTransactionTimeout());
+ }
+
+ _endpoint.beforeDelivery(QpidActivation.ONMESSAGE);
+ beforeDelivery = true;
+
+ if(_transacted)
+ {
+ message.acknowledge();
+ }
+
+ ((MessageListener)_endpoint).onMessage(message);
+
+ if (_transacted && (_tm.getTransaction() != null))
+ {
+ final int status = _tm.getStatus() ;
+ final boolean rollback = status == Status.STATUS_MARKED_ROLLBACK
+ || status == Status.STATUS_ROLLING_BACK
+ || status == Status.STATUS_ROLLEDBACK;
+ if (rollback)
+ {
+ _session.recover() ;
+ }
+ }
+ else
+ {
+ message.acknowledge();
+ }
+
+ try
+ {
+ _endpoint.afterDelivery();
+ }
+ catch (ResourceException e)
+ {
+ _log.warn("Unable to call after delivery", e);
+ return;
+ }
+ if (_useLocalTx)
+ {
+ _session.commit();
+ }
+ }
+ catch (Throwable e)
+ {
+ _log.error("Failed to deliver message", e);
+ // we need to call before/afterDelivery as a pair
+ if (beforeDelivery)
+ {
+ try
+ {
+ _endpoint.afterDelivery();
+ }
+ catch (ResourceException e1)
+ {
+ _log.warn("Unable to call after delivery", e);
+ }
+ }
+ if (_useLocalTx || !_activation.isDeliveryTransacted())
+ {
+ try
+ {
+ _session.rollback();
+ }
+ catch (JMSException e1)
+ {
+ _log.warn("Unable to roll local transaction back", e1);
+ }
+ }
+ else
+ {
+ try
+ {
+ _session.recover() ;
+ }
+ catch (JMSException e1)
+ {
+ _log.warn("Unable to recover XA transaction", e1);
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/tm/GeronimoTransactionManagerLocator.java b/java/jca/src/main/java/org/apache/qpid/ra/tm/GeronimoTransactionManagerLocator.java
new file mode 100644
index 0000000000..3a47824631
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/tm/GeronimoTransactionManagerLocator.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra.tm;
+
+import java.util.Set;
+
+import javax.transaction.TransactionManager;
+
+import org.apache.geronimo.gbean.AbstractName;
+import org.apache.geronimo.gbean.AbstractNameQuery;
+import org.apache.geronimo.kernel.Kernel;
+import org.apache.geronimo.kernel.KernelRegistry;
+
+public class GeronimoTransactionManagerLocator
+{
+
+ public GeronimoTransactionManagerLocator()
+ {
+ }
+
+ public TransactionManager getTransactionManager()
+ {
+ try
+ {
+ Kernel kernel = KernelRegistry.getSingleKernel();
+ AbstractNameQuery query = new AbstractNameQuery(TransactionManager.class.getName ());
+ Set<AbstractName> names = kernel.listGBeans(query);
+
+ if (names.size() != 1)
+ {
+ throw new IllegalStateException("Expected one transaction manager, not " + names.size());
+ }
+
+ AbstractName name = names.iterator().next();
+ TransactionManager transMg = (TransactionManager) kernel.getGBean(name);
+ return (TransactionManager)transMg;
+
+ }
+ catch(Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/tm/JBoss7TransactionManagerLocator.java b/java/jca/src/main/java/org/apache/qpid/ra/tm/JBoss7TransactionManagerLocator.java
new file mode 100644
index 0000000000..266c56bd63
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/tm/JBoss7TransactionManagerLocator.java
@@ -0,0 +1,33 @@
+package org.apache.qpid.ra.tm;
+
+import javax.naming.InitialContext;
+import javax.transaction.TransactionManager;
+
+public class JBoss7TransactionManagerLocator
+{
+ private static final String TM_JNDI_NAME = "java:jboss/TransactionManager";
+
+ public TransactionManager getTm() throws Exception
+ {
+ InitialContext ctx = null;
+
+ try
+ {
+ ctx = new InitialContext();
+ return (TransactionManager)ctx.lookup(TM_JNDI_NAME);
+ }
+ finally
+ {
+ try
+ {
+ if(ctx != null)
+ {
+ ctx.close();
+ }
+ }
+ catch(Exception ignore)
+ {
+ }
+ }
+ }
+}
diff --git a/java/jca/src/main/java/org/apache/qpid/ra/tm/JBossTransactionManagerLocator.java b/java/jca/src/main/java/org/apache/qpid/ra/tm/JBossTransactionManagerLocator.java
new file mode 100644
index 0000000000..5a5b585984
--- /dev/null
+++ b/java/jca/src/main/java/org/apache/qpid/ra/tm/JBossTransactionManagerLocator.java
@@ -0,0 +1,70 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.ra.tm;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import javax.transaction.TransactionManager;
+
+/**
+ */
+public class JBossTransactionManagerLocator
+{
+ private final String LOCATOR = "org.jboss.tm.TransactionManagerLocator" ;
+
+ public TransactionManager getTm()
+ throws SecurityException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
+ {
+ final ClassLoader classLoader = Thread.currentThread().getContextClassLoader() ;
+ final Class<?> locatorClass ;
+ try
+ {
+ locatorClass = classLoader.loadClass(LOCATOR) ;
+ }
+ catch (final ClassNotFoundException cnfe)
+ {
+ return null ;
+ }
+
+ Method instanceMethod = null ;
+ try
+ {
+ instanceMethod = locatorClass.getMethod("getInstance") ;
+ }
+ catch (final NoSuchMethodException nsme) {} // ignore
+
+ final Object instance ;
+ final String locatorMethodName ;
+ if (instanceMethod != null)
+ {
+ instance = instanceMethod.invoke(null) ;
+ locatorMethodName = "locate" ;
+ }
+ else
+ {
+ instance = null ;
+ locatorMethodName = "locateTransactionManager" ;
+ }
+ final Method locatorMethod = locatorClass.getMethod(locatorMethodName) ;
+ return (TransactionManager) locatorMethod.invoke(instance) ;
+ }
+}
diff --git a/java/jca/src/main/resources/META-INF/jboss-ra.xml b/java/jca/src/main/resources/META-INF/jboss-ra.xml
new file mode 100644
index 0000000000..f459b1efc1
--- /dev/null
+++ b/java/jca/src/main/resources/META-INF/jboss-ra.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you 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.
+ -
+ -->
+<jboss-ra>
+ <ra-config-property>
+ <ra-config-property-name>TransactionManagerLocatorClass</ra-config-property-name>
+ <ra-config-property-type>java.lang.String</ra-config-property-type>
+ <ra-config-property-value>org.apache.qpid.ra.tm.JBossTransactionManagerLocator</ra-config-property-value>
+ </ra-config-property>
+ <ra-config-property>
+ <ra-config-property-name>TransactionManagerLocatorMethod</ra-config-property-name>
+ <ra-config-property-type>java.lang.String</ra-config-property-type>
+ <ra-config-property-value>getTm</ra-config-property-value>
+ </ra-config-property>
+</jboss-ra>
diff --git a/java/jca/src/main/resources/META-INF/ra.xml b/java/jca/src/main/resources/META-INF/ra.xml
new file mode 100755
index 0000000000..90dc7b3b8e
--- /dev/null
+++ b/java/jca/src/main/resources/META-INF/ra.xml
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you 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.
+ -
+ -->
+
+<connector xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
+ http://java.sun.com/xml/ns/j2ee/connector_1_5.xsd"
+ version="1.5">
+
+ <description>QPID Resource Adapter</description>
+ <display-name>QPID Resource Adapter</display-name>
+
+ <vendor-name>Apache Software Foundation</vendor-name>
+ <eis-type>JMS 1.1 Server</eis-type>
+ <resourceadapter-version>1.0</resourceadapter-version>
+
+ <license>
+ <description>
+ The ASF licenses this file to you 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.
+ </description>
+ <license-required>true</license-required>
+ </license>
+
+ <resourceadapter>
+ <resourceadapter-class>org.apache.qpid.ra.QpidResourceAdapter</resourceadapter-class>
+ <config-property>
+ <description>Client ID for the connection</description>
+ <config-property-name>ClientId</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>client_id</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Number of setup attempts before failing</description>
+ <config-property-name>SetupAttempts</config-property-name>
+ <config-property-type>java.lang.Integer</config-property-type>
+ <config-property-value>5</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Interval between setup attempts</description>
+ <config-property-name>SetupInterval</config-property-name>
+ <config-property-type>java.lang.Long</config-property-type>
+ <config-property-value>5000</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Use local transactions rather than XA</description>
+ <config-property-name>UseLocalTx</config-property-name>
+ <config-property-type>java.lang.Boolean</config-property-type>
+ <config-property-value>false</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Broker host</description>
+ <config-property-name>Host</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>localhost</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Broker port</description>
+ <config-property-name>Port</config-property-name>
+ <config-property-type>java.lang.Integer</config-property-type>
+ <config-property-value>5672</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Virtual Path for Connection Factory</description>
+ <config-property-name>Path</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>test</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>connection URL</description>
+ <config-property-name>ConnectionURL</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>amqp://guest:guest@/test?brokerlist='tcp://localhost:5672'</config-property-value>
+ </config-property>
+
+ <outbound-resourceadapter>
+ <connection-definition>
+ <managedconnectionfactory-class>org.apache.qpid.ra.QpidRAManagedConnectionFactory</managedconnectionfactory-class>
+
+ <config-property>
+ <description>Default session type</description>
+ <config-property-name>sessionDefaultType</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>javax.jms.Queue</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Specify lock timeout in seconds</description>
+ <config-property-name>useTryLock</config-property-name>
+ <config-property-type>java.lang.Integer</config-property-type>
+ <config-property-value>0</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Use local transactions rather than XA</description>
+ <config-property-name>UseLocalTx</config-property-name>
+ <config-property-type>java.lang.Boolean</config-property-type>
+ <config-property-value>false</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Client ID for the connection</description>
+ <config-property-name>ClientID</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>client_id</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Connection URL</description>
+ <config-property-name>ConnectionURL</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value></config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Broker host</description>
+ <config-property-name>Host</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>localhost</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Broker port</description>
+ <config-property-name>Port</config-property-name>
+ <config-property-type>java.lang.Integer</config-property-type>
+ <config-property-value>5672</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Virtual Path for Connection Factory</description>
+ <config-property-name>Path</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>test</config-property-value>
+ </config-property>
+
+ <connectionfactory-interface>org.apache.qpid.ra.QpidRAConnectionFactory</connectionfactory-interface>
+ <connectionfactory-impl-class>org.apache.qpid.ra.QpidRAConnectionFactoryImpl</connectionfactory-impl-class>
+ <connection-interface>javax.jms.Session</connection-interface>
+ <connection-impl-class>org.apache.qpid.ra.QpidRASessionImpl</connection-impl-class>
+ </connection-definition>
+ <transaction-support>XATransaction</transaction-support>
+ <authentication-mechanism>
+ <authentication-mechanism-type>BasicPassword</authentication-mechanism-type>
+ <credential-interface>javax.resource.spi.security.PasswordCredential</credential-interface>
+ </authentication-mechanism>
+ <reauthentication-support>false</reauthentication-support>
+ </outbound-resourceadapter>
+ <inbound-resourceadapter>
+ <messageadapter>
+ <messagelistener>
+ <messagelistener-type>javax.jms.MessageListener</messagelistener-type>
+ <activationspec>
+ <activationspec-class>org.apache.qpid.ra.inflow.QpidActivationSpec</activationspec-class>
+ <required-config-property>
+ <config-property-name>destination</config-property-name>
+ </required-config-property>
+ </activationspec>
+ </messagelistener>
+ </messageadapter>
+ </inbound-resourceadapter>
+
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class> org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <config-property>
+ <config-property-name>destinationAddress </config-property-name>
+ <config-property-type>java.lang.String </config-property-type>
+ </config-property>
+ <config-property>
+ <config-property-name>destinationType</config-property-name>
+ <config-property-type>java.lang.String </config-property-type>
+ </config-property>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.ConnectionFactory</adminobject-interface>
+ <adminobject-class> org.apache.qpid.ra.admin.QpidConnectionFactoryProxy</adminobject-class>
+ <config-property>
+ <config-property-name>connectionURL</config-property-name>
+ <config-property-type>java.lang.String </config-property-type>
+ </config-property>
+ </adminobject>
+ </resourceadapter>
+</connector>