From fb08688252d1043b202e1b88a9cd5b37da67794c Mon Sep 17 00:00:00 2001 From: Andrew Stitcher Date: Sun, 18 Dec 2011 05:09:07 +0000 Subject: 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 --- .../qpid/ra/ConnectionFactoryObjectFactory.java | 62 + .../qpid/ra/ConnectionFactoryProperties.java | 215 +++ .../org/apache/qpid/ra/QpidRABytesMessage.java | 462 ++++++ .../apache/qpid/ra/QpidRAConnectionFactory.java | 58 + .../qpid/ra/QpidRAConnectionFactoryImpl.java | 442 +++++ .../apache/qpid/ra/QpidRAConnectionManager.java | 80 + .../apache/qpid/ra/QpidRAConnectionMetaData.java | 208 +++ .../qpid/ra/QpidRAConnectionRequestInfo.java | 361 ++++ .../java/org/apache/qpid/ra/QpidRACredential.java | 245 +++ .../java/org/apache/qpid/ra/QpidRAException.java | 70 + .../org/apache/qpid/ra/QpidRALocalTransaction.java | 129 ++ .../org/apache/qpid/ra/QpidRAMCFProperties.java | 177 ++ .../apache/qpid/ra/QpidRAManagedConnection.java | 880 ++++++++++ .../qpid/ra/QpidRAManagedConnectionFactory.java | 623 +++++++ .../java/org/apache/qpid/ra/QpidRAMapMessage.java | 457 ++++++ .../java/org/apache/qpid/ra/QpidRAMessage.java | 782 +++++++++ .../org/apache/qpid/ra/QpidRAMessageConsumer.java | 353 ++++ .../org/apache/qpid/ra/QpidRAMessageListener.java | 74 + .../org/apache/qpid/ra/QpidRAMessageProducer.java | 419 +++++ .../java/org/apache/qpid/ra/QpidRAMetaData.java | 116 ++ .../org/apache/qpid/ra/QpidRAObjectMessage.java | 85 + .../java/org/apache/qpid/ra/QpidRAProperties.java | 186 +++ .../org/apache/qpid/ra/QpidRAQueueBrowser.java | 139 ++ .../org/apache/qpid/ra/QpidRAQueueReceiver.java | 70 + .../java/org/apache/qpid/ra/QpidRAQueueSender.java | 147 ++ .../java/org/apache/qpid/ra/QpidRASession.java | 33 + .../org/apache/qpid/ra/QpidRASessionFactory.java | 62 + .../apache/qpid/ra/QpidRASessionFactoryImpl.java | 911 ++++++++++ .../java/org/apache/qpid/ra/QpidRASessionImpl.java | 1732 ++++++++++++++++++++ .../org/apache/qpid/ra/QpidRAStreamMessage.java | 415 +++++ .../java/org/apache/qpid/ra/QpidRATextMessage.java | 83 + .../org/apache/qpid/ra/QpidRATopicPublisher.java | 220 +++ .../org/apache/qpid/ra/QpidRATopicSubscriber.java | 86 + .../java/org/apache/qpid/ra/QpidRAXAResource.java | 245 +++ .../org/apache/qpid/ra/QpidResourceAdapter.java | 820 +++++++++ .../jca/src/main/java/org/apache/qpid/ra/Util.java | 184 +++ .../apache/qpid/ra/admin/AdminObjectFactory.java | 74 + .../org/apache/qpid/ra/admin/QpidBindingURL.java | 52 + .../qpid/ra/admin/QpidConnectionFactoryProxy.java | 156 ++ .../apache/qpid/ra/admin/QpidDestinationProxy.java | 162 ++ .../java/org/apache/qpid/ra/admin/QpidQueue.java | 51 + .../java/org/apache/qpid/ra/admin/QpidTopic.java | 52 + .../org/apache/qpid/ra/inflow/QpidActivation.java | 593 +++++++ .../apache/qpid/ra/inflow/QpidActivationSpec.java | 604 +++++++ .../apache/qpid/ra/inflow/QpidMessageHandler.java | 245 +++ .../ra/tm/GeronimoTransactionManagerLocator.java | 63 + .../ra/tm/JBoss7TransactionManagerLocator.java | 33 + .../qpid/ra/tm/JBossTransactionManagerLocator.java | 70 + java/jca/src/main/resources/META-INF/jboss-ra.xml | 33 + java/jca/src/main/resources/META-INF/ra.xml | 220 +++ 50 files changed, 14039 insertions(+) create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryObjectFactory.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryProperties.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRABytesMessage.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactory.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactoryImpl.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionManager.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionMetaData.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionRequestInfo.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRACredential.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAException.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRALocalTransaction.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAMCFProperties.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnectionFactory.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAMapMessage.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageConsumer.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageListener.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageProducer.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAMetaData.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAObjectMessage.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAProperties.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueBrowser.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueReceiver.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueSender.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRASession.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactory.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactoryImpl.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAStreamMessage.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRATextMessage.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicPublisher.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicSubscriber.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidRAXAResource.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/QpidResourceAdapter.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/Util.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/admin/AdminObjectFactory.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/admin/QpidBindingURL.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxy.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/admin/QpidDestinationProxy.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/admin/QpidQueue.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/admin/QpidTopic.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivationSpec.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidMessageHandler.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/tm/GeronimoTransactionManagerLocator.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/tm/JBoss7TransactionManagerLocator.java create mode 100644 java/jca/src/main/java/org/apache/qpid/ra/tm/JBossTransactionManagerLocator.java create mode 100644 java/jca/src/main/resources/META-INF/jboss-ra.xml create mode 100755 java/jca/src/main/resources/META-INF/ra.xml (limited to 'java/jca/src') 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 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 + { + /** 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 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 _eventListeners; + + /** Handles */ + private final Set _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()); + _handles = Collections.synchronizedSet(new HashSet()); + + 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 null + * @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 _sessions = new HashSet(); + + /** The temporary queues */ + private final Set _tempQueues = new HashSet(); + + /** The temporary topics */ + private final Set _tempTopics = new HashSet(); + + /** + * 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 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 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 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 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 _consumers; + + /** The message producers */ + private final Set _producers; + + /** The queue browsers */ + private final Set _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(); + _producers = new HashSet(); + _browsers = new HashSet(); + } + + /** + * 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 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 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 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 _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(); + } + + 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 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 overrideConnectionParameters(final Map connectionParams, + final Map overrideConnectionParams) + { + Map map = new HashMap(); + + if(connectionParams != null) + { + map.putAll(connectionParams); + } + if(overrideConnectionParams != null) + { + for (Map.Entry 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 lookup(final Context context, final String name, final Class 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 _handlers = new ArrayList(); + + 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 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 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 @@ + + + + + TransactionManagerLocatorClass + java.lang.String + org.apache.qpid.ra.tm.JBossTransactionManagerLocator + + + TransactionManagerLocatorMethod + java.lang.String + getTm + + 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 @@ + + + + + + QPID Resource Adapter + QPID Resource Adapter + + Apache Software Foundation + JMS 1.1 Server + 1.0 + + + + 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. + + true + + + + org.apache.qpid.ra.QpidResourceAdapter + + Client ID for the connection + ClientId + java.lang.String + client_id + + + + Number of setup attempts before failing + SetupAttempts + java.lang.Integer + 5 + + + + Interval between setup attempts + SetupInterval + java.lang.Long + 5000 + + + + Use local transactions rather than XA + UseLocalTx + java.lang.Boolean + false + + + + Broker host + Host + java.lang.String + localhost + + + + Broker port + Port + java.lang.Integer + 5672 + + + + Virtual Path for Connection Factory + Path + java.lang.String + test + + + + connection URL + ConnectionURL + java.lang.String + amqp://guest:guest@/test?brokerlist='tcp://localhost:5672' + + + + + org.apache.qpid.ra.QpidRAManagedConnectionFactory + + + Default session type + sessionDefaultType + java.lang.String + javax.jms.Queue + + + + Specify lock timeout in seconds + useTryLock + java.lang.Integer + 0 + + + + Use local transactions rather than XA + UseLocalTx + java.lang.Boolean + false + + + + Client ID for the connection + ClientID + java.lang.String + client_id + + + + Connection URL + ConnectionURL + java.lang.String + + + + + Broker host + Host + java.lang.String + localhost + + + + Broker port + Port + java.lang.Integer + 5672 + + + + Virtual Path for Connection Factory + Path + java.lang.String + test + + + org.apache.qpid.ra.QpidRAConnectionFactory + org.apache.qpid.ra.QpidRAConnectionFactoryImpl + javax.jms.Session + org.apache.qpid.ra.QpidRASessionImpl + + XATransaction + + BasicPassword + javax.resource.spi.security.PasswordCredential + + false + + + + + javax.jms.MessageListener + + org.apache.qpid.ra.inflow.QpidActivationSpec + + destination + + + + + + + + javax.jms.Destination + org.apache.qpid.ra.admin.QpidDestinationProxy + + destinationAddress + java.lang.String + + + destinationType + java.lang.String + + + + javax.jms.ConnectionFactory + org.apache.qpid.ra.admin.QpidConnectionFactoryProxy + + connectionURL + java.lang.String + + + + -- cgit v1.2.1