summaryrefslogtreecommitdiff
path: root/qpid/java/jca
diff options
context:
space:
mode:
authorAndrew Stitcher <astitcher@apache.org>2011-12-18 05:09:07 +0000
committerAndrew Stitcher <astitcher@apache.org>2011-12-18 05:09:07 +0000
commit8581b766bdd0fe06b128ea0f4fdf814435e618cb (patch)
tree0ba5887a27cd45b207be2b7eaa998a193a1b035f /qpid/java/jca
parent345dac43c4453608f3b53728dcd310ff4767a544 (diff)
downloadqpid-python-8581b766bdd0fe06b128ea0f4fdf814435e618cb.tar.gz
QPID-3044: Implement JCA Adapter for Java JMS client
- Large contributions from Weston Price & Kevin Conner git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1220336 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java/jca')
-rw-r--r--qpid/java/jca/README-GERONIMO.txt29
-rw-r--r--qpid/java/jca/README-JBOSS.txt168
-rw-r--r--qpid/java/jca/README.txt241
-rw-r--r--qpid/java/jca/build.xml69
-rw-r--r--qpid/java/jca/example/.gitignore2
-rw-r--r--qpid/java/jca/example/README.txt277
-rw-r--r--qpid/java/jca/example/build-geronimo-properties.xml169
-rw-r--r--qpid/java/jca/example/build-jboss-properties.xml115
-rw-r--r--qpid/java/jca/example/build-properties.xml23
-rw-r--r--qpid/java/jca/example/build-properties.xml.temp23
-rw-r--r--qpid/java/jca/example/build.xml204
-rw-r--r--qpid/java/jca/example/conf/application.xml37
-rw-r--r--qpid/java/jca/example/conf/ejb-jar.xml67
-rw-r--r--qpid/java/jca/example/conf/geronimo-application.xml151
-rw-r--r--qpid/java/jca/example/conf/geronimo-ra.xml138
-rw-r--r--qpid/java/jca/example/conf/jboss-web.xml34
-rw-r--r--qpid/java/jca/example/conf/jboss.xml80
-rw-r--r--qpid/java/jca/example/conf/log4j.properties18
-rw-r--r--qpid/java/jca/example/conf/qpid-jca-ds.xml123
-rw-r--r--qpid/java/jca/example/conf/web.xml52
-rw-r--r--qpid/java/jca/example/qpid-jca-example-properties.xml79
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidRequestResponseClient.java159
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestClient.java135
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestUtil.java52
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeListenerBean.java65
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeSubscriberBean.java27
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloListenerBean.java118
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloSubscriberBean.java121
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidJMSResponderBean.java100
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTest.java30
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestBean.java123
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestLocal.java29
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestRemote.java29
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidUtil.java90
-rw-r--r--qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/web/QpidTestServlet.java209
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryObjectFactory.java62
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryProperties.java215
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRABytesMessage.java462
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactory.java58
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactoryImpl.java442
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionManager.java80
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionMetaData.java208
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionRequestInfo.java361
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRACredential.java245
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAException.java70
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRALocalTransaction.java129
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMCFProperties.java177
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java880
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnectionFactory.java623
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMapMessage.java457
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java782
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageConsumer.java353
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageListener.java74
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageProducer.java419
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMetaData.java116
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAObjectMessage.java85
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAProperties.java186
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueBrowser.java139
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueReceiver.java70
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueSender.java147
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASession.java33
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactory.java62
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactoryImpl.java911
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java1732
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAStreamMessage.java415
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATextMessage.java83
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicPublisher.java220
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicSubscriber.java86
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAXAResource.java245
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidResourceAdapter.java820
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/Util.java184
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/AdminObjectFactory.java74
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidBindingURL.java52
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxy.java156
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidDestinationProxy.java162
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidQueue.java51
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidTopic.java52
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java593
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivationSpec.java604
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidMessageHandler.java245
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/GeronimoTransactionManagerLocator.java63
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/JBoss7TransactionManagerLocator.java33
-rw-r--r--qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/JBossTransactionManagerLocator.java70
-rw-r--r--qpid/java/jca/src/main/resources/META-INF/jboss-ra.xml33
-rwxr-xr-xqpid/java/jca/src/main/resources/META-INF/ra.xml220
85 files changed, 17425 insertions, 0 deletions
diff --git a/qpid/java/jca/README-GERONIMO.txt b/qpid/java/jca/README-GERONIMO.txt
new file mode 100644
index 0000000000..3b72a7e094
--- /dev/null
+++ b/qpid/java/jca/README-GERONIMO.txt
@@ -0,0 +1,29 @@
+Qpid JCA Resource Adapter
+
+Apache Geronimo 2.x Installation and Configuration Instructions
+
+Overview
+========
+The Qpid Resource Adapter is a JCA 1.5 compliant resource adapter that allows
+for JEE integration between EE applications and AMQP 0.10 message brokers.
+
+The adapter provides both outbound and inbound connectivity and
+exposes a variety of options to fine tune your messaging applications.
+Currently the adapter only supports C++ based brokers and has only been tested with Apache Qpid C++ broker.
+
+
+The following document explains how to configure the resource adapter for deployment in Geronimo 2.x
+
+Configuration and Deployment
+============================
+
+The Apache Geronimo 2.x application server requires the use of an RA deployment plan to deploy and configure
+a resource adapter. A sample deployment plan has been provided as geronimo-ra.xml which is included in the
+META-INF directory of the qpid-ra-<version>.rar file. If you need to modify this file, simply extract
+the RAR file, edit the geronimo-ra.xml file and recompress the file.
+
+Please refer to the general README.txt file for a description of each configuration property
+the adapter supports for resource adapter, managedconnectionfatory and activationspec level configuration.
+
+
+
diff --git a/qpid/java/jca/README-JBOSS.txt b/qpid/java/jca/README-JBOSS.txt
new file mode 100644
index 0000000000..77bf91e6dd
--- /dev/null
+++ b/qpid/java/jca/README-JBOSS.txt
@@ -0,0 +1,168 @@
+Qpid JCA Resource Adapter
+
+JBoss EAP 5.x Installation and Configuration Instructions
+
+Overview
+========
+The Qpid Resource Adapter is a JCA 1.5 compliant resource adapter that allows
+for JEE integration between EE applications and AMQP 0.10 message brokers.
+
+The adapter provides both outbound and inbound connectivity and
+exposes a variety of options to fine tune your messaging applications.
+Currently the adapter only supports C++ based brokers and has only been tested with Apache Qpid C++ broker.
+
+The following document explains how to configure the resource adapter for deployment in JBoss EAP 5.x.
+
+
+Deployment
+==========
+To deploy the Qpid JCA adapter for either JBoss EAP, simply copy the qpid-ra-<version>.rar file
+to your JBoss deploy directory. By default this can be found at JBOSS_ROOT/server/<server-name>/deploy,
+where JBOSS_ROOT denotes the root directory of your JBoss installation and <server-name> denotes the
+name of your deployment server. A successful adapter installation will be accompanied by the
+following INFO message:
+
+ INFO [QpidResourceAdapter] Qpid resource adaptor started
+
+At this point the adapter is deployed and ready for configuration.
+
+Configuration Overview
+======================
+The standard configuration mechanism for 1.5 JCA adapters is the ra.xml
+deployment descriptor. Like other EE based descriptors this file can be found
+in the META-INF directory of the provided EE artifact (ie .rar file). A majority
+of the properties in the ra.xml will seem familiar to anyone who has worked with
+Apache Qpid in a standalone environment. A reasonable set of configuration defaults
+have been provided.
+
+The resource adapter configuration properties provide generic properties for both
+inbound and outbound connectivity. These properties can be overridden when deploying
+managed connection factories as well as inbound activations using the standard JBoss
+configuration artifacts, the *-ds.xml file and MDB activation spec . A sample *-ds.xml file,
+qpid-jca-ds.xml, can be found in your Qpid JCA resource adapter directory.
+
+The general README.txt file provides a detailed description of all the properties associated
+with the Qpid JCA Resource adapter. Please consult this file for further explanation of
+how configuration properties are treated within the Qpid JCA adapter.
+
+ConnectionFactory Configuration
+======================================
+As per the JCA specification, the standard outbound-connectivity component is the
+ConnectionFactory. In EAP 5.x ConnectionFactories are configured
+via the *-ds.xml file. As previously mentioned, a sample *-ds.xml file, qpid-jca-ds.xml
+hasbeen provided with your distribution. This file can be easily modified to suit
+your development/deployment needs. The following describes the ConnectionFactory
+portion of the sample file.
+
+XA ConnectionFactory
+====================
+ <tx-connection-factory>
+ <jndi-name>QpidJMSXA</jndi-name>
+ <xa-transaction/>
+ <rar-name>qpid-ra-<ra-version>.rar</rar-name>
+ <connection-definition>org.apache.qpid.ra.QpidRAConnectionFactory</connection-definition>
+ <config-property name="connectionURL">amqp://guest:guest@/test?brokerlist='tcp://localhost:5672?sasl_mechs='ANONYMOUS''</config-property>
+ <max-pool-size>20</max-pool-size>
+ </tx-connection-factory>
+
+The QpidJMSXA connection factory defines an XA capable ManagedConnectionFactory. You will need to insert your particular rar version for
+the rar-name property. The jndi-name and connectionURL property are both configurable and can be modified for your environment. After deployment
+the ConnectionFactory will be bound into JNDI under the name
+
+java:<jndi-name>
+
+For the previous example, this would resolve to
+
+java:QpidJMSXA
+
+Local ConnectionFactory
+=======================
+ <tx-connection-factory>
+ <jndi-name>QpidJMS</jndi-name>
+ <rar-name>qpid-ra-0.10.rar</rar-name>
+ <local-transaction/>
+ <config-property name="useLocalTx" type="java.lang.Boolean">true</config-property>
+ <config-property name="connectionURL">amqp://anonymous:@client/test?brokerlist='tcp://localhost:5672?sasl_mechs='ANONYMOUS''</config-property>
+ <connection-definition>org.apache.qpid.ra.QpidRAConnectionFactory</connection-definition>
+ <max-pool-size>20</max-pool-size>
+ </tx-connection-factory>
+
+The QpidJMS connection factory defines a non XA connection factory. Typically this is used as a specialized ConnectionFactory where either XA
+is not desired, or you are running with a clustered Qpid Broker configuration which at this time, does not support XA. The configuration
+properties mirror those of the XA ConnectionFactory.
+
+Admininstered Object Configuration
+==================================
+Destinations (queues, topics) are configured in EAP via JCA standard Administered Objects (AdminObjects). These objects
+are placed within the *-ds.xml file alongside your ConnectionFactory configurations. The sample file qpid-jca-ds.xml
+provides two such objects
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=HelloQueue">
+ <attribute name="JNDIName">Hello</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='qpid-ra-0.10.rar'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=QUEUE
+ destinationAddress=amq.direct
+ </attribute>
+ </mbean>
+
+The above XML defines a JMS Queue which is bound into JNDI as
+
+queue/HelloQueue
+
+This destination can be retrieved from JNDI and be used for the consumption or production of messages. The desinationAddress property
+can be customized for your environment. Please see the Qpid Java Client documentation for specific configuration options.
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=HelloTopic">
+ <attribute name="JNDIName">HelloTopic</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='qpid-ra-0.10.rar'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=TOPIC
+ destinationAddress=amq.topic
+ </attribute>
+ </mbean>
+
+
+The above XML defines a JMS Topic which is bound into JNDI as
+
+HelloTopic
+
+This destination can be retrieved from JNDI and be used for the consumption or production of messages. The desinationAddress property
+can be customized for your environment. Please see the Qpid Java Client documentation for specific configuration options.
+
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=QpidConnectionFactory">
+ <attribute name="JNDIName">QpidConnectionFactory</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='qpid-ra-0.10.rar'</depends>
+ <attribute name="Type">javax.jms.ConnectionFactory</attribute>
+ <attribute name="Properties">
+ connectionURL=amqp://anonymous:@client/test?brokerlist='tcp://localhost:5672?sasl_mechs='ANONYMOUS''
+ </attribute>
+ </mbean>
+
+The above XML defines a ConnectionFactory that can be used external to EAP 5.x. Typically this connection factory
+is used by standalone or 'thin' clients that do not require an application server. This object is bound into
+the EAP 5.x JNDI tree as
+
+QpidConnectionFactory
+
+ActivationSpec Configuration
+============================
+The standard method for inbound communication is the MessageDrivenBean architecture with is configured
+via the ActivationSpec mechanism. Please see the general README.tx file for an explanation of the
+QpidActivationSpec, as well as general inbound connectivity options.
+
+An ActivationSpec can either be configured via the Java Annotation mechanism, or in the ejb-jar.xml deployment
+descriptor.
+
+Summary
+=======
+The above description for the Qpid JCA adapter for EAP 5.x is just a general guide for deploying and configuring
+the Qpid JCA adapter. The sample file provided can be easily modified and it is expected you will do so to
+conform to your own environment.
+
diff --git a/qpid/java/jca/README.txt b/qpid/java/jca/README.txt
new file mode 100644
index 0000000000..29e6825c4c
--- /dev/null
+++ b/qpid/java/jca/README.txt
@@ -0,0 +1,241 @@
+Qpid JCA Resource Adapter Installation/Configuration Instructions
+
+Overview
+========
+The Qpid Resource Adapter is a JCA 1.5 compliant resource adapter that allows
+for JEE integration between EE applications and AMQP 0.10 message brokers.
+
+The adapter provides both outbound and inbound connectivity and
+exposes a variety of options to fine tune your messaging applications. Currently
+the adapter only supports C++ based brokers and has only been tested with Apache Qpid C++ broker.
+
+The following document explains general configuration information for the Qpid JCA RA. Details for
+specific application server platforms are provided in separate README files typically designated as
+README-<server-platform>.txt.
+
+Configuration
+=============
+As per the JCA specification, there are four main components of a JCA resource adapter:
+
+ The ResourceAdapter JavaBean
+ The ManagedConnectionFactory JavaBean
+ The ActivationSpec JavaBean
+ Administered Objects
+
+Each of these components provide configuration options in the form of properties. The Resource Adapter
+JavaBean provides a set of global configuration options while the ManagedConnectionFactory JavaBean allows
+for the configuration of outbound connectivity options. The ActivationSpec JavaBean provides configuration
+options for inbound connectivity.
+
+When a ManagedConnectionFactory JavaBean or ActivationSpec JavaBean are deployed they can choose to inherit
+the configuration properties from the ResourceAdapter or provide specific properties which in turn will override
+the defaults.
+
+While some of the properties from the three componets are specific to the JCA adapter, a majority of the
+properties directly correspond the the Qpid JMS client. As such, it is strongly encouraged your familiarize
+yourself with the correct syntax, configuration options for the JMS client as well as the JCA adapter. Similarly,
+familiarity with the 1.5 JCA specification is encouraged though not strictly required.
+
+The ResourceAdapter JavaBean
+============================
+
+The ResourceAdapter JavaBean provides global configuration options for both inbound and outbound connectivity.
+The set of ResourceAdapter properties are described below. The ResourceAdapter properties can be found in the META-INF/ra.xml
+deployment descriptor which is provided with the adapter. Note, deploying a ResourceAdapter, ManagedConnectionFactory
+or ActivationSpec is application server specific. As such, this document provides an explanation of these properties
+but not how they are configured as this is environment specific.
+
+ResourceAdapter JavaBean Properties
+===================================
+
+ClientID
+ The unique client identifier. From the JMS API this is used only in the context of durable subscriptions.
+Default: client_id
+
+SetupAttempts
+ The number of attempts the ResourceAdapter will make to successfully setup an inbound activation on deployment, or when an exception
+ occurs at runtime.
+Default: 5
+
+SetupInterval
+ The interval in milliseconds the adapter will wait between setup attempts.
+Default: 5000
+
+UseLocalTx
+ Whether or not to use local transactions instead of XA.
+Default: false
+
+DefaultUserName
+ The default user name to use.
+Default: guest
+
+DefaultPassword
+ The default password to use.
+Default: guest
+
+Host
+ The hostname/ip address of the broker.
+Default: localhost
+
+Port
+ The port of the broker.
+Default: 5672
+
+Path
+ The virtual path for the connection factory.
+Default: test
+
+ConnectionURL
+ The full connection URL to the broker.
+Default:amqp://guest:guest@/test?brokerlist='tcp://localhost:5672'
+
+TransactionManagerLocatorClass
+ The class responsible for locating the transaction manager within a specific application server. This is a ResourceAdapter
+ Java Bean specific property and is application server specific. As such, it is currently commented out. Two examples have
+ been provided.
+Default: none
+
+TransactionManagerLocatorMethod
+ The specific method on the class above used to acquire a reference to the platform specific transaction manager.
+ This is a ResourceAdapter Java Bean specific property and is application server specific.
+ As such, it is currently commented out. Two examples have been provided.
+Default:none
+
+Note, if you require XA support, both the TransactionManagerLocatorClass and the TransactionManagerLocatorMethod
+properties MUST be set. While application servers typically provide a mechanism to do this in the form of a specific
+deployment descriptor, or GUI console, the ra.xml file can also be modified directly.
+
+The ManagedConnectionFactory JavaBean
+=====================================
+
+The ManagedConnectionFactory JavaBean provides outbound connectivity for the Qpid JCA adapter. In addition to most of the properties
+inherited from the ResourceAdapter JavaBean, the ManagedConnectionFactory JavaBean provides specific properties only applicable
+to outbound connectivity.
+
+sessionDefaulType
+ The default type of Session. Currently unused.
+Default: java.jms.Queue
+
+useTryLock
+ Multi-purpose property used to specify both that a lock on the underlying managed connection should be used, as well as the
+ wait duration to aquire the lock. Primarily used for transaction management. A null or zero value will atttempt to acquire
+ the lock without a duration. Anything greater than zero will wait n number of seconds before failing to acquire the lock.
+Default:0
+
+KeyStorePassword
+ The KeyStore password for SSL
+Default:none
+
+KeyStorePath
+ The path to the KeyStore.
+Default:none
+
+CertType
+ The type of certificate.
+Default:SunX509
+
+The ActivationSpec JavaBean
+===========================
+The ActivationSpec JavaBean provides inbound connectivity for the Qpid JCA adapter. In addition to most of the properties
+inherited from the ResourceAdapter JavaBean, the ActivationSpec JavaBean provides specific properties only applicable
+to inbound connectivity. As opposed to the ResourceAdapter and ManagedConnectionFactory JavaBean a majority of the
+ActivationSpec JavaBean properties have no default value. It is expected that these will be provided via Java annotations
+or deployment descriptor configuration properties. The Qpid JCA adapter provides inbound connectivity in conjunction
+with the Message Driven Bean architecture from the EJB 3.x specification.
+
+UseJNDI
+ Whether or not to attempt looking up an inbound destination from JNDI. If false, an attempt will be made to construct
+ the destination from the other ActivationSpec properties.
+Default: true
+
+Destination
+ The name of the destination on which to listen for messages.
+Default:none
+
+DestinationType
+ The type of destination on which to listen. Valid values are javax.jms.Queue or java.jms.Topic.
+Default:none
+
+MessageSelector
+ The JMS properties that will be used in selecting specific message. Please see the JMS specification for further details.
+Default:none
+
+AcknowlegeMode
+ Whether or not the client or consumer will acknowledge any messages it receives. Ignored in a transacted scenario.
+ Please see the JMS specification for more details.
+Default:AUTO_ACKNOWLEDGE
+
+SubscriptionDurablity
+ Whether or not the subscription is durable.
+Default:none
+
+SubscriptionName
+ The name of the subscription.
+Default:none
+
+MaxSession
+ The maximum number of sessions that this activation supports.
+Default:15
+
+TransactionTimeout
+ The timeout for the XA transaction for inbound messages.
+Default:0
+
+PrefetchLow
+ Qpid specific -- TODO more explanation
+
+PrefetchHigh
+ Qpid specific -- TODO more explanation
+
+
+Administered Objects
+======================
+The JCA specification provides for administered objects. Ass per the specification, administered objects are
+JavaBeans that specific to the messaging provider. The Qpid JCA Resource Adapter provides two administered
+objects that can be used to configure JMS destinations and a specialized JMS Connection Factory respectively.
+Both these administered objects have properities to support configuration and deployment.
+
+QpidDestinationProxy
+====================
+ The QpidDestinationProxy allows a developer, deployer or adminstrator to create destinations (queues or topic) and
+ bind these destinations into JNDI. The following lists the properties applicable to the QpidDestinationProxy
+
+destinationType
+ The type of destination to create. Valid values are QUEUE or TOPIC.
+
+destinationAddress
+ The address string of the destination. Please see the Qpid Java JMS client documentation for valid values.
+
+QpidConnectionFactoryProxy
+ The QpidConnectionFactoryProxy allows for a non-JCA ConnectionFactory to be bound into the JNDI tree. This
+ ConnectionFactory can in turn be used outside of the application server. Typically a ConnectionFactory of
+ this sort is used by Swing or other two-tier clients not requiring JCA. The QpidConnectionFactoryProxy provides
+ one property
+
+connectionURL
+ This is the url used to configure the connection factory. Please see the Qpid Java Client documentation for
+ further details.
+
+
+Transaction Support
+===================
+The Qpid JCA Resource Adapter provides three levels of transaction support: XA, LocalTransactions and NoTransaction.
+Typical usage of the Qpid JCA Resource adapter implies the use of XA transactions, though there are certain scenarios
+where this is not preferred. Transaction support configuration is application server specific and as such, is explained
+in the corresponding documentation for each supported application server. However, there are two limitations with
+the Qpid JCA adapter at this time:
+
+1) Currently, the Qpid C++ broker does not support he use of XA within the context of clustered brokers. As such, if
+you are running in a cluster, you will need to configure the adapter to use LocalTransactions.
+
+2)XARecovery is currently not implemented. In the case of a system failure, in doubt transactions will have to be
+manually resolved by and administrator or otherwise qualified personnel.
+
+Conclusion
+==========
+The above documentation provides a general description of the capabilities and configuration properites of the
+Qpid JCA Resource Adapter. As previously mentioned, deploying an adapter in an application server requires
+specific descriptors and configuration mechanisms. Please see the accompanying doc for your application server
+for further details.
+
+
diff --git a/qpid/java/jca/build.xml b/qpid/java/jca/build.xml
new file mode 100644
index 0000000000..3430232003
--- /dev/null
+++ b/qpid/java/jca/build.xml
@@ -0,0 +1,69 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<project name="Qpid JCA RA" default="build">
+
+ <property name="module.depends" value="common client"/>
+ <property name="module.name" value="ra"/>
+
+ <import file="../module.xml"/>
+
+ <property name="module.rar" value="${build.lib}/${project.name}-${module.name}-${project.version}.rar"/>
+ <property name="module.resources" value="src/main/resources"/>
+
+
+ <target name="rar" depends="jar">
+ <jar destfile="${module.rar}">
+ <fileset dir="${module.resources}">
+ <include name="**/*.xml"/>
+ </fileset>
+ <fileset dir="${build.lib}">
+ <include name="${project.name}-ra-${project.version}.jar"/>
+ <include name="${project.name}-client-${project.version}.jar"/>
+ <include name="${project.name}-common-${project.version}.jar"/>
+ </fileset>
+ </jar>
+ </target>
+
+ <!-- Create properties file for examples -->
+ <target name="example-properties-file">
+ <copy file="example/build-properties.xml.temp" tofile="example/build-properties.xml">
+ <filterset>
+ <filter token="project.version" value="${project.version}"/>
+ </filterset>
+ </copy>
+ </target>
+
+ <!-- Copy jars for standalone examples -->
+ <target name="example-jars">
+ <mkdir dir="example/lib"/>
+ <copy todir="example/lib">
+ <fileset dir="${build.lib}">
+ <include name="${project.name}-ra-${project.version}.jar"/>
+ <include name="${project.name}-client-${project.version}.jar"/>
+ <include name="${project.name}-common-${project.version}.jar"/>
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="examples" depends="example-properties-file, example-jars"/>
+
+ <target name="build" depends="rar, examples"/>
+</project>
diff --git a/qpid/java/jca/example/.gitignore b/qpid/java/jca/example/.gitignore
new file mode 100644
index 0000000000..597acff14b
--- /dev/null
+++ b/qpid/java/jca/example/.gitignore
@@ -0,0 +1,2 @@
+build/*
+lib/*
diff --git a/qpid/java/jca/example/README.txt b/qpid/java/jca/example/README.txt
new file mode 100644
index 0000000000..d94bbfa7e5
--- /dev/null
+++ b/qpid/java/jca/example/README.txt
@@ -0,0 +1,277 @@
+Qpid JCA Example
+
+Overview
+=======
+The Qpid JCA example provides a sample JEE application that demonstrates how to
+configure, install and run applications using the Qpid JCA adapter for EE
+connectivity and the Apache Qpid C++ Broker. This example code can be used as a
+convenient starting point for your own development and deployment
+efforts. Currently the example is supported on JBoss EAP 5.x, JBoss 6.x and
+Apache Geronimo 2.x.
+
+Example Components
+===================
+Currently the example application consists of the following components:
+
+Destinations and ConnectionFactories
+
+Any messaging application relies on destinations (queues or topics )
+in order to produce or consume messages.The Qpid JCA example provides
+five destinations by default:
+
+ HelloTopic
+ GoodByeTopic
+ HelloGoodByeTopic
+ HelloQueue
+ GoodByeQueue
+ QpidResponderQueue
+
+
+Similar to destinations, ConnectionFactories are a core component of both JMS
+and JCA. ConnectionFactories provide the necessary starting point to make a connection,
+establish a session and produce or consume (or both) messages from your JMS provider.
+
+The Qpid JCA example provides three connection factories by default:
+
+ QpidJMSXA
+ QpidJMS
+ QpidConnectionFactory
+
+Each of these ConnectionFactories varies in their capabilities and the context in which
+they should be used. These concepts will be explained later in this document.
+
+The deployment configuration for destinations, and ConnectionFactories varies by platform.
+In JBossEAP, the configuration mechanism is a *-ds.xml file. Geronimo 2.2.x has the notion
+of a deployment plan in the form of a geronimo-ra.xml file.
+
+The Qpid JCA Example provides both a qpid-jca-ds.xml file as well as a geronimo-ra.xml deployment
+plan. Both mechanisms provide a reasonable set of defaults to allow you to deploy the Qpid JCA
+adapter in either environment and get up and running quickly.
+
+EJB 3.x
+
+There are a six EJB 3.x components provided as part of the example.
+
+ QpidHelloSubscriberBean - MessageDrivenBean (MDB)
+ QpidGoodByeSubscriberBean - (MDB)
+ QpidHelloListenerBean - (MDB)
+ QpidGoodByeListenerBean - (MDB)
+ QpidJMSResponderBean - (MDB)
+ QpidTestBean - Stateless Session Bean (SLSB)
+
+Servlet 2.5
+
+ QpidTestServlet
+
+A sample EE 2.5 servlet is provided allowing testing from a browser versus a JNDI
+client
+
+EE EAR archive
+ An EAR wrapper for the ejb and web components.
+
+
+ An RMI client used to excercise the EJB 3.x component.
+
+Sample *-ds.xml file
+ A sample *-ds.xml file is provided to create destinations and ManagedConnectionFactories
+ in the JBoss environment.
+
+Sample geronimo-ra.xml
+ A sample geronimo-ra.xml file is provided to create destinations and ManagedConnectionFactories
+ in the Geronimo environment. This file is semantically equivalent to the JBoss *-ds.xml artifact.
+
+A build.xml file
+ An ant build.xml file to configure, install and deploy the aforementioned components.
+
+
+Requirements
+============
+
+Depending upon your target platform (eg. JBoss EAP or Geronimo) you will need to set either
+the JBOSS_HOME or GERONIMO_HOME property. By default, these properties are assumed to be
+set from your environment. This can be modified in the build.xml file.
+
+JBoss EAP 5.x, JBoss 6.x
+ To use the sample application you will need to have JBoss EAP 5.x or JBoss 6.x running.
+
+Geronimo 2.x
+ To use the sample application you will need to have Geronimo 2.x running.
+
+Apache Qpid Broker
+ To run the sample it is assumed you have an Apache Qpid C++ broker configured and running.
+ The example code assumes that the broker will run at localhost on port 5672. This can be
+ modified within the build.xml file if this does not suit your particular environment.
+
+
+Quickstart
+==========
+After satifsying the above requirements you are ready to deploy and run the example application.
+The steps to deploy and run in the supported application servers are largely the same, however,
+if you are targeting JBoss you will either need to modify the property in the example build.xml file
+
+
+ <property name="target.platform" value="geronimo"/>
+
+to be jboss
+
+ <property name="target.platform" value="jboss"/>
+
+or set this property via the command line.
+
+Example:
+
+ ant -Dtarget.platform=jboss <target>
+
+**Note**
+Any time you wish to change platforms, this property needs to be modified and a complete clean
+and rebuild needs to be performed.
+
+Step 1 -- Package, Deploy and configure the Qpid JCA adapter
+
+The core component of the example is the Qpid JCA adapter. The following lists the steps
+for the respective platforms
+
+**Note**
+
+Regardless of platform, if you are building the Qpid JCA adapter from source code
+you will need to use to package the RAR file via the Ant build system. To do this, from
+the example directory execute
+
+ ant deploy-rar
+
+This task packages the adapter and includes the necessary dependent jar files.
+
+
+JBoss
+ There are no additional steps to package the adapter for JBoss deployment. Simply copy
+ the qpid-ra-<qpid.version>rar to your JBoss deploy directory.
+
+ To configure the Qpid JCA Adapter in JBoss the *-ds.xml file mechanism is used. A sample
+ file is provided in the conf directory.
+
+ If the defaults are suitable, you can simply execute
+
+ ant deploy-ds
+
+ While any property can be modified in the qpid-jca-ds.xml file, typically you will want to
+ change the URL of the broker to which you are trying to connect. Rather than modifying
+ the qpid-jca-ds.xml file directly you can modify the
+
+ <property name="broker.url" value="amqp://anonymous:@client/test?brokerlist='tcp://localhost:5672?sasl_mechs='ANONYMOUS''"/>
+
+ line in the build.xml file. This will dynamically insert the broker.url value into the qpid-jca-ds.xml file.
+
+ Once this file is copied to your JBoss deploy directory and you received no exceptions, the adapter is now deployed, configured
+ and ready for use.
+
+Geronimo
+ By default, the Qpid JCA adapter ships with the geronimo-ra.xml deployment plan embedded
+ in the RAR file. This file is located in the META-INF directory alongside the ra.xml file.
+ By default the adapter is configured to access a broker located at localhost with the
+ default port of 5672. The ANONYMOUS security mechanism is also in use. If this is not
+ desirable, you have two approaches to configure the adapter.
+
+
+ 1) Extract the META-INF/ra.xml file from the RAR file, modify and recompress the RAR archive
+ with the updated contents.
+
+ 2) Use the example build system to package the adapter. The example build.xml file includes
+ a target
+
+ package-rar
+
+ that can be used to package the RAR file as well as allowing changes to the geronimo-ra.xml
+ file without having to extract the RAR file by hand. The conf/geronimo-ra.xml file is used
+ when you use the example build system.
+
+ While any property can be modified in the geronimo-ra.xml file, typically you will want to
+ change the URL of the broker to which you are trying to connect. Rather than modifying
+ the geronimo-ra.xml file directly you can modify the
+
+
+ <property name="broker.url" value="amqp://anonymous:@client/test?brokerlist='tcp://10.0.1.44:5672?sasl_mechs='ANONYMOUS''"/>
+
+ line in the build.xml file. This will dynamically insert the broker.url value into the geronimo-ra.xml file.
+
+ Once you have made your modifications you can execute
+
+
+ ant clean package-rar deploy-rar
+
+ Note, your Geronimo server must be running and your GERONIMO_HOME environment variable must be set. Barring any exceptions, the
+ adapter is now deployed and ready for use in Geronimo.
+
+
+Step 2 -- Deploy the application component(s).
+
+As previously mentioned, the adapter comes with a variety of EE components for use in your respective application server. You can choose to deploy
+these components individually, or as a single EAR archive. This document assumes that you will use the EAR to deploy and run the example.
+
+The command to package and deploy the EAR archive is the same across application servers. Executing the following command
+
+ant deploy-ear
+
+will, depending upon platform, package the EAR and deploy the archive in your respective environment. Once this step is executed, the example
+is ready for use.
+
+
+Step 3 -- Test the Example
+
+The Qpid JCA example provides an EJB application, as well as a Web application. Both can be used to test/run the example:
+
+EJB
+If you want to use the EJB application to test the example you can execute
+
+ ant run-client
+
+Running this command will perform a JNDI lookup of the SLSB in either JBoss or Geronimo and send a simple string to the SLSB. The SLSB will receive
+this string, construct a JMS message and place this message on a configured queue. The MDB will in turn receive this message and print the contents
+to the console.
+
+The main properties involved in this task are
+
+server.host
+jndi.context
+
+These vary depending upon which application server you are runnning. These can be modified to suit your environment. Looking at the run-client task you
+will see the following:
+
+
+ <sysproperty key="qpid.ejb.name" value="qpid-jcaex/QpidTestBean/remote"/>
+
+This is the JNDI name of the SLSB component and it varies by application server. Typically you do not have to change this. Also, the task supports another property
+
+
+ <sysproperty key="qpid.message" value="insert-value-here"/>
+
+You can set this property if you want to modify the message contents being routed through the system.
+
+Web
+The Qpid JCA Example comes with a web application. To access the web component, simply use a browser of your choice and navigate to
+
+http://<server-host-name>:<server-port>/qpid-jca-web/qpid
+
+where server-host and server-port are the host and port where you are running your application server. By default this is localhost:8080. Similar to the EJB component,
+the web application supports a few options:
+
+
+http://<server-host-name>:<server-port>/qpid-jca-web/qpid?messsage=<yourmessage>
+
+will allow you to customize the message contents that are routed through the system. By default, the Web application posts to a configured queue in the system. If you want to
+test XA functionality, or use an alternate approach, you can specify
+
+
+http://<server-host-name>:<server-port>/qpid-jca-web/qpid?useEJB=true
+
+instead of posting to a queue, the web application will use the local interface of the EJB component to send the message. This is functionally equivalent to running the
+RMI client.
+
+
+Summary
+=======
+While conceptually simple, the Qpid JCA example provides a majority of the component types and messaging patterns you are most likely to use your development efforts.
+With the Web and EJB components, you can experiment with various aspects of JCA as well as EE development in general using the Qpid Broker as your messaging provider.
+While this documentation highlights the major components and steps needed to take to get the example running, the possiblities for modifcation are numerous. You are
+encouraged to experiment with the example as you develop your own messaging applications.
+
+
diff --git a/qpid/java/jca/example/build-geronimo-properties.xml b/qpid/java/jca/example/build-geronimo-properties.xml
new file mode 100644
index 0000000000..79cf5adc74
--- /dev/null
+++ b/qpid/java/jca/example/build-geronimo-properties.xml
@@ -0,0 +1,169 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<project name="qpid-jca-example-geronimo-properties" basedir="." default="">
+
+ <property name="geronimo.jndi.scheme" value="name"/>
+ <property name="qpid.xacf.jndi.name" value="jca:/qpid.jca/QpidJCAAdapter/JCAManagedConnectionFactory/QpidJMSXA"/>
+ <property name="qpid.cf.jndi.name" value="jca:/qpid.jca/QpidJCAAdapter/JCAAdminObject/QpidConnectionFactory"/>
+ <property name="qpid.hello.queue.jndi.name" value="jca:/qpid.jca/QpidJCAAdapter/JCAAdminObject/HelloQueue"/>
+ <property name="qpid.goodbye.queue.jndi.name" value="jca:/qpid.jca/QpidJCAAdapter/JCAAdminObject/GoodByeQueue"/>
+ <property name="qpid.responder.queue.jndi.name" value="jca:/qpid.jca/QpidJCAAdapter/JCAAdminObject/ResponderQueue"/>
+ <property name="qpid.hello.topic.jndi.name" value="jca:/qpid.jca/QpidJCAAdapter/JCAAdminObject/HelloTopic"/>
+ <property name="qpid.goodbye.topic.jndi.name" value="jca:/qpid.jca/QpidJCAAdapter/JCAAdminObject/GoodByeTopic"/>
+ <property name="qpid.ejb.jndi.name" value="name=&quot;QpidTestEJB&quot;"/>
+ <property name="qpid.ejb.name" value="QpidTestBeanRemote"/>
+
+ <property name="jndi.context" value="org.openejb.client.RemoteInitialContextFactory"/>
+ <property name="server.host" value="ejbd://localhost:4201"/>
+ <property name="geronimo.home" location="${env.GERONIMO_HOME}"/>
+ <property name="geronimo.user" value="system"/>
+ <property name="geronimo.password" value="manager"/>
+
+ <property name="geronimo.rar.group.id" value="qpid.jca"/>
+ <property name="geronimo.rar.artifact.id" value="QpidJCAAdapter"/>
+ <property name="geronimo.rar.version" value="1.0"/>
+ <property name="geronimo.rar.type" value="rar"/>
+ <property name="geronimo.rar.id" value="${geronimo.rar.group.id}/${geronimo.rar.artifact.id}/${geronimo.rar.version}/${geronimo.rar.type}"/>
+
+ <property name="geronimo.ejb.group.id" value="qpid.jca.example"/>
+ <property name="geronimo.ejb.artifact.id" value="QpidJCAEJBExample"/>
+ <property name="geronimo.ejb.version" value="1.0"/>
+ <property name="geronimo.ejb.type" value="car"/>
+ <property name="geronimo.ejb.id" value="${geronimo.ejb.group.id}/${geronimo.ejb.artifact.id}/${geronimo.ejb.version}/${geronimo.ejb.type}"/>
+
+ <property name="geronimo.war.group.id" value="qpid.jca.example"/>
+ <property name="geronimo.war.artifact.id" value="QpidJCAWebExample"/>
+ <property name="geronimo.war.version" value="1.0"/>
+ <property name="geronimo.war.type" value="war"/>
+ <property name="geronimo.war.id" value="${geronimo.war.group.id}/${geronimo.war.artifact.id}/${geronimo.war.version}/${geronimo.war.type}"/>
+
+ <property name="geronimo.ear.group.id" value="qpid.jca.example"/>
+ <property name="geronimo.ear.artifact.id" value="QpidJCAEARExample"/>
+ <property name="geronimo.ear.version" value="1.0"/>
+ <property name="geronimo.ear.type" value="ear"/>
+ <property name="geronimo.ear.id" value="${geronimo.ear.group.id}/${geronimo.ear.artifact.id}/${geronimo.ear.version}/${geronimo.ear.type}"/>
+
+ <property name="geronimo.rar.plan" value="${gen.dir}/geronimo-ra.xml"/>
+ <property name="geronimo.ear.plan" value="${gen.dir}/geronimo-application.xml"/>
+
+ <path id="compile.classpath">
+ <fileset dir="${geronimo.home}/repository/org/apache/geronimo/specs">
+ <include name="geronimo-jms_1.1_spec/1.1.1/geronimo-jms_1.1_spec-1.1.1.jar"/>
+ <include name="geronimo-servlet_2.5_spec/1.2/geronimo-servlet_2.5_spec-1.2.jar"/>
+ <include name="geronimo-ejb_3.0_spec/1.0.1/geronimo-ejb_3.0_spec-1.0.1.jar"/>
+ <include name="geronimo-jta_1.1_spec/1.1.1/geronimo-jta_1.1_spec-1.1.1.jar"/>
+ </fileset>
+ <fileset dir="${geronimo.home}/lib/">
+ <include name="slf4j-api-*.jar"/>
+ </fileset>
+ </path>
+
+ <path id="run.classpath">
+ <fileset dir="${lib.dir}">
+ <include name="qpid-ra-*.jar"/>
+ <include name="qpid-client-*.jar"/>
+ <include name="qpid-common-*.jar"/>
+ </fileset>
+ <fileset dir="${geronimo.home}/repository/org/apache/geronimo/specs">
+ <include name="geronimo-j2ee-connector_1.5_spec/2.0.0/geronimo-j2ee-connector_1.5_spec-2.0.0.jar"/>
+ <include name="geronimo-jms_1.1_spec/1.1.1/geronimo-jms_1.1_spec-1.1.1.jar"/>
+ <include name="geronimo-servlet_2.5_spec/1.2/geronimo-servlet_2.5_spec-1.2.jar"/>
+ <include name="geronimo-ejb_3.0_spec/1.0.1/geronimo-ejb_3.0_spec-1.0.1.jar"/>
+ <include name="geronimo-jta_1.1_spec/1.1.1/geronimo-jta_1.1_spec-1.1.1.jar"/>
+ </fileset>
+ <fileset dir="${geronimo.home}/lib/">
+ <include name="slf4j-api-*.jar"/>
+ <include name="slf4j-log4j*-*.jar"/>
+ <include name="log4j-*.jar"/>
+ </fileset>
+ <fileset dir="${geronimo.home}/repository/org/apache/openejb/openejb-client/3.1.4/"/>
+ </path>
+
+ <filterset id="extra.filterset">
+ <filter token="geronimo.ejb.group.id" value="${geronimo.ejb.group.id}"/>
+ <filter token="geronimo.ejb.artifact.id" value="${geronimo.ejb.artifact.id}"/>
+ <filter token="geronimo.ejb.version" value="${geronimo.ejb.version}"/>
+ <filter token="geronimo.ejb.type" value="${geronimo.ejb.type}"/>
+ <filter token="geronimo.war.group.id" value="${geronimo.war.group.id}"/>
+ <filter token="geronimo.war.artifact.id" value="${geronimo.war.artifact.id}"/>
+ <filter token="geronimo.war.version" value="${geronimo.war.version}"/>
+ <filter token="geronimo.war.type" value="${geronimo.war.type}"/>
+ <filter token="geronimo.ear.group.id" value="${geronimo.ear.group.id}"/>
+ <filter token="geronimo.ear.artifact.id" value="${geronimo.ear.artifact.id}"/>
+ <filter token="geronimo.ear.version" value="${geronimo.ear.version}"/>
+ <filter token="geronimo.ear.type" value="${geronimo.ear.type}"/>
+ </filterset>
+
+ <macrodef name="geronimo">
+ <attribute name="user" default="${geronimo.user}"/>
+ <attribute name="password" default="${geronimo.password}"/>
+ <attribute name="action" default="list-modules"/>
+ <attribute name="module"/>
+ <attribute name="plan" default=""/>
+ <sequential>
+ <exec executable="${geronimo.home}/bin/deploy.sh">
+ <arg line="-u @{user} -p @{password} @{action} @{module} @{plan}"/>
+ </exec>
+ </sequential>
+ </macrodef>
+
+ <!-- Deployment is target specific so is included here -->
+ <target name="deploy-rar" depends="generate" description="Deploy the RAR file.">
+ <geronimo action="deploy" module="${qpid.jca.dir}/${rar.name}" plan="${geronimo.rar.plan}"/>
+ </target>
+
+ <target name="undeploy-rar" description="Undeploys the RAR deployment.">
+ <geronimo action="undeploy" module="${geronimo.rar.id}"/>
+ </target>
+
+ <target name="start-rar" description="Starts the RAR deployment in the Geronimo environment.">
+ <geronimo action="start" module="${geronimo.rar.id}"/>
+ </target>
+
+ <target name="stop-rar" description="Stops the RAR deployment in the Geronimo environment.">
+ <geronimo action="stop" module="${geronimo.rar.id}"/>
+ </target>
+
+ <target name="restart-rar" description="Restarts the RAR deployment in the Geronimo environment.">
+ <geronimo action="restart" module="${geronimo.rar.id}"/>
+ </target>
+
+ <target name="deploy-ear" depends="package-ear" description="Deploys the EAR archive.">
+ <geronimo action="deploy" module="${build.dir}/${ear.name}" plan="${geronimo.ear.plan}"/>
+ </target>
+
+ <target name="undeploy-ear" description="Undeployes the EAR archive.">
+ <geronimo action="undeploy" module="${geronimo.ear.id}"/>
+ </target>
+
+ <target name="start-ear" description="Starts the EAR deployment in the Geronimo environment.">
+ <geronimo action="start" module="${geronimo.ear.id}"/>
+ </target>
+
+ <target name="stop-ear" description="Stops the EAR deployment in the Geronimo environment.">
+ <geronimo action="stop" module="${geronimo.ear.id}"/>
+ </target>
+
+ <target name="restart-ear" description="Restarts the EAR deployment in the Geronimo environment.">
+ <geronimo action="restart" module="${geronimo.ear.id}"/>
+ </target>
+
+</project>
diff --git a/qpid/java/jca/example/build-jboss-properties.xml b/qpid/java/jca/example/build-jboss-properties.xml
new file mode 100644
index 0000000000..3554488d2d
--- /dev/null
+++ b/qpid/java/jca/example/build-jboss-properties.xml
@@ -0,0 +1,115 @@
+<!--
+ -
+ - 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.
+ -
+-->
+<project name="qpid-jca-example-jboss-properties" basedir="." default="">
+
+ <property name="jboss.jndi.scheme" value="mappedName"/>
+ <property name="qpid.xacf.jndi.name" value="java:QpidJMSXA"/>
+ <property name="qpid.cf.jndi.name" value="QpidConnectionFactory"/>
+ <property name="qpid.hello.topic.jndi.name" value="HelloTopic"/>
+ <property name="qpid.goodbye.topic.jndi.name" value="GoodByeTopic"/>
+ <property name="qpid.hello.queue.jndi.name" value="HelloQueue"/>
+ <property name="qpid.goodbye.queue.jndi.name" value="GoodByeQueue"/>
+ <property name="qpid.responder.queue.jndi.name" value="QpidResponderQueue"/>
+ <property name="qpid.ejb.jndi.name" value="mappedName=&quot;QpidTestEJB&quot;"/>
+ <property name="qpid.ejb.ref.name" value="QpidTestBean/local"/>
+ <property name="qpid.ejb.name" value="qpid-jcaex/QpidTestBean/remote"/>
+
+ <property name="jndi.context" value="org.jnp.interfaces.NamingContextFactory"/>
+ <property name="server.host" value="jnp://localhost:1099"/>
+
+ <property name="jboss.home" location="${env.JBOSS_HOME}"/>
+ <property name="jboss.server" value="default"/>
+ <property name="jboss.deploy" location="${jboss.home}/server/${jboss.server}/deploy"/>
+ <property name="jboss.client" location="${jboss.home}/client"/>
+
+ <path id="compile.classpath">
+ <fileset dir="${jboss.client}">
+ <!-- JBoss 5-->
+ <include name="jboss-javaee.jar"/>
+
+ <!-- JBoss 6 -->
+ <include name="jboss-servlet-api_3.0_spec.jar"/>
+ <include name="jboss-jms-api_1.1_spec.jar"/>
+ <include name="jboss-ejb-api_3.1_spec.jar"/>
+ <include name="jboss-transaction-api_1.1_spec.jar"/>
+
+ <!-- Common to JBoss 5/6 -->
+ <include name="slf4j-api.jar"/>
+ </fileset>
+
+ <!-- JBoss 5 -->
+ <fileset dir="${jboss.home}/common/lib">
+ <include name="servlet-api.jar"/>
+ </fileset>
+ </path>
+
+ <path id="run.classpath">
+ <fileset dir="${lib.dir}">
+ <include name="qpid-ra-*.jar"/>
+ <include name="qpid-client-*.jar"/>
+ <include name="qpid-common-*.jar"/>
+ </fileset>
+ <fileset dir="${jboss.client}">
+ <!-- Shortcut to get it working!-->
+ <include name="jbossall-client.jar"/>
+ </fileset>
+ </path>
+
+ <filterset id="extra.filterset"/>
+
+ <!-- Deployment is target specific so is included here -->
+ <target name="deploy-rar" description="Deploy the RAR file.">
+ <copy todir="${jboss.deploy}" overwrite="true">
+ <fileset dir="${qpid.jca.dir}">
+ <include name="${rar.name}"/>
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="undeploy-rar" description="Undeploys the RAR deployment.">
+ <delete file="${jboss.deploy}/${rar.name}"/>
+ </target>
+
+ <target name="deploy-ear" depends="package-ear" description="Deploys the EAR archive.">
+ <copy todir="${jboss.deploy}" overwrite="true">
+ <fileset dir="${build.dir}">
+ <include name="${ear.name}"/>
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="undeploy-ear" description="Undeploys the EAR archive.">
+ <delete file="${jboss.deploy}/${ear.name}"/>
+ </target>
+
+ <target name="deploy-ds" depends="generate" description="Deploys the ds.xml file to the JBoss environment.">
+ <copy todir="${jboss.deploy}" overwrite="true">
+ <fileset dir="${gen.dir}">
+ <include name="qpid-jca-ds.xml"/>
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="undeploy-ds" description="Undeploys the ds.xml file from the JBoss environment.">
+ <delete file="${jboss.deploy}/qpid-jca-ds.xml"/>
+ </target>
+
+</project>
diff --git a/qpid/java/jca/example/build-properties.xml b/qpid/java/jca/example/build-properties.xml
new file mode 100644
index 0000000000..5ac1d50ce9
--- /dev/null
+++ b/qpid/java/jca/example/build-properties.xml
@@ -0,0 +1,23 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<project name="qpid-jca-example-build-properties" basedir="." default="">
+ <property name="qpid.ver" value="0.15"/>
+</project>
diff --git a/qpid/java/jca/example/build-properties.xml.temp b/qpid/java/jca/example/build-properties.xml.temp
new file mode 100644
index 0000000000..9eae869c27
--- /dev/null
+++ b/qpid/java/jca/example/build-properties.xml.temp
@@ -0,0 +1,23 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<project name="qpid-jca-example-build-properties" basedir="." default="">
+ <property name="qpid.ver" value="@project.version@"/>
+</project>
diff --git a/qpid/java/jca/example/build.xml b/qpid/java/jca/example/build.xml
new file mode 100644
index 0000000000..9d0cfc887e
--- /dev/null
+++ b/qpid/java/jca/example/build.xml
@@ -0,0 +1,204 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<project name="qpid-jca-example" default="help" basedir="">
+
+ <!-- Valid target platforms are currently geronimo & jboss -->
+ <property name="target.platform" value="geronimo"/>
+
+ <!-- Change to BURL for older syntax support -->
+ <property name="qpid.dest_syntax" value="ADDR"/>
+
+ <!-- Broker specific properties. By default in the adapter we use localhost here you an override this with host specific info-->
+ <property name="broker.address" value="localhost"/>
+
+ <!-- Properties controlling running sample standalone client -->
+ <property name="client.use.ejb" value="false"/> <!-- uses JNDI/JMS or JNDI/RMI -->
+ <property name="client.message" value="Hello Qpid World"/>
+ <property name="client.message.count" value="1"/>
+ <property name="client.use.topic" value="false"/> <!-- Use topic/queue -->
+ <property name="client.say.goodbye" value="false"/>
+
+ <!-- Pull in environment vars as properties -->
+ <property environment="env"/>
+
+ <!-- QPID version property -->
+ <import file="${basedir}/build-properties.xml"/>
+
+ <import file="${basedir}/qpid-jca-example-properties.xml"/>
+
+ <!-- Target specific properties/targets -->
+ <import file="${basedir}/build-${target.platform}-properties.xml"/>
+
+ <macrodef name="compile">
+ <attribute name="classpath"/>
+ <sequential>
+ <javac srcdir="${gen.dir}"
+ destdir="${build.classes.dir}"
+ classpathref="@{classpath}"
+ debug="true" optimize="false"/>
+ </sequential>
+ </macrodef>
+
+ <echo message="Using Qpid version ${qpid.ver}"/>
+ <echo message="Building for platform ${target.platform}"/>
+ <echo message="Broker url is currently set to ${broker.url}"/>
+ <echo message="Qpid Destination Syntax is ${qpid.dest_syntax}"/>
+
+ <target name="init">
+ <mkdir dir="${build.classes.dir}"/>
+ <mkdir dir="${gen.dir}"/>
+ <mkdir dir="${log.dir}"/>
+ </target>
+
+ <target name="generate" depends="init">
+ <copy todir="${gen.dir}" overwrite="true">
+ <fileset dir="${conf.dir}"/>
+ <filterset>
+ <filter token="rar.name" value="${rar.name}"/>
+ <filter token="ejb.name" value="${ejb.name}"/>
+ <filter token="war.name" value="${war.name}"/>
+
+ <filter token="broker.url" value="${broker.url}"/>
+
+ <filter token="qpid.hello.topic.dest.address" value="${qpid.hello.topic.dest.address}"/>
+ <filter token="qpid.goodbye.topic.dest.address" value="${qpid.goodbye.topic.dest.address}"/>
+ <filter token="qpid.hellogoodbye.topic.dest.address" value="${qpid.hellogoodbye.topic.dest.address}"/>
+ <filter token="qpid.hello.queue.dest.address" value="${qpid.hello.queue.dest.address}"/>
+ <filter token="qpid.goodbye.queue.dest.address" value="${qpid.goodbye.queue.dest.address}"/>
+ <filter token="qpid.responder.queue.dest.address" value="${qpid.responder.queue.dest.address}"/>
+
+ </filterset>
+ <filterset refid="extra.filterset"/>
+ </copy>
+ <copy todir="${gen.dir}">
+ <fileset dir="${src.dir}"/>
+ <filterset>
+ <filter token="rar.name" value="${rar.name}"/>
+ <filter token="broker.url" value="${broker.url}"/>
+ <filter token="jndi.scheme" value="${jndi.scheme}"/>
+ <filter token="qpid.xacf.jndi.name" value="${qpid.xacf.jndi.name}"/>
+ <filter token="qpid.hello.topic.jndi.name" value="${qpid.hello.topic.jndi.name}"/>
+ <filter token="qpid.goodbye.topic.jndi.name" value="${qpid.goodbye.topic.jndi.name}"/>
+ <filter token="qpid.hello.queue.jndi.name" value="${qpid.hello.queue.jndi.name}"/>
+ <filter token="qpid.goodbye.queue.jndi.name" value="${qpid.goodbye.queue.jndi.name}"/>
+ <filter token="qpid.responder.queue.jndi.name" value="${qpid.responder.queue.jndi.name}"/>
+ <filter token="qpid.ejb.jndi.name" value="${qpid.ejb.jndi.name}"/>
+ </filterset>
+ </copy>
+ </target>
+
+ <target name="compile" depends="generate" description="Compiles the source files for the Qpid JCA example">
+ <compile classpath="compile.classpath"/>
+ </target>
+
+ <target name="package-war" depends="compile" description="Packages the WAR file for deployment.">
+ <war destfile="${build.dir}/${war.name}" webxml="${gen.dir}/web.xml">
+ <classes dir="${build.classes.dir}">
+ <include name="org/apache/qpid/jca/example/web/**"/>
+ </classes>
+ <webinf dir="${gen.dir}">
+ <include name="jboss-web.xml"/>
+ </webinf>
+ </war>
+ </target>
+
+ <target name="package-ejb" depends="compile" description="Packages the EJB archive for deployment.">
+ <jar destfile="${build.dir}/${ejb.name}" basedir="${build.classes.dir}">
+ <include name="org/apache/qpid/jca/example/ejb/**/*.class"/>
+ <metainf dir="${gen.dir}">
+ <include name="jboss.xml"/>
+ <include name="ejb-jar.xml"/>
+ </metainf>
+ </jar>
+ </target>
+
+ <target name="package-ear" depends="generate, package-war, package-ejb" description="Packages the EAR archive for deployment.">
+ <jar destfile="${build.dir}/${ear.name}" basedir="${build.dir}">
+ <include name="*.war"/>
+ <include name="*.jar"/>
+ <metainf dir="${gen.dir}">
+ <include name="application.xml"/>
+ </metainf>
+ </jar>
+ </target>
+
+ <target name="run-client" depends="compile" description="Runs the RMI client.">
+ <java classname="org.apache.qpid.jca.example.client.QpidTestClient">
+ <classpath>
+ <pathelement path="${build.classes.dir}"/>
+ <path refid="run.classpath"/>
+ </classpath>
+ <sysproperty key="java.naming.factory.initial" value="${jndi.context}"/>
+ <sysproperty key="java.naming.provider.url" value="${server.host}"/>
+ <sysproperty key="qpid.ejb.name" value="${qpid.ejb.name}"/>
+ <sysproperty key="qpid.cf.name" value="${qpid.cf.jndi.name}"/>
+ <sysproperty key="qpid.dest_syntax" value="${qpid.dest_syntax}"/>
+ <sysproperty key="qpid.dest.name" value="${qpid.hello.queue.jndi.name}"/>
+ <sysproperty key="log4j.configuration" value="file://${conf.dir}/log4j.properties"/>
+
+ <sysproperty key="qpid.message" value="${client.message}"/>
+ <sysproperty key="message.count" value="${client.message.count}"/>
+ <sysproperty key="use.topic" value="${client.use.topic}"/>
+ <sysproperty key="use.ejb" value="${client.use.ejb}"/>
+ <sysproperty key="say.goodbye" value="${client.say.goodbye}"/>
+ </java>
+ </target>
+
+ <target name="run-reqresp" depends="compile">
+ <java classname="org.apache.qpid.jca.example.client.QpidRequestResponseClient">
+ <classpath>
+ <pathelement path="${build.classes.dir}"/>
+ <path refid="run.classpath"/>
+ </classpath>
+ <sysproperty key="java.naming.factory.initial" value="${jndi.context}"/>
+ <sysproperty key="java.naming.provider.url" value="${server.host}"/>
+ <sysproperty key="qpid.message" value="Hello, World"/>
+ <sysproperty key="message.count" value="1"/>
+ <sysproperty key="thread.count" value="5"/>
+ <sysproperty key="qpid.cf.name" value="${qpid.cf.jndi.name}"/>
+ <sysproperty key="qpid.dest.name" value="${qpid.responder.queue.jndi.name}"/>
+ <sysproperty key="log4j.configuration" value="file://${conf.dir}/log4j.properties"/>
+ <sysproperty key="qpid.dest_syntax" value="${qpid.dest_syntax}"/>
+ </java>
+ </target>
+
+ <target name="clean" description="Deletes the build directory and all related files.">
+ <delete dir="${build.dir}"/>
+ </target>
+
+ <target name="help">
+ <echo>
+
+ ant compile
+ This will compile all the source code for the Qpid JCA example project to the ${build.classes.dir} directory.
+
+ ant deploy-rar deploy-ear
+ Deploys a particular component which could be rar, ear (or ds for JBoss)
+
+ ant undeploy-ear undeploy-rar
+ Undeploys a particular component which could be rar, ear (or ds for JBoss)
+
+ ant run-client run-reqresp
+ Runs the RMI/thin client or the request-response client example
+ </echo>
+ </target>
+
+</project>
diff --git a/qpid/java/jca/example/conf/application.xml b/qpid/java/jca/example/conf/application.xml
new file mode 100644
index 0000000000..d181bcda67
--- /dev/null
+++ b/qpid/java/jca/example/conf/application.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<application xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="5"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd">
+
+ <module>
+ <ejb>@ejb.name@</ejb>
+ </module>
+
+ <module>
+ <web>
+ <web-uri>@war.name@</web-uri>
+ <context-root>/qpid-jca-web</context-root>
+ </web>
+ </module>
+
+</application>
+
diff --git a/qpid/java/jca/example/conf/ejb-jar.xml b/qpid/java/jca/example/conf/ejb-jar.xml
new file mode 100644
index 0000000000..2f513bd3f8
--- /dev/null
+++ b/qpid/java/jca/example/conf/ejb-jar.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" version="3.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
+ http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd">
+
+ <enterprise-beans>
+ <message-driven>
+ <ejb-name>QpidHelloListenerBean</ejb-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.jms.ConnectionFactory</res-type>
+ <res-auth>Container</res-auth>
+ <res-sharing-scope>Shareable</res-sharing-scope>
+ </resource-ref>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidHelloSubscriberBean</ejb-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.jms.ConnectionFactory</res-type>
+ <res-auth>Container</res-auth>
+ <res-sharing-scope>Shareable</res-sharing-scope>
+ </resource-ref>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidJMSResponderBean</ejb-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.jms.ConnectionFactory</res-type>
+ <res-auth>Container</res-auth>
+ <res-sharing-scope>Shareable</res-sharing-scope>
+ </resource-ref>
+ </message-driven>
+ <session>
+ <ejb-name>QpidTestBean</ejb-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.jms.ConnectionFactory</res-type>
+ <res-auth>Container</res-auth>
+ <res-sharing-scope>Shareable</res-sharing-scope>
+ </resource-ref>
+ </session>
+ </enterprise-beans>
+
+
+</ejb-jar>
diff --git a/qpid/java/jca/example/conf/geronimo-application.xml b/qpid/java/jca/example/conf/geronimo-application.xml
new file mode 100644
index 0000000000..832496e76f
--- /dev/null
+++ b/qpid/java/jca/example/conf/geronimo-application.xml
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<application xmlns="http://geronimo.apache.org/xml/ns/j2ee/application-2.0"
+ xmlns:sys="http://geronimo.apache.org/xml/ns/deployment-1.2"
+ xmlns:naming="http://geronimo.apache.org/xml/ns/naming-1.2"
+ application-name="QpidJCAExampleApplication">
+
+ <sys:environment>
+ <sys:moduleId>
+ <sys:groupId>@geronimo.ear.group.id@</sys:groupId>
+ <sys:artifactId>@geronimo.ear.artifact.id@</sys:artifactId>
+ <sys:version>@geronimo.ear.version@</sys:version>
+ <sys:type>@geronimo.ear.type@</sys:type>
+ </sys:moduleId>
+ </sys:environment>
+
+ <!-- Plan for embedded WAR -->
+ <module>
+ <web>qpid-jcaex-web.war</web>
+ <web-app xmlns="http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1">
+
+ <sys:environment>
+ <sys:moduleId>
+ <sys:groupId>@geronimo.war.group.id@</sys:groupId>
+ <sys:artifactId>@geronimo.war.artifact.id@</sys:artifactId>
+ <sys:version>@geronimo.war.version@</sys:version>
+ <sys:type>@geronimo.war.type@</sys:type>
+ </sys:moduleId>
+
+ <sys:dependencies>
+ <sys:dependency>
+ <sys:groupId>qpid.jca</sys:groupId>
+ <sys:artifactId>QpidJCAAdapter</sys:artifactId>
+ <sys:version>1.0</sys:version>
+ <sys:type>rar</sys:type>
+ </sys:dependency>
+ </sys:dependencies>
+ </sys:environment>
+
+ <context-root>/qpid-jca-web</context-root>
+
+ <naming:ejb-local-ref>
+ <naming:ref-name>QpidTestBean</naming:ref-name>
+ <naming:ejb-link>QpidTestBean</naming:ejb-link>
+ </naming:ejb-local-ref>
+
+ <naming:resource-ref>
+ <naming:ref-name>QpidJMSXA</naming:ref-name>
+ <naming:resource-link>QpidJMSXA</naming:resource-link>
+ </naming:resource-ref>
+ </web-app>
+ </module>
+
+ <!-- Plan for embedded EJBs -->
+ <module>
+ <ejb>qpid-jcaex-ejb.jar</ejb>
+ <openejb-jar xmlns="http://www.openejb.org/xml/ns/openejb-jar-2.1">
+
+ <sys:environment>
+ <sys:moduleId>
+ <sys:groupId>@geronimo.ejb.group.id@</sys:groupId>
+ <sys:artifactId>@geronimo.ejb.artifact.id@</sys:artifactId>
+ <sys:version>@geronimo.ejb.version@</sys:version>
+ <sys:type>@geronimo.ejb.type@</sys:type>
+ </sys:moduleId>
+
+ <sys:dependencies>
+ <sys:dependency>
+ <sys:groupId>qpid.jca</sys:groupId>
+ <sys:artifactId>QpidJCAAdapter</sys:artifactId>
+ <sys:version>1.0</sys:version>
+ <sys:type>rar</sys:type>
+ </sys:dependency>
+ </sys:dependencies>
+ <sys:hidden-classes/>
+ <sys:non-overridable-classes/>
+ </sys:environment>
+
+ <enterprise-beans>
+ <message-driven>
+ <ejb-name>QpidHelloListenerBean</ejb-name>
+ <resource-adapter>
+ <resource-link>QpidResourceAdapter</resource-link>
+ </resource-adapter>
+ <naming:resource-ref>
+ <naming:ref-name>QpidJMSXA</naming:ref-name>
+ <naming:resource-link>QpidJMSXA</naming:resource-link>
+ </naming:resource-ref>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidGoodByeListenerBean</ejb-name>
+ <resource-adapter>
+ <resource-link>QpidResourceAdapter</resource-link>
+ </resource-adapter>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidHelloSubscriberBean</ejb-name>
+ <resource-adapter>
+ <resource-link>QpidResourceAdapter</resource-link>
+ </resource-adapter>
+ <naming:resource-ref>
+ <naming:ref-name>QpidJMSXA</naming:ref-name>
+ <naming:resource-link>QpidJMSXA</naming:resource-link>
+ </naming:resource-ref>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidGoodByeSubscriberBean</ejb-name>
+ <resource-adapter>
+ <resource-link>QpidResourceAdapter</resource-link>
+ </resource-adapter>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidJMSResponderBean</ejb-name>
+ <resource-adapter>
+ <resource-link>QpidResourceAdapter</resource-link>
+ </resource-adapter>
+ <naming:resource-ref>
+ <naming:ref-name>QpidJMSXA</naming:ref-name>
+ <naming:resource-link>QpidJMSXA</naming:resource-link>
+ </naming:resource-ref>
+ </message-driven>
+ <session>
+ <ejb-name>QpidTestBean</ejb-name>
+ <naming:resource-ref>
+ <naming:ref-name>QpidJMSXA</naming:ref-name>
+ <naming:resource-link>QpidJMSXA</naming:resource-link>
+ </naming:resource-ref>
+ </session>
+ </enterprise-beans>
+ </openejb-jar>
+ </module>
+</application>
diff --git a/qpid/java/jca/example/conf/geronimo-ra.xml b/qpid/java/jca/example/conf/geronimo-ra.xml
new file mode 100644
index 0000000000..2943ac0a58
--- /dev/null
+++ b/qpid/java/jca/example/conf/geronimo-ra.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<connector xmlns="http://geronimo.apache.org/xml/ns/j2ee/connector-1.2">
+ <dep:environment xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2">
+ <dep:moduleId>
+ <dep:groupId>qpid.jca</dep:groupId>
+ <dep:artifactId>QpidJCAAdapter</dep:artifactId>
+ <dep:version>1.0</dep:version>
+ <dep:type>rar</dep:type>
+ </dep:moduleId>
+ </dep:environment>
+ <resourceadapter>
+ <resourceadapter-instance>
+ <resourceadapter-name>QpidResourceAdapter</resourceadapter-name>
+ <config-property-setting name="ClientId">client_id</config-property-setting>
+ <config-property-setting name="TransactionManagerLocatorClass">org.apache.qpid.ra.tm.GeronimoTransactionManagerLocator</config-property-setting>
+ <config-property-setting name="TransactionManagerLocatorMethod">getTransactionManager</config-property-setting>
+ <!-- Note, currently there is a bug with end/suspend and Geronimo. For now use local transactions-->
+ <config-property-setting name="UseLocalTx">true</config-property-setting>
+ <workmanager>
+ <gbean-link>DefaultWorkManager</gbean-link>
+ </workmanager>
+ </resourceadapter-instance>
+ <outbound-resourceadapter>
+ <connection-definition>
+ <connectionfactory-interface>org.apache.qpid.ra.QpidRAConnectionFactory</connectionfactory-interface>
+ <connectiondefinition-instance>
+ <name>QpidJMSXA</name>
+ <implemented-interface>javax.jms.QueueConnectionFactory</implemented-interface>
+ <implemented-interface>javax.jms.TopicConnectionFactory</implemented-interface>
+ <config-property-setting name="ConnectionURL">@broker.url@</config-property-setting>
+ <connectionmanager>
+ <!-- Note, currently there is a bug with end/suspend and Geronimo. For now use no transactions outbound -->
+ <no-transaction/>
+ <single-pool>
+ <max-size>20</max-size>
+ <min-size>0</min-size>
+ <match-one/>
+ </single-pool>
+ </connectionmanager>
+ </connectiondefinition-instance>
+ </connection-definition>
+ </outbound-resourceadapter>
+ <!-- Note, do not remove this admin object. There appears to be a bug in Geronimo's deployer that does not correctly create JNDI references
+ if an extra admin object is not present -->
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>Dummy</message-destination-name>
+ <config-property-setting name="destinationType">TOPIC</config-property-setting>
+ <config-property-setting name="destinationAddress">amq.topic</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>HelloTopic</message-destination-name>
+ <config-property-setting name="destinationType">TOPIC</config-property-setting>
+ <config-property-setting name="destinationAddress">@qpid.hello.topic.dest.address@</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>GoodByeTopic</message-destination-name>
+ <config-property-setting name="destinationType">TOPIC</config-property-setting>
+ <config-property-setting name="destinationAddress">@qpid.goodbye.topic.dest.address@</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>HelloGoodByeTopic</message-destination-name>
+ <config-property-setting name="destinationType">TOPIC</config-property-setting>
+ <config-property-setting name="destinationAddress">@qpid.hellogoodbye.topic.dest.address@</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>HelloQueue</message-destination-name>
+ <config-property-setting name="destinationType">QUEUE</config-property-setting>
+ <config-property-setting name="destinationAddress">@qpid.hello.queue.dest.address@</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>GoodByeQueue</message-destination-name>
+ <config-property-setting name="destinationType">QUEUE</config-property-setting>
+ <config-property-setting name="destinationAddress">@qpid.goodbye.queue.dest.address@</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>ResponderQueue</message-destination-name>
+ <config-property-setting name="destinationType">QUEUE</config-property-setting>
+ <config-property-setting name="destinationAddress">@qpid.responder.queue.dest.address@</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.ConnectionFactory</adminobject-interface>
+ <adminobject-class>org.apache.qpid.ra.admin.QpidConnectionFactoryProxy</adminobject-class>
+ <adminobject-instance>
+ <message-destination-name>QpidConnectionFactory</message-destination-name>
+ <config-property-setting name="connectionURL">@broker.url@</config-property-setting>
+ </adminobject-instance>
+ </adminobject>
+ </resourceadapter>
+</connector>
+
diff --git a/qpid/java/jca/example/conf/jboss-web.xml b/qpid/java/jca/example/conf/jboss-web.xml
new file mode 100644
index 0000000000..edacf8d418
--- /dev/null
+++ b/qpid/java/jca/example/conf/jboss-web.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<jboss-web>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.jms.ConnectionFactory</res-type>
+ <jndi-name>java:/QpidJMSXA</jndi-name>
+ </resource-ref>
+ <ejb-local-ref>
+ <ejb-ref-name>QpidTestBean</ejb-ref-name>
+ <jndi-name>qpid-jcaex/QpidTestBean/local</jndi-name>
+ </ejb-local-ref>
+ <context-root>qpid-jca-web</context-root>
+</jboss-web>
+
diff --git a/qpid/java/jca/example/conf/jboss.xml b/qpid/java/jca/example/conf/jboss.xml
new file mode 100644
index 0000000000..8b62ca73b0
--- /dev/null
+++ b/qpid/java/jca/example/conf/jboss.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<jboss
+ xmlns="http://www.jboss.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee
+ http://www.jboss.org/j2ee/schema/jboss_5_0.xsd"
+ version="3.0">
+
+ <enterprise-beans>
+ <message-driven>
+ <ejb-name>QpidHelloListenerBean</ejb-name>
+ <resource-adapter-name>@rar.name@</resource-adapter-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.sql.DataSource</res-type>
+ <jndi-name>java:/QpidJMSXA</jndi-name>
+ </resource-ref>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidGoodByeListenerBean</ejb-name>
+ <resource-adapter-name>@rar.name@</resource-adapter-name>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidHelloSubscriberBean</ejb-name>
+ <resource-adapter-name>@rar.name@</resource-adapter-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.sql.DataSource</res-type>
+ <jndi-name>java:/QpidJMSXA</jndi-name>
+ </resource-ref>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidGoodByeSubscriberBean</ejb-name>
+ <resource-adapter-name>@rar.name@</resource-adapter-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.sql.DataSource</res-type>
+ <jndi-name>java:/QpidJMSXA</jndi-name>
+ </resource-ref>
+ </message-driven>
+ <message-driven>
+ <ejb-name>QpidJMSResponderBean</ejb-name>
+ <resource-adapter-name>@rar.name@</resource-adapter-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.sql.DataSource</res-type>
+ <jndi-name>java:/QpidJMSXA</jndi-name>
+ </resource-ref>
+ </message-driven>
+ <session>
+ <ejb-name>QpidTestBean</ejb-name>
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.sql.DataSource</res-type>
+ <jndi-name>java:/QpidJMSXA</jndi-name>
+ </resource-ref>
+ </session>
+ </enterprise-beans>
+
+</jboss>
diff --git a/qpid/java/jca/example/conf/log4j.properties b/qpid/java/jca/example/conf/log4j.properties
new file mode 100644
index 0000000000..f1847f4418
--- /dev/null
+++ b/qpid/java/jca/example/conf/log4j.properties
@@ -0,0 +1,18 @@
+log4j.rootLogger=DEBUG, CONSOLE, FILE
+
+#Console Appender
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+log4j.appender.CONSOLE.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
+
+#File Appender
+log4j.appender.FILE=org.apache.log4j.FileAppender
+log4j.appender.FILE.File=./build/log/qpid-jca-example.log
+log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
+log4j.appender.FILE.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
+
+log4j.logger.org.jboss=WARN
+log4j.logger.org.jnp.interfaces=WARN
+log4j.logger.org.apache.qpid=ERROR
+log4j.logger.org.apache.qpid.jca.example=DEBUG
+
diff --git a/qpid/java/jca/example/conf/qpid-jca-ds.xml b/qpid/java/jca/example/conf/qpid-jca-ds.xml
new file mode 100644
index 0000000000..9e589169e3
--- /dev/null
+++ b/qpid/java/jca/example/conf/qpid-jca-ds.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<connection-factories>
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=HelloTopic">
+ <attribute name="JNDIName">HelloTopic</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='@rar.name@'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=TOPIC
+ destinationAddress=@qpid.hello.topic.dest.address@
+ </attribute>
+ </mbean>
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=GoodByeTopic">
+ <attribute name="JNDIName">GoodByeTopic</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='@rar.name@'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=TOPIC
+ destinationAddress=@qpid.goodbye.topic.dest.address@
+ </attribute>
+ </mbean>
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=HelloGoodByeTopic">
+ <attribute name="JNDIName">HelloGoodByeTopic</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='@rar.name@'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=TOPIC
+ destinationAddress=@qpid.hellogoodbye.topic.dest.address@
+ </attribute>
+ </mbean>
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=HelloQueue">
+ <attribute name="JNDIName">HelloQueue</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='@rar.name@'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=QUEUE
+ destinationAddress=@qpid.hello.queue.dest.address@
+ </attribute>
+ </mbean>
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=GoodByeQueue">
+ <attribute name="JNDIName">GoodByeQueue</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='@rar.name@'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=QUEUE
+ destinationAddress=@qpid.goodbye.queue.dest.address@
+ </attribute>
+ </mbean>
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=QpidResponderQueue">
+ <attribute name="JNDIName">QpidResponderQueue</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='@rar.name@'</depends>
+ <attribute name="Type">javax.jms.Destination</attribute>
+ <attribute name="Properties">
+ destinationType=QUEUE
+ destinationAddress=@qpid.responder.queue.dest.address@
+ </attribute>
+ </mbean>
+
+ <mbean code="org.jboss.resource.deployment.AdminObject"
+ name="qpid.jca:name=QpidConnectionFactory">
+ <attribute name="JNDIName">QpidConnectionFactory</attribute>
+ <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='@rar.name@'</depends>
+ <attribute name="Type">javax.jms.ConnectionFactory</attribute>
+ <attribute name="Properties">
+ connectionURL=@broker.url@
+ </attribute>
+ </mbean>
+
+ <!-- Non XA connection factory. Can be used when running adapter against clustered Brokers -->
+ <tx-connection-factory>
+ <jndi-name>QpidJMS</jndi-name>
+ <rar-name>@rar.name@</rar-name>
+ <local-transaction/>
+ <config-property name="useLocalTx" type="java.lang.Boolean">true</config-property>
+ <config-property name="connectionURL">@broker.url@</config-property>
+ <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Queue</config-property>
+ <connection-definition>org.apache.qpid.ra.QpidRAConnectionFactory</connection-definition>
+ <max-pool-size>20</max-pool-size>
+ </tx-connection-factory>
+
+ <!--XA ConnectionFactory-->
+ <tx-connection-factory>
+ <jndi-name>QpidJMSXA</jndi-name>
+ <xa-transaction/>
+ <rar-name>@rar.name@</rar-name>
+ <config-property name="connectionURL">@broker.url@</config-property>
+ <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Queue</config-property>
+ <connection-definition>org.apache.qpid.ra.QpidRAConnectionFactory</connection-definition>
+ <max-pool-size>20</max-pool-size>
+ </tx-connection-factory>
+
+</connection-factories>
diff --git a/qpid/java/jca/example/conf/web.xml b/qpid/java/jca/example/conf/web.xml
new file mode 100644
index 0000000000..509612dc90
--- /dev/null
+++ b/qpid/java/jca/example/conf/web.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
+
+ <resource-ref>
+ <res-ref-name>QpidJMSXA</res-ref-name>
+ <res-type>javax.jms.ConnectionFactory</res-type>
+ <res-auth>Container</res-auth>
+ <res-sharing-scope>Shareable</res-sharing-scope>
+ </resource-ref>
+
+ <ejb-local-ref>
+ <ejb-ref-name>QpidTestBean</ejb-ref-name>
+ <ejb-ref-type>Session</ejb-ref-type>
+ <local>org.apache.qpid.jca.example.ejb.QpidTestLocal</local>
+ </ejb-local-ref>
+
+ <servlet>
+ <display-name>QpidTestServlet</display-name>
+ <servlet-name>QpidTestServlet</servlet-name>
+ <servlet-class>org.apache.qpid.jca.example.web.QpidTestServlet</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>QpidTestServlet</servlet-name>
+ <url-pattern>/qpid</url-pattern>
+ </servlet-mapping>
+
+
+</web-app>
+
diff --git a/qpid/java/jca/example/qpid-jca-example-properties.xml b/qpid/java/jca/example/qpid-jca-example-properties.xml
new file mode 100644
index 0000000000..ee0478a6e5
--- /dev/null
+++ b/qpid/java/jca/example/qpid-jca-example-properties.xml
@@ -0,0 +1,79 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<project name="qpid-jca-example-properties" basedir="." default="">
+
+ <property name="src.dir" location="${basedir}/src/main/java"/>
+ <property name="lib.dir" location="${basedir}/lib"/>
+ <property name="conf.dir" location="${basedir}/conf"/>
+ <property name="build.dir" location="${basedir}/build"/>
+ <property name="build.classes.dir" location="${build.dir}/classes"/>
+ <property name="gen.dir" location="${build.dir}/gen"/>
+ <property name="log.dir" location="${build.dir}/log"/>
+ <property name="qpid.jca.dir" location="${env.QPID_JCA_HOME}"/>
+
+ <property name="ejb.name" value="qpid-jcaex-ejb.jar"/>
+ <property name="war.name" value="qpid-jcaex-web.war"/>
+ <property name="ear.name" value="qpid-jcaex.ear"/>
+
+ <property name="rar.ver" value="${qpid.ver}"/>
+ <property name="rar.name" value="qpid-ra-${rar.ver}.rar"/>
+
+ <property name="broker.url" value="amqp://anonymous:passwd@client/test?brokerlist='tcp://${broker.address}?sasl_mechs='ANONYMOUS''"/>
+
+ <property name="qpid.hello.topic.dest.address.ADDR" value="amq.topic/hello.Topic"/>
+ <property name="qpid.goodbye.topic.dest.address.ADDR" value="amq.topic/goodbye.Topic"/>
+ <property name="qpid.hellogoodbye.topic.dest.address.ADDR" value="amq.topic/goodbye.Topic"/>
+ <property name="qpid.hello.queue.dest.address.ADDR"
+ value="hello.Queue;{create:always, node:{type:queue, x-declare:{auto-delete:true}}}"/>
+ <property name="qpid.goodbye.queue.dest.address.ADDR"
+ value="goodbye.Queue;{create:always, node:{type:queue, x-declare:{auto-delete:true}}}"/>
+ <property name="qpid.responder.queue.dest.address.ADDR"
+ value="responder.Queue;{create:always, node:{type:queue, x-declare:{auto-delete:true}}}"/>
+
+ <property name="qpid.hello.topic.dest.address.BURL"
+ value="topic://amq.topic//hello.jcaTopic?routingKey='hello.jcaTopic',autodelete='true'"/>
+ <property name="qpid.goodbye.topic.dest.address.BURL"
+ value="topic://amq.topic//goodbye.jcaTopic?routingKey='goodbye.jcaTopic',autodelete='true'"/>
+ <property name="qpid.hellogoodbye.topic.dest.address.BURL"
+ value="topic://amq.topic//#.jcaTopic"/>
+ <property name="qpid.hello.queue.dest.address.BURL"
+ value="direct://amq.direct//hello.Queue?routingkey='hello.Queue'"/>
+ <property name="qpid.goodbye.queue.dest.address.BURL"
+ value="direct://amq.direct//goodbye.Queue?routingkey='goodbye.Queue'"/>
+ <property name="qpid.responder.queue.dest.address.BURL"
+ value="direct://amq.direct//responder.Queue?routingkey='responder.Queue'"/>
+
+ <!-- This macro allows us to construct a property name which contains a property expansion -->
+ <macrodef name="set-address-property">
+ <attribute name="name"/>
+ <attribute name="syntax"/>
+ <sequential>
+ <property name="@{name}" value="${@{name}.@{syntax}}"/>
+ </sequential>
+ </macrodef>
+
+ <set-address-property name="qpid.hello.topic.dest.address" syntax="${qpid.dest_syntax}"/>
+ <set-address-property name="qpid.goodbye.topic.dest.address" syntax="${qpid.dest_syntax}"/>
+ <set-address-property name="qpid.hellogoodbye.topic.dest.address" syntax="${qpid.dest_syntax}"/>
+ <set-address-property name="qpid.hello.queue.dest.address" syntax="${qpid.dest_syntax}"/>
+ <set-address-property name="qpid.goodbye.queue.dest.address" syntax="${qpid.dest_syntax}"/>
+ <set-address-property name="qpid.responder.queue.dest.address" syntax="${qpid.dest_syntax}"/>
+</project>
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidRequestResponseClient.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidRequestResponseClient.java
new file mode 100644
index 0000000000..734df1c0f3
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidRequestResponseClient.java
@@ -0,0 +1,159 @@
+/*
+ *
+ * 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.jca.example.client;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.apache.qpid.jca.example.ejb.QpidUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class QpidRequestResponseClient implements MessageListener, Runnable
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidRequestResponseClient.class);
+
+ private static final String DEFAULT_CF_JNDI = "QpidConnectionFactory";
+ private static final String DEFAULT_DESTINATION_JNDI = "QpidResponderQueue";
+ private static final String DEFAULT_MESSAGE = "Hello, World!";
+ private static final int DEFAULT_MESSAGE_COUNT = 1;
+ private static final int DEFAULT_THREAD_COUNT = 1;
+ private static CountDownLatch THREAD_LATCH;
+ private static InitialContext CONTEXT;
+
+ private ConnectionFactory _connectionFactory;
+ private Connection _connection;
+ private Session _session;
+ private CountDownLatch _latch = null;
+ private int _count = DEFAULT_MESSAGE_COUNT;
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) throws Exception
+ {
+ int threadCount = (System.getProperty("thread.count") == null)
+ ? DEFAULT_THREAD_COUNT : Integer.valueOf(System.getProperty("thread.count"));
+
+ _log.debug("Creating " + threadCount + " threads for execution.");
+
+ THREAD_LATCH = new CountDownLatch(threadCount);
+
+ CONTEXT = new InitialContext();
+
+ for(int i = 0; i < threadCount; i++)
+ {
+ new Thread(new QpidRequestResponseClient()).start();
+ }
+
+ _log.debug("Waiting for " + threadCount + " to finish.");
+ THREAD_LATCH.await(10, TimeUnit.SECONDS);
+
+ QpidUtil.closeResources(CONTEXT);
+ }
+
+ @Override
+ public void onMessage(Message message)
+ {
+ _latch.countDown();
+
+ if(message instanceof TextMessage)
+ {
+ try
+ {
+ _log.debug("Thread " + Thread.currentThread().getId() + " received response message with content " + ((TextMessage)message).getText());
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ }
+
+ if(_latch.getCount() == _count)
+ {
+ QpidUtil.closeResources(_session, _connection);
+ }
+
+ THREAD_LATCH.countDown();
+
+ }
+
+ public void run()
+ {
+ MessageProducer producer = null;
+ Destination requestQueue = null;
+ Destination responseQueue = null;
+
+ String cfName = (System.getProperty("qpid.cf.name") == null) ? DEFAULT_CF_JNDI : System.getProperty("qpid.cf.name");
+ String destName = (System.getProperty("qpid.dest.name") == null) ? DEFAULT_DESTINATION_JNDI : System.getProperty("qpid.dest.name");
+
+ try
+ {
+ _count = (System.getProperty("message.count") == null) ? DEFAULT_MESSAGE_COUNT : Integer.valueOf(System.getProperty("message.count"));
+ _latch = new CountDownLatch(_count);
+
+ _connectionFactory = (ConnectionFactory)QpidTestUtil.getFromJNDI(CONTEXT, cfName);
+ requestQueue = (Destination)QpidTestUtil.getFromJNDI(CONTEXT, destName);
+ _connection = _connectionFactory.createConnection();
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ producer = _session.createProducer(requestQueue);
+ responseQueue = _session.createTemporaryQueue();
+ _session.createConsumer(responseQueue).setMessageListener(this);
+
+
+ _connection.start();
+
+ String content = (System.getProperty("qpid.message") == null) ? DEFAULT_MESSAGE : System.getProperty("qpid.message");
+
+ for(int i = 0; i < _count; i++)
+ {
+ TextMessage message = _session.createTextMessage();
+ message.setText(content);
+ message.setJMSReplyTo(responseQueue);
+ producer.send(message);
+
+ }
+
+ _latch.await();
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(producer);
+ }
+
+ }
+
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestClient.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestClient.java
new file mode 100644
index 0000000000..a5a33e36ec
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestClient.java
@@ -0,0 +1,135 @@
+/*
+ *
+ * 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.jca.example.client;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+
+import org.apache.qpid.jca.example.ejb.QpidTest;
+import org.apache.qpid.jca.example.ejb.QpidUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class QpidTestClient
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidTestClient.class);
+
+ private static final String DEFAULT_EJB_JNDI = "QpidTestBean/remote";
+ private static final String DEFAULT_CF_JNDI = "QpidConnectionFactory";
+ private static final String DEFAULT_MESSAGE = "Hello,World!";
+ private static final int DEFAULT_MESSAGE_COUNT = 1;
+ private static final boolean DEFAULT_USE_TOPIC = false;
+ private static final boolean DEFAULT_USE_EJB = true;
+ private static final String DEFAULT_DESTINATION_JNDI = "HelloQueue";
+ private static final boolean DEFAULT_SAY_GOODBYE = false;
+
+ public static void main(String[] args) throws Exception
+ {
+ String content = (System.getProperty("qpid.message") == null) ? DEFAULT_MESSAGE : System.getProperty("qpid.message");
+ boolean useEJB = (System.getProperty("use.ejb") == null) ? DEFAULT_USE_EJB : Boolean.valueOf(System.getProperty("use.ejb"));
+ int total = (System.getProperty("message.count") == null) ? DEFAULT_MESSAGE_COUNT : Integer.valueOf(System.getProperty("message.count"));
+ boolean useTopic = (System.getProperty("use.topic") == null) ? DEFAULT_USE_TOPIC : Boolean.valueOf(System.getProperty("use.topic"));
+ String destType = (useTopic) ? "Topic" : "Queue";
+ boolean goodbye = (System.getProperty("say.goodbye") == null) ? DEFAULT_SAY_GOODBYE : Boolean.valueOf(System.getProperty("say.goodbye"));
+
+ _log.debug("Environment: ");
+ _log.debug("JNDI IntialContectFactory: " + System.getProperty("java.naming.factory.initial"));
+ _log.debug("JNDI Provider: " + System.getProperty("java.naming.provider.url"));
+ _log.debug("Message content: " + content);
+ _log.debug("Message count:" + total);
+ _log.debug("Protocol: " + ((useEJB) ? "EJB" : "JMS"));
+ _log.debug("Destination Type: " + destType);
+ _log.debug("Say GoodBye : " + goodbye);
+
+ Context context = new InitialContext();
+
+ if(useEJB)
+ {
+
+ String ejbName = (System.getProperty("qpid.ejb.name") == null) ? DEFAULT_EJB_JNDI : System.getProperty("qpid.ejb.name");
+
+ QpidTest ejb = (QpidTest)QpidTestUtil.getFromJNDI(context, ejbName);
+
+ _log.debug("Found SLSB " + ejbName + "in JNDI");
+ ejb.testQpidAdapter(content, total, useTopic, false, goodbye);
+
+ }
+ else
+ {
+ ConnectionFactory connectionFactory = null;
+ Connection connection = null;
+ Session session = null;
+ MessageProducer messageProducer = null;
+ Destination destination = null;
+ int count = 0;
+
+ String cfName = (System.getProperty("qpid.cf.name") == null) ? DEFAULT_CF_JNDI : System.getProperty("qpid.cf.name");
+ String destName = (System.getProperty("qpid.dest.name") == null) ? DEFAULT_DESTINATION_JNDI : System.getProperty("qpid.dest.name");
+
+ _log.debug("Using JMS with CF name " + cfName + " and Destination name " + destName + " to send " + total + " message(s) with content " + content);
+
+ try
+ {
+ _log.debug("Using JNDI at " + System.getProperty("java.naming.provider.url"));
+
+ connectionFactory = (ConnectionFactory)QpidTestUtil.getFromJNDI(context, cfName);
+ destination = (Destination)QpidTestUtil.getFromJNDI(context, destName);
+
+ _log.debug("Using CF: " + connectionFactory);
+ _log.debug("Destination " + destination);
+
+ connection = connectionFactory.createConnection();
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ messageProducer = session.createProducer(destination);
+
+ _log.debug("Sending " + total + " message(s) with content: " + content + " to destination " + destName);
+
+ for(int i = 0; i < total; i++)
+ {
+ TextMessage message = session.createTextMessage(content);
+ message.setBooleanProperty("say.goodbye", goodbye);
+ messageProducer.send(message);
+ count++;
+ }
+
+
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ _log.error(e.getMessage());
+ }
+ finally
+ {
+ QpidUtil.closeResources(session, connection, context);
+ }
+
+ _log.debug(count + " message(s) sent successfully");
+ }
+
+ }
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestUtil.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestUtil.java
new file mode 100644
index 0000000000..7a53335d79
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/client/QpidTestUtil.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.jca.example.client;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.spi.NamingManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class QpidTestUtil {
+ private static final Logger _log = LoggerFactory.getLogger(QpidTestUtil.class);
+
+ /*
+ * Encapsulate looking up in JNDI and working around a seeming bug in OpenEJB which returns a
+ * Reference when it should just return an object constructed from it
+ */
+ static Object getFromJNDI(Context context, String name) throws NamingException, Exception
+ {
+ Object o = context.lookup(name);
+ if (o instanceof Reference)
+ {
+ _log.debug("Got a Reference back from JNDI for " + name + " - working around");
+ return NamingManager.getObjectInstance(o, null, null, null);
+ }
+ else
+ {
+ return o;
+ }
+ }
+
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeListenerBean.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeListenerBean.java
new file mode 100644
index 0000000000..9cf220de2a
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeListenerBean.java
@@ -0,0 +1,65 @@
+/*
+ *
+ * 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.jca.example.ejb;
+
+import java.util.Date;
+
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.TextMessage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@MessageDriven(activationConfig = {
+ @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "@qpid.goodbye.queue.jndi.name@"),
+ @ActivationConfigProperty(propertyName = "connectionURL", propertyValue = "@broker.url@"),
+ @ActivationConfigProperty(propertyName = "useLocalTx", propertyValue = "false"),
+ @ActivationConfigProperty(propertyName = "maxSession", propertyValue = "10")
+})
+public class QpidGoodByeListenerBean implements MessageListener
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidGoodByeListenerBean.class);
+
+ @Override
+ public void onMessage(Message message)
+ {
+ try
+ {
+ if(message instanceof TextMessage)
+ {
+ String content = ((TextMessage)message).getText();
+
+ _log.info("Received text message with contents: [" + content + "] at " + new Date());
+ }
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+
+ }
+
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeSubscriberBean.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeSubscriberBean.java
new file mode 100644
index 0000000000..8ad8aaa482
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidGoodByeSubscriberBean.java
@@ -0,0 +1,27 @@
+package org.apache.qpid.jca.example.ejb;
+
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+@MessageDriven(activationConfig = {
+ @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "@qpid.goodbye.topic.jndi.name@"),
+ @ActivationConfigProperty(propertyName = "connectionURL", propertyValue = "@broker.url@"),
+ @ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "NotDurable"),
+ @ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "hello.Topic"),
+ @ActivationConfigProperty(propertyName = "maxSession", propertyValue = "10")
+})
+
+public class QpidGoodByeSubscriberBean implements MessageListener
+{
+
+ @Override
+ public void onMessage(Message message)
+ {
+ System.out.println(message);
+ }
+
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloListenerBean.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloListenerBean.java
new file mode 100644
index 0000000000..d6d08d1557
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloListenerBean.java
@@ -0,0 +1,118 @@
+/*
+ *
+ * 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.jca.example.ejb;
+
+import java.util.Date;
+
+import javax.annotation.PostConstruct;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@MessageDriven(activationConfig = {
+ @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "@qpid.hello.queue.jndi.name@"),
+ @ActivationConfigProperty(propertyName = "connectionURL", propertyValue = "@broker.url@"),
+ @ActivationConfigProperty(propertyName = "maxSession", propertyValue = "10")
+})
+public class QpidHelloListenerBean implements MessageListener
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidHelloListenerBean.class);
+
+ private ConnectionFactory _connectionFactory;
+
+ private Destination _queue;
+
+ @PostConstruct
+ public void init()
+ {
+ InitialContext context = null;
+
+ try
+ {
+ context = new InitialContext();
+ _connectionFactory = (ConnectionFactory)context.lookup("java:comp/env/QpidJMSXA");
+ _queue = (Destination)context.lookup("@qpid.goodbye.queue.jndi.name@");
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(context);
+ }
+
+ }
+
+ @Override
+ public void onMessage(Message message)
+ {
+ Connection connection = null;
+ Session session = null;
+ MessageProducer messageProducer = null;
+ TextMessage response = null;
+
+ try
+ {
+ if(message instanceof TextMessage)
+ {
+ String content = ((TextMessage)message).getText();
+
+ _log.info("Received text message with contents: [" + content + "] at " + new Date());
+
+ StringBuffer temp = new StringBuffer();
+ temp.append("QpidHelloListenerBean received message with content: [" + content);
+ temp.append("] at " + new Date());
+
+ if(message.propertyExists("say.goodbye") && message.getBooleanProperty("say.goodbye"))
+ {
+ connection = _connectionFactory.createConnection();
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ messageProducer = session.createProducer(_queue);
+ response = session.createTextMessage(temp.toString());
+ messageProducer.send(response);
+ }
+ }
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(session, connection);
+ }
+ }
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloSubscriberBean.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloSubscriberBean.java
new file mode 100644
index 0000000000..43ccf9defd
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidHelloSubscriberBean.java
@@ -0,0 +1,121 @@
+/*
+ *
+ * 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.jca.example.ejb;
+
+import java.util.Date;
+
+import javax.annotation.PostConstruct;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+@MessageDriven(activationConfig = {
+ @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "@qpid.hello.topic.jndi.name@"),
+ @ActivationConfigProperty(propertyName = "connectionURL", propertyValue = "@broker.url@"),
+ @ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "NotDurable"),
+ @ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "hello.Topic"),
+ @ActivationConfigProperty(propertyName = "maxSession", propertyValue = "10")
+})
+public class QpidHelloSubscriberBean implements MessageListener
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidHelloSubscriberBean.class);
+
+ private ConnectionFactory _connectionFactory;
+
+ private Destination _topic;
+
+ @PostConstruct
+ public void init()
+ {
+ InitialContext context = null;
+
+ try
+ {
+ context = new InitialContext();
+ _connectionFactory = (ConnectionFactory)context.lookup("java:comp/env/QpidJMSXA");
+ _topic = (Destination)context.lookup("@qpid.goodbye.topic.jndi.name@");
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(context);
+ }
+
+ }
+
+ @Override
+ public void onMessage(Message message)
+ {
+ Connection connection = null;
+ Session session = null;
+ MessageProducer messageProducer = null;
+ TextMessage response = null;
+
+ try
+ {
+ if(message instanceof TextMessage)
+ {
+ String content = ((TextMessage)message).getText();
+
+ _log.info("Received text message with contents: [" + content + "] at " + new Date());
+
+ StringBuffer temp = new StringBuffer();
+ temp.append("QpidHelloSubscriberBean received message with content: [" + content);
+ temp.append("] at " + new Date());
+
+ if(message.propertyExists("say.goodbye") && message.getBooleanProperty("say.goodbye"))
+ {
+ connection = _connectionFactory.createConnection();
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ messageProducer = session.createProducer(_topic);
+ response = session.createTextMessage(temp.toString());
+ messageProducer.send(response);
+ }
+ }
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(session, connection);
+ }
+ }
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidJMSResponderBean.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidJMSResponderBean.java
new file mode 100644
index 0000000000..74d6fb6d89
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidJMSResponderBean.java
@@ -0,0 +1,100 @@
+package org.apache.qpid.jca.example.ejb;
+
+import java.util.Date;
+
+import javax.annotation.PostConstruct;
+import javax.ejb.ActivationConfigProperty;
+import javax.ejb.MessageDriven;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@MessageDriven(activationConfig = {
+ @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
+ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName = "destination", propertyValue = "@qpid.responder.queue.jndi.name@"),
+ @ActivationConfigProperty(propertyName = "connectionURL", propertyValue = "@broker.url@"),
+ @ActivationConfigProperty(propertyName = "maxSession", propertyValue = "10")
+})
+public class QpidJMSResponderBean implements MessageListener
+{
+
+ private static final Logger _log = LoggerFactory.getLogger(QpidJMSResponderBean.class);
+
+ private ConnectionFactory _connectionFactory;
+
+ @PostConstruct
+ public void init()
+ {
+ InitialContext context = null;
+
+ try
+ {
+ context = new InitialContext();
+ _connectionFactory = (ConnectionFactory)context.lookup("java:comp/env/QpidJMSXA");
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(context);
+ }
+
+ }
+
+ @Override
+ public void onMessage(Message message)
+ {
+ Connection connection = null;
+ Session session = null;
+ MessageProducer messageProducer = null;
+ TextMessage response = null;
+
+ try
+ {
+ if(message instanceof TextMessage)
+ {
+ String content = ((TextMessage)message).getText();
+
+ _log.info("Received text message with contents: [" + content + "] at " + new Date());
+
+ StringBuffer temp = new StringBuffer();
+ temp.append("QpidJMSResponderBean received message with content: [" + content);
+ temp.append("] at " + new Date());
+
+ if(message.getJMSReplyTo() != null)
+ {
+ connection = _connectionFactory.createConnection();
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ messageProducer = session.createProducer(message.getJMSReplyTo());
+ response = session.createTextMessage();
+ response.setText(temp.toString());
+ messageProducer.send(response);
+ }
+ else
+ {
+ _log.warn("Response was requested with no JMSReplyToDestination set. Will not respond to message.");
+ }
+ }
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(session, connection);
+ }
+ }
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTest.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTest.java
new file mode 100644
index 0000000000..14488fda53
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTest.java
@@ -0,0 +1,30 @@
+/*
+ *
+ * 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.jca.example.ejb;
+
+public interface QpidTest
+{
+ public void testQpidAdapter(String content) throws Exception;
+ public void testQpidAdapter(String content, int count) throws Exception;
+ public void testQpidAdapter(String content, int count, boolean useTopic) throws Exception;
+ public void testQpidAdapter(String content, int count, boolean useTopic, boolean respond, boolean sayGoodbye) throws Exception;
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestBean.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestBean.java
new file mode 100644
index 0000000000..17e37b9475
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestBean.java
@@ -0,0 +1,123 @@
+/*
+ *
+ * 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.jca.example.ejb;
+
+import javax.annotation.PostConstruct;
+import javax.ejb.Stateless;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Stateless
+public class QpidTestBean implements QpidTestRemote, QpidTestLocal
+{
+
+ private static final Logger _log = LoggerFactory.getLogger(QpidTestBean.class);
+
+ private ConnectionFactory _connectionFactory;
+
+ private Destination _queue;
+
+ private Destination _topic;
+
+ @PostConstruct
+ public void init()
+ {
+ InitialContext context = null;
+
+ try
+ {
+ context = new InitialContext();
+ _connectionFactory = (ConnectionFactory)context.lookup("java:comp/env/QpidJMSXA");
+ _queue = (Destination)context.lookup("@qpid.hello.queue.jndi.name@");
+ _topic = (Destination)context.lookup("@qpid.hello.topic.jndi.name@");
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(context);
+ }
+
+ }
+ @Override
+ public void testQpidAdapter(String content) throws Exception
+ {
+ testQpidAdapter(content, 1);
+ }
+
+ @Override
+ public void testQpidAdapter(String content, int count) throws Exception
+ {
+ testQpidAdapter(content, count, false);
+ }
+
+ public void testQpidAdapter(final String content, int count, boolean useTopic) throws Exception
+ {
+ testQpidAdapter(content, count, useTopic, false, false);
+ }
+
+ @Override
+ public void testQpidAdapter(String content, int count, boolean useTopic,
+ boolean respond, boolean sayGoodbye) throws Exception
+ {
+ Connection connection = null;
+ Session session = null;
+ MessageProducer messageProducer = null;
+
+ _log.info("Sending " + count + " message(s) to MDB with content " + content);
+
+ try
+ {
+ connection = _connectionFactory.createConnection();
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ messageProducer = (useTopic) ? session.createProducer(_topic) : session.createProducer(_queue);
+
+ for(int i = 0; i < count; i++)
+ {
+ TextMessage message = session.createTextMessage(content);
+ message.setBooleanProperty("say.goodbye", sayGoodbye);
+ messageProducer.send(message);
+ }
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ throw e;
+ }
+ finally
+ {
+ QpidUtil.closeResources(messageProducer, session, connection);
+ }
+ }
+
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestLocal.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestLocal.java
new file mode 100644
index 0000000000..73a0de08c2
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestLocal.java
@@ -0,0 +1,29 @@
+/*
+ *
+ * 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.jca.example.ejb;
+
+import javax.ejb.Local;
+
+@Local
+public interface QpidTestLocal extends QpidTest
+{
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestRemote.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestRemote.java
new file mode 100644
index 0000000000..2abb4d71f5
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidTestRemote.java
@@ -0,0 +1,29 @@
+/*
+ *
+ * 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.jca.example.ejb;
+
+import javax.ejb.Remote;
+
+@Remote
+public interface QpidTestRemote extends QpidTest
+{
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidUtil.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidUtil.java
new file mode 100644
index 0000000000..d96a4e8163
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/ejb/QpidUtil.java
@@ -0,0 +1,90 @@
+/*
+ *
+ * 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.jca.example.ejb;
+
+import java.lang.reflect.Method;
+import java.util.Enumeration;
+
+import javax.jms.Message;
+import javax.jms.TextMessage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class QpidUtil
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidTestBean.class);
+
+ public static void handleMessage(String beanName, final Message message) throws Exception
+ {
+ if(message instanceof TextMessage)
+ {
+ String content = ((TextMessage)message).getText();
+ _log.debug(beanName + ": Received text message with contents " + content);
+
+ if(content.contains("PrintEnv"))
+ {
+ printJMSHeaders(message);
+ printProperties(message);
+ }
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static void printProperties(final Message message) throws Exception
+ {
+ _log.debug("Priting Message Properties:");
+
+ Enumeration e = message.getPropertyNames();
+
+ while(e.hasMoreElements())
+ {
+ _log.debug(e + ":" + message.getObjectProperty(e.toString()));
+ }
+ }
+
+ public static void printJMSHeaders(final Message message) throws Exception
+ {
+ _log.debug("JMSCorrelationID:" + message.getJMSCorrelationID());
+ _log.debug("JMSDeliveryMode:" + message.getJMSDeliveryMode());
+ _log.debug("JMSExpires:" + message.getJMSExpiration());
+ _log.debug("JMSMessageID:" + message.getJMSMessageID());
+ _log.debug("JMSPriority:" + message.getJMSPriority());
+ _log.debug("JMSTimestamp:" + message.getJMSTimestamp());
+ _log.debug("JMSType:" + message.getJMSType());
+ _log.debug("JMSReplyTo:" + message.getJMSReplyTo());
+ }
+
+ public static void closeResources(Object...objects)
+ {
+ try
+ {
+ for(Object object: objects)
+ {
+ Method close = object.getClass().getMethod("close", new Class[]{});
+ close.invoke(object, new Object[]{});
+ }
+ }
+ catch(Exception ignore)
+ {
+ }
+ }
+}
diff --git a/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/web/QpidTestServlet.java b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/web/QpidTestServlet.java
new file mode 100644
index 0000000000..71289b22c3
--- /dev/null
+++ b/qpid/java/jca/example/src/main/java/org/apache/qpid/jca/example/web/QpidTestServlet.java
@@ -0,0 +1,209 @@
+/*
+ *
+ * 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.jca.example.web;
+import java.io.IOException;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.InitialContext;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.transaction.UserTransaction;
+
+import org.apache.qpid.jca.example.ejb.QpidTest;
+import org.apache.qpid.jca.example.ejb.QpidUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@SuppressWarnings("serial")
+public class QpidTestServlet extends HttpServlet
+{
+ private static final Logger _log = LoggerFactory.getLogger(QpidTestServlet.class);
+
+ private static final String DEFAULT_MESSAGE = "Hello, World!";
+ private static final int DEFAULT_COUNT = 1;
+ private static final boolean DEFAULT_TOPIC = false;
+ private static final boolean DEFAULT_XA = false;
+ private static final boolean DEFAULT_SAY_GOODBYE = true;
+
+ private ConnectionFactory _connectionFactory;
+
+ private Destination _queue;
+
+ private Destination _topic;
+
+ public void init(ServletConfig config) throws ServletException
+ {
+
+ InitialContext context = null;
+
+ try
+ {
+ context = new InitialContext();
+ _connectionFactory = (ConnectionFactory)context.lookup("java:comp/env/QpidJMSXA");
+ _queue = (Destination)context.lookup("@qpid.hello.queue.jndi.name@");
+ _topic = (Destination)context.lookup("@qpid.hello.topic.jndi.name@");
+
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ throw new ServletException(e.getMessage(), e);
+ }
+ finally
+ {
+ QpidUtil.closeResources(context);
+ }
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ doPost(req, resp);
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ InitialContext ctx = null;
+ Connection connection = null;
+ Session session = null;
+ MessageProducer messageProducer = null;
+ UserTransaction ut = null;
+ boolean useXA = false;
+ boolean rollback = false;
+
+ try
+ {
+ String content = (req.getParameter("message") == null) ? DEFAULT_MESSAGE : req.getParameter("message");
+ boolean useEJB = (req.getParameter("useEJB") == null) ? false : Boolean.valueOf(req.getParameter("useEJB"));
+ int count = (req.getParameter("count") == null) ? DEFAULT_COUNT : Integer.valueOf(req.getParameter("count"));
+ boolean useTopic = (req.getParameter("useTopic") == null) ? DEFAULT_TOPIC : Boolean.valueOf(req.getParameter("useTopic"));
+ useXA = (req.getParameter("useXA") == null) ? DEFAULT_XA : Boolean.valueOf(req.getParameter("useXA"));
+ ctx = new InitialContext();
+ boolean sayGoodBye = (req.getParameter("sayGoodBye") == null) ? DEFAULT_SAY_GOODBYE : Boolean.valueOf(req.getParameter("sayGoodBye"));
+
+ _log.debug("Environment: ");
+ _log.debug("Message content: " + content);
+ _log.debug("Message count:" + count);
+ _log.debug("Protocol: " + ((useEJB) ? "EJB" : "JMS"));
+ _log.debug("Destination Type: " + ((useTopic) ? "Topic" : "Queue"));
+ _log.debug("Using XA: " + useXA);
+ _log.debug("Say GoodBye: ", sayGoodBye);
+
+ resp.getOutputStream().println("Environment: ");
+ resp.getOutputStream().println("Message content: " + content);
+ resp.getOutputStream().println("Message count:" + count);
+ resp.getOutputStream().println("Protocol: " + ((useEJB) ? "EJB" : "JMS"));
+ resp.getOutputStream().println("Destination Type: " + ((useTopic) ? "Topic" : "Queue"));
+ resp.getOutputStream().println("Using XA: " + useXA);
+ resp.getOutputStream().println("Say GoodBye: " + sayGoodBye);
+
+ if(useEJB)
+ {
+ QpidTest ejb = (QpidTest)ctx.lookup("java:comp/env/QpidTestBean");
+ ejb.testQpidAdapter(content, count, useTopic, false, sayGoodBye);
+ }
+ else
+ {
+ if(useXA)
+ {
+ ut = (UserTransaction)ctx.lookup("java:comp/UserTransaction");
+ ut.begin();
+ }
+
+ connection = _connectionFactory.createConnection();
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ messageProducer = (useTopic) ? session.createProducer(_topic) : session.createProducer(_queue);
+
+ for(int i = 0; i < count; i++)
+ {
+ TextMessage message = session.createTextMessage(content);
+ message.setBooleanProperty("say.goodbye", sayGoodBye);
+ messageProducer.send(message);
+ }
+
+ }
+
+ resp.getOutputStream().println("Sent " + count + " messages with content '" + content + "'");
+ resp.getOutputStream().flush();
+
+ }
+ catch(Exception e)
+ {
+
+ if(useXA && ut != null)
+ {
+ try
+ {
+ rollback = true;
+ ut.setRollbackOnly();
+ }
+ catch(Exception ex)
+ {
+ _log.error(ex.getMessage(), ex);
+ throw new ServletException(ex.getMessage(), ex);
+ }
+ }
+
+ _log.error(e.getMessage(), e);
+ throw new ServletException(e.getMessage(), e);
+ }
+ finally
+ {
+ if(useXA && ut != null)
+ {
+ try
+ {
+ if(rollback)
+ {
+ ut.rollback();
+ }
+ else
+ {
+ ut.commit();
+ }
+ }
+ catch(Exception e)
+ {
+ _log.error(e.getMessage(), e);
+ throw new ServletException(e.getMessage(), e);
+
+ }
+ }
+
+ QpidUtil.closeResources(session, connection, ctx);
+ }
+ }
+
+
+
+}
+
+
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryObjectFactory.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryObjectFactory.java
new file mode 100644
index 0000000000..2dc94ed194
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryProperties.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/ConnectionFactoryProperties.java
new file mode 100644
index 0000000000..be129a67cc
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRABytesMessage.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRABytesMessage.java
new file mode 100644
index 0000000000..d30a45c739
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactory.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactory.java
new file mode 100644
index 0000000000..1e8fb13c79
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactoryImpl.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionFactoryImpl.java
new file mode 100644
index 0000000000..77a38d5b34
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionManager.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionManager.java
new file mode 100644
index 0000000000..7ba5dd5374
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionMetaData.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionMetaData.java
new file mode 100644
index 0000000000..ec14c2a492
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionMetaData.java
@@ -0,0 +1,208 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+
+import javax.jms.ConnectionMetaData;
+
+import org.apache.qpid.client.CustomJMSXProperty;
+import org.apache.qpid.common.QpidProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class implements javax.jms.ConnectionMetaData
+ *
+ */
+public class QpidRAConnectionMetaData implements ConnectionMetaData
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAConnectionMetaData.class);
+
+ private static final String PROVIDER_VERSION ;
+ private static final int PROVIDER_MAJOR ;
+ private static final int PROVIDER_MINOR ;
+ private static final String[] JMSX_PROPERTY_NAMES ;
+
+ /**
+ * Constructor
+ */
+ public QpidRAConnectionMetaData()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+ }
+
+ /**
+ * Get the JMS version
+ * @return The version
+ */
+ public String getJMSVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSVersion()");
+ }
+
+ return "1.1";
+ }
+
+ /**
+ * Get the JMS major version
+ * @return The major version
+ */
+ public int getJMSMajorVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSMajorVersion()");
+ }
+
+ return 1;
+ }
+
+ /**
+ * Get the JMS minor version
+ * @return The minor version
+ */
+ public int getJMSMinorVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSMinorVersion()");
+ }
+
+ return 1;
+ }
+
+ /**
+ * Get the JMS provider name
+ * @return The name
+ */
+ public String getJMSProviderName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getJMSProviderName()");
+ }
+
+ return QpidProperties.getProductName() + " Resource Adapter" ;
+ }
+
+ /**
+ * Get the provider version
+ * @return The version
+ */
+ public String getProviderVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getProviderVersion()");
+ }
+
+ return PROVIDER_VERSION ;
+ }
+
+ /**
+ * Get the provider major version
+ * @return The version
+ */
+ public int getProviderMajorVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getProviderMajorVersion()");
+ }
+
+ return PROVIDER_MAJOR ;
+ }
+
+ /**
+ * Get the provider minor version
+ * @return The version
+ */
+ public int getProviderMinorVersion()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getProviderMinorVersion()");
+ }
+
+ return PROVIDER_MINOR ;
+ }
+
+ /**
+ * Get the JMS XPropertyNames
+ * @return The names
+ */
+ public Enumeration<String> getJMSXPropertyNames()
+ {
+ // Bug in CustomJMSXProperty.asEnumeration() so we handle this here
+ return Collections.enumeration(Arrays.asList(JMSX_PROPERTY_NAMES)) ;
+ }
+
+ static
+ {
+ final String version = QpidProperties.getReleaseVersion() ;
+ int major = -1 ;
+ int minor = -1 ;
+ if (version != null)
+ {
+ final int separator = version.indexOf('.') ;
+ if (separator != -1)
+ {
+ major = parseInt(version.substring(0, separator), "major") ;
+ minor = parseInt(version.substring(separator+1, version.length()), "minor") ;
+ }
+ }
+ PROVIDER_VERSION = version ;
+ PROVIDER_MAJOR = major ;
+ PROVIDER_MINOR = minor ;
+
+ final CustomJMSXProperty[] properties = CustomJMSXProperty.values();
+ final String[] names = new String[properties.length] ;
+ int count = 0 ;
+ for(CustomJMSXProperty property : properties)
+ {
+ names[count++] = property.toString() ;
+ }
+ JMSX_PROPERTY_NAMES = names ;
+ }
+
+ private static int parseInt(final String value, final String name)
+ {
+ try
+ {
+ return Integer.parseInt(value) ;
+ }
+ catch (final NumberFormatException nfe)
+ {
+ _log.warn("Failed to parse " + name + ": " + value) ;
+ return -1 ;
+ }
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionRequestInfo.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAConnectionRequestInfo.java
new file mode 100644
index 0000000000..c37a264ebc
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRACredential.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRACredential.java
new file mode 100644
index 0000000000..2b42f9dc3d
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRACredential.java
@@ -0,0 +1,245 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra;
+
+import java.io.Serializable;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Set;
+
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.resource.spi.SecurityException;
+import javax.resource.spi.security.PasswordCredential;
+import javax.security.auth.Subject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Credential information
+ *
+ */
+public class QpidRACredential implements Serializable
+{
+ /** Serial version UID */
+ private static final long serialVersionUID = 7040664839205409352L;
+
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRACredential.class);
+
+ /** The user name */
+ private String _userName;
+
+ /** The password */
+ private String _password;
+
+ /**
+ * Private constructor
+ */
+ private QpidRACredential()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+ }
+
+ /**
+ * Get the user name
+ * @return The value
+ */
+ public String getUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUserName()");
+ }
+
+ return _userName;
+ }
+
+ /**
+ * Set the user name
+ * @param userName The value
+ */
+ private void setUserName(final String userName)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUserName(" + userName + ")");
+ }
+
+ this._userName = userName;
+ }
+
+ /**
+ * Get the password
+ * @return The value
+ */
+ public String getPassword()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPassword()");
+ }
+
+ return _password;
+ }
+
+ /**
+ * Set the password
+ * @param password The value
+ */
+ private void setPassword(final String password)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPassword(****)");
+ }
+
+ this._password = password;
+ }
+
+ /**
+ * Get credentials
+ * @param mcf The managed connection factory
+ * @param subject The subject
+ * @param info The connection request info
+ * @return The credentials
+ * @exception SecurityException Thrown if the credentials cant be retrieved
+ */
+ public static QpidRACredential getCredential(final ManagedConnectionFactory mcf,
+ final Subject subject,
+ final ConnectionRequestInfo info) throws SecurityException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getCredential(" + mcf + ", " + subject + ", " + info + ")");
+ }
+
+ QpidRACredential jc = new QpidRACredential();
+ if (subject == null && info != null)
+ {
+ jc.setUserName(((QpidRAConnectionRequestInfo)info).getUserName());
+ jc.setPassword(((QpidRAConnectionRequestInfo)info).getPassword());
+ }
+ else if (subject != null)
+ {
+ PasswordCredential pwdc = GetCredentialAction.getCredential(subject, mcf);
+
+ if (pwdc == null)
+ {
+ throw new SecurityException("No password credentials found");
+ }
+
+ jc.setUserName(pwdc.getUserName());
+ jc.setPassword(new String(pwdc.getPassword()));
+ }
+ else
+ {
+ throw new SecurityException("No Subject or ConnectionRequestInfo set, could not get credentials");
+ }
+
+ return jc;
+ }
+
+ /**
+ * String representation
+ * @return The representation
+ */
+ @Override
+ public String toString()
+ {
+ return super.toString() + "{ username=" + _userName + ", password=**** }";
+ }
+
+ /**
+ * Privileged class to get credentials
+ */
+ private static class GetCredentialAction implements PrivilegedAction<PasswordCredential>
+ {
+ /** The subject */
+ private final Subject subject;
+
+ /** The managed connection factory */
+ private final ManagedConnectionFactory mcf;
+
+ /**
+ * Constructor
+ * @param subject The subject
+ * @param mcf The managed connection factory
+ */
+ GetCredentialAction(final Subject subject, final ManagedConnectionFactory mcf)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + subject + ", " + mcf + ")");
+ }
+
+ this.subject = subject;
+ this.mcf = mcf;
+ }
+
+ /**
+ * Run
+ * @return The credential
+ */
+ public PasswordCredential run()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("run()");
+ }
+
+ Set<PasswordCredential> creds = subject.getPrivateCredentials(PasswordCredential.class);
+ PasswordCredential pwdc = null;
+
+ for (PasswordCredential curCred : creds)
+ {
+ if (curCred.getManagedConnectionFactory().equals(mcf))
+ {
+ pwdc = curCred;
+ break;
+ }
+ }
+ return pwdc;
+ }
+
+ /**
+ * Get credentials
+ * @param subject The subject
+ * @param mcf The managed connection factory
+ * @return The credential
+ */
+ static PasswordCredential getCredential(final Subject subject, final ManagedConnectionFactory mcf)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getCredential(" + subject + ", " + mcf + ")");
+ }
+
+ GetCredentialAction action = new GetCredentialAction(subject, mcf);
+ return AccessController.doPrivileged(action);
+ }
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAException.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAException.java
new file mode 100644
index 0000000000..9c070f6184
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRALocalTransaction.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRALocalTransaction.java
new file mode 100644
index 0000000000..eeb49b6b52
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMCFProperties.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMCFProperties.java
new file mode 100644
index 0000000000..dd60c175de
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java
new file mode 100644
index 0000000000..fb1b7f060c
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java
@@ -0,0 +1,880 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.jms.Connection;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.ResourceAllocationException;
+import javax.jms.Session;
+import javax.jms.QueueConnection;
+import javax.jms.TopicConnection;
+import javax.jms.XAQueueConnection;
+import javax.jms.XASession;
+import javax.jms.XATopicConnection;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionEvent;
+import javax.resource.spi.ConnectionEventListener;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.IllegalStateException;
+import javax.resource.spi.LocalTransaction;
+import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.ManagedConnectionMetaData;
+import javax.resource.spi.SecurityException;
+import javax.security.auth.Subject;
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAResource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The managed connection
+ *
+ */
+public class QpidRAManagedConnection implements ManagedConnection, ExceptionListener
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAManagedConnection.class);
+
+ /** The managed connection factory */
+ private final QpidRAManagedConnectionFactory _mcf;
+
+ /** The connection request information */
+ private final QpidRAConnectionRequestInfo _cri;
+
+ /** The user name */
+ private final String _userName;
+
+ /** The password */
+ private final String _password;
+
+ /** Has the connection been destroyed */
+ private final AtomicBoolean _isDestroyed = new AtomicBoolean(false);
+
+ /** Event listeners */
+ private final List<ConnectionEventListener> _eventListeners;
+
+ /** Handles */
+ private final Set<QpidRASessionImpl> _handles;
+
+ /** Lock */
+ private ReentrantLock _lock = new ReentrantLock();
+
+ // Physical JMS connection stuff
+ private Connection _connection;
+
+ private XASession _xaSession;
+
+ private XAResource _xaResource;
+
+ private Session _session;
+
+ private final TransactionManager _tm;
+
+ private boolean _inManagedTx;
+
+ /**
+ * Constructor
+ * @param mcf The managed connection factory
+ * @param cri The connection request information
+ * @param userName The user name
+ * @param password The password
+ */
+ public QpidRAManagedConnection(final QpidRAManagedConnectionFactory mcf,
+ final QpidRAConnectionRequestInfo cri,
+ final TransactionManager tm,
+ final String userName,
+ final String password) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + mcf + ", " + cri + ", " + userName + ", ****)");
+ }
+
+ this._mcf = mcf;
+ this._cri = cri;
+ this._tm = tm;
+ this._userName = userName;
+ this._password = password;
+ _eventListeners = Collections.synchronizedList(new ArrayList<ConnectionEventListener>());
+ _handles = Collections.synchronizedSet(new HashSet<QpidRASessionImpl>());
+
+ try
+ {
+ setup();
+ }
+ catch (Throwable t)
+ {
+ try
+ {
+ destroy();
+ }
+ catch (Throwable ignored)
+ {
+ }
+ throw new ResourceException("Error during setup", t);
+ }
+ }
+
+ /**
+ * Get a connection
+ * @param subject The security subject
+ * @param cxRequestInfo The request info
+ * @return The connection
+ * @exception ResourceException Thrown if an error occurs
+ */
+ public synchronized Object getConnection(final Subject subject, final ConnectionRequestInfo cxRequestInfo) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getConnection(" + subject + ", " + cxRequestInfo + ")");
+ }
+
+ // Check user first
+ QpidRACredential credential = QpidRACredential.getCredential(_mcf, subject, cxRequestInfo);
+
+ // Null users are allowed!
+ if (_userName != null && !_userName.equals(credential.getUserName()))
+ {
+ throw new SecurityException("Password credentials not the same, reauthentication not allowed");
+ }
+
+ if (_userName == null && credential.getUserName() != null)
+ {
+ throw new SecurityException("Password credentials not the same, reauthentication not allowed");
+ }
+
+ if (_isDestroyed.get())
+ {
+ throw new IllegalStateException("The managed connection is already destroyed");
+ }
+
+ QpidRASessionImpl session = new QpidRASessionImpl(this, (QpidRAConnectionRequestInfo)cxRequestInfo);
+ _handles.add(session);
+ return session;
+ }
+
+ /**
+ * Destroy all handles.
+ * @exception ResourceException Failed to close one or more handles.
+ */
+ private void destroyHandles() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("destroyHandles()");
+ }
+
+ try
+ {
+ if (_connection != null)
+ {
+ _connection.stop();
+ }
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Ignored error stopping connection", t);
+ }
+
+ for (QpidRASessionImpl session : _handles)
+ {
+ session.destroy();
+ }
+
+ _handles.clear();
+ }
+
+ /**
+ * Destroy the physical connection.
+ * @exception ResourceException Could not property close the session and connection.
+ */
+ public void destroy() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("destroy()");
+ }
+
+ if (_isDestroyed.get() || _connection == null)
+ {
+ return;
+ }
+
+ _isDestroyed.set(true);
+
+ try
+ {
+ _connection.setExceptionListener(null);
+ }
+ catch (JMSException e)
+ {
+ _log.debug("Error unsetting the exception listener " + this, e);
+ }
+
+ destroyHandles();
+
+ try
+ {
+ try
+ {
+ if (_xaSession != null)
+ {
+ _xaSession.close();
+ }
+ }
+ catch (JMSException e)
+ {
+ _log.debug("Error closing session " + this, e);
+ }
+
+ if (_connection != null)
+ {
+ _connection.close();
+ }
+ }
+ catch (Throwable e)
+ {
+ throw new ResourceException("Could not properly close the session and connection", e);
+ }
+ }
+
+ /**
+ * Cleanup
+ * @exception ResourceException Thrown if an error occurs
+ */
+ public void cleanup() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("cleanup()");
+ }
+
+ if (_isDestroyed.get())
+ {
+ throw new IllegalStateException("ManagedConnection already destroyed");
+ }
+
+ destroyHandles();
+
+ _inManagedTx = false;
+
+ // I'm recreating the lock object when we return to the pool
+ // because it looks too nasty to expect the connection handle
+ // to unlock properly in certain race conditions
+ // where the dissociation of the managed connection is "random".
+ _lock = new ReentrantLock();
+ }
+
+ /**
+ * Move a handler from one mc to this one.
+ * @param obj An object of type QpidRASession.
+ * @throws ResourceException Failed to associate connection.
+ * @throws IllegalStateException ManagedConnection in an illegal state.
+ */
+ public void associateConnection(final Object obj) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("associateConnection(" + obj + ")");
+ }
+
+ if (!_isDestroyed.get() && obj instanceof QpidRASessionImpl)
+ {
+ QpidRASessionImpl h = (QpidRASessionImpl)obj;
+ h.setManagedConnection(this);
+ _handles.add(h);
+ }
+ else
+ {
+ throw new IllegalStateException("ManagedConnection in an illegal state");
+ }
+ }
+
+ public void checkTransactionActive() throws JMSException
+ {
+ // don't bother looking at the transaction if there's an active XID
+ if (!_inManagedTx && _tm != null)
+ {
+ try
+ {
+ Transaction tx = _tm.getTransaction();
+ if (tx != null)
+ {
+ int status = tx.getStatus();
+ // Only allow states that will actually succeed
+ if (status != Status.STATUS_ACTIVE && status != Status.STATUS_PREPARING &&
+ status != Status.STATUS_PREPARED &&
+ status != Status.STATUS_COMMITTING)
+ {
+ throw new javax.jms.IllegalStateException("Transaction " + tx + " not active");
+ }
+ }
+ }
+ catch (SystemException e)
+ {
+ JMSException jmsE = new javax.jms.IllegalStateException("Unexpected exception on the Transaction ManagerTransaction");
+ jmsE.initCause(e);
+ throw jmsE;
+ }
+ }
+ }
+
+
+ /**
+ * Aqquire a lock on the managed connection
+ */
+ protected void lock()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("lock()");
+ }
+
+ _lock.lock();
+ }
+
+ /**
+ * Aqquire a lock on the managed connection within the specified period
+ * @exception JMSException Thrown if an error occurs
+ */
+ protected void tryLock() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("tryLock()");
+ }
+
+ Integer tryLock = _mcf.getUseTryLock();
+ if (tryLock == null || tryLock.intValue() <= 0)
+ {
+ lock();
+ return;
+ }
+ try
+ {
+ if (_lock.tryLock(tryLock.intValue(), TimeUnit.SECONDS) == false)
+ {
+ throw new ResourceAllocationException("Unable to obtain lock in " + tryLock + " seconds: " + this);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ throw new ResourceAllocationException("Interrupted attempting lock: " + this);
+ }
+ }
+
+ /**
+ * Unlock the managed connection
+ */
+ protected void unlock()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("unlock()");
+ }
+
+ if (_lock.isHeldByCurrentThread())
+ {
+ _lock.unlock();
+ }
+ }
+
+ /**
+ * Add a connection event listener.
+ * @param l The connection event listener to be added.
+ */
+ public void addConnectionEventListener(final ConnectionEventListener l)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addConnectionEventListener(" + l + ")");
+ }
+
+ _eventListeners.add(l);
+ }
+
+ /**
+ * Remove a connection event listener.
+ * @param l The connection event listener to be removed.
+ */
+ public void removeConnectionEventListener(final ConnectionEventListener l)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("removeConnectionEventListener(" + l + ")");
+ }
+
+ _eventListeners.remove(l);
+ }
+
+ /**
+ * Get the XAResource for the connection.
+ * @return The XAResource for the connection.
+ * @exception ResourceException XA transaction not supported
+ */
+ public XAResource getXAResource() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getXAResource()");
+ }
+
+ //
+ // Spec says a mc must allways return the same XA resource,
+ // so we cache it.
+ //
+ if (_xaResource == null)
+ {
+ _xaResource = new QpidRAXAResource(this, _xaSession.getXAResource());
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("XAResource=" + _xaResource);
+ }
+
+ return _xaResource;
+ }
+
+ /**
+ * Get the location transaction for the connection.
+ * @return The local transaction for the connection.
+ * @exception ResourceException Thrown if operation fails.
+ */
+ public LocalTransaction getLocalTransaction() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getLocalTransaction()");
+ }
+
+ LocalTransaction tx = new QpidRALocalTransaction(this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("LocalTransaction=" + tx);
+ }
+
+ return tx;
+ }
+
+ /**
+ * Get the meta data for the connection.
+ * @return The meta data for the connection.
+ * @exception ResourceException Thrown if the operation fails.
+ * @exception IllegalStateException Thrown if the managed connection already is destroyed.
+ */
+ public ManagedConnectionMetaData getMetaData() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMetaData()");
+ }
+
+ if (_isDestroyed.get())
+ {
+ throw new IllegalStateException("The managed connection is already destroyed");
+ }
+
+ return new QpidRAMetaData(this);
+ }
+
+ /**
+ * Set the log writer -- NOT SUPPORTED
+ * @param out The log writer
+ * @exception ResourceException If operation fails
+ */
+ public void setLogWriter(final PrintWriter out) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setLogWriter(" + out + ")");
+ }
+ }
+
+ /**
+ * Get the log writer -- NOT SUPPORTED
+ * @return Always null
+ * @exception ResourceException If operation fails
+ */
+ public PrintWriter getLogWriter() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getLogWriter()");
+ }
+
+ return null;
+ }
+
+ /**
+ * Notifies user of a JMS exception.
+ * @param exception The JMS exception
+ */
+ public void onException(final JMSException exception)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("onException(" + exception + ")");
+ }
+
+ if (_isDestroyed.get())
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Ignoring error on already destroyed connection " + this, exception);
+ }
+ return;
+ }
+
+ _log.warn("Handling JMS exception failure: " + this, exception);
+
+ try
+ {
+ _connection.setExceptionListener(null);
+ }
+ catch (JMSException e)
+ {
+ _log.debug("Unable to unset exception listener", e);
+ }
+
+ ConnectionEvent event = new ConnectionEvent(this, ConnectionEvent.CONNECTION_ERROR_OCCURRED, exception);
+ sendEvent(event);
+ }
+
+ /**
+ * Get the session for this connection.
+ * @return The session
+ * @throws JMSException
+ */
+ protected Session getSession() throws JMSException
+ {
+ if(_xaSession != null && !_mcf.getUseLocalTx())
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSession() -> XA session " + Util.asString(_xaSession));
+ }
+
+ return _xaSession;
+ }
+ else
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSession() -> session " + Util.asString(_session));
+ }
+
+ return _session;
+ }
+ }
+
+ /**
+ * Send an event.
+ * @param event The event to send.
+ */
+ protected void sendEvent(final ConnectionEvent event)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("sendEvent(" + event + ")");
+ }
+
+ int type = event.getId();
+
+ // convert to an array to avoid concurrent modification exceptions
+ ConnectionEventListener[] list = _eventListeners.toArray(new ConnectionEventListener[_eventListeners.size()]);
+
+ for (ConnectionEventListener l : list)
+ {
+ switch (type)
+ {
+ case ConnectionEvent.CONNECTION_CLOSED:
+ l.connectionClosed(event);
+ break;
+
+ case ConnectionEvent.LOCAL_TRANSACTION_STARTED:
+ l.localTransactionStarted(event);
+ break;
+
+ case ConnectionEvent.LOCAL_TRANSACTION_COMMITTED:
+ l.localTransactionCommitted(event);
+ break;
+
+ case ConnectionEvent.LOCAL_TRANSACTION_ROLLEDBACK:
+ l.localTransactionRolledback(event);
+ break;
+
+ case ConnectionEvent.CONNECTION_ERROR_OCCURRED:
+ l.connectionErrorOccurred(event);
+ break;
+
+ default:
+ throw new IllegalArgumentException("Illegal eventType: " + type);
+ }
+ }
+ }
+
+ /**
+ * Remove a handle from the handle map.
+ * @param handle The handle to remove.
+ */
+ protected void removeHandle(final QpidRASessionImpl handle)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("removeHandle(" + handle + ")");
+ }
+
+ _handles.remove(handle);
+ }
+
+ /**
+ * Get the request info for this connection.
+ * @return The connection request info for this connection.
+ */
+ protected QpidRAConnectionRequestInfo getCRI()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getCRI()");
+ }
+
+ return _cri;
+ }
+
+ /**
+ * Get the connection factory for this connection.
+ * @return The connection factory for this connection.
+ */
+ protected QpidRAManagedConnectionFactory getManagedConnectionFactory()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getManagedConnectionFactory()");
+ }
+
+ return _mcf;
+ }
+
+ /**
+ * Start the connection
+ * @exception JMSException Thrown if the connection cant be started
+ */
+ void start() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start()");
+ }
+
+ if (_connection != null)
+ {
+ _connection.start();
+ }
+ }
+
+ /**
+ * Stop the connection
+ * @exception JMSException Thrown if the connection cant be stopped
+ */
+ void stop() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("stop()");
+ }
+
+ if (_connection != null)
+ {
+ _connection.stop();
+ }
+ }
+
+ /**
+ * Get the user name
+ * @return The user name
+ */
+ protected String getUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUserName()");
+ }
+
+ return _userName;
+ }
+
+ /**
+ * Setup the connection.
+ * @exception ResourceException Thrown if a connection couldnt be created
+ */
+ private void setup() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setup()");
+ }
+
+ try
+ {
+ boolean transacted = _cri.isTransacted();
+ int acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+ boolean localTx = _mcf.getUseLocalTx();
+
+ if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
+ {
+ if (_userName != null && _password != null)
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createXATopicConnection(_userName, _password);
+ }
+ else
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createTopicConnection();
+ }
+ }
+ else
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createXATopicConnection();
+ }
+ else
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createTopicConnection();
+ }
+ }
+
+ if(!localTx)
+ {
+ _xaSession = ((XATopicConnection)_connection).createXATopicSession();
+
+ }
+ else
+ {
+ _session = ((TopicConnection)_connection).createTopicSession(localTx, acknowledgeMode);
+ }
+ }
+ else if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION)
+ {
+ if (_userName != null && _password != null)
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createXAQueueConnection(_userName, _password);
+ }
+ else
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createQueueConnection();
+ }
+ }
+ else
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createXAQueueConnection();
+ }
+ else
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createQueueConnection();
+ }
+ }
+
+ if(!localTx)
+ {
+ _xaSession = ((XAQueueConnection)_connection).createXAQueueSession();
+
+ }
+ else
+ {
+ _session = ((QueueConnection)_connection).createQueueSession(localTx, acknowledgeMode);
+
+ }
+ }
+ else
+ {
+ if (_userName != null && _password != null)
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createXAConnection(_userName, _password);
+ }
+ else
+ {
+ _connection = _mcf.getCleanAMQConnectionFactory().createConnection();
+ }
+ }
+ else
+ {
+ if(!localTx)
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createXAConnection();
+ }
+ else
+ {
+ _connection = _mcf.getDefaultAMQConnectionFactory().createConnection();
+ }
+ }
+
+ if(!localTx)
+ {
+ _xaSession = ((XAQueueConnection)_connection).createXASession();
+
+ }
+ else
+ {
+ _session = ((QueueConnection)_connection).createSession(localTx, acknowledgeMode);
+
+ }
+ }
+
+ _connection.setExceptionListener(this);
+ }
+ catch (JMSException je)
+ {
+ throw new ResourceException(je.getMessage(), je);
+ }
+ }
+
+ protected void setInManagedTx(boolean inManagedTx)
+ {
+ this._inManagedTx = inManagedTx;
+ }
+
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnectionFactory.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnectionFactory.java
new file mode 100644
index 0000000000..377a0c6253
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnectionFactory.java
@@ -0,0 +1,623 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra;
+
+import java.io.PrintWriter;
+import java.util.Set;
+
+import javax.jms.ConnectionMetaData;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionManager;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.resource.spi.ResourceAdapter;
+import javax.resource.spi.ResourceAdapterAssociation;
+import javax.security.auth.Subject;
+
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Qpid ManagedConectionFactory
+ *
+ */
+public class QpidRAManagedConnectionFactory implements ManagedConnectionFactory, ResourceAdapterAssociation
+{
+ /**
+ * Serial version UID
+ */
+ private static final long serialVersionUID = -8798804592247643959L;
+
+ /**
+ * The logger
+ */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRAManagedConnectionFactory.class);
+
+ /**
+ * The resource adapter
+ */
+ private QpidResourceAdapter _ra;
+
+ /**
+ * Connection manager
+ */
+ private ConnectionManager _cm;
+
+ /**
+ * The managed connection factory properties
+ */
+ private final QpidRAMCFProperties _mcfProperties;
+
+ /**
+ * Connection Factory used if properties are set
+ */
+ private AMQConnectionFactory _connectionFactory;
+
+ /**
+ * Constructor
+ */
+ public QpidRAManagedConnectionFactory()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+
+ _ra = null;
+ _cm = null;
+ _mcfProperties = new QpidRAMCFProperties();
+ }
+
+ /**
+ * Creates a Connection Factory instance
+ *
+ * @return javax.resource.cci.ConnectionFactory instance
+ * @throws ResourceException Thrown if a connection factory cant be created
+ */
+ public Object createConnectionFactory() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionFactory()");
+ }
+
+ return createConnectionFactory(new QpidRAConnectionManager());
+ }
+
+ /**
+ * Creates a Connection Factory instance
+ *
+ * @param cxManager The connection manager
+ * @return javax.resource.cci.ConnectionFactory instance
+ * @throws ResourceException Thrown if a connection factory cant be created
+ */
+ public Object createConnectionFactory(final ConnectionManager cxManager) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionFactory(" + cxManager + ")");
+ }
+
+ _cm = cxManager;
+
+ QpidRAConnectionFactory cf = new QpidRAConnectionFactoryImpl(this, _cm);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Created connection factory: " + cf +
+ ", using connection manager: " +
+ _cm);
+ }
+
+ return cf;
+ }
+
+ /**
+ * Creates a new physical connection to the underlying EIS resource manager.
+ *
+ * @param subject Caller's security information
+ * @param cxRequestInfo Additional resource adapter specific connection request information
+ * @return The managed connection
+ * @throws ResourceException Thrown if a managed connection cant be created
+ */
+ public ManagedConnection createManagedConnection(final Subject subject, final ConnectionRequestInfo cxRequestInfo) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createManagedConnection(" + subject + ", " + cxRequestInfo + ")");
+ }
+
+ QpidRAConnectionRequestInfo cri = getCRI((QpidRAConnectionRequestInfo)cxRequestInfo);
+
+ QpidRACredential credential = QpidRACredential.getCredential(this, subject, cri);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("jms credential: " + credential);
+ }
+
+ QpidRAManagedConnection mc = new QpidRAManagedConnection(this,
+ cri,
+ _ra.getTM(),
+ credential.getUserName(),
+ credential.getPassword());
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("created new managed connection: " + mc);
+ }
+
+ return mc;
+ }
+
+ /**
+ * Returns a matched connection from the candidate set of connections.
+ *
+ * @param connectionSet The candidate connection set
+ * @param subject Caller's security information
+ * @param cxRequestInfo Additional resource adapter specific connection request information
+ * @return The managed connection
+ * @throws ResourceException Thrown if no managed connection can be found
+ */
+ @SuppressWarnings("rawtypes")
+ public ManagedConnection matchManagedConnections(final Set connectionSet,
+ final Subject subject,
+ final ConnectionRequestInfo cxRequestInfo) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("matchManagedConnections(" + connectionSet +
+ ", " +
+ subject +
+ ", " +
+ cxRequestInfo +
+ ")");
+ }
+
+ QpidRAConnectionRequestInfo cri = getCRI((QpidRAConnectionRequestInfo)cxRequestInfo);
+ QpidRACredential credential = QpidRACredential.getCredential(this, subject, cri);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Looking for connection matching credentials: " + credential);
+ }
+
+ for (final Object obj : connectionSet)
+ {
+ if (obj instanceof QpidRAManagedConnection)
+ {
+ QpidRAManagedConnection mc = (QpidRAManagedConnection)obj;
+ ManagedConnectionFactory mcf = mc.getManagedConnectionFactory();
+
+ if ((mc.getUserName() == null || mc.getUserName() != null && mc.getUserName()
+ .equals(credential.getUserName())) && mcf.equals(this))
+ {
+ if (cri.equals(mc.getCRI()))
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Found matching connection: " + mc);
+ }
+
+ return mc;
+ }
+ }
+ }
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("No matching connection was found");
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the log writer -- NOT SUPPORTED
+ *
+ * @param out The writer
+ * @throws ResourceException Thrown if the writer cant be set
+ */
+ public void setLogWriter(final PrintWriter out) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setLogWriter(" + out + ")");
+ }
+ }
+
+ /**
+ * Get the log writer -- NOT SUPPORTED
+ *
+ * @return The writer
+ * @throws ResourceException Thrown if the writer cant be retrieved
+ */
+ public PrintWriter getLogWriter() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getLogWriter()");
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the resource adapter
+ *
+ * @return The resource adapter
+ */
+ public ResourceAdapter getResourceAdapter()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getResourceAdapter()");
+ }
+
+ return _ra;
+ }
+
+ /**
+ * Set the resource adapter
+ *
+ * @param ra The resource adapter
+ * @throws ResourceException Thrown if incorrect resource adapter
+ */
+ public void setResourceAdapter(final ResourceAdapter ra) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setResourceAdapter(" + ra + ")");
+ }
+
+ if (!(ra instanceof QpidResourceAdapter))
+ {
+ throw new ResourceException("Resource adapter is " + ra);
+ }
+
+ this._ra = (QpidResourceAdapter)ra;
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this one.
+ *
+ * @param obj Object with which to compare
+ * @return True if this object is the same as the obj argument; false otherwise.
+ */
+ @Override
+ public boolean equals(final Object obj)
+ {
+ if (obj instanceof QpidRAManagedConnectionFactory)
+ {
+ QpidRAManagedConnectionFactory other = (QpidRAManagedConnectionFactory)obj;
+
+ return _mcfProperties.equals(other.getProperties()) && _ra.equals(other.getResourceAdapter());
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Return the hash code for the object
+ *
+ * @return The hash code
+ */
+ @Override
+ public int hashCode()
+ {
+ int hash = _mcfProperties.hashCode();
+ hash += 31 * _ra.hashCode();
+
+ return hash;
+ }
+
+ /**
+ * Get the default session type
+ *
+ * @return The value
+ */
+ public String getSessionDefaultType()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSessionDefaultType()");
+ }
+
+ return _mcfProperties.getSessionDefaultType();
+ }
+
+ /**
+ * Set the default session type
+ *
+ * @param type either javax.jms.Topic or javax.jms.Queue
+ */
+ public void setSessionDefaultType(final String type)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSessionDefaultType(" + type + ")");
+ }
+
+ _mcfProperties.setSessionDefaultType(type);
+ }
+
+ public String getClientID()
+ {
+ return _mcfProperties.getClientId();
+ }
+
+ public void setClientID(final String clientID)
+ {
+ _mcfProperties.setClientId(clientID);
+ }
+
+ public String getConnectionURL()
+ {
+ return _mcfProperties.getConnectionURL() ;
+ }
+
+ public void setConnectionURL(final String connectionURL)
+ {
+ _mcfProperties.setConnectionURL(connectionURL);
+ }
+
+ public String getPassword()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDefaultPassword()");
+ }
+ return _mcfProperties.getPassword();
+ }
+
+ public void setPassword(final String defaultPassword)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDefaultPassword(" + defaultPassword + ")");
+ }
+ _mcfProperties.setPassword(defaultPassword);
+ }
+
+ public String getUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getDefaultUsername()");
+ }
+ return _mcfProperties.getUserName();
+ }
+
+ public void setUserName(final String defaultUsername)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setDefaultUsername(" + defaultUsername + ")");
+ }
+ _mcfProperties.setUserName(defaultUsername);
+ }
+
+ public String getHost()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getHost()");
+ }
+ return _mcfProperties.getHost();
+ }
+
+ public void setHost(final String host)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setHost(" + host + ")");
+ }
+ _mcfProperties.setHost(host);
+ }
+
+ public Integer getPort()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPort()");
+ }
+ return _mcfProperties.getPort();
+ }
+
+ public void setPort(final Integer port)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPort(" + port + ")");
+ }
+ _mcfProperties.setPort(port);
+ }
+
+ public String getPath()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPath()");
+ }
+ return _mcfProperties.getPath();
+ }
+
+ public void setPath(final String path)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPath(" + path + ")");
+ }
+ _mcfProperties.setPath(path);
+ }
+
+ /**
+ * Get the useTryLock.
+ *
+ * @return the useTryLock.
+ */
+ public Integer getUseTryLock()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUseTryLock()");
+ }
+
+ return _mcfProperties.getUseTryLock();
+ }
+
+ /**
+ * Set the useTryLock.
+ *
+ * @param useTryLock the useTryLock.
+ */
+ public void setUseTryLock(final Integer useTryLock)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUseTryLock(" + useTryLock + ")");
+ }
+
+ _mcfProperties.setUseTryLock(useTryLock);
+ }
+
+ /**
+ * Get the connection metadata
+ *
+ * @return The metadata
+ */
+ public ConnectionMetaData getMetaData()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMetadata()");
+ }
+
+ return new QpidRAConnectionMetaData();
+ }
+
+ /**
+ * Get the default connection factory
+ *
+ * @return The factory
+ */
+ protected synchronized AMQConnectionFactory getDefaultAMQConnectionFactory() throws ResourceException
+ {
+ if (_connectionFactory == null)
+ {
+ try
+ {
+ _connectionFactory = _ra.createAMQConnectionFactory(_mcfProperties);
+ }
+ catch (final QpidRAException qpidrae)
+ {
+ throw new ResourceException("Unexpected exception creating the connection factory", qpidrae) ;
+ }
+ }
+ return _connectionFactory;
+ }
+
+ /**
+ * Get a clean connection factory
+ *
+ * @return The factory
+ */
+ protected AMQConnectionFactory getCleanAMQConnectionFactory() throws ResourceException
+ {
+ try
+ {
+ return _ra.createAMQConnectionFactory(_mcfProperties);
+ }
+ catch (final QpidRAException qpidrae)
+ {
+ throw new ResourceException("Unexpected exception creating the connection factory", qpidrae) ;
+ }
+ }
+
+ /**
+ * Get the managed connection factory properties
+ *
+ * @return The properties
+ */
+ protected QpidRAMCFProperties getProperties()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getProperties()");
+ }
+
+ return _mcfProperties;
+ }
+
+ /**
+ * Get a connection request info instance
+ *
+ * @param info The instance that should be updated; may be <code>null</code>
+ * @return The instance
+ * @throws ResourceException
+ */
+ private QpidRAConnectionRequestInfo getCRI(final QpidRAConnectionRequestInfo info)
+ throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getCRI(" + info + ")");
+ }
+
+ if (info == null)
+ {
+ // Create a default one
+ return new QpidRAConnectionRequestInfo(_ra, _mcfProperties.getType());
+ }
+ else
+ {
+ // Fill the one with any defaults
+ info.setDefaults(_ra);
+ return info;
+ }
+ }
+
+ public Boolean getUseLocalTx()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUseLocalTx()");
+ }
+
+ return _mcfProperties.isUseLocalTx();
+ }
+
+ public void setUseLocalTx(final Boolean localTx)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUseLocalTx(" + localTx + ")");
+ }
+
+ _mcfProperties.setUseLocalTx(localTx);
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMapMessage.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMapMessage.java
new file mode 100644
index 0000000000..797a28a09a
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java
new file mode 100644
index 0000000000..691fe8c40a
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageConsumer.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageConsumer.java
new file mode 100644
index 0000000000..aa0e6adb0e
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageListener.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageListener.java
new file mode 100644
index 0000000000..e272df818f
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageProducer.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessageProducer.java
new file mode 100644
index 0000000000..ce0656e30d
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMetaData.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMetaData.java
new file mode 100644
index 0000000000..0ad7d089c3
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAObjectMessage.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAObjectMessage.java
new file mode 100644
index 0000000000..926319bb85
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAProperties.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAProperties.java
new file mode 100644
index 0000000000..21f7d2574f
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueBrowser.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueBrowser.java
new file mode 100644
index 0000000000..bcd2d3b63c
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueReceiver.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueReceiver.java
new file mode 100644
index 0000000000..ad1f7fc43b
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueSender.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAQueueSender.java
new file mode 100644
index 0000000000..7a123618be
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASession.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASession.java
new file mode 100644
index 0000000000..081677ca4b
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactory.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactory.java
new file mode 100644
index 0000000000..cf28d5bba1
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactoryImpl.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactoryImpl.java
new file mode 100644
index 0000000000..e2bc2d2008
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionFactoryImpl.java
@@ -0,0 +1,911 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.jms.ConnectionConsumer;
+import javax.jms.ConnectionMetaData;
+import javax.jms.Destination;
+import javax.jms.ExceptionListener;
+import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.QueueSession;
+import javax.jms.ServerSessionPool;
+import javax.jms.Session;
+import javax.jms.TemporaryQueue;
+import javax.jms.TemporaryTopic;
+import javax.jms.Topic;
+import javax.jms.TopicSession;
+import javax.jms.XAQueueSession;
+import javax.jms.XASession;
+import javax.jms.XATopicSession;
+import javax.naming.Reference;
+import javax.resource.Referenceable;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implements the JMS Connection API and produces {@link QpidRASessionImpl} objects.
+ *
+ */
+public class QpidRASessionFactoryImpl implements QpidRASessionFactory, Referenceable
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRASessionFactoryImpl.class);
+
+ /** Are we closed? */
+ private boolean _closed = false;
+
+ /** The naming reference */
+ private Reference _reference;
+
+ /** The user name */
+ private String _userName;
+
+ /** The password */
+ private String _password;
+
+ /** The client ID */
+ private String _clientID;
+
+ /** The connection type */
+ private final int _type;
+
+ /** Whether we are started */
+ private boolean _started = false;
+
+ /** The managed connection factory */
+ private final QpidRAManagedConnectionFactory _mcf;
+
+ /** The connection manager */
+ private ConnectionManager _cm;
+
+ /** The sessions */
+ private final Set<QpidRASession> _sessions = new HashSet<QpidRASession>();
+
+ /** The temporary queues */
+ private final Set<TemporaryQueue> _tempQueues = new HashSet<TemporaryQueue>();
+
+ /** The temporary topics */
+ private final Set<TemporaryTopic> _tempTopics = new HashSet<TemporaryTopic>();
+
+ /**
+ * Constructor
+ * @param mcf The managed connection factory
+ * @param cm The connection manager
+ * @param type The connection type
+ */
+ public QpidRASessionFactoryImpl(final QpidRAManagedConnectionFactory mcf,
+ final ConnectionManager cm,
+ final int type)
+ {
+ this._mcf = mcf;
+
+ if (cm == null)
+ {
+ this._cm = new QpidRAConnectionManager();
+ }
+ else
+ {
+ this._cm = cm;
+ }
+
+ this._type = type;
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + mcf + ", " + cm + ", " + type);
+ }
+ }
+
+ /**
+ * Set the naming reference
+ * @param reference The reference
+ */
+ public void setReference(final Reference reference)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setReference(" + reference + ")");
+ }
+
+ this._reference = reference;
+ }
+
+ /**
+ * Get the naming reference
+ * @return The reference
+ */
+ public Reference getReference()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getReference()");
+ }
+
+ return _reference;
+ }
+
+ /**
+ * Set the user name
+ * @param name The user name
+ */
+ public void setUserName(final String name)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUserName(" + name + ")");
+ }
+
+ _userName = name;
+ }
+
+ /**
+ * Set the password
+ * @param password The password
+ */
+ public void setPassword(final String password)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPassword(****)");
+ }
+
+ this._password = password;
+ }
+
+ /**
+ * Get the client ID
+ * @return The client ID
+ * @exception JMSException Thrown if an error occurs
+ */
+ public String getClientID() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getClientID()");
+ }
+
+ checkClosed();
+
+ if (_clientID == null)
+ {
+ try
+ {
+ return _mcf.getDefaultAMQConnectionFactory().getConnectionURL().getClientName() ;
+ }
+ catch (final ResourceException re)
+ {
+ final JMSException jmse = new JMSException("Unexpected exception obtaining resource") ;
+ jmse.initCause(re) ;
+ throw jmse ;
+ }
+ }
+
+ return _clientID;
+ }
+
+ /**
+ * Set the client ID -- throws IllegalStateException
+ * @param cID The client ID
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setClientID(final String cID) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setClientID(" + cID + ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a queue session
+ * @param transacted Use transactions
+ * @param acknowledgeMode The acknowledge mode
+ * @return The queue session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueSession createQueueSession(final boolean transacted, final int acknowledgeMode) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createQueueSession(" + transacted + ", " + acknowledgeMode + ")");
+ }
+
+ checkClosed();
+
+ if (_type == QpidRAConnectionFactory.TOPIC_CONNECTION || _type == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Can not get a queue session from a topic connection");
+ }
+
+ return (QueueSession)allocateConnection(transacted, acknowledgeMode, _type);
+ }
+
+ /**
+ * Create a XA queue session
+ * @return The XA queue session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public XAQueueSession createXAQueueSession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXAQueueSession()");
+ }
+
+ checkClosed();
+
+ if (_type == QpidRAConnectionFactory.CONNECTION || _type == QpidRAConnectionFactory.TOPIC_CONNECTION ||
+ _type == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Can not get a topic session from a queue connection");
+ }
+
+ return (XAQueueSession) allocateConnection(_type);
+ }
+
+ /**
+ * Create a connection consumer -- throws IllegalStateException
+ * @param queue The queue
+ * @param messageSelector The message selector
+ * @param sessionPool The session pool
+ * @param maxMessages The number of max messages
+ * @return The connection consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionConsumer createConnectionConsumer(final Queue queue,
+ final String messageSelector,
+ final ServerSessionPool sessionPool,
+ final int maxMessages) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionConsumer(" + queue +
+ ", " +
+ messageSelector +
+ ", " +
+ sessionPool +
+ ", " +
+ maxMessages +
+ ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a topic session
+ * @param transacted Use transactions
+ * @param acknowledgeMode The acknowledge mode
+ * @return The topic session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSession createTopicSession(final boolean transacted, final int acknowledgeMode) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTopicSession(" + transacted + ", " + acknowledgeMode + ")");
+ }
+
+ checkClosed();
+
+ if (_type == QpidRAConnectionFactory.QUEUE_CONNECTION || _type == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Can not get a topic session from a queue connection");
+ }
+
+ return (TopicSession) allocateConnection(transacted, acknowledgeMode, _type);
+ }
+
+ /**
+ * Create a XA topic session
+ * @return The XA topic session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public XATopicSession createXATopicSession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXATopicSession()");
+ }
+
+ checkClosed();
+
+ if (_type == QpidRAConnectionFactory.CONNECTION || _type == QpidRAConnectionFactory.QUEUE_CONNECTION ||
+ _type == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Can not get a topic session from a queue connection");
+ }
+
+ return (XATopicSession) allocateConnection(_type);
+ }
+
+ /**
+ * Create a connection consumer -- throws IllegalStateException
+ * @param topic The topic
+ * @param messageSelector The message selector
+ * @param sessionPool The session pool
+ * @param maxMessages The number of max messages
+ * @return The connection consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionConsumer createConnectionConsumer(final Topic topic,
+ final String messageSelector,
+ final ServerSessionPool sessionPool,
+ final int maxMessages) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionConsumer(" + topic +
+ ", " +
+ messageSelector +
+ ", " +
+ sessionPool +
+ ", " +
+ maxMessages +
+ ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a durable connection consumer -- throws IllegalStateException
+ * @param topic The topic
+ * @param subscriptionName The subscription name
+ * @param messageSelector The message selector
+ * @param sessionPool The session pool
+ * @param maxMessages The number of max messages
+ * @return The connection consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionConsumer createDurableConnectionConsumer(final Topic topic,
+ final String subscriptionName,
+ final String messageSelector,
+ final ServerSessionPool sessionPool,
+ final int maxMessages) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionConsumer(" + topic +
+ ", " +
+ subscriptionName +
+ ", " +
+ messageSelector +
+ ", " +
+ sessionPool +
+ ", " +
+ maxMessages +
+ ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a connection consumer -- throws IllegalStateException
+ * @param destination The destination
+ * @param pool The session pool
+ * @param maxMessages The number of max messages
+ * @return The connection consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionConsumer createConnectionConsumer(final Destination destination,
+ final ServerSessionPool pool,
+ final int maxMessages) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionConsumer(" + destination +
+ ", " +
+ pool +
+ ", " +
+ maxMessages +
+ ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a connection consumer -- throws IllegalStateException
+ * @param destination The destination
+ * @param name The name
+ * @param pool The session pool
+ * @param maxMessages The number of max messages
+ * @return The connection consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionConsumer createConnectionConsumer(final Destination destination,
+ final String name,
+ final ServerSessionPool pool,
+ final int maxMessages) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConnectionConsumer(" + destination +
+ ", " +
+ name +
+ ", " +
+ pool +
+ ", " +
+ maxMessages +
+ ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Create a session
+ * @param transacted Use transactions
+ * @param acknowledgeMode The acknowledge mode
+ * @return The session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Session createSession(final boolean transacted, final int acknowledgeMode) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createSession(" + transacted + ", " + acknowledgeMode + ")");
+ }
+
+ checkClosed();
+ return (Session) allocateConnection(transacted, acknowledgeMode, _type);
+ }
+
+ /**
+ * Create a XA session
+ * @return The XA session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public XASession createXASession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createXASession()");
+ }
+
+ checkClosed();
+ return (XASession) allocateConnection(_type);
+ }
+
+ /**
+ * Get the connection metadata
+ * @return The connection metadata
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ConnectionMetaData getMetaData() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMetaData()");
+ }
+
+ checkClosed();
+ return _mcf.getMetaData();
+ }
+
+ /**
+ * Get the exception listener -- throws IllegalStateException
+ * @return The exception listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ExceptionListener getExceptionListener() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getExceptionListener()");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Set the exception listener -- throws IllegalStateException
+ * @param listener The exception listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setExceptionListener(final ExceptionListener listener) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setExceptionListener(" + listener + ")");
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Start
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void start() throws JMSException
+ {
+ checkClosed();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start() " + this);
+ }
+
+ synchronized (_sessions)
+ {
+ if (_started)
+ {
+ return;
+ }
+ _started = true;
+ for (Iterator<QpidRASession> i = _sessions.iterator(); i.hasNext();)
+ {
+ QpidRASessionImpl session = (QpidRASessionImpl)i.next();
+ session.start();
+ }
+ }
+ }
+
+ /**
+ * Stop -- throws IllegalStateException
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void stop() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("stop() " + this);
+ }
+
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+
+ /**
+ * Close
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void close() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("close() " + this);
+ }
+
+ if (_closed)
+ {
+ return;
+ }
+
+ _closed = true;
+
+ synchronized (_sessions)
+ {
+ for (Iterator<QpidRASession> i = _sessions.iterator(); i.hasNext();)
+ {
+ QpidRASessionImpl session = (QpidRASessionImpl)i.next();
+ try
+ {
+ session.closeSession();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error closing session", t);
+ }
+ i.remove();
+ }
+ }
+
+ synchronized (_tempQueues)
+ {
+ for (Iterator<TemporaryQueue> i = _tempQueues.iterator(); i.hasNext();)
+ {
+ TemporaryQueue temp = (TemporaryQueue)i.next();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Closing temporary queue " + temp + " for " + this);
+ }
+ temp.delete();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error deleting temporary queue", t);
+ }
+ i.remove();
+ }
+ }
+
+ synchronized (_tempTopics)
+ {
+ for (Iterator<TemporaryTopic> i = _tempTopics.iterator(); i.hasNext();)
+ {
+ TemporaryTopic temp = (TemporaryTopic)i.next();
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Closing temporary topic " + temp + " for " + this);
+ }
+ temp.delete();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error deleting temporary queue", t);
+ }
+ i.remove();
+ }
+ }
+ }
+
+ /**
+ * Close session
+ * @param session The session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void closeSession(final QpidRASessionImpl session) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("closeSession(" + session + ")");
+ }
+
+ synchronized (_sessions)
+ {
+ _sessions.remove(session);
+ }
+ }
+
+ /**
+ * Add temporary queue
+ * @param temp The temporary queue
+ */
+ public void addTemporaryQueue(final TemporaryQueue temp)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addTemporaryQueue(" + temp + ")");
+ }
+
+ synchronized (_tempQueues)
+ {
+ _tempQueues.add(temp);
+ }
+ }
+
+ /**
+ * Add temporary topic
+ * @param temp The temporary topic
+ */
+ public void addTemporaryTopic(final TemporaryTopic temp)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addTemporaryTopic(" + temp + ")");
+ }
+
+ synchronized (_tempTopics)
+ {
+ _tempTopics.add(temp);
+ }
+ }
+
+ /**
+ * Allocation a connection
+ * @param sessionType The session type
+ * @return The session
+ * @exception JMSException Thrown if an error occurs
+ */
+ protected QpidRASession allocateConnection(final int sessionType) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("allocateConnection(" + sessionType + ")");
+ }
+
+ try
+ {
+ synchronized (_sessions)
+ {
+ if (_sessions.isEmpty() == false)
+ {
+ throw new IllegalStateException("Only allowed one session per connection. See the J2EE spec, e.g. J2EE1.4 Section 6.6");
+ }
+
+ QpidRAConnectionRequestInfo info = new QpidRAConnectionRequestInfo(sessionType);
+ info.setUserName(_userName);
+ info.setPassword(_password);
+ info.setClientID(_clientID);
+ info.setDefaults(_mcf.getDefaultAMQConnectionFactory().getConnectionURL());
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Allocating session for " + this + " with request info=" + info);
+ }
+
+ QpidRASession session = (QpidRASession)_cm.allocateConnection(_mcf, info);
+
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Allocated " + this + " session=" + session);
+ }
+
+ session.setQpidSessionFactory(this);
+
+ if (_started)
+ {
+ session.start();
+ }
+
+ _sessions.add(session);
+
+ return session;
+ }
+ catch (Throwable t)
+ {
+ try
+ {
+ session.close();
+ }
+ catch (Throwable ignored)
+ {
+ }
+ if (t instanceof Exception)
+ {
+ throw (Exception)t;
+ }
+ else
+ {
+ throw new RuntimeException("Unexpected error: ", t);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ _log.error("Could not create session", e);
+
+ JMSException je = new JMSException("Could not create a session: " + e.getMessage());
+ je.setLinkedException(e);
+ throw je;
+ }
+ }
+
+ /**
+ * Allocation a connection
+ * @param transacted Use transactions
+ * @param acknowledgeMode The acknowledge mode
+ * @param sessionType The session type
+ * @return The session
+ * @exception JMSException Thrown if an error occurs
+ */
+ protected QpidRASession allocateConnection(final boolean transacted, int acknowledgeMode, final int sessionType) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("allocateConnection(" + transacted +
+ ", " +
+ acknowledgeMode +
+ ", " +
+ sessionType +
+ ")");
+ }
+
+ try
+ {
+ synchronized (_sessions)
+ {
+ if (_sessions.isEmpty() == false)
+ {
+ throw new IllegalStateException("Only allowed one session per connection. See the J2EE spec, e.g. J2EE1.4 Section 6.6");
+ }
+
+ if (transacted)
+ {
+ acknowledgeMode = Session.SESSION_TRANSACTED;
+ }
+
+ QpidRAConnectionRequestInfo info = new QpidRAConnectionRequestInfo(transacted,
+ acknowledgeMode,
+ sessionType);
+ info.setUserName(_userName);
+ info.setPassword(_password);
+ info.setClientID(_clientID);
+ info.setDefaults(_mcf.getDefaultAMQConnectionFactory().getConnectionURL());
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Allocating session for " + this + " with request info=" + info);
+ }
+
+ QpidRASession session = (QpidRASession)_cm.allocateConnection(_mcf, info);
+
+ try
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Allocated " + this + " session=" + session);
+ }
+
+ session.setQpidSessionFactory(this);
+
+ if (_started)
+ {
+ session.start();
+ }
+
+ _sessions.add(session);
+
+ return session;
+ }
+ catch (Throwable t)
+ {
+ try
+ {
+ session.close();
+ }
+ catch (Throwable ignored)
+ {
+ }
+ if (t instanceof Exception)
+ {
+ throw (Exception)t;
+ }
+ else
+ {
+ throw new RuntimeException("Unexpected error: ", t);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ _log.error("Could not create session", e);
+
+ JMSException je = new JMSException("Could not create a session: " + e.getMessage());
+ je.setLinkedException(e);
+ throw je;
+ }
+ }
+
+ /**
+ * Check if we are closed
+ * @exception IllegalStateException Thrown if closed
+ */
+ protected void checkClosed() throws IllegalStateException
+ {
+ if (_closed)
+ {
+ throw new IllegalStateException("The connection is closed");
+ }
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java
new file mode 100644
index 0000000000..a270253c13
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java
@@ -0,0 +1,1732 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.ra;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jms.BytesMessage;
+import javax.jms.Destination;
+import javax.jms.IllegalStateException;
+import javax.jms.InvalidDestinationException;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+import javax.jms.QueueReceiver;
+import javax.jms.QueueSender;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.StreamMessage;
+import javax.jms.TemporaryQueue;
+import javax.jms.TemporaryTopic;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.jms.TopicPublisher;
+import javax.jms.TopicSession;
+import javax.jms.TopicSubscriber;
+import javax.jms.TransactionInProgressException;
+import javax.jms.XAQueueSession;
+import javax.jms.XASession;
+import javax.jms.XATopicSession;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionEvent;
+import javax.resource.spi.ManagedConnection;
+import javax.transaction.xa.XAResource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A joint interface for JMS sessions
+ *
+ */
+public class QpidRASessionImpl implements Session, QueueSession, TopicSession, XASession, XAQueueSession, XATopicSession, QpidRASession
+{
+ /** The logger */
+ private static final Logger _log = LoggerFactory.getLogger(QpidRASessionImpl.class);
+
+ /** The managed connection */
+ private volatile QpidRAManagedConnection _mc;
+ /** The locked managed connection */
+ private QpidRAManagedConnection _lockedMC;
+
+ /** The connection request info */
+ private final QpidRAConnectionRequestInfo _cri;
+
+ /** The session factory */
+ private QpidRASessionFactory _sf;
+
+ /** The message consumers */
+ private final Set<MessageConsumer> _consumers;
+
+ /** The message producers */
+ private final Set<MessageProducer> _producers;
+
+ /** The queue browsers */
+ private final Set<QueueBrowser> _browsers;
+
+ /** Are we started */
+ private AtomicBoolean _started = new AtomicBoolean(false) ;
+
+ /**
+ * Constructor
+ * @param mc The managed connection
+ * @param cri The connection request info
+ */
+ public QpidRASessionImpl(final QpidRAManagedConnection mc, final QpidRAConnectionRequestInfo cri)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + mc + ", " + cri + ")");
+ }
+
+ this._mc = mc;
+ this._cri = cri;
+ _sf = null;
+ _consumers = new HashSet<MessageConsumer>();
+ _producers = new HashSet<MessageProducer>();
+ _browsers = new HashSet<QueueBrowser>();
+ }
+
+ /**
+ * Set the session factory
+ * @param sf The session factory
+ */
+ public void setQpidSessionFactory(final QpidRASessionFactory sf)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setQpidSessionFactory(" + sf + ")");
+ }
+
+ _started.set(false) ;
+ this._sf = sf;
+ }
+
+ /**
+ * Lock
+ * @exception JMSException Thrown if an error occurs
+ * @exception IllegalStateException The session is closed
+ */
+ protected void lock() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("lock()");
+ }
+
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ mc.tryLock();
+ _lockedMC = mc ;
+ }
+ else
+ {
+ throw new IllegalStateException("Connection is not associated with a managed connection. " + this);
+ }
+ }
+
+ /**
+ * Unlock
+ */
+ protected void unlock()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("unlock()");
+ }
+
+ if (_lockedMC != null)
+ {
+ try
+ {
+ _lockedMC.unlock();
+ }
+ finally
+ {
+ _lockedMC = null ;
+ }
+ }
+
+ // We recreate the lock when returned to the pool
+ // so missing the unlock after disassociation is not important
+ }
+
+ /**
+ * Create a bytes message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public BytesMessage createBytesMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createBytesMessage" + Util.asString(session));
+ }
+
+ return session.createBytesMessage();
+ }
+
+ /**
+ * Create a map message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MapMessage createMapMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createMapMessage" + Util.asString(session));
+ }
+
+ return session.createMapMessage();
+ }
+
+ /**
+ * Create a message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Message createMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createMessage" + Util.asString(session));
+ }
+
+ return session.createMessage();
+ }
+
+ /**
+ * Create an object message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ObjectMessage createObjectMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createObjectMessage" + Util.asString(session));
+ }
+
+ return session.createObjectMessage();
+ }
+
+ /**
+ * Create an object message
+ * @param object The object
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public ObjectMessage createObjectMessage(final Serializable object) throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createObjectMessage(" + object + ")" + Util.asString(session));
+ }
+
+ return session.createObjectMessage(object);
+ }
+
+ /**
+ * Create a stream message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public StreamMessage createStreamMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createStreamMessage" + Util.asString(session));
+ }
+
+ return session.createStreamMessage();
+ }
+
+ /**
+ * Create a text message
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TextMessage createTextMessage() throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTextMessage" + Util.asString(session));
+ }
+
+ return session.createTextMessage();
+ }
+
+ /**
+ * Create a text message
+ * @param string The text
+ * @return The message
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TextMessage createTextMessage(final String string) throws JMSException
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTextMessage(" + string + ")" + Util.asString(session));
+ }
+
+ return session.createTextMessage(string);
+ }
+
+ /**
+ * Get transacted
+ * @return True if transacted; otherwise false
+ * @exception JMSException Thrown if an error occurs
+ */
+ public boolean getTransacted() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransacted()");
+ }
+
+ getSessionInternal();
+ return _cri.isTransacted();
+ }
+
+ /**
+ * Get the message listener -- throws IllegalStateException
+ * @return The message listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageListener getMessageListener() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMessageListener()");
+ }
+
+ throw new IllegalStateException("Method not allowed");
+ }
+
+ /**
+ * Set the message listener -- Throws IllegalStateException
+ * @param listener The message listener
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void setMessageListener(final MessageListener listener) throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setMessageListener(" + listener + ")");
+ }
+
+ throw new IllegalStateException("Method not allowed");
+ }
+
+ /**
+ * Always throws an Error.
+ * @exception Error Method not allowed.
+ */
+ public void run()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("run()");
+ }
+
+ throw new Error("Method not allowed");
+ }
+
+ /**
+ * Closes the session. Sends a ConnectionEvent.CONNECTION_CLOSED to the
+ * managed connection.
+ * @exception JMSException Failed to close session.
+ */
+ public void close() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("close()");
+ }
+
+ _sf.closeSession(this);
+ closeSession();
+ }
+
+ /**
+ * Commit
+ * @exception JMSException Failed to close session.
+ */
+ public void commit() throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.XA_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new TransactionInProgressException("XA connection");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_cri.isTransacted() == false)
+ {
+ throw new IllegalStateException("Session is not transacted");
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Commit session " + this);
+ }
+
+ session.commit();
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Rollback
+ * @exception JMSException Failed to close session.
+ */
+ public void rollback() throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.XA_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new TransactionInProgressException("XA connection");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_cri.isTransacted() == false)
+ {
+ throw new IllegalStateException("Session is not transacted");
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Rollback session " + this);
+ }
+
+ session.rollback();
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Recover
+ * @exception JMSException Failed to close session.
+ */
+ public void recover() throws JMSException
+ {
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_cri.isTransacted())
+ {
+ throw new IllegalStateException("Session is transacted");
+ }
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("Recover session " + this);
+ }
+
+ session.recover();
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a topic
+ * @param topicName The topic name
+ * @return The topic
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Topic createTopic(final String topicName) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create topic for javax.jms.QueueSession");
+ }
+
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTopic " + Util.asString(session) + " topicName=" + topicName);
+ }
+
+ Topic result = session.createTopic(topicName);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdTopic " + Util.asString(session) + " topic=" + result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Create a topic subscriber
+ * @param topic The topic
+ * @return The subscriber
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSubscriber createSubscriber(final Topic topic) throws JMSException
+ {
+ lock();
+ try
+ {
+ TopicSession session = getTopicSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createSubscriber " + Util.asString(session) + " topic=" + topic);
+ }
+
+ TopicSubscriber result = session.createSubscriber(topic);
+ result = new QpidRATopicSubscriber(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdSubscriber " + Util.asString(session) + " QpidRATopicSubscriber=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a topic subscriber
+ * @param topic The topic
+ * @param messageSelector The message selector
+ * @param noLocal If true inhibits the delivery of messages published by its own connection
+ * @return The subscriber
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSubscriber createSubscriber(final Topic topic, final String messageSelector, final boolean noLocal) throws JMSException
+ {
+ lock();
+ try
+ {
+ TopicSession session = getTopicSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createSubscriber " + Util.asString(session) +
+ " topic=" +
+ topic +
+ " selector=" +
+ messageSelector +
+ " noLocal=" +
+ noLocal);
+ }
+
+ TopicSubscriber result = session.createSubscriber(topic, messageSelector, noLocal);
+ result = new QpidRATopicSubscriber(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdSubscriber " + Util.asString(session) + " QpidRATopicSubscriber=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a durable topic subscriber
+ * @param topic The topic
+ * @param name The name
+ * @return The subscriber
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSubscriber createDurableSubscriber(final Topic topic, final String name) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create durable subscriber from javax.jms.QueueSession");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createDurableSubscriber " + Util.asString(session) + " topic=" + topic + " name=" + name);
+ }
+
+ TopicSubscriber result = session.createDurableSubscriber(topic, name);
+ result = new QpidRATopicSubscriber(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdDurableSubscriber " + Util.asString(session) + " QpidRATopicSubscriber=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a topic subscriber
+ * @param topic The topic
+ * @param name The name
+ * @param messageSelector The message selector
+ * @param noLocal If true inhibits the delivery of messages published by its own connection
+ * @return The subscriber
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSubscriber createDurableSubscriber(final Topic topic,
+ final String name,
+ final String messageSelector,
+ final boolean noLocal) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create durable subscriber from javax.jms.QueueSession");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createDurableSubscriber " + Util.asString(session) +
+ " topic=" +
+ topic +
+ " name=" +
+ name +
+ " selector=" +
+ messageSelector +
+ " noLocal=" +
+ noLocal);
+ }
+
+ TopicSubscriber result = session.createDurableSubscriber(topic, name, messageSelector, noLocal);
+ result = new QpidRATopicSubscriber(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdDurableSubscriber " + Util.asString(session) + " QpidRATopicSubscriber=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a topic publisher
+ * @param topic The topic
+ * @return The publisher
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicPublisher createPublisher(final Topic topic) throws JMSException
+ {
+ lock();
+ try
+ {
+ TopicSession session = getTopicSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createPublisher " + Util.asString(session) + " topic=" + topic);
+ }
+
+ TopicPublisher result = session.createPublisher(topic);
+ result = new QpidRATopicPublisher(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdPublisher " + Util.asString(session) + " publisher=" + result);
+ }
+
+ addProducer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a temporary topic
+ * @return The temporary topic
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TemporaryTopic createTemporaryTopic() throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create temporary topic for javax.jms.QueueSession");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTemporaryTopic " + Util.asString(session));
+ }
+
+ TemporaryTopic temp = session.createTemporaryTopic();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdTemporaryTopic " + Util.asString(session) + " temp=" + temp);
+ }
+
+ _sf.addTemporaryTopic(temp);
+
+ return temp;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Unsubscribe
+ * @param name The name
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void unsubscribe(final String name) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_QUEUE_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot unsubscribe for javax.jms.QueueSession");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("unsubscribe " + Util.asString(session) + " name=" + name);
+ }
+
+ session.unsubscribe(name);
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a browser
+ * @param queue The queue
+ * @return The browser
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueBrowser createBrowser(final Queue queue) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create browser for javax.jms.TopicSession");
+ }
+
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createBrowser " + Util.asString(session) + " queue=" + queue);
+ }
+
+ QueueBrowser result = session.createBrowser(queue);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdBrowser " + Util.asString(session) + " browser=" + result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Create a browser
+ * @param queue The queue
+ * @param messageSelector The message selector
+ * @return The browser
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueBrowser createBrowser(final Queue queue, final String messageSelector) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create browser for javax.jms.TopicSession");
+ }
+
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createBrowser " + Util.asString(session) + " queue=" + queue + " selector=" + messageSelector);
+ }
+
+ QueueBrowser result = session.createBrowser(queue, messageSelector);
+ result = new QpidRAQueueBrowser(result, this);
+ addQueueBrowser(result) ;
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdBrowser " + Util.asString(session) + " browser=" + result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Create a queue
+ * @param queueName The queue name
+ * @return The queue
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Queue createQueue(final String queueName) throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create browser or javax.jms.TopicSession");
+ }
+
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createQueue " + Util.asString(session) + " queueName=" + queueName);
+ }
+
+ Queue result = session.createQueue(queueName);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdQueue " + Util.asString(session) + " queue=" + result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Create a queue receiver
+ * @param queue The queue
+ * @return The queue receiver
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueReceiver createReceiver(final Queue queue) throws JMSException
+ {
+ lock();
+ try
+ {
+ QueueSession session = getQueueSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createReceiver " + Util.asString(session) + " queue=" + queue);
+ }
+
+ QueueReceiver result = session.createReceiver(queue);
+ result = new QpidRAQueueReceiver(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdReceiver " + Util.asString(session) + " receiver=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a queue receiver
+ * @param queue The queue
+ * @param messageSelector
+ * @return The queue receiver
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueReceiver createReceiver(final Queue queue, final String messageSelector) throws JMSException
+ {
+ lock();
+ try
+ {
+ QueueSession session = getQueueSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createReceiver " + Util.asString(session) + " queue=" + queue + " selector=" + messageSelector);
+ }
+
+ QueueReceiver result = session.createReceiver(queue, messageSelector);
+ result = new QpidRAQueueReceiver(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdReceiver " + Util.asString(session) + " receiver=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a queue sender
+ * @param queue The queue
+ * @return The queue sender
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueSender createSender(final Queue queue) throws JMSException
+ {
+ lock();
+ try
+ {
+ QueueSession session = getQueueSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createSender " + Util.asString(session) + " queue=" + queue);
+ }
+
+ QueueSender result = session.createSender(queue);
+ result = new QpidRAQueueSender(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdSender " + Util.asString(session) + " sender=" + result);
+ }
+
+ addProducer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a temporary queue
+ * @return The temporary queue
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TemporaryQueue createTemporaryQueue() throws JMSException
+ {
+ if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION || _cri.getType() == QpidRAConnectionFactory.XA_TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Cannot create temporary queue for javax.jms.TopicSession");
+ }
+
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createTemporaryQueue " + Util.asString(session));
+ }
+
+ TemporaryQueue temp = session.createTemporaryQueue();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdTemporaryQueue " + Util.asString(session) + " temp=" + temp);
+ }
+
+ _sf.addTemporaryQueue(temp);
+
+ return temp;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a message consumer
+ * @param destination The destination
+ * @return The message consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageConsumer createConsumer(final Destination destination) throws JMSException
+ {
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConsumer " + Util.asString(session) + " dest=" + destination);
+ }
+
+ MessageConsumer result = session.createConsumer(destination);
+ result = new QpidRAMessageConsumer(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdConsumer " + Util.asString(session) + " consumer=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a message consumer
+ * @param destination The destination
+ * @param messageSelector The message selector
+ * @return The message consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageConsumer createConsumer(final Destination destination, final String messageSelector) throws JMSException
+ {
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConsumer " + Util.asString(session) +
+ " dest=" +
+ destination +
+ " messageSelector=" +
+ messageSelector);
+ }
+
+ MessageConsumer result = session.createConsumer(destination, messageSelector);
+ result = new QpidRAMessageConsumer(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdConsumer " + Util.asString(session) + " consumer=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a message consumer
+ * @param destination The destination
+ * @param messageSelector The message selector
+ * @param noLocal If true inhibits the delivery of messages published by its own connection
+ * @return The message consumer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageConsumer createConsumer(final Destination destination,
+ final String messageSelector,
+ final boolean noLocal) throws JMSException
+ {
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createConsumer " + Util.asString(session) +
+ " dest=" +
+ destination +
+ " messageSelector=" +
+ messageSelector +
+ " noLocal=" +
+ noLocal);
+ }
+
+ MessageConsumer result = session.createConsumer(destination, messageSelector, noLocal);
+ result = new QpidRAMessageConsumer(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdConsumer " + Util.asString(session) + " consumer=" + result);
+ }
+
+ addConsumer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Create a message producer
+ * @param destination The destination
+ * @return The message producer
+ * @exception JMSException Thrown if an error occurs
+ */
+ public MessageProducer createProducer(final Destination destination) throws JMSException
+ {
+ lock();
+ try
+ {
+ Session session = getSessionInternal();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createProducer " + Util.asString(session) + " dest=" + destination);
+ }
+
+ MessageProducer result = session.createProducer(destination);
+ result = new QpidRAMessageProducer(result, this);
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("createdProducer " + Util.asString(session) + " producer=" + result);
+ }
+
+ addProducer(result);
+
+ return result;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Get the acknowledge mode
+ * @return The mode
+ * @exception JMSException Thrown if an error occurs
+ */
+ public int getAcknowledgeMode() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getAcknowledgeMode()");
+ }
+
+ getSessionInternal();
+ return _cri.getAcknowledgeMode();
+ }
+
+ /**
+ * Get the XA resource
+ * @return The XA resource
+ * @exception IllegalStateException If non XA connection
+ */
+ public XAResource getXAResource()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getXAResource()");
+ }
+
+ if (_cri.getType() == QpidRAConnectionFactory.CONNECTION || _cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
+ {
+ return null;
+ }
+
+ try
+ {
+ lock();
+
+ return getXAResourceInternal();
+ }
+ catch (Throwable t)
+ {
+ return null;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Get the session
+ * @return The session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public Session getSession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSession()");
+ }
+
+ if (_cri.getType() == QpidRAConnectionFactory.CONNECTION || _cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Non XA connection");
+ }
+
+ lock();
+ try
+ {
+ return this;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Get the queue session
+ * @return The queue session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public QueueSession getQueueSession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getQueueSession()");
+ }
+
+ if (_cri.getType() == QpidRAConnectionFactory.CONNECTION || _cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Non XA connection");
+ }
+
+ lock();
+ try
+ {
+ return this;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Get the topic session
+ * @return The topic session
+ * @exception JMSException Thrown if an error occurs
+ */
+ public TopicSession getTopicSession() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTopicSession()");
+ }
+
+ if (_cri.getType() == QpidRAConnectionFactory.CONNECTION || _cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION ||
+ _cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
+ {
+ throw new IllegalStateException("Non XA connection");
+ }
+
+ lock();
+ try
+ {
+ return this;
+ }
+ finally
+ {
+ unlock();
+ }
+ }
+
+ /**
+ * Set the managed connection
+ * @param managedConnection The managed connection
+ */
+ void setManagedConnection(final QpidRAManagedConnection managedConnection)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setManagedConnection(" + managedConnection + ")");
+ }
+
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ mc.removeHandle(this);
+ }
+
+ this._mc = managedConnection;
+ }
+
+ /** for tests only */
+ public ManagedConnection getManagedConnection()
+ {
+ return _mc;
+ }
+
+ /**
+ * Destroy
+ */
+ void destroy()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("destroy()");
+ }
+
+ _mc = null;
+ }
+
+ /**
+ * Start
+ * @exception JMSException Thrown if an error occurs
+ */
+ public void start() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start()");
+ }
+
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ _started.set(true) ;
+ mc.start();
+ }
+ }
+
+ /**
+ * Stop
+ * @exception JMSException Thrown if an error occurs
+ */
+ void stop() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("stop()");
+ }
+
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ mc.stop();
+ _started.set(false) ;
+ }
+ }
+
+ /**
+ * Check strict
+ * @exception JMSException Thrown if an error occurs
+ */
+ void checkStrict() throws JMSException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("checkStrict()");
+ }
+
+ if (_mc != null)
+ {
+ throw new IllegalStateException(QpidRASessionFactory.ISE);
+ }
+ }
+
+ /**
+ * Close session
+ * @exception JMSException Thrown if an error occurs
+ */
+ void closeSession() throws JMSException
+ {
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ _log.trace("Closing session");
+
+ try
+ {
+ mc.stop();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error stopping managed connection", t);
+ }
+
+ synchronized (_consumers)
+ {
+ for (Iterator<MessageConsumer> i = _consumers.iterator(); i.hasNext();)
+ {
+ QpidRAMessageConsumer consumer = (QpidRAMessageConsumer)i.next();
+ try
+ {
+ consumer.closeConsumer();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error closing consumer", t);
+ }
+ i.remove();
+ }
+ }
+
+ synchronized (_producers)
+ {
+ for (Iterator<MessageProducer> i = _producers.iterator(); i.hasNext();)
+ {
+ QpidRAMessageProducer producer = (QpidRAMessageProducer)i.next();
+ try
+ {
+ producer.closeProducer();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error closing producer", t);
+ }
+ i.remove();
+ }
+ }
+
+ synchronized (_browsers)
+ {
+ for (Iterator<QueueBrowser> i = _browsers.iterator(); i.hasNext();)
+ {
+ QpidRAQueueBrowser browser = (QpidRAQueueBrowser)i.next();
+ try
+ {
+ browser.close();
+ }
+ catch (Throwable t)
+ {
+ _log.trace("Error closing browser", t);
+ }
+ i.remove();
+ }
+ }
+
+ mc.removeHandle(this);
+ ConnectionEvent ev = new ConnectionEvent(mc, ConnectionEvent.CONNECTION_CLOSED);
+ ev.setConnectionHandle(this);
+ mc.sendEvent(ev);
+ this._mc = null;
+ }
+ }
+
+ /**
+ * Add consumer
+ * @param consumer The consumer
+ */
+ void addConsumer(final MessageConsumer consumer)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addConsumer(" + consumer + ")");
+ }
+
+ synchronized (_consumers)
+ {
+ _consumers.add(consumer);
+ }
+ }
+
+ /**
+ * Remove consumer
+ * @param consumer The consumer
+ */
+ void removeConsumer(final MessageConsumer consumer)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("removeConsumer(" + consumer + ")");
+ }
+
+ synchronized (_consumers)
+ {
+ _consumers.remove(consumer);
+ }
+ }
+
+ /**
+ * Add producer
+ * @param producer The producer
+ */
+ void addProducer(final MessageProducer producer)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addProducer(" + producer + ")");
+ }
+
+ synchronized (_producers)
+ {
+ _producers.add(producer);
+ }
+ }
+
+ /**
+ * Remove producer
+ * @param producer The producer
+ */
+ void removeProducer(final MessageProducer producer)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("removeProducer(" + producer + ")");
+ }
+
+ synchronized (_producers)
+ {
+ _producers.remove(producer);
+ }
+ }
+
+ /**
+ * Add queue browser
+ * @param browser The queue browser
+ */
+ void addQueueBrowser(final QueueBrowser browser)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("addQueueBrowser(" + browser + ")");
+ }
+
+ synchronized (_browsers)
+ {
+ _browsers.add(browser);
+ }
+ }
+
+ /**
+ * Remove queue browser
+ * @param browser The queue browser
+ */
+ void removeQueueBrowser(final QueueBrowser browser)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("removeQueueBrowser(" + browser + ")");
+ }
+
+ synchronized (_browsers)
+ {
+ _browsers.remove(browser);
+ }
+ }
+
+ /**
+ * Get the session and ensure that it is open
+ * @return The session
+ * @exception JMSException Thrown if an error occurs
+ * @exception IllegalStateException The session is closed
+ */
+ Session getSessionInternal() throws JMSException
+ {
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc == null)
+ {
+ throw new IllegalStateException("The session is closed");
+ }
+
+ Session session = mc.getSession();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSessionInternal " + Util.asString(session) + " for " + this);
+ }
+
+ return session;
+ }
+
+ /**
+ * Get the XA resource and ensure that it is open
+ * @return The XA Resource
+ * @exception JMSException Thrown if an error occurs
+ * @exception IllegalStateException The session is closed
+ */
+ XAResource getXAResourceInternal() throws JMSException
+ {
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc == null)
+ {
+ throw new IllegalStateException("The session is closed");
+ }
+
+ try
+ {
+ XAResource xares = mc.getXAResource();
+
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getXAResourceInternal " + xares + " for " + this);
+ }
+
+ return xares;
+ }
+ catch (ResourceException e)
+ {
+ JMSException jmse = new JMSException("Unable to get XA Resource");
+ jmse.initCause(e);
+ throw jmse;
+ }
+ }
+
+ /**
+ * Get the queue session
+ * @return The queue session
+ * @exception JMSException Thrown if an error occurs
+ * @exception IllegalStateException The session is closed
+ */
+ QueueSession getQueueSessionInternal() throws JMSException
+ {
+ Session s = getSessionInternal();
+ if (!(s instanceof QueueSession))
+ {
+ throw new InvalidDestinationException("Attempting to use QueueSession methods on: " + this);
+ }
+ return (QueueSession)s;
+ }
+
+ /**
+ * Get the topic session
+ * @return The topic session
+ * @exception JMSException Thrown if an error occurs
+ * @exception IllegalStateException The session is closed
+ */
+ TopicSession getTopicSessionInternal() throws JMSException
+ {
+ Session s = getSessionInternal();
+ if (!(s instanceof TopicSession))
+ {
+ throw new InvalidDestinationException("Attempting to use TopicSession methods on: " + this);
+ }
+ return (TopicSession)s;
+ }
+
+ /**
+ * @throws SystemException
+ * @throws RollbackException
+ *
+ */
+ public void checkState() throws JMSException
+ {
+ final QpidRAManagedConnection mc = this._mc;
+ if (mc != null)
+ {
+ mc.checkTransactionActive();
+ }
+ }
+
+ /**
+ * Has this session been started?
+ * @return true if started, false if stopped.
+ */
+ public boolean isStarted()
+ {
+ return _started.get();
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAStreamMessage.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAStreamMessage.java
new file mode 100644
index 0000000000..3c2bee33f2
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATextMessage.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATextMessage.java
new file mode 100644
index 0000000000..d74d006a7f
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicPublisher.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicPublisher.java
new file mode 100644
index 0000000000..b753690142
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicSubscriber.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRATopicSubscriber.java
new file mode 100644
index 0000000000..e423f468e0
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAXAResource.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAXAResource.java
new file mode 100644
index 0000000000..22b39792b1
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidResourceAdapter.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidResourceAdapter.java
new file mode 100644
index 0000000000..d56f520db4
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidResourceAdapter.java
@@ -0,0 +1,820 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.ra;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jms.Session;
+import javax.jms.XASession;
+import javax.resource.ResourceException;
+import javax.resource.spi.ActivationSpec;
+import javax.resource.spi.BootstrapContext;
+import javax.resource.spi.ResourceAdapter;
+import javax.resource.spi.ResourceAdapterInternalException;
+import javax.resource.spi.endpoint.MessageEndpointFactory;
+import javax.resource.spi.work.WorkManager;
+import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAResource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.client.XAConnectionImpl;
+import org.apache.qpid.ra.inflow.QpidActivation;
+import org.apache.qpid.ra.inflow.QpidActivationSpec;
+import org.apache.qpid.url.URLSyntaxException;
+
+/**
+ * The resource adapter for Qpid
+ *
+ */
+public class QpidResourceAdapter implements ResourceAdapter, Serializable
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = -2446231446818098726L;
+
+ /**
+ * The logger
+ */
+ private static final Logger _log = LoggerFactory.getLogger(QpidResourceAdapter.class);
+
+ /**
+ * The bootstrap context
+ */
+ private BootstrapContext _ctx;
+
+ /**
+ * The resource adapter properties
+ */
+ private final QpidRAProperties _raProperties;
+
+ /**
+ * Have the factory been configured
+ */
+ private final AtomicBoolean _configured;
+
+ /**
+ * The activations by activation spec
+ */
+ private final Map<ActivationSpec, QpidActivation> _activations;
+
+ private AMQConnectionFactory _defaultAMQConnectionFactory;
+
+ private TransactionManager _tm;
+
+ /**
+ * Constructor
+ */
+ public QpidResourceAdapter()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor()");
+ }
+
+ _raProperties = new QpidRAProperties();
+ _configured = new AtomicBoolean(false);
+ _activations = new ConcurrentHashMap<ActivationSpec, QpidActivation>();
+ }
+
+ public TransactionManager getTM()
+ {
+ return _tm;
+ }
+
+ /**
+ * Endpoint activation
+ *
+ * @param endpointFactory The endpoint factory
+ * @param spec The activation spec
+ * @throws ResourceException Thrown if an error occurs
+ */
+ public void endpointActivation(final MessageEndpointFactory endpointFactory, final ActivationSpec spec) throws ResourceException
+ {
+ if (!_configured.getAndSet(true))
+ {
+ try
+ {
+ setup();
+ }
+ catch (QpidRAException e)
+ {
+ throw new ResourceException("Unable to create activation", e);
+ }
+ }
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("endpointActivation(" + endpointFactory + ", " + spec + ")");
+ }
+
+ QpidActivation activation = new QpidActivation(this, endpointFactory, (QpidActivationSpec)spec);
+ _activations.put(spec, activation);
+ activation.start();
+ }
+
+ /**
+ * Endpoint deactivation
+ *
+ * @param endpointFactory The endpoint factory
+ * @param spec The activation spec
+ */
+ public void endpointDeactivation(final MessageEndpointFactory endpointFactory, final ActivationSpec spec)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("endpointDeactivation(" + endpointFactory + ", " + spec + ")");
+ }
+
+ QpidActivation activation = _activations.remove(spec);
+ if (activation != null)
+ {
+ activation.stop();
+ }
+ }
+
+ /**
+ * Get XA resources
+ *
+ * @param specs The activation specs
+ * @return The XA resources
+ * @throws ResourceException Thrown if an error occurs or unsupported
+ */
+ public XAResource[] getXAResources(final ActivationSpec[] specs) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getXAResources(" + specs + ")");
+ }
+
+ return null;
+ }
+
+ /**
+ * Start
+ *
+ * @param ctx The bootstrap context
+ * @throws ResourceAdapterInternalException
+ * Thrown if an error occurs
+ */
+ public void start(final BootstrapContext ctx) throws ResourceAdapterInternalException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start(" + ctx + ")");
+ }
+
+ locateTM();
+
+ this._ctx = ctx;
+
+ _log.info("Qpid resource adapter started");
+ }
+
+ /**
+ * Stop
+ */
+ public void stop()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("stop()");
+ }
+
+ for (Map.Entry<ActivationSpec, QpidActivation> entry : _activations.entrySet())
+ {
+ try
+ {
+ entry.getValue().stop();
+ }
+ catch (Exception ignored)
+ {
+ _log.debug("Ignored", ignored);
+ }
+ }
+
+ _activations.clear();
+
+ _log.info("Qpid resource adapter stopped");
+ }
+
+ /**
+ * Get the user name
+ *
+ * @return The value
+ */
+ public String getDefaultUserName()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUserName()");
+ }
+
+ return _raProperties.getUserName();
+ }
+
+ /**
+ * Set the user name
+ *
+ * @param userName The value
+ */
+ public void setDefaultUserName(final String userName)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUserName(" + userName + ")");
+ }
+
+ _raProperties.setUserName(userName);
+ }
+
+ /**
+ * Get the password
+ *
+ * @return The value
+ */
+ public String getDefaultPassword()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPassword()");
+ }
+
+ return _raProperties.getPassword();
+ }
+
+ /**
+ * Set the password
+ *
+ * @param password The value
+ */
+ public void setDefaultPassword(final String password)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPassword(****)");
+ }
+
+ _raProperties.setPassword(password);
+ }
+
+ /**
+ * Get the client ID
+ *
+ * @return The value
+ */
+ public String getClientId()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getClientID()");
+ }
+
+ return _raProperties.getClientId();
+ }
+
+ /**
+ * Set the client ID
+ *
+ * @param clientID The client id
+ */
+ public void setClientId(final String clientID)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setClientID(" + clientID + ")");
+ }
+
+ _raProperties.setClientId(clientID);
+ }
+
+ /**
+ * Get the host
+ *
+ * @return The value
+ */
+ public String getHost()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getHost()");
+ }
+
+ return _raProperties.getHost();
+ }
+
+ /**
+ * Set the host
+ *
+ * @param host The host
+ */
+ public void setHost(final String host)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setHost(" + host + ")");
+ }
+
+ _raProperties.setHost(host);
+ }
+
+ /**
+ * Get the port
+ *
+ * @return The value
+ */
+ public Integer getPort()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPort()");
+ }
+
+ return _raProperties.getPort();
+ }
+
+ /**
+ * Set the client ID
+ *
+ * @param port The port
+ */
+ public void setPort(final Integer port)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPort(" + port + ")");
+ }
+
+ _raProperties.setPort(port);
+ }
+
+ /**
+ * Get the connection url
+ *
+ * @return The value
+ */
+ public String getPath()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getPath()");
+ }
+
+ return _raProperties.getPath();
+ }
+
+ /**
+ * Set the client ID
+ *
+ * @param path The path
+ */
+ public void setPath(final String path)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setPath(" + path + ")");
+ }
+
+ _raProperties.setPath(path);
+ }
+
+ /**
+ * Get the connection url
+ *
+ * @return The value
+ */
+ public String getConnectionURL()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getConnectionURL()");
+ }
+
+ return _raProperties.getConnectionURL();
+ }
+
+ /**
+ * Set the client ID
+ *
+ * @param connectionURL The connection url
+ */
+ public void setConnectionURL(final String connectionURL)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setConnectionURL(" + connectionURL + ")");
+ }
+
+ _raProperties.setConnectionURL(connectionURL);
+ }
+
+ /**
+ * Get the transaction manager locator class
+ *
+ * @return The value
+ */
+ public String getTransactionManagerLocatorClass()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransactionManagerLocatorClass()");
+ }
+
+ return _raProperties.getTransactionManagerLocatorClass();
+ }
+
+ /**
+ * Set the transaction manager locator class
+ *
+ * @param locator The transaction manager locator class
+ */
+ public void setTransactionManagerLocatorClass(final String locator)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTransactionManagerLocatorClass(" + locator + ")");
+ }
+
+ _raProperties.setTransactionManagerLocatorClass(locator);
+ }
+
+ /**
+ * Get the transaction manager locator method
+ *
+ * @return The value
+ */
+ public String getTransactionManagerLocatorMethod()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getTransactionManagerLocatorMethod()");
+ }
+
+ return _raProperties.getTransactionManagerLocatorMethod();
+ }
+
+ /**
+ * Set the transaction manager locator method
+ *
+ * @param method The transaction manager locator method
+ */
+ public void setTransactionManagerLocatorMethod(final String method)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setTransactionManagerLocatorMethod(" + method + ")");
+ }
+
+ _raProperties.setTransactionManagerLocatorMethod(method);
+ }
+
+ /**
+ * Get the use XA flag
+ *
+ * @return The value
+ */
+ public Boolean getUseLocalTx()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getUseLocalTx()");
+ }
+
+ return _raProperties.getUseLocalTx();
+ }
+
+ /**
+ * Set the use XA flag
+ *
+ * @param localTx The value
+ */
+ public void setUseLocalTx(final Boolean localTx)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setUseLocalTx(" + localTx + ")");
+ }
+
+ _raProperties.setUseLocalTx(localTx);
+ }
+
+ public Integer getSetupAttempts()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSetupAttempts()");
+ }
+ return _raProperties.getSetupAttempts();
+ }
+
+ public void setSetupAttempts(Integer setupAttempts)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSetupAttempts(" + setupAttempts + ")");
+ }
+ _raProperties.setSetupAttempts(setupAttempts);
+ }
+
+ public Long getSetupInterval()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getSetupInterval()");
+ }
+ return _raProperties.getSetupInterval();
+ }
+
+ public void setSetupInterval(Long interval)
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setSetupInterval(" + interval + ")");
+ }
+ _raProperties.setSetupInterval(interval);
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this one.
+ *
+ * @param obj Object with which to compare
+ * @return True if this object is the same as the obj argument; false otherwise.
+ */
+ public boolean equals(final Object obj)
+ {
+ if (obj == null)
+ {
+ return false;
+ }
+
+ if (obj instanceof QpidResourceAdapter)
+ {
+ return _raProperties.equals(((QpidResourceAdapter)obj).getProperties());
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Return the hash code for the object
+ *
+ * @return The hash code
+ */
+ public int hashCode()
+ {
+ return _raProperties.hashCode();
+ }
+
+ /**
+ * Get the work manager
+ *
+ * @return The manager
+ */
+ public WorkManager getWorkManager()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getWorkManager()");
+ }
+
+ if (_ctx == null)
+ {
+ return null;
+ }
+
+ return _ctx.getWorkManager();
+ }
+
+ public XASession createXASession(final XAConnectionImpl connection)
+ throws Exception
+ {
+ final XASession result = connection.createXASession() ;
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Using session " + Util.asString(result));
+ }
+ return result ;
+ }
+
+ public Session createSession(final AMQConnection connection,
+ final int ackMode,
+ final boolean useLocalTx,
+ final Integer prefetchLow,
+ final Integer prefetchHigh) throws Exception
+ {
+ Session result;
+
+ if (prefetchLow == null)
+ {
+ result = connection.createSession(useLocalTx, ackMode) ;
+ }
+ else if (prefetchHigh == null)
+ {
+ result = connection.createSession(useLocalTx, ackMode, prefetchLow) ;
+ }
+ else
+ {
+ result = connection.createSession(useLocalTx, ackMode, prefetchHigh, prefetchLow) ;
+ }
+
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Using session " + Util.asString(result));
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Get the resource adapter properties
+ *
+ * @return The properties
+ */
+ protected QpidRAProperties getProperties()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getProperties()");
+ }
+
+ return _raProperties;
+ }
+
+ /**
+ * Setup the factory
+ */
+ protected void setup() throws QpidRAException
+ {
+ _defaultAMQConnectionFactory = createAMQConnectionFactory(_raProperties);
+ }
+
+
+ public AMQConnectionFactory getDefaultAMQConnectionFactory() throws ResourceException
+ {
+ if (!_configured.getAndSet(true))
+ {
+ try
+ {
+ setup();
+ }
+ catch (QpidRAException e)
+ {
+ throw new ResourceException("Unable to create activation", e);
+ }
+ }
+ return _defaultAMQConnectionFactory;
+ }
+
+ public AMQConnectionFactory createAMQConnectionFactory(final ConnectionFactoryProperties overrideProperties)
+ throws QpidRAException
+ {
+ try
+ {
+ return createFactory(overrideProperties);
+ }
+ catch (final URLSyntaxException urlse)
+ {
+ throw new QpidRAException("Unexpected exception creating connection factory", urlse) ;
+ }
+ }
+
+ public Map<String, Object> overrideConnectionParameters(final Map<String, Object> connectionParams,
+ final Map<String, Object> overrideConnectionParams)
+ {
+ Map<String, Object> map = new HashMap<String, Object>();
+
+ if(connectionParams != null)
+ {
+ map.putAll(connectionParams);
+ }
+ if(overrideConnectionParams != null)
+ {
+ for (Map.Entry<String, Object> stringObjectEntry : overrideConnectionParams.entrySet())
+ {
+ map.put(stringObjectEntry.getKey(), stringObjectEntry.getValue());
+ }
+ }
+ return map;
+ }
+
+ private void locateTM()
+ {
+ if(_raProperties.getTransactionManagerLocatorClass() != null && _raProperties.getTransactionManagerLocatorMethod() != null)
+ {
+
+ String locatorClasses[] = _raProperties.getTransactionManagerLocatorClass().split(";");
+ String locatorMethods[] = _raProperties.getTransactionManagerLocatorMethod().split(";");
+
+ for (int i = 0 ; i < locatorClasses.length; i++)
+ {
+ _tm = Util.locateTM(locatorClasses[i], locatorMethods[i]);
+ if (_tm != null)
+ {
+ break;
+ }
+ }
+
+
+ }
+
+ if (_tm == null)
+ {
+ _log.warn("It wasn't possible to lookup a Transaction Manager through the configured properties TransactionManagerLocatorClass and TransactionManagerLocatorMethod");
+ _log.warn("Qpid Resource Adapter won't be able to set and verify transaction timeouts in certain cases.");
+ }
+ else
+ {
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("TM located = " + _tm);
+ }
+ }
+ }
+
+
+ private AMQConnectionFactory createFactory(final ConnectionFactoryProperties overrideProperties)
+ throws URLSyntaxException, QpidRAException
+ {
+ final String overrideURL = overrideProperties.getConnectionURL() ;
+ final String url = overrideURL != null ? overrideURL : _raProperties.getConnectionURL() ;
+
+ final String overrideClientID = overrideProperties.getClientId() ;
+ final String clientID = (overrideClientID != null ? overrideClientID : _raProperties.getClientId()) ;
+
+ final String overrideDefaultPassword = overrideProperties.getPassword() ;
+ final String defaultPassword = (overrideDefaultPassword != null ? overrideDefaultPassword : _raProperties.getPassword()) ;
+
+ final String overrideDefaultUsername = overrideProperties.getUserName() ;
+ final String defaultUsername = (overrideDefaultUsername != null ? overrideDefaultUsername : _raProperties.getUserName()) ;
+
+ final String overrideHost = overrideProperties.getHost() ;
+ final String host = (overrideHost != null ? overrideHost : _raProperties.getHost()) ;
+
+ final Integer overridePort = overrideProperties.getPort() ;
+ final Integer port = (overridePort != null ? overridePort : _raProperties.getPort()) ;
+
+ final String overridePath = overrideProperties.getPath() ;
+ final String path = (overridePath != null ? overridePath : _raProperties.getPath()) ;
+
+ final AMQConnectionFactory cf ;
+
+ if (url != null)
+ {
+ cf = new AMQConnectionFactory(url) ;
+
+ if (clientID != null)
+ {
+ cf.getConnectionURL().setClientName(clientID) ;
+ }
+ }
+ else
+ {
+ // create a URL to force the connection details
+ if ((host == null) || (port == null) || (path == null))
+ {
+ throw new QpidRAException("Configuration requires host/port/path if connectionURL is not specified") ;
+ }
+ final String username = (defaultUsername != null ? defaultUsername : "") ;
+ final String password = (defaultPassword != null ? defaultPassword : "") ;
+ final String client = (clientID != null ? clientID : "") ;
+
+ final String newurl = AMQConnectionURL.AMQ_PROTOCOL + "://" + username +":" + password + "@" + client + "/" + path + '?' + AMQConnectionURL.OPTIONS_BROKERLIST + "='tcp://" + host + ':' + port + '\'' ;
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Initialising connectionURL to " + newurl) ;
+ }
+
+ cf = new AMQConnectionFactory(newurl) ;
+ }
+
+ return cf ;
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/Util.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/Util.java
new file mode 100644
index 0000000000..b927aaa0be
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/Util.java
@@ -0,0 +1,184 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.ra;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+import javax.naming.Context;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.transaction.TransactionManager;
+
+import org.apache.qpid.ra.admin.QpidQueue;
+import org.apache.qpid.ra.admin.QpidTopic;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Various utility functions
+ *
+ */
+public class Util
+{
+
+ private static final Logger _log = LoggerFactory.getLogger(Util.class);
+
+ /**
+ * Compare two strings.
+ * @param me First value
+ * @param you Second value
+ * @return True if object equals else false.
+ */
+ public static boolean compare(final String me, final String you)
+ {
+ // If both null or intern equals
+ if (me == you)
+ {
+ return true;
+ }
+
+ // if me null and you are not
+ if (me == null && you != null)
+ {
+ return false;
+ }
+
+ // me will not be null, test for equality
+ return me.equals(you);
+ }
+
+ /**
+ * Lookup an object in the default initial context
+ * @param context The context to use
+ * @param name the name to lookup
+ * @param clazz the expected type
+ * @return the object
+ * @throws Exception for any error
+ */
+ public static <T> T lookup(final Context context, final String name, final Class<T> clazz) throws Exception
+ {
+ Object object = context.lookup(name);
+
+ if (object instanceof Reference)
+ {
+
+ Reference ref = (Reference) object;
+ String addressContent = null;
+
+ if (ref.getClassName().equals(QpidQueue.class.getName()))
+ {
+ RefAddr addr = ref.get(QpidQueue.class.getName());
+ addressContent = (String) addr.getContent();
+
+ if (addr != null)
+ {
+ return (T)new QpidQueue(addressContent);
+ }
+ }
+
+ if (ref.getClassName().equals(QpidTopic.class.getName()))
+ {
+ RefAddr addr = ref.get(QpidTopic.class.getName());
+ addressContent = (String) addr.getContent();
+
+ if (addr != null)
+ {
+ return (T)new QpidTopic(addressContent);
+ }
+ }
+ }
+
+ return clazz.cast(object);
+
+ }
+
+ /** The Resource adapter can't depend on any provider's specific library. Because of that we use reflection to locate the
+ * transaction manager during startup.
+ *
+ *
+ * TODO: We should use a proper SPI instead of reflection
+ * We would need to define a proper SPI package for this.
+ **/
+ public static TransactionManager locateTM(final String locatorClass, final String locatorMethod)
+ {
+ try
+ {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ Class<?> aClass = loader.loadClass(locatorClass);
+ Object o = aClass.newInstance();
+ Method m = aClass.getMethod(locatorMethod);
+ return (TransactionManager)m.invoke(o);
+ }
+ catch (Throwable e)
+ {
+ _log.debug(e.getMessage(), e);
+ return null;
+ }
+ }
+
+ /**
+ * Serialize the object into a byte array.
+ * @param serializable The serializable object
+ * @return The generated byte array
+ * @throws IOException For errors during serialization.
+ */
+ public static byte[] serialize(final Serializable serializable)
+ throws IOException
+ {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
+ final ObjectOutputStream oos = new ObjectOutputStream(baos) ;
+ oos.writeObject(serializable) ;
+ oos.close() ;
+ return baos.toByteArray() ;
+ }
+
+ /**
+ * Deserialize the byte array into an object.
+ * @param data The serialized object as a byte array
+ * @return The serializable object.
+ * @throws IOException For errors during deserialization
+ * @throws ClassNotFoundException If the deserialized class cannot be found.
+ */
+ public static Object deserialize(final byte[] data)
+ throws IOException, ClassNotFoundException
+ {
+ final ByteArrayInputStream bais = new ByteArrayInputStream(data) ;
+ final ObjectInputStream ois = new ObjectInputStream(bais) ;
+ return ois.readObject() ;
+ }
+
+ /**
+ * Return a string identification for the specified object.
+ * @param object The object value.
+ * @return The string identification.
+ */
+ public static String asString(final Object object)
+ {
+ return (object == null ? "null" : object.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(object))) ;
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/AdminObjectFactory.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/AdminObjectFactory.java
new file mode 100644
index 0000000000..11f2903c72
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidBindingURL.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidBindingURL.java
new file mode 100644
index 0000000000..503f59eecc
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxy.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxy.java
new file mode 100644
index 0000000000..41242fefae
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidDestinationProxy.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidDestinationProxy.java
new file mode 100644
index 0000000000..738ce4be0d
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidQueue.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidQueue.java
new file mode 100644
index 0000000000..caef0c8ffd
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidTopic.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/admin/QpidTopic.java
new file mode 100644
index 0000000000..3f181b93eb
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java
new file mode 100644
index 0000000000..98427d7f9d
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java
@@ -0,0 +1,593 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.ra.inflow;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.resource.ResourceException;
+import javax.resource.spi.endpoint.MessageEndpointFactory;
+import javax.resource.spi.work.Work;
+import javax.resource.spi.work.WorkManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.XAConnectionImpl;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.ra.QpidResourceAdapter;
+import org.apache.qpid.ra.Util;
+
+/**
+ * The activation.
+ *
+ */
+public class QpidActivation implements ExceptionListener
+{
+ /**
+ * The logger
+ */
+ private static final Logger _log = LoggerFactory.getLogger(QpidActivation.class);
+
+ /**
+ * The onMessage method
+ */
+ public static final Method ONMESSAGE;
+
+ /**
+ * The resource adapter
+ */
+ private final QpidResourceAdapter _ra;
+
+ /**
+ * The activation spec
+ */
+ private final QpidActivationSpec _spec;
+
+ /**
+ * The message endpoint factory
+ */
+ private final MessageEndpointFactory _endpointFactory;
+
+ /**
+ * Whether delivery is active
+ */
+ private final AtomicBoolean _deliveryActive = new AtomicBoolean(false);
+
+ /**
+ * The destination type
+ */
+ private boolean _isTopic = false;
+
+ /**
+ * Is the delivery transacted
+ */
+ private boolean _isDeliveryTransacted;
+
+ private Destination _destination;
+
+ /**
+ * The connection
+ */
+ private Connection _connection;
+
+ private final List<QpidMessageHandler> _handlers = new ArrayList<QpidMessageHandler>();
+
+ private AMQConnectionFactory _factory;
+
+ // Whether we are in the failure recovery loop
+ private AtomicBoolean _inFailure = new AtomicBoolean(false);
+
+ static
+ {
+ try
+ {
+ ONMESSAGE = MessageListener.class.getMethod("onMessage", new Class[] { Message.class });
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ * @param ra The resource adapter
+ * @param endpointFactory The endpoint factory
+ * @param spec The activation spec
+ * @throws ResourceException Thrown if an error occurs
+ */
+ public QpidActivation(final QpidResourceAdapter ra,
+ final MessageEndpointFactory endpointFactory,
+ final QpidActivationSpec spec) throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("constructor(" + ra + ", " + endpointFactory + ", " + spec + ")");
+ }
+
+ this._ra = ra;
+ this._endpointFactory = endpointFactory;
+ this._spec = spec;
+ try
+ {
+ _isDeliveryTransacted = endpointFactory.isDeliveryTransacted(QpidActivation.ONMESSAGE);
+ }
+ catch (Exception e)
+ {
+ throw new ResourceException(e);
+ }
+ }
+
+ /**
+ * Get the activation spec
+ *
+ * @return The value
+ */
+ public QpidActivationSpec getActivationSpec()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getActivationSpec()");
+ }
+
+ return _spec;
+ }
+
+ /**
+ * Get the message endpoint factory
+ *
+ * @return The value
+ */
+ public MessageEndpointFactory getMessageEndpointFactory()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getMessageEndpointFactory()");
+ }
+
+ return _endpointFactory;
+ }
+
+ /**
+ * Get whether delivery is transacted
+ *
+ * @return The value
+ */
+ public boolean isDeliveryTransacted()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("isDeliveryTransacted()");
+ }
+
+ return _isDeliveryTransacted;
+ }
+
+ /**
+ * Get the work manager
+ *
+ * @return The value
+ */
+ public WorkManager getWorkManager()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("getWorkManager()");
+ }
+
+ return _ra.getWorkManager();
+ }
+
+ /**
+ * Is the destination a topic
+ *
+ * @return The value
+ */
+ public boolean isTopic()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("isTopic()");
+ }
+
+ return _isTopic;
+ }
+
+ /**
+ * Start the activation
+ *
+ * @throws ResourceException Thrown if an error occurs
+ */
+ public void start() throws ResourceException
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("start()");
+ }
+ _deliveryActive.set(true);
+ _ra.getWorkManager().scheduleWork(new SetupActivation());
+ }
+
+ /**
+ * Stop the activation
+ */
+ public void stop()
+ {
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("stop()");
+ }
+
+ _deliveryActive.set(false);
+ teardown();
+ }
+
+ /**
+ * Setup the activation
+ *
+ * @throws Exception Thrown if an error occurs
+ */
+ protected synchronized void setup() throws Exception
+ {
+ _log.debug("Setting up " + _spec);
+ setupCF();
+
+ setupDestination();
+ final AMQConnection amqConnection ;
+ final boolean useLocalTx = _spec.isUseLocalTx() ;
+ final boolean isXA = _isDeliveryTransacted && !useLocalTx ;
+
+ if (isXA)
+ {
+ amqConnection = (XAConnectionImpl)_factory.createXAConnection() ;
+ }
+ else
+ {
+ amqConnection = (AMQConnection)_factory.createConnection() ;
+ }
+
+ amqConnection.setExceptionListener(this) ;
+
+ for (int i = 0; i < _spec.getMaxSession(); i++)
+ {
+ Session session = null;
+
+ try
+ {
+ if (isXA)
+ {
+ session = _ra.createXASession((XAConnectionImpl)amqConnection) ;
+ }
+ else
+ {
+ session = _ra.createSession((AMQConnection)amqConnection,
+ _spec.getAcknowledgeModeInt(),
+ useLocalTx,
+ _spec.getPrefetchLow(),
+ _spec.getPrefetchHigh());
+ }
+
+ _log.debug("Using session " + Util.asString(session));
+ QpidMessageHandler handler = new QpidMessageHandler(this, _ra.getTM(), session);
+ handler.setup();
+ _handlers.add(handler);
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ amqConnection.close() ;
+ }
+ catch (Exception e2)
+ {
+ _log.trace("Ignored error closing connection", e2);
+ }
+
+ throw e;
+ }
+ }
+ amqConnection.start() ;
+ this._connection = amqConnection ;
+
+ _log.debug("Setup complete " + this);
+ }
+
+ /**
+ * Teardown the activation
+ */
+ protected synchronized void teardown()
+ {
+ _log.debug("Tearing down " + _spec);
+
+ try
+ {
+ if (_connection != null)
+ {
+ _connection.stop();
+ }
+ }
+ catch (Throwable t)
+ {
+ _log.debug("Error stopping connection " + Util.asString(_connection), t);
+ }
+
+ for (QpidMessageHandler handler : _handlers)
+ {
+ handler.teardown();
+ }
+
+ try
+ {
+ if (_connection != null)
+ {
+ _connection.close();
+ }
+ }
+ catch (Throwable t)
+ {
+ _log.debug("Error closing connection " + Util.asString(_connection), t);
+ }
+ if (_spec.isHasBeenUpdated())
+ {
+ _factory = null;
+ }
+ _log.debug("Tearing down complete " + this);
+ }
+
+ protected void setupCF() throws Exception
+ {
+ if (_spec.isHasBeenUpdated())
+ {
+ _factory = _ra.createAMQConnectionFactory(_spec);
+ }
+ else
+ {
+ _factory = _ra.getDefaultAMQConnectionFactory();
+ }
+ }
+
+ public Destination getDestination()
+ {
+ return _destination;
+ }
+
+ protected void setupDestination() throws Exception
+ {
+
+ String destinationName = _spec.getDestination();
+ String destinationTypeString = _spec.getDestinationType();
+
+ if (_spec.isUseJNDI())
+ {
+ Context ctx = new InitialContext();
+ _log.debug("Using context " + ctx.getEnvironment() + " for " + _spec);
+ if (_log.isTraceEnabled())
+ {
+ _log.trace("setupDestination(" + ctx + ")");
+ }
+
+ if (destinationTypeString != null && !destinationTypeString.trim().equals(""))
+ {
+ _log.debug("Destination type defined as " + destinationTypeString);
+
+ Class<? extends Destination> destinationType;
+ if (Topic.class.getName().equals(destinationTypeString))
+ {
+ destinationType = Topic.class;
+ _isTopic = true;
+ }
+ else
+ {
+ destinationType = Queue.class;
+ }
+
+ _log.debug("Retrieving destination " + destinationName +
+ " of type " +
+ destinationType.getName());
+ _destination = Util.lookup(ctx, destinationName, destinationType);
+ //_destination = (Destination)ctx.lookup(destinationName);
+
+ }
+ else
+ {
+ _log.debug("Destination type not defined");
+ _log.debug("Retrieving destination " + destinationName +
+ " of type " +
+ Destination.class.getName());
+
+ _destination = Util.lookup(ctx, destinationName, AMQDestination.class);
+ _isTopic = !(_destination instanceof Queue) ;
+ }
+ }
+ else
+ {
+ _destination = (AMQDestination)AMQDestination.createDestination(_spec.getDestination());
+ if (destinationTypeString != null && !destinationTypeString.trim().equals(""))
+ {
+ _log.debug("Destination type defined as " + destinationTypeString);
+ final boolean match ;
+ if (Topic.class.getName().equals(destinationTypeString))
+ {
+ match = (_destination instanceof Topic) ;
+ _isTopic = true;
+ }
+ else
+ {
+ match = (_destination instanceof Queue) ;
+ }
+ if (!match)
+ {
+ throw new ClassCastException("Expected destination of type " + destinationTypeString + " but created destination " + _destination) ;
+ }
+ }
+ else
+ {
+ _isTopic = !(_destination instanceof Queue) ;
+ }
+ }
+
+ _log.debug("Got destination " + _destination + " from " + destinationName);
+ }
+
+ /**
+ * Get a string representation
+ *
+ * @return The value
+ */
+ @Override
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(QpidActivation.class.getName()).append('(');
+ buffer.append("spec=").append(_spec.getClass().getName());
+ buffer.append(" mepf=").append(_endpointFactory.getClass().getName());
+ buffer.append(" active=").append(_deliveryActive.get());
+ if (_spec.getDestination() != null)
+ {
+ buffer.append(" destination=").append(_spec.getDestination());
+ }
+ buffer.append(" transacted=").append(_isDeliveryTransacted);
+ buffer.append(')');
+ return buffer.toString();
+ }
+
+ public void onException(final JMSException jmse)
+ {
+ handleFailure(jmse) ;
+ }
+
+ /**
+ * Handles any failure by trying to reconnect
+ *
+ * @param failure the reason for the failure
+ */
+ public void handleFailure(Throwable failure)
+ {
+ if(doesNotExist(failure))
+ {
+ _log.info("awaiting topic/queue creation " + getActivationSpec().getDestination());
+ }
+ else
+ {
+ _log.warn("Failure in Qpid activation " + _spec, failure);
+ }
+ int reconnectCount = 0;
+ int setupAttempts = _spec.getSetupAttempts();
+ long setupInterval = _spec.getSetupInterval();
+
+ // Only enter the failure loop once
+ if (_inFailure.getAndSet(true))
+ return;
+ try
+ {
+ while (_deliveryActive.get() && (setupAttempts == -1 || reconnectCount < setupAttempts))
+ {
+ teardown();
+
+ try
+ {
+ Thread.sleep(setupInterval);
+ }
+ catch (InterruptedException e)
+ {
+ _log.debug("Interrupted trying to reconnect " + _spec, e);
+ break;
+ }
+
+ _log.info("Attempting to reconnect " + _spec);
+ try
+ {
+ setup();
+ _log.info("Reconnected with Qpid");
+ break;
+ }
+ catch (Throwable t)
+ {
+ if(doesNotExist(failure))
+ {
+ _log.info("awaiting topic/queue creation " + getActivationSpec().getDestination());
+ }
+ else
+ {
+ _log.error("Unable to reconnect " + _spec, t);
+ }
+ }
+ ++reconnectCount;
+ }
+ }
+ finally
+ {
+ // Leaving failure recovery loop
+ _inFailure.set(false);
+ }
+ }
+
+ /**
+ * Check to see if the failure represents a missing endpoint
+ * @param failure The failure.
+ * @return true if it represents a missing endpoint, false otherwise
+ */
+ private boolean doesNotExist(final Throwable failure)
+ {
+ return (failure instanceof AMQException) && (((AMQException)failure).getErrorCode() == AMQConstant.NOT_FOUND) ;
+ }
+
+ /**
+ * Handles the setup
+ */
+ private class SetupActivation implements Work
+ {
+ public void run()
+ {
+ try
+ {
+ setup();
+ }
+ catch (Throwable t)
+ {
+ handleFailure(t);
+ }
+ }
+
+ public void release()
+ {
+ }
+ }
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivationSpec.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivationSpec.java
new file mode 100644
index 0000000000..5f4e2dcf6b
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidMessageHandler.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidMessageHandler.java
new file mode 100644
index 0000000000..473efab31f
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/GeronimoTransactionManagerLocator.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/GeronimoTransactionManagerLocator.java
new file mode 100644
index 0000000000..3a47824631
--- /dev/null
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/GeronimoTransactionManagerLocator.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.ra.tm;
+
+import java.util.Set;
+
+import javax.transaction.TransactionManager;
+
+import org.apache.geronimo.gbean.AbstractName;
+import org.apache.geronimo.gbean.AbstractNameQuery;
+import org.apache.geronimo.kernel.Kernel;
+import org.apache.geronimo.kernel.KernelRegistry;
+
+public class GeronimoTransactionManagerLocator
+{
+
+ public GeronimoTransactionManagerLocator()
+ {
+ }
+
+ public TransactionManager getTransactionManager()
+ {
+ try
+ {
+ Kernel kernel = KernelRegistry.getSingleKernel();
+ AbstractNameQuery query = new AbstractNameQuery(TransactionManager.class.getName ());
+ Set<AbstractName> names = kernel.listGBeans(query);
+
+ if (names.size() != 1)
+ {
+ throw new IllegalStateException("Expected one transaction manager, not " + names.size());
+ }
+
+ AbstractName name = names.iterator().next();
+ TransactionManager transMg = (TransactionManager) kernel.getGBean(name);
+ return (TransactionManager)transMg;
+
+ }
+ catch(Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+
+}
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/JBoss7TransactionManagerLocator.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/JBoss7TransactionManagerLocator.java
new file mode 100644
index 0000000000..266c56bd63
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/JBossTransactionManagerLocator.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/tm/JBossTransactionManagerLocator.java
new file mode 100644
index 0000000000..5a5b585984
--- /dev/null
+++ b/qpid/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/qpid/java/jca/src/main/resources/META-INF/jboss-ra.xml b/qpid/java/jca/src/main/resources/META-INF/jboss-ra.xml
new file mode 100644
index 0000000000..f459b1efc1
--- /dev/null
+++ b/qpid/java/jca/src/main/resources/META-INF/jboss-ra.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+<jboss-ra>
+ <ra-config-property>
+ <ra-config-property-name>TransactionManagerLocatorClass</ra-config-property-name>
+ <ra-config-property-type>java.lang.String</ra-config-property-type>
+ <ra-config-property-value>org.apache.qpid.ra.tm.JBossTransactionManagerLocator</ra-config-property-value>
+ </ra-config-property>
+ <ra-config-property>
+ <ra-config-property-name>TransactionManagerLocatorMethod</ra-config-property-name>
+ <ra-config-property-type>java.lang.String</ra-config-property-type>
+ <ra-config-property-value>getTm</ra-config-property-value>
+ </ra-config-property>
+</jboss-ra>
diff --git a/qpid/java/jca/src/main/resources/META-INF/ra.xml b/qpid/java/jca/src/main/resources/META-INF/ra.xml
new file mode 100755
index 0000000000..90dc7b3b8e
--- /dev/null
+++ b/qpid/java/jca/src/main/resources/META-INF/ra.xml
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
+
+<connector xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
+ http://java.sun.com/xml/ns/j2ee/connector_1_5.xsd"
+ version="1.5">
+
+ <description>QPID Resource Adapter</description>
+ <display-name>QPID Resource Adapter</display-name>
+
+ <vendor-name>Apache Software Foundation</vendor-name>
+ <eis-type>JMS 1.1 Server</eis-type>
+ <resourceadapter-version>1.0</resourceadapter-version>
+
+ <license>
+ <description>
+ The ASF licenses this file to you under the Apache License,
+ Version 2.0 (the "License"); you may not use this file except
+ in compliance with the License. You may obtain a copy of the
+ License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ </description>
+ <license-required>true</license-required>
+ </license>
+
+ <resourceadapter>
+ <resourceadapter-class>org.apache.qpid.ra.QpidResourceAdapter</resourceadapter-class>
+ <config-property>
+ <description>Client ID for the connection</description>
+ <config-property-name>ClientId</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>client_id</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Number of setup attempts before failing</description>
+ <config-property-name>SetupAttempts</config-property-name>
+ <config-property-type>java.lang.Integer</config-property-type>
+ <config-property-value>5</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Interval between setup attempts</description>
+ <config-property-name>SetupInterval</config-property-name>
+ <config-property-type>java.lang.Long</config-property-type>
+ <config-property-value>5000</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Use local transactions rather than XA</description>
+ <config-property-name>UseLocalTx</config-property-name>
+ <config-property-type>java.lang.Boolean</config-property-type>
+ <config-property-value>false</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Broker host</description>
+ <config-property-name>Host</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>localhost</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Broker port</description>
+ <config-property-name>Port</config-property-name>
+ <config-property-type>java.lang.Integer</config-property-type>
+ <config-property-value>5672</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Virtual Path for Connection Factory</description>
+ <config-property-name>Path</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>test</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>connection URL</description>
+ <config-property-name>ConnectionURL</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>amqp://guest:guest@/test?brokerlist='tcp://localhost:5672'</config-property-value>
+ </config-property>
+
+ <outbound-resourceadapter>
+ <connection-definition>
+ <managedconnectionfactory-class>org.apache.qpid.ra.QpidRAManagedConnectionFactory</managedconnectionfactory-class>
+
+ <config-property>
+ <description>Default session type</description>
+ <config-property-name>sessionDefaultType</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>javax.jms.Queue</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Specify lock timeout in seconds</description>
+ <config-property-name>useTryLock</config-property-name>
+ <config-property-type>java.lang.Integer</config-property-type>
+ <config-property-value>0</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Use local transactions rather than XA</description>
+ <config-property-name>UseLocalTx</config-property-name>
+ <config-property-type>java.lang.Boolean</config-property-type>
+ <config-property-value>false</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Client ID for the connection</description>
+ <config-property-name>ClientID</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>client_id</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Connection URL</description>
+ <config-property-name>ConnectionURL</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value></config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Broker host</description>
+ <config-property-name>Host</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>localhost</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Broker port</description>
+ <config-property-name>Port</config-property-name>
+ <config-property-type>java.lang.Integer</config-property-type>
+ <config-property-value>5672</config-property-value>
+ </config-property>
+
+ <config-property>
+ <description>Virtual Path for Connection Factory</description>
+ <config-property-name>Path</config-property-name>
+ <config-property-type>java.lang.String</config-property-type>
+ <config-property-value>test</config-property-value>
+ </config-property>
+
+ <connectionfactory-interface>org.apache.qpid.ra.QpidRAConnectionFactory</connectionfactory-interface>
+ <connectionfactory-impl-class>org.apache.qpid.ra.QpidRAConnectionFactoryImpl</connectionfactory-impl-class>
+ <connection-interface>javax.jms.Session</connection-interface>
+ <connection-impl-class>org.apache.qpid.ra.QpidRASessionImpl</connection-impl-class>
+ </connection-definition>
+ <transaction-support>XATransaction</transaction-support>
+ <authentication-mechanism>
+ <authentication-mechanism-type>BasicPassword</authentication-mechanism-type>
+ <credential-interface>javax.resource.spi.security.PasswordCredential</credential-interface>
+ </authentication-mechanism>
+ <reauthentication-support>false</reauthentication-support>
+ </outbound-resourceadapter>
+ <inbound-resourceadapter>
+ <messageadapter>
+ <messagelistener>
+ <messagelistener-type>javax.jms.MessageListener</messagelistener-type>
+ <activationspec>
+ <activationspec-class>org.apache.qpid.ra.inflow.QpidActivationSpec</activationspec-class>
+ <required-config-property>
+ <config-property-name>destination</config-property-name>
+ </required-config-property>
+ </activationspec>
+ </messagelistener>
+ </messageadapter>
+ </inbound-resourceadapter>
+
+ <adminobject>
+ <adminobject-interface>javax.jms.Destination</adminobject-interface>
+ <adminobject-class> org.apache.qpid.ra.admin.QpidDestinationProxy</adminobject-class>
+ <config-property>
+ <config-property-name>destinationAddress </config-property-name>
+ <config-property-type>java.lang.String </config-property-type>
+ </config-property>
+ <config-property>
+ <config-property-name>destinationType</config-property-name>
+ <config-property-type>java.lang.String </config-property-type>
+ </config-property>
+ </adminobject>
+ <adminobject>
+ <adminobject-interface>javax.jms.ConnectionFactory</adminobject-interface>
+ <adminobject-class> org.apache.qpid.ra.admin.QpidConnectionFactoryProxy</adminobject-class>
+ <config-property>
+ <config-property-name>connectionURL</config-property-name>
+ <config-property-type>java.lang.String </config-property-type>
+ </config-property>
+ </adminobject>
+ </resourceadapter>
+</connector>