Author: timothyjward
Date: Wed Apr 6 10:06:08 2016
New Revision: 1737958
URL: http://svn.apache.org/viewvc?rev=1737958&view=rev
Log:
[tx-control] Add support for resource local JPA using EclipseLink
Added:
aries/trunk/tx-control/tx-control-jpa-itests/
aries/trunk/tx-control/tx-control-jpa-itests/.gitignore
aries/trunk/tx-control/tx-control-jpa-itests/pom.xml
aries/trunk/tx-control/tx-control-jpa-itests/src/
aries/trunk/tx-control/tx-control-jpa-itests/src/test/
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractJPATransactionTest.java
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/SimpleTransactionTest.java
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/entity/
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/entity/Message.java
aries/trunk/tx-control/tx-control-jpa-itests/src/test/resources/
aries/trunk/tx-control/tx-control-jpa-itests/src/test/resources/META-INF/
aries/trunk/tx-control/tx-control-jpa-itests/src/test/resources/META-INF/persistence.xml
aries/trunk/tx-control/tx-control-provider-jpa-local/
aries/trunk/tx-control/tx-control-provider-jpa-local/.gitignore
aries/trunk/tx-control/tx-control-provider-jpa-local/pom.xml
aries/trunk/tx-control/tx-control-provider-jpa-local/src/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/DriverDataSource.java
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/EntityManagerWrapper.java
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/ScopedEntityManagerWrapper.java
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/TxEntityManagerWrapper.java
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/Activator.java
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/JPAEntityManagerProviderFactoryImpl.java
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/JPAEntityManagerProviderImpl.java
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LifecycleAware.java
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/ManagedJPADataSourceSetup.java
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/ManagedJPAEMFLocator.java
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/ManagedServiceFactoryImpl.java
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/TxContextBindingEntityManager.java
aries/trunk/tx-control/tx-control-provider-jpa-local/src/test/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/test/java/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/test/java/org/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/test/java/org/apache/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/test/java/org/apache/aries/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/test/java/org/apache/aries/tx/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/test/java/org/apache/aries/tx/control/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/test/java/org/apache/aries/tx/control/jpa/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/test/java/org/apache/aries/tx/control/jpa/local/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/test/java/org/apache/aries/tx/control/jpa/local/impl/
aries/trunk/tx-control/tx-control-provider-jpa-local/src/test/java/org/apache/aries/tx/control/jpa/local/impl/TxContextBindingEntityManagerTest.java
Modified:
aries/trunk/tx-control/pom.xml
Modified: aries/trunk/tx-control/pom.xml
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/pom.xml?rev=1737958&r1=1737957&r2=1737958&view=diff
==============================================================================
--- aries/trunk/tx-control/pom.xml (original)
+++ aries/trunk/tx-control/pom.xml Wed Apr 6 10:06:08 2016
@@ -48,9 +48,14 @@
<module>tx-control-provider-jdbc-common</module>
<module>tx-control-provider-jdbc-local</module>
<module>tx-control-provider-jdbc-xa</module>
+ <module>tx-control-provider-jpa-local</module>
<module>tx-control-itests</module>
+ <module>tx-control-jpa-itests</module>
</modules>
</profile>
</profiles>
+ <modules>
+ <module>tx-control-provider-jpa-local</module>
+ </modules>
</project>
\ No newline at end of file
Added: aries/trunk/tx-control/tx-control-jpa-itests/.gitignore
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-jpa-itests/.gitignore?rev=1737958&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-jpa-itests/.gitignore (added)
+++ aries/trunk/tx-control/tx-control-jpa-itests/.gitignore Wed Apr 6 10:06:08
2016
@@ -0,0 +1 @@
+/target/
Added: aries/trunk/tx-control/tx-control-jpa-itests/pom.xml
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-jpa-itests/pom.xml?rev=1737958&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-jpa-itests/pom.xml (added)
+++ aries/trunk/tx-control/tx-control-jpa-itests/pom.xml Wed Apr 6 10:06:08
2016
@@ -0,0 +1,231 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.aries</groupId>
+ <artifactId>parent</artifactId>
+ <version>2.0.1</version>
+ <relativePath>../../parent/pom.xml</relativePath>
+ </parent>
+ <groupId>org.apache.aries.tx-control</groupId>
+ <artifactId>org.apache.aries.tx-control-jpa-itests</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <name>Apache Aries Transaction Control JPA iTests</name>
+ <description>
+ JPA Integration tests using the Transaction Control service
+ </description>
+
+ <scm>
+ <connection>
+
scm:svn:http://svn.apache.org/repos/asf/aries/trunk/tx-control/tx-control-jpa-itests
+ </connection>
+ <developerConnection>
+
scm:svn:https://svn.apache.org/repos/asf/aries/trunk/tx-control/tx-control-jpa-itests
+ </developerConnection>
+ <url>
+
http://svn.apache.org/viewvc/aries/trunk/proxy/tx-control/tx-control-jpa-itests
+ </url>
+ </scm>
+
+
+ <properties>
+ <exam.version>3.4.0</exam.version>
+ <url.version>1.6.0</url.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <scope>test</scope>
+ <version>5.0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.tx-control</groupId>
+ <artifactId>tx-control-api</artifactId>
+ <scope>provided</scope>
+ <version>0.0.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.tx-control</groupId>
+ <artifactId>tx-control-service-local</artifactId>
+ <scope>test</scope>
+ <version>0.0.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.coordinator</artifactId>
+ <scope>test</scope>
+ <version>1.0.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.configadmin</artifactId>
+ <scope>test</scope>
+ <version>1.8.8</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.tx-control</groupId>
+ <artifactId>tx-control-provider-jpa-local</artifactId>
+ <scope>test</scope>
+ <version>0.0.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.persistence</groupId>
+ <artifactId>javax.persistence</artifactId>
+ <scope>test</scope>
+ <version>2.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.jdbc</artifactId>
+ <version>1.0.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.h2database</groupId>
+ <artifactId>h2</artifactId>
+ <version>1.4.191</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.testsupport</groupId>
+
<artifactId>org.apache.aries.testsupport.unit</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- pax exam -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.7.7</version>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-forked</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit4</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-link-mvn</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-aether</artifactId>
+ <version>${url.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>0.9.29</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>0.9.29</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.tinybundles</groupId>
+ <artifactId>tinybundles</artifactId>
+ <version>2.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.inject</groupId>
+ <artifactId>javax.inject</artifactId>
+ <version>1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.logging</groupId>
+ <artifactId>pax-logging-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.logging</groupId>
+ <artifactId>pax-logging-service</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <forkMode>pertest</forkMode>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.servicemix.tooling</groupId>
+ <artifactId>depends-maven-plugin</artifactId>
+ <version>1.2</version>
+ <executions>
+ <execution>
+ <id>generate-depends-file</id>
+ <goals>
+
<goal>generate-depends-file</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>ci-build-profile</id>
+ <activation>
+ <property>
+ <name>maven.repo.local</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+
<groupId>org.apache.maven.plugins</groupId>
+
<artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <!-- when the local
repo location has been specified, we need to pass
+ on this
information to PAX mvn url -->
+
<argLine>-Dorg.ops4j.pax.url.mvn.localRepository=${maven.repo.local}</argLine>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+</project>
\ No newline at end of file
Added:
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractJPATransactionTest.java
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractJPATransactionTest.java?rev=1737958&view=auto
==============================================================================
---
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractJPATransactionTest.java
(added)
+++
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractJPATransactionTest.java
Wed Apr 6 10:06:08 2016
@@ -0,0 +1,216 @@
+/*
+ * 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 WARRANTIESOR 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.tx.control.itests;
+
+import static org.ops4j.pax.exam.CoreOptions.bootClasspathLibrary;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemPackage;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import static org.ops4j.pax.exam.CoreOptions.when;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import javax.persistence.EntityManager;
+
+import org.apache.aries.itest.AbstractIntegrationTest;
+import org.apache.aries.tx.control.itests.entity.Message;
+import org.h2.tools.Server;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.ProbeBuilder;
+import org.ops4j.pax.exam.TestProbeBuilder;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.jdbc.DataSourceFactory;
+import org.osgi.service.jpa.EntityManagerFactoryBuilder;
+import org.osgi.service.transaction.control.TransactionControl;
+import org.osgi.service.transaction.control.jpa.JPAEntityManagerProvider;
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public abstract class AbstractJPATransactionTest extends
AbstractIntegrationTest {
+
+ protected TransactionControl txControl;
+
+ protected EntityManager em;
+
+ private Server server;
+
+ @Before
+ public void setUp() throws Exception {
+
+ txControl = context().getService(TransactionControl.class,
5000);
+
+ server = Server.createTcpServer("-tcpPort", "0");
+ server.start();
+
+ String jdbcUrl = "jdbc:h2:tcp://127.0.0.1:" + server.getPort()
+ "/" + getRemoteDBPath();
+
+ em = configuredEntityManager(jdbcUrl);
+ }
+
+ private String getRemoteDBPath() {
+ String fullResourceName = getClass().getName().replace('.',
'/') + ".class";
+
+ String resourcePath =
getClass().getResource(getClass().getSimpleName() + ".class").getPath();
+
+ File testClassesDir = new File(resourcePath.substring(0,
resourcePath.length() - fullResourceName.length()));
+
+ String dbPath = new File(testClassesDir.getParentFile(),
"testdb/db1").getAbsolutePath();
+ return dbPath;
+ }
+
+ private EntityManager configuredEntityManager(String jdbcUrl) throws
IOException {
+
+ Dictionary<String, Object> props = new Hashtable<>();
+
+ props.put(DataSourceFactory.OSGI_JDBC_DRIVER_CLASS,
"org.h2.Driver");
+ props.put(DataSourceFactory.JDBC_URL, jdbcUrl);
+ props.put(EntityManagerFactoryBuilder.JPA_UNIT_NAME,
"test-unit");
+
+ ConfigurationAdmin cm =
context().getService(ConfigurationAdmin.class, 5000);
+
+ String pid = "org.apache.aries.tx.control.jpa.local";
+
+ System.out.println("Configuring connection provider with pid "
+ pid);
+
+ org.osgi.service.cm.Configuration config =
cm.createFactoryConfiguration(
+ pid, null);
+ config.update(props);
+
+ return context().getService(JPAEntityManagerProvider.class,
5000).getResource(txControl);
+ }
+
+ @After
+ public void tearDown() {
+
+ try {
+ txControl.required(() ->
+ em.createQuery(
+
em.getCriteriaBuilder().createCriteriaDelete(Message.class)
+ ).executeUpdate());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+
+ clearConfiguration();
+
+ if(server != null) {
+ server.stop();
+ }
+
+ em = null;
+ }
+
+ private void clearConfiguration() {
+ ConfigurationAdmin cm =
context().getService(ConfigurationAdmin.class, 5000);
+ org.osgi.service.cm.Configuration[] cfgs = null;
+ try {
+ cfgs = cm.listConfigurations(null);
+ } catch (Exception e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+
+ if(cfgs != null) {
+ for(org.osgi.service.cm.Configuration cfg : cfgs) {
+ try {
+ cfg.delete();
+ } catch (Exception e) {}
+ }
+ try {
+ Thread.sleep(250);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @ProbeBuilder
+ public TestProbeBuilder probeConfiguration(TestProbeBuilder probe) {
+ // makes sure the generated Test-Bundle contains this import!
+ probe.setHeader("Meta-Persistence", "META-INF/persistence.xml");
+ return probe;
+ }
+
+ @Configuration
+ public Option[] localTxConfiguration() {
+ String localRepo = System.getProperty("maven.repo.local");
+ if (localRepo == null) {
+ localRepo =
System.getProperty("org.ops4j.pax.url.mvn.localRepository");
+ }
+
+ return options(junitBundles(),
systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"),
+ when(localRepo != null)
+
.useOptions(CoreOptions.vmOption("-Dorg.ops4j.pax.url.mvn.localRepository=" +
localRepo)),
+ mavenBundle("org.apache.aries.testsupport",
"org.apache.aries.testsupport.unit").versionAsInProject(),
+ localTxControlService(),
+ localJpaResourceProviderWithH2(),
+ eclipseLink2_3_0(),
+ ariesJPA(),
+ mavenBundle("org.apache.felix",
"org.apache.felix.configadmin").versionAsInProject(),
+ mavenBundle("org.ops4j.pax.logging",
"pax-logging-api").versionAsInProject(),
+ mavenBundle("org.ops4j.pax.logging",
"pax-logging-service").versionAsInProject()
+
+//
,CoreOptions.vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005")
+ );
+ }
+
+ public Option localTxControlService() {
+ return CoreOptions.composite(
+ mavenBundle("org.apache.felix",
"org.apache.felix.coordinator").versionAsInProject(),
+ mavenBundle("org.apache.aries.tx-control",
"tx-control-service-local").versionAsInProject());
+ }
+
+ public Option localJpaResourceProviderWithH2() {
+ return CoreOptions.composite(
+ mavenBundle("com.h2database",
"h2").versionAsInProject(),
+ mavenBundle("org.apache.aries.tx-control",
"tx-control-provider-jpa-local").versionAsInProject());
+ }
+
+ public Option eclipseLink2_3_0() {
+ return CoreOptions.composite(
+ systemPackage("javax.transaction;version=1.1"),
+
systemPackage("javax.transaction.xa;version=1.1"),
+
bootClasspathLibrary(mavenBundle("org.apache.geronimo.specs",
"geronimo-jta_1.1_spec", "1.1.1")),
+ mavenBundle("org.eclipse.persistence",
"org.eclipse.persistence.jpa", "2.6.0"),
+ mavenBundle("org.eclipse.persistence",
"org.eclipse.persistence.core", "2.6.0"),
+ mavenBundle("org.eclipse.persistence",
"org.eclipse.persistence.asm", "2.6.0"),
+ mavenBundle("org.eclipse.persistence",
"org.eclipse.persistence.antlr", "2.6.0"),
+ mavenBundle("org.eclipse.persistence",
"org.eclipse.persistence.jpa.jpql", "2.6.0"),
+ mavenBundle("org.apache.aries.jpa",
"org.apache.aries.jpa.eclipselink.adapter", "2.3.0"));
+ }
+
+ public Option ariesJPA() {
+ return mavenBundle("org.apache.aries.jpa",
"org.apache.aries.jpa.container", "2.3.0");
+ }
+}
Added:
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/SimpleTransactionTest.java
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/SimpleTransactionTest.java?rev=1737958&view=auto
==============================================================================
---
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/SimpleTransactionTest.java
(added)
+++
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/SimpleTransactionTest.java
Wed Apr 6 10:06:08 2016
@@ -0,0 +1,240 @@
+/*
+ * 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 WARRANTIESOR 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.tx.control.itests;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+
+import org.apache.aries.tx.control.itests.entity.Message;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class SimpleTransactionTest extends AbstractJPATransactionTest {
+
+ @Test
+ public void testTx() {
+
+ Message message = new Message();
+ message.message = "Hello World!";
+
+ txControl.required(() -> {
+ em.persist(message);
+ return null;
+ });
+
+ assertEquals("Hello World!", txControl.notSupported(() -> {
+ return em.find(Message.class, message.id).message;
+ }));
+ }
+
+ @Test
+ public void testRollback() {
+
+ Message message = new Message();
+ message.message = "Hello World!";
+
+ txControl.required(() -> {
+ em.persist(message);
+ txControl.setRollbackOnly();
+ return null;
+ });
+
+ assertEquals(Long.valueOf(0), txControl.notSupported(() -> {
+ CriteriaBuilder cb = em.getCriteriaBuilder();
+ CriteriaQuery<Long> countQuery =
cb.createQuery(Long.class);
+
countQuery.select(cb.count(countQuery.from(Message.class)));
+
+ return em.createQuery(countQuery).getSingleResult();
+ }));
+ }
+
+ @Test
+ public void testNestedTx() {
+ Message message = new Message();
+ message.message = "Hello World!";
+
+ Message message2 = new Message();
+ message2.message = "Hello Nested World!";
+
+ txControl.required(() -> {
+ em.persist(message);
+
+ txControl.requiresNew(() -> {
+ em.persist(message2);
+ return null;
+ });
+
+ return null;
+ });
+
+ List<Message> results = txControl.notSupported(() -> {
+ CriteriaBuilder cb = em.getCriteriaBuilder();
+ CriteriaQuery<Message> query =
cb.createQuery(Message.class);
+
query.orderBy(cb.asc(query.from(Message.class).get("message")));
+
+ return em.createQuery(query).getResultList();
+ });
+
+ System.out.println(results);
+
+ assertEquals(2, results.size());
+ assertEquals("Hello Nested World!", results.get(0).message);
+ assertEquals("Hello World!", results.get(1).message);
+ }
+
+ @Test
+ public void testNestedTxOuterRollback() {
+ Message message = new Message();
+ message.message = "Hello World!";
+
+ Message message2 = new Message();
+ message2.message = "Hello Nested World!";
+
+ txControl.required(() -> {
+ // This will not end up in the database
+ em.persist(message);
+
+ // This should only apply to the current transaction
level
+ txControl.setRollbackOnly();
+
+ // This nested transaction will commit
+ txControl.requiresNew(() -> {
+ em.persist(message2);
+ return null;
+ });
+
+ return null;
+ });
+
+ List<Message> results = txControl.notSupported(() -> {
+ CriteriaBuilder cb = em.getCriteriaBuilder();
+ CriteriaQuery<Message> query =
cb.createQuery(Message.class);
+
query.orderBy(cb.asc(query.from(Message.class).get("message")));
+
+ return em.createQuery(query).getResultList();
+ });
+
+ System.out.println(results);
+
+ assertEquals(1, results.size());
+ assertEquals("Hello Nested World!", results.get(0).message);
+ }
+
+ @Test
+ public void testNestedTxInnerRollback() {
+
+ Message message = new Message();
+ message.message = "Hello World!";
+
+ Message message2 = new Message();
+ message2.message = "Hello Nested World!";
+
+ txControl.required(() -> {
+ // This will end up in the database
+ em.persist(message);
+
+ // This nested transaction will not commit
+ txControl.requiresNew(() -> {
+ em.persist(message2);
+ txControl.setRollbackOnly();
+ return null;
+ });
+
+ return null;
+ });
+
+ List<Message> results = txControl.notSupported(() -> {
+ CriteriaBuilder cb = em.getCriteriaBuilder();
+ CriteriaQuery<Message> query =
cb.createQuery(Message.class);
+
query.orderBy(cb.asc(query.from(Message.class).get("message")));
+
+ return em.createQuery(query).getResultList();
+ });
+
+ System.out.println(results);
+
+ assertEquals(1, results.size());
+ assertEquals("Hello World!", results.get(0).message);
+ }
+
+ @Test
+ public void testRequiredInheritsTx() {
+
+ Message message = new Message();
+ message.message = "Hello World!";
+
+ Message message2 = new Message();
+ message2.message = "Hello Nested World!";
+
+ txControl.required(() -> {
+ em.persist(message);
+
+ txControl.required(() -> {
+ em.persist(message2);
+ return null;
+ });
+
+ return null;
+ });
+
+ List<Message> results = txControl.notSupported(() -> {
+ CriteriaBuilder cb = em.getCriteriaBuilder();
+ CriteriaQuery<Message> query =
cb.createQuery(Message.class);
+
query.orderBy(cb.asc(query.from(Message.class).get("message")));
+
+ return em.createQuery(query).getResultList();
+ });
+
+ System.out.println(results);
+
+ assertEquals(2, results.size());
+ assertEquals("Hello Nested World!", results.get(0).message);
+ assertEquals("Hello World!", results.get(1).message);
+ }
+
+ @Test
+ public void testSuspendedTx() {
+
+ Message message = new Message();
+ message.message = "Hello World!";
+
+ txControl.required(() -> {
+ em.persist(message);
+
+ assertEquals(Long.valueOf(0),
txControl.notSupported(() -> {
+ CriteriaBuilder cb =
em.getCriteriaBuilder();
+ CriteriaQuery<Long> countQuery =
cb.createQuery(Long.class);
+
countQuery.select(cb.count(countQuery.from(Message.class)));
+
+ return
em.createQuery(countQuery).getSingleResult();
+ }));
+
+ return null;
+ });
+ }
+}
Added:
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/entity/Message.java
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/entity/Message.java?rev=1737958&view=auto
==============================================================================
---
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/entity/Message.java
(added)
+++
aries/trunk/tx-control/tx-control-jpa-itests/src/test/java/org/apache/aries/tx/control/itests/entity/Message.java
Wed Apr 6 10:06:08 2016
@@ -0,0 +1,21 @@
+package org.apache.aries.tx.control.itests.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+@Entity
+public class Message {
+
+ @Id
+ @GeneratedValue
+ public Integer id;
+
+ public String message;
+
+ @Override
+ public String toString() {
+ return "Message [id=" + id + ", message=" + message + "]";
+ }
+
+}
Added:
aries/trunk/tx-control/tx-control-jpa-itests/src/test/resources/META-INF/persistence.xml
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-jpa-itests/src/test/resources/META-INF/persistence.xml?rev=1737958&view=auto
==============================================================================
---
aries/trunk/tx-control/tx-control-jpa-itests/src/test/resources/META-INF/persistence.xml
(added)
+++
aries/trunk/tx-control/tx-control-jpa-itests/src/test/resources/META-INF/persistence.xml
Wed Apr 6 10:06:08 2016
@@ -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.
+-->
+<persistence xmlns="http://java.sun.com/xml/ns/persistence"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
+ version="2.0">
+
+ <persistence-unit name="test-unit">
+ <description>Test persistence unit for the Transaction Control JPA
Provider</description>
+
+ <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.schema-generation.database.action"
value="drop-and-create"/>
+ </properties>
+ </persistence-unit>
+</persistence>
\ No newline at end of file
Added: aries/trunk/tx-control/tx-control-provider-jpa-local/.gitignore
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jpa-local/.gitignore?rev=1737958&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jpa-local/.gitignore (added)
+++ aries/trunk/tx-control/tx-control-provider-jpa-local/.gitignore Wed Apr 6
10:06:08 2016
@@ -0,0 +1 @@
+/target/
Added: aries/trunk/tx-control/tx-control-provider-jpa-local/pom.xml
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jpa-local/pom.xml?rev=1737958&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jpa-local/pom.xml (added)
+++ aries/trunk/tx-control/tx-control-provider-jpa-local/pom.xml Wed Apr 6
10:06:08 2016
@@ -0,0 +1,181 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.aries</groupId>
+ <artifactId>parent</artifactId>
+ <version>2.0.1</version>
+ <relativePath>../../parent/pom.xml</relativePath>
+ </parent>
+ <groupId>org.apache.aries.tx-control</groupId>
+ <artifactId>tx-control-provider-jpa-local</artifactId>
+ <packaging>bundle</packaging>
+ <name>OSGi Transaction Control JPA Resource Provider - Local
Transactions</name>
+ <version>0.0.1-SNAPSHOT</version>
+
+ <description>
+ This bundle contains a JPA resource provider for use with the OSGi
Transaction Control Service that supports local transactions.
+ </description>
+
+ <scm>
+ <connection>
+
scm:svn:http://svn.apache.org/repos/asf/aries/trunk/tx-control/tx-control-provider-jpa-local
+ </connection>
+ <developerConnection>
+
scm:svn:https://svn.apache.org/repos/asf/aries/trunk/tx-control/tx-control-provider-jpa-local
+ </developerConnection>
+ <url>
+
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jpa-local
+ </url>
+ </scm>
+
+ <properties>
+ <aries.osgi.activator>
+ org.apache.aries.tx.control.jpa.local.impl.Activator
+ </aries.osgi.activator>
+ <!-- We keep the versioning from Geronimo as it makes most
things work,
+ even though everything should use the JavaJPA contract -->
+ <aries.osgi.export.pkg>
+ org.osgi.service.transaction.control.jpa,
+ org.osgi.service.cm,
+ org.osgi.service.jdbc,
+ org.osgi.service.jpa,
+ javax.persistence;version=1.2;jpa=2.1,
+ javax.persistence.criteria;version=1.2;jpa=2.1,
+ javax.persistence.metamodel;version=1.2;jpa=2.1,
+ javax.persistence.spi;version=1.2;jpa=2.1,
+ javax.persistence;version=2.1,
+ javax.persistence.criteria;version=2.1,
+ javax.persistence.metamodel;version=2.1,
+ javax.persistence.spi;version=2.1
+ </aries.osgi.export.pkg>
+ <aries.osgi.private.pkg>
+ org.apache.aries.tx.control.jpa.*,
+ org.apache.geronimo.osgi.locator,
+ org.apache.geronimo.specs.jpa,
+ com.zaxxer.hikari,
+ com.zaxxer.hikari.metrics,
+ com.zaxxer.hikari.pool,
+ com.zaxxer.hikari.util
+ </aries.osgi.private.pkg>
+ <aries.osgi.import.pkg>
+ !com.codahale.*,
+ !com.zaxxer.hikari.metrics.dropwizard,
+ !javassist.*,
+ !org.apache.geronimo.osgi.registry.api,
+ javax.persistence;version="0.0.0",
+ javax.persistence.criteria;version="0.0.0",
+ javax.persistence.metamodel;version="0.0.0",
+ javax.persistence.spi;version="0.0.0",
+
org.osgi.service.transaction.control;version="[0.0.1,0.0.2)",
+
org.osgi.service.transaction.control.jpa;version="[0.0.1,0.0.2)",
+ org.osgi.service.cm,
+ org.osgi.service.jdbc,
+ org.osgi.service.jpa,
+ *
+ </aries.osgi.import.pkg>
+ <lastReleaseVersion>0.0.1-SNAPSHOT</lastReleaseVersion>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.tx-control</groupId>
+ <artifactId>tx-control-api</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.jdbc</artifactId>
+ <version>1.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-jpa_2.1_spec</artifactId>
+ <version>1.0-alpha-1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.jpa</artifactId>
+ <version>1.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.cm</artifactId>
+ <version>1.5.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.util.tracker</artifactId>
+ <version>1.5.1</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.zaxxer</groupId>
+ <artifactId>HikariCP</artifactId>
+ <version>2.4.3</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.aries.versioning</groupId>
+
<artifactId>org.apache.aries.versioning.plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-verify</id>
+ <phase>verify</phase>
+ <goals>
+
<goal>version-check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <!-- We have to use a newer bnd due to a bug in
its handling of
+ provided contract version lists -->
+ <version>3.0.1</version>
+ <configuration>
+ <instructions>
+
<Provide-Capability>osgi.contract;osgi.contract="JavaJPA";version:List<Version>="1.0,2.0,2.1";uses:="javax.persistence,javax.persistence.criteria,javax.persistence.metamodel,javax.persistence.spi"</Provide-Capability>
+
<Require-Capability>osgi.contract;filter:="(&(osgi.contract=JavaJPA)(version=2.1))"</Require-Capability>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
Added:
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/DriverDataSource.java
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/DriverDataSource.java?rev=1737958&view=auto
==============================================================================
---
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/DriverDataSource.java
(added)
+++
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/DriverDataSource.java
Wed Apr 6 10:06:08 2016
@@ -0,0 +1,70 @@
+package org.apache.aries.tx.control.jpa.common.impl;
+
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+import javax.sql.DataSource;
+
+public class DriverDataSource implements DataSource {
+
+ private final Driver driver;
+ private final String jdbcURL;
+ private final Properties properties;
+
+ public DriverDataSource(Driver driver, String jdbcURL, Properties
properties) {
+ this.driver = driver;
+ this.jdbcURL = jdbcURL;
+ this.properties = properties;
+ }
+
+ @Override
+ public PrintWriter getLogWriter() throws SQLException {
+ throw new SQLFeatureNotSupportedException("Driver based JDBC
does not support log writing");
+ }
+
+ @Override
+ public void setLogWriter(PrintWriter out) throws SQLException {
+ throw new SQLFeatureNotSupportedException("Driver based JDBC
does not support log writing");
+ }
+
+ @Override
+ public void setLoginTimeout(int seconds) throws SQLException {
+ throw new SQLFeatureNotSupportedException("Driver based JDBC
does not support login timeouts");
+ }
+
+ @Override
+ public int getLoginTimeout() throws SQLException {
+ throw new SQLFeatureNotSupportedException("Driver based JDBC
does not support login timeouts");
+ }
+
+ @Override
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ throw new SQLFeatureNotSupportedException("Driver based JDBC
does not support log writing");
+ }
+
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ throw new SQLFeatureNotSupportedException("Driver based JDBC
does not support unwrapping");
+ }
+
+ @Override
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ return false;
+ }
+
+ @Override
+ public Connection getConnection() throws SQLException {
+ return driver.connect(jdbcURL, properties);
+ }
+
+ @Override
+ public Connection getConnection(String username, String password)
throws SQLException {
+ return getConnection();
+ }
+
+}
Added:
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/EntityManagerWrapper.java
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/EntityManagerWrapper.java?rev=1737958&view=auto
==============================================================================
---
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/EntityManagerWrapper.java
(added)
+++
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/EntityManagerWrapper.java
Wed Apr 6 10:06:08 2016
@@ -0,0 +1,229 @@
+package org.apache.aries.tx.control.jpa.common.impl;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.EntityGraph;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.FlushModeType;
+import javax.persistence.LockModeType;
+import javax.persistence.Query;
+import javax.persistence.StoredProcedureQuery;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaDelete;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.CriteriaUpdate;
+import javax.persistence.metamodel.Metamodel;
+
+public abstract class EntityManagerWrapper implements EntityManager {
+
+ public void persist(Object entity) {
+ getRealEntityManager().persist(entity);
+ }
+
+ public <T> T merge(T entity) {
+ return getRealEntityManager().merge(entity);
+ }
+
+ public void remove(Object entity) {
+ getRealEntityManager().remove(entity);
+ }
+
+ public <T> T find(Class<T> entityClass, Object primaryKey) {
+ return getRealEntityManager().find(entityClass, primaryKey);
+ }
+
+ public <T> T find(Class<T> entityClass, Object primaryKey, Map<String,
Object> properties) {
+ return getRealEntityManager().find(entityClass, primaryKey,
properties);
+ }
+
+ public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType
lockMode) {
+ return getRealEntityManager().find(entityClass, primaryKey,
lockMode);
+ }
+
+ public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType
lockMode, Map<String, Object> properties) {
+ return getRealEntityManager().find(entityClass, primaryKey,
lockMode, properties);
+ }
+
+ public <T> T getReference(Class<T> entityClass, Object primaryKey) {
+ return getRealEntityManager().getReference(entityClass,
primaryKey);
+ }
+
+ public void flush() {
+ getRealEntityManager().flush();
+ }
+
+ public void setFlushMode(FlushModeType flushMode) {
+ getRealEntityManager().setFlushMode(flushMode);
+ }
+
+ public FlushModeType getFlushMode() {
+ return getRealEntityManager().getFlushMode();
+ }
+
+ public void lock(Object entity, LockModeType lockMode) {
+ getRealEntityManager().lock(entity, lockMode);
+ }
+
+ public void lock(Object entity, LockModeType lockMode, Map<String,
Object> properties) {
+ getRealEntityManager().lock(entity, lockMode, properties);
+ }
+
+ public void refresh(Object entity) {
+ getRealEntityManager().refresh(entity);
+ }
+
+ public void refresh(Object entity, Map<String, Object> properties) {
+ getRealEntityManager().refresh(entity, properties);
+ }
+
+ public void refresh(Object entity, LockModeType lockMode) {
+ getRealEntityManager().refresh(entity, lockMode);
+ }
+
+ public void refresh(Object entity, LockModeType lockMode, Map<String,
Object> properties) {
+ getRealEntityManager().refresh(entity, lockMode, properties);
+ }
+
+ public void clear() {
+ getRealEntityManager().clear();
+ }
+
+ public void detach(Object entity) {
+ getRealEntityManager().detach(entity);
+ }
+
+ public boolean contains(Object entity) {
+ return getRealEntityManager().contains(entity);
+ }
+
+ public LockModeType getLockMode(Object entity) {
+ return getRealEntityManager().getLockMode(entity);
+ }
+
+ public void setProperty(String propertyName, Object value) {
+ getRealEntityManager().setProperty(propertyName, value);
+ }
+
+ public Map<String, Object> getProperties() {
+ return getRealEntityManager().getProperties();
+ }
+
+ public Query createQuery(String qlString) {
+ return getRealEntityManager().createQuery(qlString);
+ }
+
+ public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
+ return getRealEntityManager().createQuery(criteriaQuery);
+ }
+
+ public Query createQuery(@SuppressWarnings("rawtypes") CriteriaUpdate
updateQuery) {
+ return getRealEntityManager().createQuery(updateQuery);
+ }
+
+ public Query createQuery(@SuppressWarnings("rawtypes") CriteriaDelete
deleteQuery) {
+ return getRealEntityManager().createQuery(deleteQuery);
+ }
+
+ public <T> TypedQuery<T> createQuery(String qlString, Class<T>
resultClass) {
+ return getRealEntityManager().createQuery(qlString,
resultClass);
+ }
+
+ public Query createNamedQuery(String name) {
+ return getRealEntityManager().createNamedQuery(name);
+ }
+
+ public <T> TypedQuery<T> createNamedQuery(String name, Class<T>
resultClass) {
+ return getRealEntityManager().createNamedQuery(name,
resultClass);
+ }
+
+ public Query createNativeQuery(String sqlString) {
+ return getRealEntityManager().createNativeQuery(sqlString);
+ }
+
+ public Query createNativeQuery(String sqlString,
@SuppressWarnings("rawtypes") Class resultClass) {
+ return getRealEntityManager().createNativeQuery(sqlString,
resultClass);
+ }
+
+ public Query createNativeQuery(String sqlString, String
resultSetMapping) {
+ return getRealEntityManager().createNativeQuery(sqlString,
resultSetMapping);
+ }
+
+ public StoredProcedureQuery createNamedStoredProcedureQuery(String
name) {
+ return
getRealEntityManager().createNamedStoredProcedureQuery(name);
+ }
+
+ public StoredProcedureQuery createStoredProcedureQuery(String
procedureName) {
+ return
getRealEntityManager().createStoredProcedureQuery(procedureName);
+ }
+
+ public StoredProcedureQuery createStoredProcedureQuery(String
procedureName, @SuppressWarnings("rawtypes") Class... resultClasses) {
+ return
getRealEntityManager().createStoredProcedureQuery(procedureName, resultClasses);
+ }
+
+ public StoredProcedureQuery createStoredProcedureQuery(String
procedureName, String... resultSetMappings) {
+ return
getRealEntityManager().createStoredProcedureQuery(procedureName,
resultSetMappings);
+ }
+
+ public void joinTransaction() {
+ getRealEntityManager().joinTransaction();
+ }
+
+ public boolean isJoinedToTransaction() {
+ return getRealEntityManager().isJoinedToTransaction();
+ }
+
+ public <T> T unwrap(Class<T> cls) {
+ return getRealEntityManager().unwrap(cls);
+ }
+
+ public Object getDelegate() {
+ return getRealEntityManager().getDelegate();
+ }
+
+ public void close() {
+ getRealEntityManager().close();
+ }
+
+ public boolean isOpen() {
+ return getRealEntityManager().isOpen();
+ }
+
+ public EntityTransaction getTransaction() {
+ return getRealEntityManager().getTransaction();
+ }
+
+ public EntityManagerFactory getEntityManagerFactory() {
+ return getRealEntityManager().getEntityManagerFactory();
+ }
+
+ public CriteriaBuilder getCriteriaBuilder() {
+ return getRealEntityManager().getCriteriaBuilder();
+ }
+
+ public Metamodel getMetamodel() {
+ return getRealEntityManager().getMetamodel();
+ }
+
+ public <T> EntityGraph<T> createEntityGraph(Class<T> rootType) {
+ return getRealEntityManager().createEntityGraph(rootType);
+ }
+
+ public EntityGraph<?> createEntityGraph(String graphName) {
+ return getRealEntityManager().createEntityGraph(graphName);
+ }
+
+ public EntityGraph<?> getEntityGraph(String graphName) {
+ return getRealEntityManager().getEntityGraph(graphName);
+ }
+
+ public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T>
entityClass) {
+ return getRealEntityManager().getEntityGraphs(entityClass);
+ }
+
+ protected abstract EntityManager getRealEntityManager();
+
+}
Added:
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/ScopedEntityManagerWrapper.java
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/ScopedEntityManagerWrapper.java?rev=1737958&view=auto
==============================================================================
---
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/ScopedEntityManagerWrapper.java
(added)
+++
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/ScopedEntityManagerWrapper.java
Wed Apr 6 10:06:08 2016
@@ -0,0 +1,33 @@
+package org.apache.aries.tx.control.jpa.common.impl;
+
+import javax.persistence.EntityManager;
+import javax.persistence.TransactionRequiredException;
+
+public class ScopedEntityManagerWrapper extends EntityManagerWrapper {
+
+ private final EntityManager entityManager;
+
+ public ScopedEntityManagerWrapper(EntityManager entityManager) {
+ this.entityManager = entityManager;
+ }
+
+ @Override
+ protected EntityManager getRealEntityManager() {
+ return entityManager;
+ }
+
+ @Override
+ public void close() {
+ // A no op
+ }
+
+ @Override
+ public void joinTransaction() {
+ throw new TransactionRequiredException("This EntityManager is
being used in the No Transaction scope. There is no transaction to join.");
+ }
+
+ @Override
+ public boolean isJoinedToTransaction() {
+ return false;
+ }
+}
Added:
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/TxEntityManagerWrapper.java
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/TxEntityManagerWrapper.java?rev=1737958&view=auto
==============================================================================
---
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/TxEntityManagerWrapper.java
(added)
+++
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/common/impl/TxEntityManagerWrapper.java
Wed Apr 6 10:06:08 2016
@@ -0,0 +1,40 @@
+package org.apache.aries.tx.control.jpa.common.impl;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityTransaction;
+
+import org.osgi.service.transaction.control.TransactionException;
+
+public class TxEntityManagerWrapper extends EntityManagerWrapper {
+
+ private final EntityManager entityManager;
+
+ public TxEntityManagerWrapper(EntityManager entityManager) {
+ this.entityManager = entityManager;
+ }
+
+ @Override
+ protected EntityManager getRealEntityManager() {
+ return entityManager;
+ }
+
+ @Override
+ public void close() {
+ // A no-op
+ }
+
+ @Override
+ public void joinTransaction() {
+ // A no-op
+ }
+
+ @Override
+ public boolean isJoinedToTransaction() {
+ return true;
+ }
+
+ @Override
+ public EntityTransaction getTransaction() {
+ throw new TransactionException("Programmatic transaction
management is not supported for a Transactional EntityManager");
+ }
+}
Added:
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/Activator.java
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/Activator.java?rev=1737958&view=auto
==============================================================================
---
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/Activator.java
(added)
+++
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/Activator.java
Wed Apr 6 10:06:08 2016
@@ -0,0 +1,56 @@
+package org.apache.aries.tx.control.jpa.local.impl;
+
+import static org.osgi.framework.Constants.SERVICE_PID;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.geronimo.specs.jpa.PersistenceActivator;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ManagedServiceFactory;
+import
org.osgi.service.transaction.control.jpa.JPAEntityManagerProviderFactory;
+
+public class Activator implements BundleActivator {
+
+ private final BundleActivator geronimoActivator;
+
+ private ServiceRegistration<JPAEntityManagerProviderFactory> reg;
+ private ServiceRegistration<ManagedServiceFactory> factoryReg;
+
+ public Activator() {
+ geronimoActivator = new PersistenceActivator();
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ geronimoActivator.start(context);
+
+ reg =
context.registerService(JPAEntityManagerProviderFactory.class,
+ new JPAEntityManagerProviderFactoryImpl(),
getProperties());
+
+ factoryReg =
context.registerService(ManagedServiceFactory.class,
+ new ManagedServiceFactoryImpl(context),
getMSFProperties());
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ reg.unregister();
+ factoryReg.unregister();
+ geronimoActivator.stop(context);
+ }
+
+ private Dictionary<String, Object> getProperties() {
+ Dictionary<String, Object> props = new Hashtable<>();
+ props.put("osgi.local.enabled", Boolean.TRUE);
+ return props;
+ }
+
+ private Dictionary<String, ?> getMSFProperties() {
+ Dictionary<String, Object> props = new Hashtable<>();
+ props.put(SERVICE_PID, "org.apache.aries.tx.control.jpa.local");
+ return props;
+ }
+
+}
Added:
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/JPAEntityManagerProviderFactoryImpl.java
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/JPAEntityManagerProviderFactoryImpl.java?rev=1737958&view=auto
==============================================================================
---
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/JPAEntityManagerProviderFactoryImpl.java
(added)
+++
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/JPAEntityManagerProviderFactoryImpl.java
Wed Apr 6 10:06:08 2016
@@ -0,0 +1,79 @@
+package org.apache.aries.tx.control.jpa.local.impl;
+
+import static java.util.Optional.ofNullable;
+import static
javax.persistence.spi.PersistenceUnitTransactionType.RESOURCE_LOCAL;
+
+import java.util.Map;
+
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+
+import org.osgi.service.jpa.EntityManagerFactoryBuilder;
+import org.osgi.service.transaction.control.TransactionException;
+import org.osgi.service.transaction.control.jpa.JPAEntityManagerProvider;
+import
org.osgi.service.transaction.control.jpa.JPAEntityManagerProviderFactory;
+
+public class JPAEntityManagerProviderFactoryImpl implements
JPAEntityManagerProviderFactory {
+
+ @Override
+ public JPAEntityManagerProvider
getProviderFor(EntityManagerFactoryBuilder emfb, Map<String, Object>
jpaProperties,
+ Map<String, Object> resourceProviderProperties) {
+ checkEnlistment(resourceProviderProperties);
+
+ EntityManagerFactory emf =
emfb.createEntityManagerFactory(jpaProperties);
+
+ validateEMF(emf);
+
+ return new JPAEntityManagerProviderImpl(emf);
+ }
+
+ private void validateEMF(EntityManagerFactory emf) {
+ Object o =
emf.getProperties().get("javax.persistence.transactionType");
+
+ PersistenceUnitTransactionType tranType;
+ if(o instanceof PersistenceUnitTransactionType) {
+ tranType = (PersistenceUnitTransactionType) o;
+ } else if (o instanceof String) {
+ tranType =
PersistenceUnitTransactionType.valueOf(o.toString());
+ } else {
+ //TODO log this?
+ tranType = null;
+ }
+
+ if(RESOURCE_LOCAL != tranType) {
+ throw new IllegalArgumentException("The supplied
EntityManagerFactory is not declared RESOURCE_LOCAL");
+ }
+ }
+
+ @Override
+ public JPAEntityManagerProvider getProviderFor(EntityManagerFactory
emf, Map<String, Object> jpaProperties,
+ Map<String, Object> resourceProviderProperties) {
+ checkEnlistment(resourceProviderProperties);
+ validateEMF(emf);
+
+ return new JPAEntityManagerProviderImpl(emf);
+ }
+
+ private void checkEnlistment(Map<String, Object>
resourceProviderProperties) {
+ if (toBoolean(resourceProviderProperties,
XA_ENLISTMENT_ENABLED, false)) {
+ throw new TransactionException("This Resource Provider
does not support XA transactions");
+ } else if (!toBoolean(resourceProviderProperties,
LOCAL_ENLISTMENT_ENABLED, true)) {
+ throw new TransactionException(
+ "This Resource Provider always enlists
in local transactions as it does not support XA");
+ }
+ }
+
+ private boolean toBoolean(Map<String, Object> props, String key,
boolean defaultValue) {
+ Object o = ofNullable(props)
+ .map(m -> m.get(key))
+ .orElse(defaultValue);
+
+ if (o instanceof Boolean) {
+ return ((Boolean) o).booleanValue();
+ } else if(o instanceof String) {
+ return Boolean.parseBoolean((String) o);
+ } else {
+ throw new IllegalArgumentException("The property " +
key + " cannot be converted to a boolean");
+ }
+ }
+}
Added:
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/JPAEntityManagerProviderImpl.java
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/JPAEntityManagerProviderImpl.java?rev=1737958&view=auto
==============================================================================
---
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/JPAEntityManagerProviderImpl.java
(added)
+++
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/JPAEntityManagerProviderImpl.java
Wed Apr 6 10:06:08 2016
@@ -0,0 +1,26 @@
+package org.apache.aries.tx.control.jpa.local.impl;
+
+import java.util.UUID;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+
+import org.osgi.service.transaction.control.TransactionControl;
+import org.osgi.service.transaction.control.TransactionException;
+import org.osgi.service.transaction.control.jpa.JPAEntityManagerProvider;
+
+public class JPAEntityManagerProviderImpl implements JPAEntityManagerProvider {
+
+ private final UUID uuid =
UUID.randomUUID();
+
+ private final EntityManagerFactory emf;
+
+ public JPAEntityManagerProviderImpl(EntityManagerFactory emf) {
+ this.emf = emf;
+ }
+
+ @Override
+ public EntityManager getResource(TransactionControl txControl) throws
TransactionException {
+ return new TxContextBindingEntityManager(txControl, emf, uuid);
+ }
+}
Added:
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LifecycleAware.java
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LifecycleAware.java?rev=1737958&view=auto
==============================================================================
---
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LifecycleAware.java
(added)
+++
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/LifecycleAware.java
Wed Apr 6 10:06:08 2016
@@ -0,0 +1,8 @@
+package org.apache.aries.tx.control.jpa.local.impl;
+
+public interface LifecycleAware {
+
+ public void start();
+
+ public void stop();
+}
Added:
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/ManagedJPADataSourceSetup.java
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/ManagedJPADataSourceSetup.java?rev=1737958&view=auto
==============================================================================
---
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/ManagedJPADataSourceSetup.java
(added)
+++
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/ManagedJPADataSourceSetup.java
Wed Apr 6 10:06:08 2016
@@ -0,0 +1,225 @@
+package org.apache.aries.tx.control.jpa.local.impl;
+
+import static java.util.Optional.ofNullable;
+import static java.util.concurrent.TimeUnit.HOURS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.osgi.framework.Constants.OBJECTCLASS;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_URL;
+import static org.osgi.service.jdbc.DataSourceFactory.OSGI_JDBC_DRIVER_CLASS;
+import static
org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory.CONNECTION_LIFETIME;
+import static
org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory.CONNECTION_POOLING_ENABLED;
+import static
org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory.CONNECTION_TIMEOUT;
+import static
org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory.IDLE_TIMEOUT;
+import static
org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory.MAX_CONNECTIONS;
+import static
org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory.MIN_CONNECTIONS;
+import static
org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory.USE_DRIVER;
+
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.sql.DataSource;
+
+import org.apache.aries.tx.control.jpa.common.impl.DriverDataSource;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.jdbc.DataSourceFactory;
+import org.osgi.service.transaction.control.TransactionException;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+
+public class ManagedJPADataSourceSetup implements LifecycleAware,
+ ServiceTrackerCustomizer<DataSourceFactory,
ManagedJPAEMFLocator> {
+
+ private final BundleContext context;
+ private final String pid;
+ private final Properties jdbcProperties;
+ private final Map<String, Object> baseJPAProperties;
+ private final Map<String, Object> providerProperties;
+
+ private final ServiceTracker<DataSourceFactory, ManagedJPAEMFLocator>
dsfTracker;
+ private final AtomicReference<ServiceReference<DataSourceFactory>>
activeDsf = new AtomicReference<>();
+
+ public ManagedJPADataSourceSetup(BundleContext context, String pid,
Properties jdbcProperties,
+ Map<String, Object> baseJPAProperties, Map<String,
Object> providerProperties) throws InvalidSyntaxException,
ConfigurationException {
+ this.context = context;
+ this.pid = pid;
+ this.jdbcProperties = jdbcProperties;
+ this.baseJPAProperties = baseJPAProperties;
+ this.providerProperties = providerProperties;
+
+ String targetFilter = (String)
providerProperties.get(ManagedServiceFactoryImpl.DSF_TARGET_FILTER);
+ if (targetFilter == null) {
+ String driver = (String)
providerProperties.get(OSGI_JDBC_DRIVER_CLASS);
+ if (driver == null) {
+ ManagedServiceFactoryImpl.LOG.error("The
configuration {} must specify a target filter or a JDBC driver class", pid);
+ throw new
ConfigurationException(OSGI_JDBC_DRIVER_CLASS,
+ "The configuration must specify
either a target filter or a JDBC driver class");
+ }
+ targetFilter = "(" + OSGI_JDBC_DRIVER_CLASS + "=" +
driver + ")";
+ }
+
+ targetFilter = "(&(" + OBJECTCLASS + "=" +
DataSourceFactory.class.getName() + ")" + targetFilter + ")";
+
+ this.dsfTracker = new ServiceTracker<>(context,
context.createFilter(targetFilter), this);
+ }
+
+ public void start() {
+ dsfTracker.open();
+ }
+
+ public void stop() {
+ dsfTracker.close();
+ }
+
+ @Override
+ public ManagedJPAEMFLocator
addingService(ServiceReference<DataSourceFactory> reference) {
+ DataSourceFactory service = context.getService(reference);
+ ManagedJPAEMFLocator toReturn;
+ try {
+ toReturn = new ManagedJPAEMFLocator(context, pid,
+ getJPAProperties(service),
providerProperties);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ return null;
+ }
+ updateService(reference, toReturn);
+
+ return toReturn;
+ }
+
+ private void updateService(ServiceReference<DataSourceFactory>
reference, ManagedJPAEMFLocator locator) {
+ boolean setDsf;
+ synchronized (this) {
+ setDsf = activeDsf.compareAndSet(null, reference);
+ }
+ try {
+ if (setDsf) {
+ locator.start();
+ }
+ } catch (Exception e) {
+ ManagedServiceFactoryImpl.LOG.error("An error occurred
when creating the connection provider for {}.", pid, e);
+ activeDsf.compareAndSet(reference, null);
+ throw new IllegalStateException("An error occurred when
creating the connection provider", e);
+ }
+ }
+
+ private Map<String, Object> getJPAProperties(DataSourceFactory dsf) {
+ Map<String, Object> props = new HashMap<>(baseJPAProperties);
+
+ DataSource unpooled;
+ try {
+ if (toBoolean(providerProperties, USE_DRIVER, false)) {
+ unpooled = new
DriverDataSource(dsf.createDriver(null), jdbcProperties.getProperty(JDBC_URL),
+ jdbcProperties);
+ } else {
+ unpooled = dsf.createDataSource(jdbcProperties);
+ }
+ } catch (SQLException sqle) {
+ throw new TransactionException("Unable to create the
JDBC resource provider", sqle);
+ }
+
+ DataSource toUse = poolIfNecessary(providerProperties,
unpooled);
+
+ props.put("javax.persistence.nonJtaDataSource", toUse);
+
+ return props;
+ }
+
+ @Override
+ public void modifiedService(ServiceReference<DataSourceFactory>
reference, ManagedJPAEMFLocator service) {
+ }
+
+ @Override
+ public void removedService(ServiceReference<DataSourceFactory>
reference, ManagedJPAEMFLocator service) {
+ service.stop();
+
+ if (activeDsf.compareAndSet(reference, null)) {
+
Map<ServiceReference<DataSourceFactory>,ManagedJPAEMFLocator> tracked =
dsfTracker.getTracked();
+ if (!tracked.isEmpty()) {
+ Entry<ServiceReference<DataSourceFactory>,
ManagedJPAEMFLocator> e = tracked.entrySet().iterator().next();
+ updateService(e.getKey(), e.getValue());
+ }
+ }
+ }
+
+
+ private DataSource poolIfNecessary(Map<String, Object>
resourceProviderProperties, DataSource unpooled) {
+ DataSource toUse;
+
+ if (toBoolean(resourceProviderProperties,
CONNECTION_POOLING_ENABLED, true)) {
+ HikariConfig hcfg = new HikariConfig();
+ hcfg.setDataSource(unpooled);
+
+ // Sizes
+
hcfg.setMaximumPoolSize(toInt(resourceProviderProperties, MAX_CONNECTIONS, 10));
+ hcfg.setMinimumIdle(toInt(resourceProviderProperties,
MIN_CONNECTIONS, 10));
+
+ // Timeouts
+
hcfg.setConnectionTimeout(toLong(resourceProviderProperties,
CONNECTION_TIMEOUT, SECONDS.toMillis(30)));
+ hcfg.setIdleTimeout(toLong(resourceProviderProperties,
IDLE_TIMEOUT, TimeUnit.MINUTES.toMillis(3)));
+ hcfg.setMaxLifetime(toLong(resourceProviderProperties,
CONNECTION_LIFETIME, HOURS.toMillis(3)));
+
+ toUse = new HikariDataSource(hcfg);
+
+ } else {
+ toUse = unpooled;
+ }
+ return toUse;
+ }
+
+ private boolean toBoolean(Map<String, Object> props, String key,
boolean defaultValue) {
+ Object o = ofNullable(props)
+ .map(m -> m.get(key))
+ .orElse(defaultValue);
+
+ if (o instanceof Boolean) {
+ return ((Boolean) o).booleanValue();
+ } else if(o instanceof String) {
+ return Boolean.parseBoolean((String) o);
+ } else {
+ throw new IllegalArgumentException("The property " +
key + " cannot be converted to a boolean");
+ }
+ }
+
+ private int toInt(Map<String, Object> props, String key, int
defaultValue) {
+
+ Object o = ofNullable(props)
+ .map(m -> m.get(key))
+ .orElse(defaultValue);
+
+ if (o instanceof Number) {
+ return ((Number) o).intValue();
+ } else if(o instanceof String) {
+ return Integer.parseInt((String) o);
+ } else {
+ throw new IllegalArgumentException("The property " +
key + " cannot be converted to an int");
+ }
+ }
+
+ private long toLong(Map<String, Object> props, String key, long
defaultValue) {
+
+ Object o = ofNullable(props)
+ .map(m -> m.get(key))
+ .orElse(defaultValue);
+
+ if (o instanceof Number) {
+ return ((Number) o).longValue();
+ } else if(o instanceof String) {
+ return Long.parseLong((String) o);
+ } else {
+ throw new IllegalArgumentException("The property " +
key + " cannot be converted to a long");
+ }
+ }
+
+}
\ No newline at end of file
Added:
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/ManagedJPAEMFLocator.java
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/ManagedJPAEMFLocator.java?rev=1737958&view=auto
==============================================================================
---
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/ManagedJPAEMFLocator.java
(added)
+++
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/ManagedJPAEMFLocator.java
Wed Apr 6 10:06:08 2016
@@ -0,0 +1,139 @@
+package org.apache.aries.tx.control.jpa.local.impl;
+
+import static
org.apache.aries.tx.control.jpa.local.impl.ManagedServiceFactoryImpl.EMF_BUILDER_TARGET_FILTER;
+import static org.osgi.framework.Constants.OBJECTCLASS;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_PASSWORD;
+import static org.osgi.service.jpa.EntityManagerFactoryBuilder.JPA_UNIT_NAME;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.jpa.EntityManagerFactoryBuilder;
+import org.osgi.service.transaction.control.jpa.JPAEntityManagerProvider;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+public class ManagedJPAEMFLocator implements LifecycleAware,
+ ServiceTrackerCustomizer<EntityManagerFactoryBuilder,
EntityManagerFactoryBuilder> {
+
+ private final BundleContext context;
+ private final String pid;
+ private final Map<String, Object> jpaProperties;
+ private final Map<String, Object> providerProperties;
+ private final ServiceTracker<EntityManagerFactoryBuilder,
EntityManagerFactoryBuilder> emfBuilderTracker;
+
+ private final AtomicReference<EntityManagerFactoryBuilder> activeDsf =
new AtomicReference<>();
+ private final
AtomicReference<ServiceRegistration<JPAEntityManagerProvider>> serviceReg = new
AtomicReference<>();
+
+ public ManagedJPAEMFLocator(BundleContext context, String pid,
Map<String, Object> jpaProperties,
+ Map<String, Object> providerProperties) throws
InvalidSyntaxException, ConfigurationException {
+ this.context = context;
+ this.pid = pid;
+ this.jpaProperties = jpaProperties;
+ this.providerProperties = providerProperties;
+
+ String unitName = (String)
providerProperties.get(JPA_UNIT_NAME);
+ if (unitName == null) {
+ ManagedServiceFactoryImpl.LOG.error("The configuration
{} must specify a persistence unit name", pid);
+ throw new ConfigurationException(JPA_UNIT_NAME,
+ "The configuration must specify a
persistence unit name");
+ }
+
+ String targetFilter = (String)
providerProperties.get(EMF_BUILDER_TARGET_FILTER);
+ if (targetFilter == null) {
+ targetFilter = "(" + JPA_UNIT_NAME + "=" + unitName +
")";
+ }
+
+ targetFilter = "(&(" + OBJECTCLASS + "=" +
EntityManagerFactoryBuilder.class.getName() + ")" + targetFilter + ")";
+
+ this.emfBuilderTracker = new ServiceTracker<>(context,
context.createFilter(targetFilter), this);
+ }
+
+ public void start() {
+ emfBuilderTracker.open();
+ }
+
+ public void stop() {
+ emfBuilderTracker.close();
+ }
+
+ @Override
+ public EntityManagerFactoryBuilder
addingService(ServiceReference<EntityManagerFactoryBuilder> reference) {
+ EntityManagerFactoryBuilder service =
context.getService(reference);
+
+ updateService(service);
+ return service;
+ }
+
+ private void updateService(EntityManagerFactoryBuilder service) {
+ boolean setEMFB;
+ synchronized (this) {
+ setEMFB = activeDsf.compareAndSet(null, service);
+ }
+
+ if (setEMFB) {
+ try {
+ JPAEntityManagerProvider provider = new
JPAEntityManagerProviderFactoryImpl().getProviderFor(service,
+ jpaProperties,
providerProperties);
+ ServiceRegistration<JPAEntityManagerProvider>
reg = context
+
.registerService(JPAEntityManagerProvider.class, provider,
getServiceProperties());
+ if (!serviceReg.compareAndSet(null, reg)) {
+ throw new IllegalStateException("Unable
to set the JDBC connection provider registration");
+ }
+ } catch (Exception e) {
+ ManagedServiceFactoryImpl.LOG.error("An error
occurred when creating the connection provider for {}.", pid, e);
+ activeDsf.compareAndSet(service, null);
+ }
+ }
+ }
+
+ private Dictionary<String, ?> getServiceProperties() {
+ Hashtable<String, Object> props = new Hashtable<>();
+ providerProperties.keySet().stream().filter(s ->
!JDBC_PASSWORD.equals(s))
+ .forEach(s -> props.put(s,
providerProperties.get(s)));
+ return props;
+ }
+
+ @Override
+ public void
modifiedService(ServiceReference<EntityManagerFactoryBuilder> reference,
EntityManagerFactoryBuilder service) {
+ }
+
+ @Override
+ public void
removedService(ServiceReference<EntityManagerFactoryBuilder> reference,
EntityManagerFactoryBuilder service) {
+ boolean dsfLeft;
+ ServiceRegistration<JPAEntityManagerProvider> oldReg = null;
+ synchronized (this) {
+ dsfLeft = activeDsf.compareAndSet(service, null);
+ if (dsfLeft) {
+ oldReg = serviceReg.getAndSet(null);
+ }
+ }
+
+ if (oldReg != null) {
+ try {
+ oldReg.unregister();
+ } catch (IllegalStateException ise) {
+ ManagedServiceFactoryImpl.LOG.debug("An
exception occurred when unregistering a service for {}", pid);
+ }
+ }
+ try {
+ context.ungetService(reference);
+ } catch (IllegalStateException ise) {
+ ManagedServiceFactoryImpl.LOG.debug("An exception
occurred when ungetting the service for {}", reference);
+ }
+
+ if (dsfLeft) {
+ EntityManagerFactoryBuilder newEMFBuilder =
emfBuilderTracker.getService();
+ if (newEMFBuilder != null) {
+ updateService(newEMFBuilder);
+ }
+ }
+ }
+}
\ No newline at end of file
Added:
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/ManagedServiceFactoryImpl.java
URL:
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/ManagedServiceFactoryImpl.java?rev=1737958&view=auto
==============================================================================
---
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/ManagedServiceFactoryImpl.java
(added)
+++
aries/trunk/tx-control/tx-control-provider-jpa-local/src/main/java/org/apache/aries/tx/control/jpa/local/impl/ManagedServiceFactoryImpl.java
Wed Apr 6 10:06:08 2016
@@ -0,0 +1,227 @@
+package org.apache.aries.tx.control.jpa.local.impl;
+
+import static java.lang.Integer.MAX_VALUE;
+import static java.util.Arrays.asList;
+import static java.util.Optional.ofNullable;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toMap;
+import static
javax.persistence.spi.PersistenceUnitTransactionType.RESOURCE_LOCAL;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_DATABASE_NAME;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_DATASOURCE_NAME;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_DESCRIPTION;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_NETWORK_PROTOCOL;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_PASSWORD;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_PORT_NUMBER;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_ROLE_NAME;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_SERVER_NAME;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_URL;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_USER;
+import static org.osgi.service.jdbc.DataSourceFactory.OSGI_JDBC_DRIVER_CLASS;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ManagedServiceFactoryImpl implements ManagedServiceFactory {
+
+ static final Logger LOG =
LoggerFactory.getLogger(ManagedServiceFactoryImpl.class);
+
+ static final String DSF_TARGET_FILTER = "aries.dsf.target.filter";
+ static final String EMF_BUILDER_TARGET_FILTER =
"aries.emf.builder.target.filter";
+ static final String JDBC_PROP_NAMES = "aries.jdbc.property.names";
+ static final List<String> JDBC_PROPERTIES = asList(JDBC_DATABASE_NAME,
JDBC_DATASOURCE_NAME,
+ JDBC_DESCRIPTION, JDBC_NETWORK_PROTOCOL, JDBC_PASSWORD,
JDBC_PORT_NUMBER, JDBC_ROLE_NAME, JDBC_SERVER_NAME,
+ JDBC_URL, JDBC_USER);
+ static final String JPA_PROP_NAMES = "aries.jpa.property.names";
+
+ private final Map<String, LifecycleAware> managedInstances = new
ConcurrentHashMap<>();
+
+ private final BundleContext context;
+
+ public ManagedServiceFactoryImpl(BundleContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public String getName() {
+ return "Aries JPAEntityManagerProvider (Local only) service";
+ }
+
+ @Override
+ public void updated(String pid, Dictionary<String, ?> properties)
throws ConfigurationException {
+
+ Map<String, Object> propsMap = new HashMap<>();
+
+ Enumeration<String> keys = properties.keys();
+ while (keys.hasMoreElements()) {
+ String key = keys.nextElement();
+ propsMap.put(key, properties.get(key));
+ }
+
+ Properties jdbcProps = getJdbcProps(pid, propsMap);
+ Map<String, Object> jpaProps = getJPAProps(pid, propsMap);
+
+ try {
+ LifecycleAware worker;
+ if(propsMap.containsKey(OSGI_JDBC_DRIVER_CLASS) ||
+
propsMap.containsKey(DSF_TARGET_FILTER)) {
+ worker = new ManagedJPADataSourceSetup(context,
pid, jdbcProps, jpaProps, propsMap);
+ } else {
+ if(!jdbcProps.isEmpty()) {
+ LOG.warn("The configuration {} contains
raw JDBC configuration, but no osgi.jdbc.driver.class or
aries.dsf.target.filter properties. No DataSourceFactory will be used byt this
bundle, so the JPA provider must be able to directly create the datasource, and
these configuration properties will likely be ignored. {}",
+ pid,
jdbcProps.stringPropertyNames());
+ }
+ worker = new ManagedJPAEMFLocator(context, pid,
jpaProps, propsMap);
+ }
+ ofNullable(managedInstances.put(pid,
worker)).ifPresent(LifecycleAware::stop);
+ worker.start();
+ } catch (InvalidSyntaxException e) {
+ LOG.error("The configuration {} contained an invalid
target filter {}", pid, e.getFilter());
+ throw new ConfigurationException(DSF_TARGET_FILTER,
"The target filter was invalid", e);
+ }
+ }
+
+ public void stop() {
+ managedInstances.values().forEach(LifecycleAware::stop);
+ }
+
+ @SuppressWarnings("unchecked")
+ private Properties getJdbcProps(String pid, Map<String, Object>
properties) throws ConfigurationException {
+
+ Object object = properties.getOrDefault(JDBC_PROP_NAMES,
JDBC_PROPERTIES);
+ Collection<String> propnames;
+ if (object instanceof String) {
+ propnames = Arrays.asList(((String) object).split(","));
+ } else if (object instanceof String[]) {
+ propnames = Arrays.asList((String[]) object);
+ } else if (object instanceof Collection) {
+ propnames = (Collection<String>) object;
+ } else {
+ LOG.error("The configuration {} contained an invalid
list of JDBC property names", pid, object);
+ throw new ConfigurationException(JDBC_PROP_NAMES,
+ "The jdbc property names must be a
String+ or comma-separated String");
+ }
+
+ Properties p = new Properties();
+
+ propnames.stream().filter(properties::containsKey)
+ .forEach(s -> p.setProperty(s,
String.valueOf(properties.get(s))));
+
+ return p;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map<String, Object> getJPAProps(String pid, Map<String, Object>
properties) throws ConfigurationException {
+
+ Object object = properties.getOrDefault(JPA_PROP_NAMES, new
AllCollection());
+ Collection<String> propnames;
+ if (object instanceof String) {
+ propnames = Arrays.asList(((String) object).split(","));
+ } else if (object instanceof String[]) {
+ propnames = Arrays.asList((String[]) object);
+ } else if (object instanceof Collection) {
+ propnames = (Collection<String>) object;
+ } else {
+ LOG.error("The configuration {} contained an invalid
list of JPA property names", pid, object);
+ throw new ConfigurationException(JDBC_PROP_NAMES,
+ "The jpa property names must be empty,
a String+, or a comma-separated String list");
+ }
+
+ Map<String, Object> result = properties.keySet().stream()
+ .filter(propnames::contains)
+ .collect(toMap(identity(), properties::get));
+
+ result.putIfAbsent("javax.persistence.transactionType",
RESOURCE_LOCAL.name());
+
+ return result;
+ }
+
+ @Override
+ public void deleted(String pid) {
+ ofNullable(managedInstances.remove(pid))
+ .ifPresent(LifecycleAware::stop);
+ }
+
+ private static class AllCollection implements Collection<String> {
+
+ @Override
+ public int size() {
+ return MAX_VALUE;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return true;
+ }
+
+ @Override
+ public Iterator<String> iterator() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object[] toArray() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> T[] toArray(T[] a) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean add(String e) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ return true;
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends String> c) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+}