You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ti...@apache.org on 2011/09/08 17:15:30 UTC

svn commit: r1166736 - in /aries/trunk/jpa: jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/ jpa-container-itest/src/test/java/org/apache/aries/jpa/context/itest/ jpa-container-testbundle-eclipselink/src/main/resources/META-INF/ ...

Author: timothyjward
Date: Thu Sep  8 15:15:29 2011
New Revision: 1166736

URL: http://svn.apache.org/viewvc?rev=1166736&view=rev
Log:
ARIES-741: Support for auto-enlistment of XADataSource objects from JNDI or DataSourceFactory

Added:
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/ConnectionKey.java
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/ConnectionWrapper.java
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/OSGiTransactionManager.java
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/XADatasourceEnlistingWrapper.java
Modified:
    aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerDataSourceFactoryTest.java
    aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/context/itest/JPAContextTest.java
    aries/trunk/jpa/jpa-container-testbundle-eclipselink/src/main/resources/META-INF/persistence.xml
    aries/trunk/jpa/jpa-container-testbundle-eclipselink/src/main/resources/OSGI-INF/blueprint/config.xml
    aries/trunk/jpa/jpa-container-testbundle/src/main/resources/META-INF/persistence.xml
    aries/trunk/jpa/jpa-container-testbundle/src/main/resources/OSGI-INF/blueprint/config.xml
    aries/trunk/jpa/jpa-container/pom.xml
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DataSourceFactoryDataSource.java
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DelayedLookupDataSource.java
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/JndiDataSource.java
    aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/PersistenceUnitInfoImpl.java
    aries/trunk/jpa/jpa-container/src/main/resources/org/apache/aries/jpa/container/nls/jpaContainerMessages.properties

Modified: aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerDataSourceFactoryTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerDataSourceFactoryTest.java?rev=1166736&r1=1166735&r2=1166736&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerDataSourceFactoryTest.java (original)
+++ aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/container/itest/JPAContainerDataSourceFactoryTest.java Thu Sep  8 15:15:29 2011
@@ -31,11 +31,13 @@ import javax.persistence.EntityManagerFa
 import javax.sql.ConnectionPoolDataSource;
 import javax.sql.DataSource;
 import javax.sql.XADataSource;
+import javax.transaction.UserTransaction;
 
 import org.apache.aries.itest.AbstractIntegrationTest;
 import org.apache.aries.jpa.container.PersistenceUnitConstants;
 import org.apache.aries.jpa.container.itest.entities.Car;
 import org.apache.derby.jdbc.EmbeddedDataSource;
+import org.apache.derby.jdbc.EmbeddedXADataSource;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.ops4j.pax.exam.Option;
@@ -95,6 +97,58 @@ public class JPAContainerDataSourceFacto
     assertNull(refs);
   }
   
+  @Test
+  public void testDataSourceFactoryXALifecycle() throws Exception {
+    //Wait for startup
+    context().getService(EntityManagerFactory.class, "(&(osgi.unit.name=test-unit)(" + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))");
+    
+    //Now go
+    ServiceReference[] refs = context().getServiceReferences(
+        EntityManagerFactory.class.getName(), "(&(osgi.unit.name=dsf-xa-test-unit)(" + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))");
+    
+    assertNull(refs);
+    
+    Hashtable<String, Object> props = new Hashtable();
+    props.put(DataSourceFactory.OSGI_JDBC_DRIVER_CLASS, "org.apache.derby.jdbc.EmbeddedDriver");
+    
+    ServiceRegistration reg = context().registerService(DataSourceFactory.class.getName(), 
+        new DerbyDataSourceFactory(), props);
+    
+    
+    EntityManagerFactory emf = context().getService(EntityManagerFactory.class, 
+        "(&(osgi.unit.name=dsf-xa-test-unit)(" + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))");
+    
+    
+    EntityManager em = emf.createEntityManager();
+    
+    //Use a JTA tran to show integration
+    UserTransaction ut = context().getService(UserTransaction.class);
+    
+    ut.begin();
+    em.joinTransaction();
+    Car c = new Car();
+    c.setNumberPlate("123456");
+    c.setColour("blue");
+    em.persist(c);
+    
+    ut.commit();
+      
+    em.close();
+    
+    em = emf.createEntityManager();
+    
+    assertEquals("blue", em.find(Car.class, "123456").getColour());
+    
+    reg.unregister();
+    
+    refs = context().getServiceReferences(
+        EntityManagerFactory.class.getName(), "(&(osgi.unit.name=dsf-xa-test-unit)(" + PersistenceUnitConstants.CONTAINER_MANAGED_PERSISTENCE_UNIT + "=true))");
+    
+    assertNull(refs);
+  }
+  
+  
+  
   private static class DerbyDataSourceFactory implements DataSourceFactory {
 
     public DataSource createDataSource(Properties props) throws SQLException {
@@ -112,8 +166,10 @@ public class JPAContainerDataSourceFacto
 
     public XADataSource createXADataSource(Properties props)
         throws SQLException {
-      // TODO Auto-generated method stub
-      return null;
+      EmbeddedXADataSource ds = new EmbeddedXADataSource();
+      ds.setDatabaseName("memory:TEST");
+      ds.setCreateDatabase("create");
+      return ds;
     }
 
     public Driver createDriver(Properties props) throws SQLException {

Modified: aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/context/itest/JPAContextTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/context/itest/JPAContextTest.java?rev=1166736&r1=1166735&r2=1166736&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/context/itest/JPAContextTest.java (original)
+++ aries/trunk/jpa/jpa-container-itest/src/test/java/org/apache/aries/jpa/context/itest/JPAContextTest.java Thu Sep  8 15:15:29 2011
@@ -38,6 +38,11 @@ import javax.persistence.Query;
 import javax.persistence.TransactionRequiredException;
 import javax.persistence.TypedQuery;
 import javax.persistence.criteria.CriteriaQuery;
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.SystemException;
 import javax.transaction.UserTransaction;
 
 import org.apache.aries.itest.AbstractIntegrationTest;
@@ -194,6 +199,13 @@ public abstract class JPAContextTest ext
     
     EntityManagerFactory emf = getProxyEMF("bp-test-unit");
     
+    doNonTxEmIsCleared(emf);
+    
+  }
+
+  private void doNonTxEmIsCleared(EntityManagerFactory emf)
+      throws NotSupportedException, SystemException, HeuristicMixedException,
+      HeuristicRollbackException, RollbackException {
     final EntityManager managedEm = emf.createEntityManager();
     
     UserTransaction ut = context().getService(UserTransaction.class);
@@ -240,6 +252,16 @@ public abstract class JPAContextTest ext
     assertEquals(2, c.getNumberOfSeats());
     assertEquals(2000, c.getEngineSize());
     assertEquals("red", c.getColour());
+  }
+  
+  @Test
+  public void testNonTxEmIsClearedUsingXADataSourceWrapper() throws Exception {
+    
+    registerClient("bp-xa-test-unit");
+    
+    EntityManagerFactory emf = getProxyEMF("bp-xa-test-unit");
+    
+    doNonTxEmIsCleared(emf);
     
   }
 

Modified: aries/trunk/jpa/jpa-container-testbundle-eclipselink/src/main/resources/META-INF/persistence.xml
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container-testbundle-eclipselink/src/main/resources/META-INF/persistence.xml?rev=1166736&r1=1166735&r2=1166736&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container-testbundle-eclipselink/src/main/resources/META-INF/persistence.xml (original)
+++ aries/trunk/jpa/jpa-container-testbundle-eclipselink/src/main/resources/META-INF/persistence.xml Thu Sep  8 15:15:29 2011
@@ -47,4 +47,19 @@
      <property name="eclipselink.ddl-generation.output-mode" value="database" />
     </properties>
   </persistence-unit>
+  
+  <persistence-unit name="bp-xa-test-unit" transaction-type="JTA">
+    <description>Test persistence unit for the JPA Container and Context iTests</description>
+    <jta-data-source>blueprint:comp/xa</jta-data-source>
+    <non-jta-data-source>blueprint:comp/nonjta</non-jta-data-source>
+    <class>org.apache.aries.jpa.container.itest.entities.Car</class>
+    <exclude-unlisted-classes>true</exclude-unlisted-classes>
+    <properties>
+     <!-- These properties are creating the database on the fly. We are using them to avoid the tests having
+          to create a database  -->
+     <property name="eclipselink.target-database" value="Derby"/>     
+     <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
+     <property name="eclipselink.ddl-generation.output-mode" value="database" />
+    </properties>
+  </persistence-unit>
 </persistence>

Modified: aries/trunk/jpa/jpa-container-testbundle-eclipselink/src/main/resources/OSGI-INF/blueprint/config.xml
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container-testbundle-eclipselink/src/main/resources/OSGI-INF/blueprint/config.xml?rev=1166736&r1=1166735&r2=1166736&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container-testbundle-eclipselink/src/main/resources/OSGI-INF/blueprint/config.xml (original)
+++ aries/trunk/jpa/jpa-container-testbundle-eclipselink/src/main/resources/OSGI-INF/blueprint/config.xml Thu Sep  8 15:15:29 2011
@@ -23,15 +23,16 @@
   </bean>
   
   
-  <service interface="javax.sql.XADataSource">
+  <service interface="javax.sql.XADataSource" ref="xa">
     <service-properties>
       <entry key="transactional" value="true"/>
     </service-properties>
-    <bean class="org.apache.derby.jdbc.EmbeddedXADataSource">
-    	<property name="databaseName" value="memory:testDB"/>
-    	<property name="createDatabase" value="create"/> 
-  	</bean>
   </service>
+  
+  <bean id="xa" class="org.apache.derby.jdbc.EmbeddedXADataSource">
+  	<property name="databaseName" value="memory:testDB"/>
+    <property name="createDatabase" value="create"/> 
+  </bean>
     
   <reference id="jta" availability="optional" interface="javax.sql.DataSource"
              filter="(transactional=true)"/>

Modified: aries/trunk/jpa/jpa-container-testbundle/src/main/resources/META-INF/persistence.xml
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container-testbundle/src/main/resources/META-INF/persistence.xml?rev=1166736&r1=1166735&r2=1166736&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container-testbundle/src/main/resources/META-INF/persistence.xml (original)
+++ aries/trunk/jpa/jpa-container-testbundle/src/main/resources/META-INF/persistence.xml Thu Sep  8 15:15:29 2011
@@ -47,6 +47,20 @@
     </properties>
   </persistence-unit>
   
+  <persistence-unit name="bp-xa-test-unit" transaction-type="JTA">
+    <description>Test persistence unit for the JPA Container and Context iTests</description>
+    <jta-data-source>blueprint:comp/xa</jta-data-source>
+    <non-jta-data-source>blueprint:comp/nonjta</non-jta-data-source>
+    <class>org.apache.aries.jpa.container.itest.entities.Car</class>
+    <exclude-unlisted-classes>true</exclude-unlisted-classes>
+    <properties>
+     <!-- These properties are creating the database on the fly. We are using them to avoid the tests having
+          to create a database  -->
+     <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+     <property name="openjpa.jdbc.DBDictionary" value="derby"/>
+    </properties>
+  </persistence-unit>
+  
   <persistence-unit name="dsf-test-unit" transaction-type="RESOURCE_LOCAL">
     <description>Test persistence unit for the JPA Container DataSourceFactory iTests</description>
     <class>org.apache.aries.jpa.container.itest.entities.Car</class>
@@ -60,4 +74,18 @@
      <property name="openjpa.jdbc.DBDictionary" value="derby"/>
     </properties>
   </persistence-unit>
+  
+  <persistence-unit name="dsf-xa-test-unit" transaction-type="JTA">
+    <description>Test persistence unit for the JPA Container DataSourceFactory iTests</description>
+    <class>org.apache.aries.jpa.container.itest.entities.Car</class>
+    <exclude-unlisted-classes>true</exclude-unlisted-classes>
+    <properties>
+     <!-- These properties are creating the database on the fly. We are using them to avoid the tests having
+          to create a database  -->
+      <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver"/>
+      <property name="javax.persistence.jdbc.url" value="jdbc:derby:memory:TEST;create=true"/>
+     <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+     <property name="openjpa.jdbc.DBDictionary" value="derby"/>
+    </properties>
+  </persistence-unit>
 </persistence>

Modified: aries/trunk/jpa/jpa-container-testbundle/src/main/resources/OSGI-INF/blueprint/config.xml
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container-testbundle/src/main/resources/OSGI-INF/blueprint/config.xml?rev=1166736&r1=1166735&r2=1166736&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container-testbundle/src/main/resources/OSGI-INF/blueprint/config.xml (original)
+++ aries/trunk/jpa/jpa-container-testbundle/src/main/resources/OSGI-INF/blueprint/config.xml Thu Sep  8 15:15:29 2011
@@ -23,15 +23,16 @@
   </bean>
   
   
-  <service interface="javax.sql.XADataSource">
+  <service interface="javax.sql.XADataSource" ref="xa">
     <service-properties>
       <entry key="transactional" value="true"/>
     </service-properties>
-    <bean class="org.apache.derby.jdbc.EmbeddedXADataSource">
+  </service>
+  
+  <bean id="xa" class="org.apache.derby.jdbc.EmbeddedXADataSource">
     	<property name="databaseName" value="memory:testDB"/>
     	<property name="createDatabase" value="create"/> 
   	</bean>
-  </service>
     
   <reference id="jta" availability="optional" interface="javax.sql.DataSource"
              filter="(transactional=true)"/>

Modified: aries/trunk/jpa/jpa-container/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/pom.xml?rev=1166736&r1=1166735&r2=1166736&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/pom.xml (original)
+++ aries/trunk/jpa/jpa-container/pom.xml Thu Sep  8 15:15:29 2011
@@ -46,6 +46,7 @@
             javax.persistence.spi;version="[1.0.0,2.1.0)",
             javax.persistence.criteria;version="[1.1.0,2.1.0)";resolution:=optional,
             javax.persistence.metamodel;version="[1.1.0,2.1.0)";resolution:=optional,
+            !javax.transaction,
             org.apache.aries.jpa.container;version="[0.1.0,1.1.0)",
             org.apache.aries.jpa.container.parsing;version="[0.1.0,1.1.0)",
             org.apache.aries.quiesce.manager;version="[0.2,1.0)";resolution:=optional,
@@ -56,6 +57,9 @@
             org.osgi.service.jdbc;version="[1,2)";resolution:=optional,
             *
         </aries.osgi.import>
+        <aries.osgi.dynamic>
+            javax.transaction;version="[1.1,2)"
+        </aries.osgi.dynamic>
       <aries.osgi.activator>
           org.apache.aries.jpa.container.impl.PersistenceBundleManager
       </aries.osgi.activator>
@@ -157,6 +161,11 @@
         	<type>jar</type>
         	<scope>compile</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-jta_1.1_spec</artifactId>
+            <version>1.1.1</version>
+        </dependency>
     </dependencies>
 
 </project>

Modified: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java?rev=1166736&r1=1166735&r2=1166736&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java (original)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/impl/PersistenceBundleManager.java Thu Sep  8 15:15:29 2011
@@ -44,6 +44,7 @@ import org.apache.aries.jpa.container.pa
 import org.apache.aries.jpa.container.parsing.PersistenceDescriptorParser;
 import org.apache.aries.jpa.container.parsing.PersistenceDescriptorParserException;
 import org.apache.aries.jpa.container.parsing.impl.PersistenceDescriptorParserImpl;
+import org.apache.aries.jpa.container.tx.impl.OSGiTransactionManager;
 import org.apache.aries.jpa.container.unit.impl.ManagedPersistenceUnitInfoFactoryImpl;
 import org.apache.aries.util.AriesFrameworkUtil;
 import org.apache.aries.util.VersionRange;
@@ -142,6 +143,10 @@ public class PersistenceBundleManager im
     if (serviceTracker != null) {
       serviceTracker.close();
     }
+    
+    OSGiTransactionManager otm = OSGiTransactionManager.get();
+    if(otm != null)
+      otm.destroy();
   } 
   public Object addingBundle(Bundle bundle, BundleEvent event) 
   {

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/ConnectionKey.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/ConnectionKey.java?rev=1166736&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/ConnectionKey.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/ConnectionKey.java Thu Sep  8 15:15:29 2011
@@ -0,0 +1,81 @@
+/*
+ * 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.aries.jpa.container.tx.impl;
+
+import javax.transaction.Transaction;
+
+public class ConnectionKey {
+
+    private final String username;
+
+    private final String password;
+
+    private final Transaction transaction;
+
+    public ConnectionKey(String username, String password, Transaction transaction) {
+        this.username = username;
+        this.password = password;
+        this.transaction = transaction;
+    }
+
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((username == null) ? 0 : username.hashCode());
+        result = prime * result + ((password == null) ? 0 : password.hashCode());                
+        result = prime * result + ((transaction == null) ? 0 : transaction.hashCode());
+        return result;
+    }
+
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        ConnectionKey other = (ConnectionKey) obj;
+        if (username == null) {
+            if (other.username != null) {
+                return false;
+            }
+        } else if (!username.equals(other.username)) {
+            return false;
+        }
+        if (password == null) {
+            if (other.password != null) {
+                return false;
+            }
+        } else if (!password.equals(other.password)) {
+            return false;
+        }
+        if (transaction == null) {
+            if (other.transaction != null) {
+                return false;
+            }
+        } else if (!transaction.equals(other.transaction)) {
+            return false;
+        }
+        return true;
+    }
+
+}

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/ConnectionWrapper.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/ConnectionWrapper.java?rev=1166736&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/ConnectionWrapper.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/ConnectionWrapper.java Thu Sep  8 15:15:29 2011
@@ -0,0 +1,306 @@
+/*
+ * 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.aries.jpa.container.tx.impl;
+
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.CallableStatement;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.NClob;
+import java.sql.PreparedStatement;
+import java.sql.SQLClientInfoException;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Savepoint;
+import java.sql.Statement;
+import java.sql.Struct;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.transaction.xa.XAResource;
+
+import org.apache.aries.jpa.container.impl.NLS;
+
+/**
+ * This class is a wrapper around a {@link Connection} that performs
+ * enlistment/delistment of an {@link XAResource} from a transaction.
+ * 
+ * @see XADatasourceEnlistingWrapper
+ */
+public class ConnectionWrapper implements Connection {
+    
+    private Connection connection;
+    
+    private boolean closed;
+    
+    private boolean enlisted;
+    
+    public ConnectionWrapper(Connection connection, boolean enlisted) {
+        this.enlisted = enlisted;
+        this.connection = connection;
+    }
+            
+    public void close() throws SQLException {
+        if (!closed) {
+            try {                       
+                // don't close connection if enlisted in a transaction
+                // the connection will be closed in once the transaction completes
+                if (!enlisted) {
+                    connection.close();
+                }
+            } finally {
+                closed = true;
+            }            
+        }
+    }
+
+    // cannot be used while enrolled in a transaction 
+    
+    public void commit() throws SQLException {
+        if (enlisted) {
+            throw new SQLException(NLS.MESSAGES.getMessage("datasource.enlised.commit"));
+        }
+        connection.commit();
+    }
+
+    public void rollback() throws SQLException {
+        if (enlisted) {
+            throw new SQLException(NLS.MESSAGES.getMessage("datasource.enlised.rollback"));
+        }
+        connection.rollback();
+    }
+
+    public void rollback(Savepoint savepoint) throws SQLException {
+        if (enlisted) {
+            throw new SQLException(NLS.MESSAGES.getMessage("datasource.enlised.rollback"));
+        }
+        connection.rollback(savepoint);
+    }
+    
+    public Savepoint setSavepoint() throws SQLException {
+        if (enlisted) {
+            throw new SQLException(NLS.MESSAGES.getMessage("datasource.enlised.savepoint"));
+        }
+        return connection.setSavepoint();
+    }
+
+    public Savepoint setSavepoint(String name) throws SQLException {
+        if (enlisted) {
+            throw new SQLException(NLS.MESSAGES.getMessage("datasource.enlised.savepoint"));
+        }
+        return connection.setSavepoint(name);
+    }
+    
+    // rest of the methods
+    
+    public void clearWarnings() throws SQLException {
+        connection.clearWarnings();
+    }
+    
+    public Array createArrayOf(String typeName, Object[] elements)
+            throws SQLException {
+        return connection.createArrayOf(typeName, elements);
+    }
+
+    public Blob createBlob() throws SQLException {
+        return connection.createBlob();
+    }
+
+    public Clob createClob() throws SQLException {
+        return connection.createClob();
+    }
+
+    public NClob createNClob() throws SQLException {
+        return connection.createNClob();
+    }
+
+    public SQLXML createSQLXML() throws SQLException {
+        return connection.createSQLXML();
+    }
+
+    public Statement createStatement() throws SQLException {
+        return connection.createStatement();
+    }
+
+    public Statement createStatement(int resultSetType,
+            int resultSetConcurrency, int resultSetHoldability)
+            throws SQLException {
+        return connection.createStatement(resultSetType, resultSetConcurrency,
+                resultSetHoldability);
+    }
+
+    public Statement createStatement(int resultSetType, int resultSetConcurrency)
+            throws SQLException {
+        return connection.createStatement(resultSetType, resultSetConcurrency);
+    }
+
+    public Struct createStruct(String typeName, Object[] attributes)
+            throws SQLException {
+        return connection.createStruct(typeName, attributes);
+    }
+
+    public boolean getAutoCommit() throws SQLException {
+        return connection.getAutoCommit();
+    }
+
+    public String getCatalog() throws SQLException {
+        return connection.getCatalog();
+    }
+
+    public Properties getClientInfo() throws SQLException {
+        return connection.getClientInfo();
+    }
+
+    public String getClientInfo(String name) throws SQLException {
+        return connection.getClientInfo(name);
+    }
+
+    public int getHoldability() throws SQLException {
+        return connection.getHoldability();
+    }
+
+    public DatabaseMetaData getMetaData() throws SQLException {
+        return connection.getMetaData();
+    }
+
+    public int getTransactionIsolation() throws SQLException {
+        return connection.getTransactionIsolation();
+    }
+
+    public Map<String, Class<?>> getTypeMap() throws SQLException {
+        return connection.getTypeMap();
+    }
+
+    public SQLWarning getWarnings() throws SQLException {
+        return connection.getWarnings();
+    }
+
+    public boolean isClosed() throws SQLException {
+        return connection.isClosed();
+    }
+
+    public boolean isReadOnly() throws SQLException {
+        return connection.isReadOnly();
+    }
+
+    public boolean isValid(int timeout) throws SQLException {
+        return connection.isValid(timeout);
+    }
+
+    public boolean isWrapperFor(Class<?> iface) throws SQLException {
+        return connection.isWrapperFor(iface);
+    }
+
+    public String nativeSQL(String sql) throws SQLException {
+        return connection.nativeSQL(sql);
+    }
+
+    public CallableStatement prepareCall(String sql, int resultSetType,
+            int resultSetConcurrency, int resultSetHoldability)
+            throws SQLException {
+        return connection.prepareCall(sql, resultSetType, resultSetConcurrency,
+                resultSetHoldability);
+    }
+
+    public CallableStatement prepareCall(String sql, int resultSetType,
+            int resultSetConcurrency) throws SQLException {
+        return connection.prepareCall(sql, resultSetType, resultSetConcurrency);
+    }
+
+    public CallableStatement prepareCall(String sql) throws SQLException {
+        return connection.prepareCall(sql);
+    }
+
+    public PreparedStatement prepareStatement(String sql, int resultSetType,
+            int resultSetConcurrency, int resultSetHoldability)
+            throws SQLException {
+        return connection.prepareStatement(sql, resultSetType,
+                resultSetConcurrency, resultSetHoldability);
+    }
+
+    public PreparedStatement prepareStatement(String sql, int resultSetType,
+            int resultSetConcurrency) throws SQLException {
+        return connection.prepareStatement(sql, resultSetType,
+                resultSetConcurrency);
+    }
+
+    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
+            throws SQLException {
+        return connection.prepareStatement(sql, autoGeneratedKeys);
+    }
+
+    public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
+            throws SQLException {
+        return connection.prepareStatement(sql, columnIndexes);
+    }
+
+    public PreparedStatement prepareStatement(String sql, String[] columnNames)
+            throws SQLException {
+        return connection.prepareStatement(sql, columnNames);
+    }
+
+    public PreparedStatement prepareStatement(String sql) throws SQLException {
+        return connection.prepareStatement(sql);
+    }
+
+    public void releaseSavepoint(Savepoint savepoint) throws SQLException {
+        connection.releaseSavepoint(savepoint);
+    }
+
+    public void setAutoCommit(boolean autoCommit) throws SQLException {
+        connection.setAutoCommit(autoCommit);
+    }
+
+    public void setCatalog(String catalog) throws SQLException {
+        connection.setCatalog(catalog);
+    }
+
+    public void setClientInfo(Properties properties)
+            throws SQLClientInfoException {
+        connection.setClientInfo(properties);
+    }
+
+    public void setClientInfo(String name, String value)
+            throws SQLClientInfoException {
+        connection.setClientInfo(name, value);
+    }
+
+    public void setHoldability(int holdability) throws SQLException {
+        connection.setHoldability(holdability);
+    }
+
+    public void setReadOnly(boolean readOnly) throws SQLException {
+        connection.setReadOnly(readOnly);
+    }
+
+    public void setTransactionIsolation(int level) throws SQLException {
+        connection.setTransactionIsolation(level);
+    }
+
+    public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
+        connection.setTypeMap(map);
+    }
+
+    public <T> T unwrap(Class<T> iface) throws SQLException {
+        return connection.unwrap(iface);
+    }
+}

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/OSGiTransactionManager.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/OSGiTransactionManager.java?rev=1166736&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/OSGiTransactionManager.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/OSGiTransactionManager.java Thu Sep  8 15:15:29 2011
@@ -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.aries.jpa.container.tx.impl;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.InvalidTransactionException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.apache.aries.jpa.container.impl.NLS;
+import org.apache.aries.util.tracker.SingleServiceTracker;
+import org.apache.aries.util.tracker.SingleServiceTracker.SingleServiceListener;
+import org.osgi.framework.BundleContext;
+
+/**
+ *  Used to avoid a dependency on javax.transaction.TransactionManager 
+ */
+public class OSGiTransactionManager implements SingleServiceListener {
+
+  private static final AtomicReference<OSGiTransactionManager> INSTANCE = 
+    new AtomicReference<OSGiTransactionManager>();
+  
+  private final SingleServiceTracker<TransactionManager> tracker;
+  
+  public static void init(BundleContext ctx) {
+    
+    try {
+      Class<TransactionManager> txMgrClass = (Class<TransactionManager>) Class.forName(
+          "javax.transaction.TransactionManager", false, 
+          OSGiTransactionManager.class.getClassLoader());
+    
+      OSGiTransactionManager otm = new OSGiTransactionManager(txMgrClass, ctx);
+      if(!!!INSTANCE.compareAndSet(null, otm))
+        otm.destroy();
+    } catch (ClassNotFoundException cnfe) {
+      //No op
+    }
+  }
+  
+  public static OSGiTransactionManager get() {
+    return INSTANCE.get();
+  }
+  
+  private OSGiTransactionManager(Class<TransactionManager> txMgrClass, BundleContext ctx) {
+      tracker = new SingleServiceTracker<TransactionManager>(ctx, txMgrClass, this);
+      tracker.open();
+  }
+  
+  private TransactionManager getTransactionManager() {
+    TransactionManager txMgr = tracker.getService();
+    
+    if(txMgr == null)
+      throw new IllegalStateException(NLS.MESSAGES.getMessage("unable.to.get.tx.mgr"));
+    
+    return txMgr;
+  }
+  
+  public void destroy() {
+    tracker.close();
+  }
+  
+  public int getStatus() throws SystemException {
+    return getTransactionManager().getStatus();
+  }
+
+  public void resume(Transaction arg0) throws IllegalStateException,
+      InvalidTransactionException, SystemException {
+    getTransactionManager().resume(arg0);
+  }
+
+  public void setRollbackOnly() throws IllegalStateException, SystemException {
+    getTransactionManager().setRollbackOnly();
+  }
+
+  public Object getTransaction() throws SystemException {
+    // TODO Auto-generated method stub
+    return getTransactionManager().getTransaction();
+  }
+
+  @Override
+  public void serviceFound() {
+    // TODO Auto-generated method stub
+    
+  }
+
+
+  @Override
+  public void serviceLost() {
+    // TODO Auto-generated method stub
+    
+  }
+
+
+  @Override
+  public void serviceReplaced() {
+    // TODO Auto-generated method stub
+    
+  }
+}

Added: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/XADatasourceEnlistingWrapper.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/XADatasourceEnlistingWrapper.java?rev=1166736&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/XADatasourceEnlistingWrapper.java (added)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/tx/impl/XADatasourceEnlistingWrapper.java Thu Sep  8 15:15:29 2011
@@ -0,0 +1,200 @@
+/*
+ * 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.aries.jpa.container.tx.impl;
+
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.sql.DataSource;
+import javax.sql.XAConnection;
+import javax.sql.XADataSource;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAResource;
+
+import org.apache.aries.jpa.container.impl.NLS;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ * This class allows JDBC XA data sources to participate in global transactions,
+ * via the {@link ConnectionWrapper} that is returned. The only service provided
+ * is enlistment/delistment of the associated {@link XAResource} in transactions.
+ * Important consideration such as connection pooling and error handling are
+ * completely ignored.
+ *
+ */
+public class XADatasourceEnlistingWrapper implements DataSource, Serializable {
+    /** The serial version UID */
+    private static final long serialVersionUID = -3200389791205501228L;
+
+    private final XADataSource wrappedDS;
+    
+    private transient Map<Object, Connection> connectionMap = 
+        new ConcurrentHashMap<Object, Connection>();
+    
+    public XADatasourceEnlistingWrapper(XADataSource toWrap) {
+      wrappedDS = toWrap;
+      OSGiTransactionManager.init(FrameworkUtil.getBundle(
+          XADatasourceEnlistingWrapper.class).getBundleContext());
+    }
+    
+    public Connection getConnection() throws SQLException {
+        Transaction transaction = getTransaction();
+        if (transaction != null) {
+            Object key = transaction;
+            Connection connection = connectionMap.get(key);
+            if (connection == null) {
+                XAConnection xaConnection = wrappedDS.getXAConnection();                                
+                connection = xaConnection.getConnection();
+                enlist(transaction, xaConnection.getXAResource(), key);
+                connectionMap.put(key, connection);                
+            }
+            return getEnlistedConnection(connection, true);
+        } else {
+            return getEnlistedConnection(wrappedDS.getXAConnection().getConnection(), false);
+        }
+    }
+
+    public Connection getConnection(String username, String password) throws SQLException {
+        Transaction transaction = getTransaction();
+        if (transaction != null) {
+            Object key = new ConnectionKey(username, password, transaction);
+            Connection connection = connectionMap.get(key);
+            if (connection == null) {
+                XAConnection xaConnection = wrappedDS.getXAConnection(username, password);
+                connection = xaConnection.getConnection();
+                enlist(transaction, xaConnection.getXAResource(), key);               
+                connectionMap.put(key, connection);
+            }
+            return getEnlistedConnection(connection, true);
+        } else {
+            return getEnlistedConnection(wrappedDS.getXAConnection(username, password).getConnection(), false);
+        }
+    }
+
+    private Transaction getTransaction() throws SQLException {
+        try {
+            return (OSGiTransactionManager.get().getStatus() == Status.STATUS_ACTIVE) ? 
+                (Transaction)OSGiTransactionManager.get().getTransaction() : null;
+        } catch (SystemException e) {
+            throw new SQLException(NLS.MESSAGES.getMessage("unable.to.get.tx"), e);
+        }
+    }
+    
+    private void enlist(Transaction transaction, XAResource xaResource, Object key) throws SQLException {
+        try {
+            transaction.enlistResource(xaResource);            
+            transaction.registerSynchronization(new TransactionListener(key));
+        } catch (Exception e) {
+            try {
+                OSGiTransactionManager.get().setRollbackOnly();
+            } catch (IllegalStateException e1) {
+                e1.printStackTrace();
+            } catch (SystemException e1) {
+                e1.printStackTrace();
+            }
+        } 
+    }
+    
+    private class TransactionListener implements Synchronization {
+
+        private final Object key;
+        
+        public TransactionListener(Object key) {
+            this.key = key;
+        }
+        
+        public void afterCompletion(int status) {
+            Connection connection = connectionMap.remove(key);
+            if (connection != null) {
+                try {
+                    connection.close();
+                } catch (SQLException e) {
+                    // ignore
+                }
+            }
+        }
+
+        public void beforeCompletion() {
+        }
+        
+    }
+    
+    public PrintWriter getLogWriter() throws SQLException
+    {
+      return wrappedDS.getLogWriter();
+    }
+
+    public int getLoginTimeout() throws SQLException
+    {
+      return wrappedDS.getLoginTimeout();
+    }
+
+    public void setLogWriter(PrintWriter out) throws SQLException
+    {
+      wrappedDS.setLogWriter(out);
+    }
+
+    public void setLoginTimeout(int seconds) throws SQLException
+    {
+      wrappedDS.setLoginTimeout(seconds);
+    }
+
+    private Connection getEnlistedConnection(Connection connection, boolean enlisted) throws SQLException
+    {
+        return new ConnectionWrapper(connection, enlisted);
+    }
+
+    
+    @Override
+    public boolean equals(Object other)
+    {
+      if (other == this) return true;
+      if (other == null) return false;
+      
+      if (other.getClass() == this.getClass()) {
+        return wrappedDS.equals(((XADatasourceEnlistingWrapper)other).wrappedDS);
+      }
+      
+      return false;
+    }
+    
+    @Override
+    public int hashCode()
+    {
+      return wrappedDS.hashCode();
+    }
+
+    public boolean isWrapperFor(Class<?> arg0) throws SQLException
+    {
+      return false;
+    }
+
+    public <T> T unwrap(Class<T> arg0) throws SQLException
+    {
+      return null;
+    }
+}

Modified: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DataSourceFactoryDataSource.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DataSourceFactoryDataSource.java?rev=1166736&r1=1166735&r2=1166736&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DataSourceFactoryDataSource.java (original)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DataSourceFactoryDataSource.java Thu Sep  8 15:15:29 2011
@@ -42,12 +42,13 @@ public class DataSourceFactoryDataSource
   private final String driverName;
   private final Bundle persistenceBundle;
   private final Properties props;
+  private final boolean jta;
   
   private final AtomicReference<SingleServiceTracker<DataSourceFactory>> trackerRef =
     new AtomicReference<SingleServiceTracker<DataSourceFactory>>();
   
   public DataSourceFactoryDataSource(Bundle bundle, String driverName, String dbURL, 
-      String dbUserName, String dbPassword) {
+      String dbUserName, String dbPassword, boolean jta) {
     this.persistenceBundle = bundle;
     this.driverName = driverName;
     props = new Properties();
@@ -57,6 +58,8 @@ public class DataSourceFactoryDataSource
       props.setProperty(DataSourceFactory.JDBC_USER, dbUserName);
     if(dbPassword != null)
       props.setProperty(DataSourceFactory.JDBC_PASSWORD, dbPassword);
+    
+    this.jta = jta;
   }
 
   @Override
@@ -82,7 +85,11 @@ public class DataSourceFactoryDataSource
       DataSourceFactory dsf = tracker.getService();
       if(dsf != null) {
         try {
-          ds.compareAndSet(null, dsf.createDataSource(props));
+          if(jta) {
+            ds.compareAndSet(null, wrapXADataSource(dsf.createXADataSource(props)));
+          } else {
+            ds.compareAndSet(null, dsf.createDataSource(props));
+          }
         } catch (SQLException e) {
           String message = NLS.MESSAGES.getMessage("datasourcefactory.sql.exception", driverName, props, 
               persistenceBundle.getSymbolicName(), persistenceBundle.getVersion());

Modified: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DelayedLookupDataSource.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DelayedLookupDataSource.java?rev=1166736&r1=1166735&r2=1166736&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DelayedLookupDataSource.java (original)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/DelayedLookupDataSource.java Thu Sep  8 15:15:29 2011
@@ -23,6 +23,10 @@ import java.sql.Connection;
 import java.sql.SQLException;
 
 import javax.sql.DataSource;
+import javax.sql.XADataSource;
+
+import org.apache.aries.jpa.container.impl.NLS;
+import org.apache.aries.jpa.container.tx.impl.XADatasourceEnlistingWrapper;
 
 public abstract class DelayedLookupDataSource implements DataSource {
 
@@ -60,4 +64,19 @@ public abstract class DelayedLookupDataS
   public <T> T unwrap(Class<T> iface) throws SQLException {
     return getDs().unwrap(iface);
   }
+  
+  protected DataSource wrapXADataSource(XADataSource xaDs) throws IllegalStateException {
+    boolean b;
+    try {
+      Class.forName("javax.transaction.TransactionManager");
+      b = true;
+    } catch (ClassNotFoundException cnfe) {
+      b = false;
+    }
+    
+    if(!b)
+      throw new IllegalStateException(NLS.MESSAGES.getMessage("no.xa.wrapping"));
+    
+    return new XADatasourceEnlistingWrapper(xaDs);
+  }
 }

Modified: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/JndiDataSource.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/JndiDataSource.java?rev=1166736&r1=1166735&r2=1166736&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/JndiDataSource.java (original)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/JndiDataSource.java Thu Sep  8 15:15:29 2011
@@ -24,6 +24,7 @@ import java.util.concurrent.atomic.Atomi
 import javax.naming.InitialContext;
 import javax.naming.NamingException;
 import javax.sql.DataSource;
+import javax.sql.XADataSource;
 
 import org.apache.aries.jpa.container.impl.NLS;
 import org.osgi.framework.Bundle;
@@ -38,11 +39,15 @@ public class JndiDataSource extends Dela
   private AtomicReference<DataSource> ds = new AtomicReference<DataSource>();
   
   private final String jndiName;
+  private final String unitName;
   private final Bundle persistenceBundle;
+  private final boolean jta;
   
-  public JndiDataSource (String jndi, Bundle persistenceBundle) {
+  public JndiDataSource (String jndi, String unit, Bundle persistenceBundle, boolean jta) {
     jndiName = jndi;
+    unitName = unit;
     this.persistenceBundle = persistenceBundle;
+    this.jta = jta;
   }
   
   @Override
@@ -56,7 +61,25 @@ public class JndiDataSource extends Dela
           throw new IllegalStateException(NLS.MESSAGES.getMessage("persistence.bundle.not.active", persistenceBundle.getSymbolicName(), persistenceBundle.getVersion()));
         props.put("osgi.service.jndi.bundleContext", bCtx);
         InitialContext ctx = new InitialContext(props);
-        ds.compareAndSet(null, (DataSource) ctx.lookup(jndiName));
+        
+        Object o = ctx.lookup(jndiName);
+        
+        if(o instanceof XADataSource) {
+          if(jta) {
+            ds.compareAndSet(null,  wrapXADataSource((XADataSource)o));
+          } else {
+            if(o instanceof DataSource)
+              ds.compareAndSet(null, (DataSource)o);
+            else 
+              throw new IllegalArgumentException(NLS.MESSAGES.getMessage("xa.datasource.non.tx", unitName, 
+                  persistenceBundle.getSymbolicName(), persistenceBundle.getVersion(), jndiName));
+          }
+        } else if (o instanceof DataSource) {
+          ds.compareAndSet(null, (DataSource)o);
+        } else {
+          throw new IllegalArgumentException(NLS.MESSAGES.getMessage("not.a.datasource", unitName,
+              persistenceBundle.getSymbolicName(), persistenceBundle.getVersion(), jndiName));
+        }
       } catch (NamingException e) {
         String message = NLS.MESSAGES.getMessage("no.data.source.found", jndiName, persistenceBundle.getSymbolicName(), persistenceBundle.getVersion());
         _logger.error(message, e);

Modified: aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/PersistenceUnitInfoImpl.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/PersistenceUnitInfoImpl.java?rev=1166736&r1=1166735&r2=1166736&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/PersistenceUnitInfoImpl.java (original)
+++ aries/trunk/jpa/jpa-container/src/main/java/org/apache/aries/jpa/container/unit/impl/PersistenceUnitInfoImpl.java Thu Sep  8 15:15:29 2011
@@ -129,7 +129,8 @@ public class PersistenceUnitInfoImpl imp
     String jndiString = (String) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.JTA_DATASOURCE);
     DataSource toReturn = null;
     if(jndiString != null) {
-      toReturn = new JndiDataSource(jndiString, bundle);
+      toReturn = new JndiDataSource(jndiString, getPersistenceUnitName(), bundle, 
+          getTransactionType() == PersistenceUnitTransactionType.JTA);
     } else if(useDataSourceFactory) {
       toReturn = jtaDSFDS.get();
       if(toReturn == null) {
@@ -143,7 +144,8 @@ public class PersistenceUnitInfoImpl imp
           jtaDSFDS.compareAndSet(null, new DataSourceFactoryDataSource(bundle, driverName,
               props.getProperty("javax.persistence.jdbc.url"), 
               props.getProperty("javax.persistence.jdbc.user"), 
-              props.getProperty("javax.persistence.jdbc.password")));
+              props.getProperty("javax.persistence.jdbc.password"),
+              getTransactionType() == PersistenceUnitTransactionType.JTA));
           toReturn = jtaDSFDS.get();
         }
       }
@@ -184,7 +186,7 @@ public class PersistenceUnitInfoImpl imp
     String jndiString = (String) unit.getPersistenceXmlMetadata().get(ParsedPersistenceUnit.NON_JTA_DATASOURCE);
     DataSource toReturn = null;
     if(jndiString != null) {
-      toReturn = new JndiDataSource(jndiString, bundle);
+      toReturn = new JndiDataSource(jndiString, getPersistenceUnitName(), bundle, false);
     } else if(useDataSourceFactory) {
       toReturn = nonJtaDSFDS.get();
       if(toReturn == null) {
@@ -198,7 +200,8 @@ public class PersistenceUnitInfoImpl imp
           nonJtaDSFDS.compareAndSet(null, new DataSourceFactoryDataSource(bundle, driverName,
               props.getProperty("javax.persistence.jdbc.url"), 
               props.getProperty("javax.persistence.jdbc.user"), 
-              props.getProperty("javax.persistence.jdbc.password")));
+              props.getProperty("javax.persistence.jdbc.password"),
+              false));
           toReturn = nonJtaDSFDS.get();
         }
       }

Modified: aries/trunk/jpa/jpa-container/src/main/resources/org/apache/aries/jpa/container/nls/jpaContainerMessages.properties
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container/src/main/resources/org/apache/aries/jpa/container/nls/jpaContainerMessages.properties?rev=1166736&r1=1166735&r2=1166736&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container/src/main/resources/org/apache/aries/jpa/container/nls/jpaContainerMessages.properties (original)
+++ aries/trunk/jpa/jpa-container/src/main/resources/org/apache/aries/jpa/container/nls/jpaContainerMessages.properties Thu Sep  8 15:15:29 2011
@@ -186,4 +186,19 @@ using.datasource.factory=The persistence
 # {0} The datasourcefactory class
 # {1} The bundle symbolic name.
 # {2} The bundle version.
-no.datasource.factory=No DataSourceFactory service is available for the JDBC driver class {0}. Persistence bundle {1}/{2} is trying to create that DataSource and cannot. One or more persistence units will be unusable until this DataSourceFactory is available.
\ No newline at end of file
+no.datasource.factory=No DataSourceFactory service is available for the JDBC driver class {0}. Persistence bundle {1}/{2} is trying to create that DataSource and cannot. One or more persistence units will be unusable until this DataSourceFactory is available.
+datasource.enlised.commit=This datasource is enrolled in a JTA transaction and can only be committed by the JTA transaction manager.
+datasource.enlised.rollback=This datasource is enrolled in a JTA transaction and can only be rolledback by the JTA transaction manager.
+datasource.enlised.savepoint=This datasource is enrolled in a JTA transaction and does not support savepoint.
+unable.to.get.tx=An error occurred while getting the current transaction.
+unable.to.get.tx.mgr=No TransactionManager is currently available.
+# {0} The name of the persistence unit.
+# {1} The symbolic name of the persistence bundle.
+# {2} The version of the persistence bundle.
+# {3} The jndi name of the datasource
+xa.datasource.non.tx=The persistence unit {0} in persistence bundle {1}/{2} uses a JNDI name {3} that looks up an XADataSource. The persistence unit is not JTA integrated so an XADataSource cannot be used. 
+# {0} The name of the persistence unit.
+# {1} The symbolic name of the persistence bundle.
+# {2} The version of the persistence bundle.
+# {3} The jndi name of the datasource
+not.a.datasource=The persistence unit {0} in persistence bundle {1}/{2} uses a JNDI name {3} that looks up an Objet that is not a DataSource or XADataSource. 
\ No newline at end of file