[ARIES-1558] JPA support for CDI git-svn-id: https://svn.apache.org/repos/asf/aries/trunk/jpa@1748153 13f79535-47bb-0310-9956-ffa450edef68
Project: http://git-wip-us.apache.org/repos/asf/aries-jpa/repo Commit: http://git-wip-us.apache.org/repos/asf/aries-jpa/commit/ad5990d4 Tree: http://git-wip-us.apache.org/repos/asf/aries-jpa/tree/ad5990d4 Diff: http://git-wip-us.apache.org/repos/asf/aries-jpa/diff/ad5990d4 Branch: refs/heads/master Commit: ad5990d4a1fcb211f0e1fe2e764770d4086e4fe2 Parents: c52145d Author: gnodet <gnodet@13f79535-47bb-0310-9956-ffa450edef68> Authored: Mon Jun 13 09:27:47 2016 +0000 Committer: gnodet <gnodet@13f79535-47bb-0310-9956-ffa450edef68> Committed: Mon Jun 13 09:27:47 2016 +0000 ---------------------------------------------------------------------- examples/pom.xml | 1 + examples/tasklist-cdi/osgi.bnd | 4 + examples/tasklist-cdi/pom.xml | 87 ++++++ .../tasklist/cdi/impl/TaskServiceImpl.java | 67 +++++ .../tasklist/cdi/impl/TasklistServlet.java | 104 +++++++ .../src/main/resources/META-INF/beans.xml | 0 .../tasklist/cdi/impl/TaskServiceImplTest.java | 65 +++++ .../src/test/resources/META-INF/persistence.xml | 33 +++ jpa-cdi/osgi.bnd | 11 + jpa-cdi/pom.xml | 87 ++++++ .../aries/jpa/cdi/EntityManagerProducer.java | 52 ++++ .../org/apache/aries/jpa/cdi/JpaExtension.java | 60 ++++ .../aries/jpa/cdi/PersistenceAnnotatedType.java | 141 ++++++++++ .../aries/jpa/cdi/TransactionExtension.java | 73 +++++ .../aries/jpa/cdi/TransactionSupport.java | 44 +++ .../aries/jpa/cdi/TransactionalContext.java | 277 +++++++++++++++++++ .../aries/jpa/cdi/TransactionalInterceptor.java | 226 +++++++++++++++ .../aries/jpa/cdi/support/FilterLiteral.java | 35 +++ .../cdi/support/ForwardingAnnotatedField.java | 73 +++++ .../cdi/support/ForwardingAnnotatedType.java | 79 ++++++ .../aries/jpa/cdi/support/InjectLiteral.java | 26 ++ .../aries/jpa/cdi/support/ServiceLiteral.java | 27 ++ .../aries/jpa/cdi/support/SimpleBean.java | 101 +++++++ .../cdi/support/SyntheticAnnotatedField.java | 65 +++++ .../aries/jpa/cdi/support/UniqueIdentifier.java | 36 +++ .../cdi/support/UniqueIdentifierLitteral.java | 38 +++ jpa-cdi/src/main/resources/META-INF/beans.xml | 5 + .../javax.enterprise.inject.spi.Extension | 2 + jpa-parent/pom.xml | 25 ++ pom.xml | 1 + 30 files changed, 1845 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/examples/pom.xml ---------------------------------------------------------------------- diff --git a/examples/pom.xml b/examples/pom.xml index 486338d..0cf3b90 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -124,6 +124,7 @@ <module>tasklist-blueprint</module> <module>tasklist-ds</module> <module>tasklist-model</module> + <module>tasklist-cdi</module> </modules> </project> http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/examples/tasklist-cdi/osgi.bnd ---------------------------------------------------------------------- diff --git a/examples/tasklist-cdi/osgi.bnd b/examples/tasklist-cdi/osgi.bnd new file mode 100644 index 0000000..1c76259 --- /dev/null +++ b/examples/tasklist-cdi/osgi.bnd @@ -0,0 +1,4 @@ +Require-Capability: \ + osgi.extender; filter:="(osgi.extender=pax.cdi)", \ + org.ops4j.pax.cdi.extension; filter:="(extension=pax-cdi-extension2)", \ + org.ops4j.pax.cdi.extension; filter:="(extension=aries-jpa-cdi)", http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/examples/tasklist-cdi/pom.xml ---------------------------------------------------------------------- diff --git a/examples/tasklist-cdi/pom.xml b/examples/tasklist-cdi/pom.xml new file mode 100644 index 0000000..f184d1d --- /dev/null +++ b/examples/tasklist-cdi/pom.xml @@ -0,0 +1,87 @@ +<?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. +--> +<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.jpa.example</groupId> + <artifactId>org.apache.aries.jpa.example.parent</artifactId> + <version>2.4.0-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + <artifactId>org.apache.aries.jpa.example.tasklist.cdi</artifactId> + <name>Apache Aries JPA example tasklist cdi</name> + <packaging>bundle</packaging> + + <properties> + <baseline.skip>true</baseline.skip> + </properties> + + <dependencies> + <dependency> + <groupId>org.eclipse.persistence</groupId> + <artifactId>javax.persistence</artifactId> + </dependency> + <dependency> + <groupId>javax.transaction</groupId> + <artifactId>javax.transaction-api</artifactId> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.compendium</artifactId> + </dependency> + <dependency> + <groupId>org.apache.aries.jpa.example</groupId> + <artifactId>org.apache.aries.jpa.example.tasklist.model</artifactId> + </dependency> + + <dependency> + <groupId>org.ops4j.pax.cdi</groupId> + <artifactId>pax-cdi-api</artifactId> + <version>1.0.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>javax.inject</groupId> + <artifactId>javax.inject</artifactId> + <version>1</version> + </dependency> + + <!-- Test dependencies --> + <dependency> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-entitymanager</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.derby</groupId> + <artifactId>derby</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>javax.enterprise</groupId> + <artifactId>cdi-api</artifactId> + <version>1.2</version> + </dependency> + </dependencies> + +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/examples/tasklist-cdi/src/main/java/org/apache/aries/jpa/example/tasklist/cdi/impl/TaskServiceImpl.java ---------------------------------------------------------------------- diff --git a/examples/tasklist-cdi/src/main/java/org/apache/aries/jpa/example/tasklist/cdi/impl/TaskServiceImpl.java b/examples/tasklist-cdi/src/main/java/org/apache/aries/jpa/example/tasklist/cdi/impl/TaskServiceImpl.java new file mode 100644 index 0000000..cab337d --- /dev/null +++ b/examples/tasklist-cdi/src/main/java/org/apache/aries/jpa/example/tasklist/cdi/impl/TaskServiceImpl.java @@ -0,0 +1,67 @@ +/* + * 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.jpa.example.tasklist.cdi.impl; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.criteria.CriteriaQuery; +import javax.transaction.Transactional; +import javax.transaction.Transactional.TxType; +import java.util.Collection; + +import org.apache.aries.jpa.example.tasklist.model.Task; +import org.apache.aries.jpa.example.tasklist.model.TaskService; + +@Transactional +public class TaskServiceImpl implements TaskService { + + @PersistenceContext(unitName = "tasklist") + EntityManager em; + + @Transactional(TxType.SUPPORTS) + @Override + public Task getTask(Integer id) { + return em.find(Task.class, id); + } + + + @Override + public void addTask(Task task) { + em.persist(task); + em.flush(); + } + + @Transactional(TxType.SUPPORTS) + @Override + public Collection<Task> getTasks() { + CriteriaQuery<Task> query = em.getCriteriaBuilder().createQuery(Task.class); + return em.createQuery(query.select(query.from(Task.class))).getResultList(); + } + + @Override + public void updateTask(Task task) { + em.persist(task); + } + + @Override + public void deleteTask(Integer id) { + em.remove(getTask(id)); + } + +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/examples/tasklist-cdi/src/main/java/org/apache/aries/jpa/example/tasklist/cdi/impl/TasklistServlet.java ---------------------------------------------------------------------- diff --git a/examples/tasklist-cdi/src/main/java/org/apache/aries/jpa/example/tasklist/cdi/impl/TasklistServlet.java b/examples/tasklist-cdi/src/main/java/org/apache/aries/jpa/example/tasklist/cdi/impl/TasklistServlet.java new file mode 100644 index 0000000..1f1f14e --- /dev/null +++ b/examples/tasklist-cdi/src/main/java/org/apache/aries/jpa/example/tasklist/cdi/impl/TasklistServlet.java @@ -0,0 +1,104 @@ +/* + * 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.jpa.example.tasklist.cdi.impl; + +import java.io.IOException; +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.Collection; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.aries.jpa.example.tasklist.model.Task; +import org.apache.aries.jpa.example.tasklist.model.TaskService; +import org.ops4j.pax.cdi.api2.Component; +import org.ops4j.pax.cdi.api2.Contract; +import org.ops4j.pax.cdi.api2.Immediate; +import org.ops4j.pax.cdi.api2.Properties; +import org.ops4j.pax.cdi.api2.Property; +import org.ops4j.pax.cdi.api2.Service; + +@Component @Service @Immediate +@Contract(Servlet.class) +@Properties(@Property(name = "alias", value="/tasklist")) +public class TasklistServlet extends HttpServlet { + + private static final long serialVersionUID = 34992072289535683L; + + @Inject + private transient TaskService taskService; + + @PostConstruct + void initialize() { + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, + IOException { + String add = req.getParameter("add"); + String taskId = req.getParameter("taskId"); + String title = req.getParameter("title"); + PrintWriter writer = resp.getWriter(); // NOSONAR + if (add != null) { + addTask(taskId, title); + } else if (taskId != null && taskId.length() > 0) { + showTask(writer, taskId); + } else { + showTaskList(writer); + } + } + + private void addTask(String taskId, String title) { + Task task = new Task(); + task.setId(new Integer(taskId)); + task.setTitle(title); + taskService.addTask(task ); + } + + private void showTaskList(PrintWriter writer) { + writer.println("<h1>Tasks</h1>"); + Collection<Task> tasks = taskService.getTasks(); + for (Task task : tasks) { + writer.println("<a href=\"?taskId=" + task.getId() + "\">" + task.getTitle() + "</a><BR/>"); + } + } + + private void showTask(PrintWriter writer, String taskId) { + SimpleDateFormat sdf = new SimpleDateFormat(); + Task task = taskService.getTask(new Integer(taskId)); + if (task != null) { + writer.println("<h1>Task " + task.getTitle() + " </h1>"); + if (task.getDueDate() != null) { + writer.println("Due date: " + sdf.format(task.getDueDate()) + "<br/>"); + } + writer.println(task.getDescription()); + } else { + writer.println("Task with id " + taskId + " not found"); + } + + } + +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/examples/tasklist-cdi/src/main/resources/META-INF/beans.xml ---------------------------------------------------------------------- diff --git a/examples/tasklist-cdi/src/main/resources/META-INF/beans.xml b/examples/tasklist-cdi/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/examples/tasklist-cdi/src/test/java/org/apache/aries/jpa/example/tasklist/cdi/impl/TaskServiceImplTest.java ---------------------------------------------------------------------- diff --git a/examples/tasklist-cdi/src/test/java/org/apache/aries/jpa/example/tasklist/cdi/impl/TaskServiceImplTest.java b/examples/tasklist-cdi/src/test/java/org/apache/aries/jpa/example/tasklist/cdi/impl/TaskServiceImplTest.java new file mode 100644 index 0000000..43a53d9 --- /dev/null +++ b/examples/tasklist-cdi/src/test/java/org/apache/aries/jpa/example/tasklist/cdi/impl/TaskServiceImplTest.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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.jpa.example.tasklist.cdi.impl; + +import java.util.HashMap; +import java.util.Map; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +import org.apache.aries.jpa.example.tasklist.cdi.impl.TaskServiceImpl; +import org.apache.aries.jpa.example.tasklist.model.Task; +import org.apache.aries.jpa.example.tasklist.model.TaskService; +import org.junit.Assert; +import org.junit.Test; + +public class TaskServiceImplTest { + @Test + public void testPersistence() { + // Make sure derby.log is in target + System.setProperty("derby.stream.error.file", "target/derby.log"); + TaskServiceImpl taskServiceImpl = new TaskServiceImpl(); + EntityManagerFactory emf = createTestEMF(); + final EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + taskServiceImpl.em = em; + + TaskService taskService = taskServiceImpl; + + Task task = new Task(); + task.setId(1); + task.setTitle("test"); + taskService.addTask(task); + + Task task2 = taskService.getTask(1); + Assert.assertEquals(task.getTitle(), task2.getTitle()); + em.getTransaction().commit(); + em.close(); + } + + private EntityManagerFactory createTestEMF() { + Map<String, String> properties = new HashMap<String, String>(); + properties.put("javax.persistence.jdbc.driver", "org.apache.derby.jdbc.EmbeddedDriver"); + properties.put("javax.persistence.jdbc.url", "jdbc:derby:memory:TEST;create=true"); + EntityManagerFactory emf = Persistence.createEntityManagerFactory("tasklist", properties); + return emf; + } +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/examples/tasklist-cdi/src/test/resources/META-INF/persistence.xml ---------------------------------------------------------------------- diff --git a/examples/tasklist-cdi/src/test/resources/META-INF/persistence.xml b/examples/tasklist-cdi/src/test/resources/META-INF/persistence.xml new file mode 100644 index 0000000..84b94ec --- /dev/null +++ b/examples/tasklist-cdi/src/test/resources/META-INF/persistence.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<persistence version="2.0" 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"> + + <persistence-unit name="tasklist" transaction-type="RESOURCE_LOCAL"> + <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> + <class>org.apache.aries.jpa.example.tasklist.model.Task</class> + <properties> + <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyTenSevenDialect"/> + <property name="hibernate.hbm2ddl.auto" value="create-drop"/> + </properties> + </persistence-unit> + +</persistence> http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/osgi.bnd ---------------------------------------------------------------------- diff --git a/jpa-cdi/osgi.bnd b/jpa-cdi/osgi.bnd new file mode 100644 index 0000000..7b9b23f --- /dev/null +++ b/jpa-cdi/osgi.bnd @@ -0,0 +1,11 @@ +Import-Package: \ + javax.persistence*;version=2.1, \ + * +Provide-Capability: \ + org.ops4j.pax.cdi.extension; extension=aries-jpa-cdi; \ + version:Version=${version;====;${replace;${project.version};-;.}} +Require-Capability: \ + org.ops4j.pax.cdi.extension; filter:="(extension=pax-cdi-extension2)" + osgi.extender; filter:="(osgi.extender=aries.jpa)" + + http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/pom.xml ---------------------------------------------------------------------- diff --git a/jpa-cdi/pom.xml b/jpa-cdi/pom.xml new file mode 100644 index 0000000..fc69007 --- /dev/null +++ b/jpa-cdi/pom.xml @@ -0,0 +1,87 @@ +<?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. +--> +<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.jpa</groupId> + <artifactId>org.apache.aries.jpa.parent</artifactId> + <version>2.4.0-SNAPSHOT</version> + <relativePath>../jpa-parent</relativePath> + </parent> + <artifactId>org.apache.aries.jpa.cdi</artifactId> + <name>Apache Aries JPA cdi</name> + <description>CDI integration for injecting EntityManager, EntityManagerFactory and EmSupplier.</description> + <packaging>bundle</packaging> + + <properties> + <baseline.skip>true</baseline.skip> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-jpa_2.0_spec</artifactId> + </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-jta_1.2_spec</artifactId> + </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-jcdi_1.1_spec</artifactId> + </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-atinject_1.0_spec</artifactId> + </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-interceptor_1.2_spec</artifactId> + </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-annotation_1.2_spec</artifactId> + </dependency> + + <dependency> + <groupId>org.ops4j.pax.cdi</groupId> + <artifactId>pax-cdi-extension2</artifactId> + <version>1.0.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.aries.jpa</groupId> + <artifactId>org.apache.aries.jpa.api</artifactId> + <version>2.4.0-SNAPSHOT</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>1.8</source> + <target>1.8</target> + </configuration> + </plugin> + </plugins> + </build> + +</project> http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/EntityManagerProducer.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/EntityManagerProducer.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/EntityManagerProducer.java new file mode 100644 index 0000000..5cdf0a5 --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/EntityManagerProducer.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.aries.jpa.cdi; + +import javax.persistence.EntityManager; +import java.lang.reflect.Proxy; + +import org.apache.aries.jpa.template.JpaTemplate; +import org.apache.aries.jpa.template.TransactionType; + +public class EntityManagerProducer { + + public static EntityManager create(JpaTemplate template) { + return (EntityManager) Proxy.newProxyInstance(EntityManager.class.getClassLoader(), + new Class<?>[]{EntityManager.class}, + (proxy, method, args) -> { + try { + return template.txExpr(TransactionType.Supports, em -> { + try { + return method.invoke(em, args); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } catch (RuntimeException e) { + if (e.getClass() == RuntimeException.class + && e.getCause() != null + && e.getCause().toString().equals(e.getMessage())) { + throw e.getCause(); + } + throw e; + } + }); + } + +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/JpaExtension.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/JpaExtension.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/JpaExtension.java new file mode 100644 index 0000000..0c2c6f6 --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/JpaExtension.java @@ -0,0 +1,60 @@ +/* + * 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.cdi; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.event.Observes; +import javax.enterprise.inject.spi.AfterBeanDiscovery; +import javax.enterprise.inject.spi.AnnotatedField; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.Extension; +import javax.enterprise.inject.spi.ProcessAnnotatedType; +import javax.persistence.PersistenceContext; +import javax.persistence.PersistenceUnit; +import java.util.ArrayList; +import java.util.List; + +@ApplicationScoped +public class JpaExtension implements Extension { + + List<Bean<?>> beans = new ArrayList<Bean<?>>(); + + public <T> void processAnnotatedType(@Observes ProcessAnnotatedType<T> event, BeanManager manager) { + boolean hasPersistenceField = false; + for (AnnotatedField<? super T> field : event.getAnnotatedType().getFields()) { + if (field.isAnnotationPresent(PersistenceContext.class) + || field.isAnnotationPresent(PersistenceUnit.class)) { + hasPersistenceField = true; + break; + } + } + if (hasPersistenceField) { + PersistenceAnnotatedType<T> pat = new PersistenceAnnotatedType<T>(manager, event.getAnnotatedType()); + beans.addAll(pat.getProducers()); + event.setAnnotatedType(pat); + } + } + + public void afterBeanDiscovery(@Observes AfterBeanDiscovery event, BeanManager manager) { + for (Bean<?> bean : beans) { + event.addBean(bean); + } + } + + +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/PersistenceAnnotatedType.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/PersistenceAnnotatedType.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/PersistenceAnnotatedType.java new file mode 100644 index 0000000..13ac947 --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/PersistenceAnnotatedType.java @@ -0,0 +1,141 @@ +/* + * 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.cdi; + +import javax.enterprise.context.Dependent; +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.AnnotatedField; +import javax.enterprise.inject.spi.AnnotatedType; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.PersistenceContext; +import javax.persistence.PersistenceUnit; +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.aries.jpa.cdi.support.FilterLiteral; +import org.apache.aries.jpa.cdi.support.ForwardingAnnotatedType; +import org.apache.aries.jpa.cdi.support.InjectLiteral; +import org.apache.aries.jpa.cdi.support.ServiceLiteral; +import org.apache.aries.jpa.cdi.support.SimpleBean; +import org.apache.aries.jpa.cdi.support.SyntheticAnnotatedField; +import org.apache.aries.jpa.cdi.support.UniqueIdentifier; +import org.apache.aries.jpa.cdi.support.UniqueIdentifierLitteral; +import org.apache.aries.jpa.template.JpaTemplate; +import org.ops4j.pax.cdi.extension2.api.OsgiExtension; + +import static java.util.Collections.unmodifiableSet; + +public class PersistenceAnnotatedType<T> extends ForwardingAnnotatedType<T> { + + private final BeanManager manager; + private final Set<AnnotatedField<? super T>> fields; + private final List<Bean<?>> beans = new ArrayList<>(); + + public PersistenceAnnotatedType(BeanManager manager, AnnotatedType<T> delegate) { + super(delegate); + this.manager = manager; + this.fields = new HashSet<>(); + for (AnnotatedField<? super T> field : delegate.getFields()) { + if (field.isAnnotationPresent(PersistenceContext.class)) { + field = decorateContext(field); + } else if (field.isAnnotationPresent(PersistenceUnit.class)) { + field = decorateUnit(field); + } + this.fields.add(field); + } + } + + private boolean hasUnitName(PersistenceContext pc) { + return !pc.unitName().isEmpty(); + } + + private boolean hasUnitName(PersistenceUnit pu) { + return !pu.unitName().isEmpty(); + } + + private <X> AnnotatedField<X> decorateContext(AnnotatedField<X> field) { + final PersistenceContext persistenceContext = field.getAnnotation(PersistenceContext.class); + final UniqueIdentifier identifier = UniqueIdentifierLitteral.random(); + + Set<Annotation> templateQualifiers = new HashSet<>(); + templateQualifiers.add(ServiceLiteral.SERVICE); + if (hasUnitName(persistenceContext)) { + templateQualifiers.add(new FilterLiteral("(osgi.unit.name=" + persistenceContext.unitName() + ")")); + } + Bean<JpaTemplate> bean = manager.getExtension(OsgiExtension.class) + .globalDependency(JpaTemplate.class, templateQualifiers); + + Set<Annotation> qualifiers = new HashSet<>(); + qualifiers.add(identifier); + Bean<EntityManager> b = new SimpleBean<>(EntityManager.class, Dependent.class, Collections.singleton(EntityManager.class), qualifiers, () -> { + CreationalContext<JpaTemplate> context = manager.createCreationalContext(bean); + JpaTemplate template = (JpaTemplate) manager.getReference(bean, JpaTemplate.class, context); + return EntityManagerProducer.create(template); + }); + beans.add(b); + + Set<Annotation> fieldAnnotations = new HashSet<>(); + fieldAnnotations.add(InjectLiteral.INJECT); + fieldAnnotations.add(identifier); + return new SyntheticAnnotatedField<>(field, fieldAnnotations); + } + + private <X> AnnotatedField<X> decorateUnit(AnnotatedField<X> field) { + final PersistenceUnit persistenceUnit = field.getAnnotation(PersistenceUnit.class); + final UniqueIdentifier identifier = UniqueIdentifierLitteral.random(); + + Set<Annotation> templateQualifiers = new HashSet<>(); + templateQualifiers.add(ServiceLiteral.SERVICE); + if (hasUnitName(persistenceUnit)) { + templateQualifiers.add(new FilterLiteral("(osgi.unit.name=" + persistenceUnit.unitName() + ")")); + } + Bean<EntityManagerFactory> bean = manager.getExtension(OsgiExtension.class) + .globalDependency(EntityManagerFactory.class, templateQualifiers); + + Set<Annotation> qualifiers = new HashSet<>(); + qualifiers.add(identifier); + Bean<EntityManagerFactory> b = new SimpleBean<>(EntityManagerFactory.class, Dependent.class, Collections.singleton(EntityManagerFactory.class), qualifiers, () -> { + CreationalContext<EntityManagerFactory> context = manager.createCreationalContext(bean); + return (EntityManagerFactory) manager.getReference(bean, EntityManagerFactory.class, context); + }); + beans.add(b); + + Set<Annotation> fieldAnnotations = new HashSet<>(); + fieldAnnotations.add(InjectLiteral.INJECT); + fieldAnnotations.add(identifier); + return new SyntheticAnnotatedField<>(field, fieldAnnotations); + } + + @Override + public Set<AnnotatedField<? super T>> getFields() { + return unmodifiableSet(fields); + } + + public Collection<? extends Bean<?>> getProducers() { + return beans; + } + + +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionExtension.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionExtension.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionExtension.java new file mode 100644 index 0000000..9968488 --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionExtension.java @@ -0,0 +1,73 @@ +/* + * 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.cdi; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.event.Observes; +import javax.enterprise.inject.spi.AfterBeanDiscovery; +import javax.enterprise.inject.spi.AnnotatedMethod; +import javax.enterprise.inject.spi.AnnotatedType; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.BeforeBeanDiscovery; +import javax.enterprise.inject.spi.Extension; +import javax.enterprise.inject.spi.ProcessManagedBean; +import javax.transaction.Transactional; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +@ApplicationScoped +public class TransactionExtension implements Extension { + + private Map<Method, Transactional> transactionAttributes; + + public TransactionExtension() { + transactionAttributes = new HashMap<>(); + } + + <X> void processBean(@Observes ProcessManagedBean<X> event) { + AnnotatedType<X> annotatedType = event.getAnnotatedBeanClass(); + Transactional classTx = annotatedType.getAnnotation(Transactional.class); + for (AnnotatedMethod<? super X> am : annotatedType.getMethods()) { + Transactional methodTx = am.getAnnotation(Transactional.class); + if (classTx != null || methodTx != null) { + Method method = am.getJavaMember(); + Transactional attrType = mergeTransactionAttributes(classTx, methodTx); + transactionAttributes.put(method, attrType); + } + } + } + + void beforeBeanDiscovery(@Observes BeforeBeanDiscovery event, BeanManager manager) { + event.addAnnotatedType(manager.createAnnotatedType(TransactionSupport.class)); + event.addAnnotatedType(manager.createAnnotatedType(TransactionalInterceptor.class)); + event.addInterceptorBinding(Transactional.class); + } + + void afterBeanDiscovered(@Observes AfterBeanDiscovery event, BeanManager beanManager) { + event.addContext(new TransactionalContext(beanManager)); + } + + private Transactional mergeTransactionAttributes(Transactional classAttribute, Transactional methodAttribute) { + return methodAttribute != null ? methodAttribute : classAttribute; + } + + Transactional getTransactionAttribute(Method method) { + return transactionAttributes.get(method); + } + +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionSupport.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionSupport.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionSupport.java new file mode 100644 index 0000000..2acb356 --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionSupport.java @@ -0,0 +1,44 @@ +/* + * 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.cdi; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; + +import org.ops4j.pax.cdi.api2.Global; +import org.ops4j.pax.cdi.api2.Service; + +@ApplicationScoped +public class TransactionSupport { + + @Inject @Global @Service + private TransactionManager transactionManager; + + @Inject @Global @Service + private TransactionSynchronizationRegistry transactionSynchronizationRegistry; + + public TransactionManager getTransactionManager() { + return transactionManager; + } + + public TransactionSynchronizationRegistry getTransactionSynchronizationRegistry() { + return transactionSynchronizationRegistry; + } + +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionalContext.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionalContext.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionalContext.java new file mode 100644 index 0000000..ce0c031 --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionalContext.java @@ -0,0 +1,277 @@ +/* + * 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.cdi; + +import javax.enterprise.context.ContextNotActiveException; +import javax.enterprise.context.spi.Context; +import javax.enterprise.context.spi.Contextual; +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; +import javax.transaction.Status; +import javax.transaction.Synchronization; +import javax.transaction.SystemException; +import javax.transaction.TransactionScoped; +import java.lang.annotation.Annotation; +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TransactionalContext implements Context { + + private static final Object TRANSACTION_BEANS_KEY = TransactionalContext.class.getName() + ".TRANSACTION_BEANS"; + + private static final Logger log = LoggerFactory.getLogger(TransactionalContext.class); + + private BeanManager beanManager; + + private volatile TransactionSupport transactionSupport; + + /** + * Creates a new transactional context. + * + * @param beanManager {@link BeanManager}. + */ + TransactionalContext(BeanManager beanManager) { + this.beanManager = beanManager; + } + + /** + * Obtains a reference to a {@link TransactionSupport} bean. + * + * @return a bean that implements {@link TransactionSupport}. + */ + private TransactionSupport getTransactionSupportReference() { + @SuppressWarnings("unchecked") + Bean<TransactionSupport> bean = (Bean<TransactionSupport>) beanManager + .resolve(beanManager.getBeans(TransactionSupport.class)); + if (bean == null) { + throw new RuntimeException("TransactionSupport was not found"); + } + + CreationalContext<TransactionSupport> ctx = beanManager.createCreationalContext(bean); + return (TransactionSupport) beanManager.getReference(bean, + TransactionSupport.class, ctx); + } + + /** + * Lazily initialize the object field and gets a reference to a bean that + * implements {@link TransactionSupport}. + * + * @return a bean that implements {@link TransactionSupport}. + */ + private TransactionSupport getTransactionSupport() { + if (transactionSupport == null) { + synchronized (this) { + if (transactionSupport == null) { + transactionSupport = getTransactionSupportReference(); + } + } + } + + return transactionSupport; + } + + /** + * Registers a synchronization object for the current transaction. + * + * @param transactionSupport a {@link TransactionSupport} bean. + * @param instances a map that contains transaction scoped beans for the + * current transaction. + */ + private <T> void registerSynchronization( + TransactionSupport transactionSupport, + Map<Contextual<T>, ContextualInstance<T>> instances) { + transactionSupport.getTransactionSynchronizationRegistry() + .registerInterposedSynchronization(new TransactionSynchronization<T>(instances)); + } + + /** + * Retrieves the map that contains transaction scoped beans for the current + * transaction. + * + * @param transactionSupport a bean that implements {@link TransactionSupport}. + * @return instances of transaction scoped beans for the current + * transaction. + */ + private <T> Map<Contextual<T>, ContextualInstance<T>> getInstances( + TransactionSupport transactionSupport) { + @SuppressWarnings("unchecked") + Map<Contextual<T>, ContextualInstance<T>> instances = + (Map<Contextual<T>, ContextualInstance<T>>) transactionSupport.getTransactionSynchronizationRegistry() + .getResource(TRANSACTION_BEANS_KEY); + if (instances == null) { + instances = new HashMap<Contextual<T>, ContextualInstance<T>>(); + transactionSupport + .getTransactionSynchronizationRegistry() + .putResource(TRANSACTION_BEANS_KEY, instances); + + registerSynchronization(transactionSupport, instances); + } + + return instances; + } + + /** + * {@inheritDoc} + */ + public <T> T get( + Contextual<T> contextual) { + return get(contextual, null); + } + + /** + * {@inheritDoc} + */ + public <T> T get( + Contextual<T> contextual, + CreationalContext<T> creationalContext) { + if (!isActive()) { + throw new ContextNotActiveException(); + } + + if (contextual == null) { + throw new IllegalArgumentException( + "No contextual specified to retrieve"); + } + + TransactionSupport transactionSupport = getTransactionSupport(); + Map<Contextual<T>, ContextualInstance<T>> instances = + getInstances(transactionSupport); + ContextualInstance<T> contextualInstance = instances.get(contextual); + if (contextualInstance != null) { + return contextualInstance.instance; + } else if (creationalContext == null) { + return null; + } else { + T instance = contextual.create(creationalContext); + contextualInstance = new ContextualInstance<T>(instance, + creationalContext); + instances.put(contextual, contextualInstance); + + if (log.isDebugEnabled()) { + log.debug("Created a new transaction scoped instance " + + contextualInstance); + } + + return instance; + } + } + + /** + * {@inheritDoc} + */ + public Class<? extends Annotation> getScope() { + return TransactionScoped.class; + } + + /** + * {@inheritDoc} + */ + public boolean isActive() { + try { + return getTransactionSupport().getTransactionManager().getStatus() == Status.STATUS_ACTIVE; + } catch (SystemException e) { + throw new RuntimeException(e); + } + } + + /** + * <p> + * Synchronization object that destroys transaction scoped beans after the + * transaction ends. + * </p> + * + * @author Vlad Arkhipov + */ + private static class TransactionSynchronization<T> + implements Synchronization { + private Map<Contextual<T>, ContextualInstance<T>> instances; + + /** + * Creates a new synchronization. + * + * @param instances instances of transaction scoped beans for the + * current transaction. + */ + TransactionSynchronization( + Map<Contextual<T>, ContextualInstance<T>> instances) { + this.instances = instances; + } + + /** + * {@inheritDoc} + */ + public void beforeCompletion() { + } + + /** + * {@inheritDoc} + */ + public void afterCompletion( + int status) { + for (Map.Entry<Contextual<T>, ContextualInstance<T>> entry : instances.entrySet()) { + entry.getValue().destroy(entry.getKey()); + } + } + } + + /** + * <p> + * An object that represents an instance of a bean. Contains a reference for + * a bean and {@link CreationalContext}. + * </p> + * + * @author Vlad Arkhipov + */ + private static class ContextualInstance<T> { + private T instance; + + private CreationalContext<T> creationalContext; + + /** + * Creates a new object that represents an instance of a bean. + * + * @param instance an instance of a bean. + * @param creationalContext a {@link CreationalContext}. + */ + public ContextualInstance( + T instance, + CreationalContext<T> creationalContext) { + this.instance = instance; + this.creationalContext = creationalContext; + } + + /** + * Destroys the bean. + * + * @param contextual a {@link Contextual}. + */ + void destroy( + Contextual<T> contextual) { + if (log.isDebugEnabled()) { + log.debug("Destroying transaction scoped bean instance " + + this); + } + + contextual.destroy(instance, creationalContext); + creationalContext.release(); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionalInterceptor.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionalInterceptor.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionalInterceptor.java new file mode 100644 index 0000000..f935ca1 --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/TransactionalInterceptor.java @@ -0,0 +1,226 @@ +/* + * 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.cdi; + +import javax.annotation.Priority; +import javax.enterprise.inject.spi.BeanManager; +import javax.inject.Inject; +import javax.interceptor.AroundInvoke; +import javax.interceptor.Interceptor; +import javax.interceptor.InvocationContext; +import javax.transaction.Status; +import javax.transaction.SystemException; +import javax.transaction.Transaction; +import javax.transaction.TransactionManager; +import javax.transaction.Transactional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Transactional +@Interceptor +@Priority(Interceptor.Priority.PLATFORM_BEFORE + 200) +class TransactionalInterceptor { + + private static final Logger log = LoggerFactory.getLogger(TransactionalInterceptor.class); + + @Inject + private BeanManager beanManager; + + @Inject + private TransactionSupport transactionSupport; + + @AroundInvoke + Object aroundInvoke(InvocationContext invocationContext) throws Exception { + + TransactionManager transactionManager = transactionSupport.getTransactionManager(); + boolean active = isTransactionActive(transactionManager); + TransactionExtension extension = beanManager.getExtension(TransactionExtension.class); + Transactional attr = extension.getTransactionAttribute(invocationContext.getMethod()); + Boolean requiresNew = requiresNew(active, attr.value()); + + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug("Invoking transactional method {}, attr = {}, active = {}, requiresNew = {}", + invocationContext.getMethod(), attr.value(), active, requiresNew); + } + + // Suspend the current transaction if transaction attribute is // REQUIRES_NEW or NOT_SUPPORTED. + Transaction previous = null; + if ((requiresNew != Boolean.FALSE) && active) { + if (debug) { + log.debug("Suspending the current transaction"); + } + previous = transactionManager.suspend(); + } + + try { + if (requiresNew == Boolean.TRUE) { + if (debug) { + log.debug("Starting a new transaction"); + } + transactionManager.begin(); + } + + Object result; + try { + result = invocationContext.proceed(); + } catch (Exception e) { + if (requiresNew == Boolean.FALSE) { + if (needsRollback(attr, e)) { + transactionManager.setRollbackOnly(); + } + } else if (requiresNew == Boolean.TRUE) { + if (needsRollback(attr, e)) { + if (debug) { + log.debug("Rolling back the current transaction"); + } + transactionManager.rollback(); + } else { + if (debug) { + log.debug("Committing the current transaction"); + } + transactionManager.commit(); + } + } + + throw e; + } + + if (requiresNew == Boolean.TRUE) { + if (transactionManager.getStatus() == Status.STATUS_MARKED_ROLLBACK) { + if (debug) { + log.debug("Rolling back the current transaction"); + } + transactionManager.rollback(); + } else { + if (debug) { + log.debug("Committing the current transaction"); + } + transactionManager.commit(); + } + } + + return result; + } finally { + // Resume the previous transaction if it was suspended. + if (previous != null) { + if (debug) { + log.debug("Resuming the previous transaction"); + } + transactionManager.resume(previous); + } + } + } + + /** + * Checks if the current transaction is active, rolled back or marked for + * rollback. + * + * @return {@code true} if the current transaction is active, rolled back or + * marked for rollback, {@code false} otherwise. + * @throws SystemException thrown if the transaction manager encounters an + * unexpected error condition + */ + private boolean isTransactionActive(TransactionManager transactionManager) throws SystemException { + switch (transactionManager.getStatus()) { + case Status.STATUS_ACTIVE: + case Status.STATUS_MARKED_ROLLBACK: + case Status.STATUS_ROLLEDBACK: + return true; + + default: + return false; + } + } + + /** + * Determines whether it is necessary to begin a new transaction. + * + * @param active the status of the current transaction. + * @param attribute the transaction attribute of the current method. + * @return {@code Boolean.TRUE} if the interceptor should suspend the + * current transaction and invoke the method within a new + * transaction, {@code Boolean.FALSE} if the interceptor should + * invoke the method within the current transaction, {@code null} if + * the interceptor should suspend the current transaction and invoke + * the method outside of transaction. + */ + private Boolean requiresNew(boolean active, Transactional.TxType attribute) { + switch (attribute) { + case MANDATORY: + if (active) { + return false; + } else { + throw new IllegalStateException("Transaction is required to perform this method"); + } + + case NEVER: + if (!active) { + return null; + } else { + throw new IllegalStateException("This method cannot be invoked within a transaction"); + } + + case NOT_SUPPORTED: + return null; + + case REQUIRED: + return !active; + + case REQUIRES_NEW: + return true; + + case SUPPORTS: + if (active) { + return false; + } else { + return null; + } + + default: + throw new UnsupportedOperationException("Unsupported TransactionAttribute value " + attribute); + } + } + + /** + * Determines whether it is necessary to rollback the current transaction + * when the specified exception occurred during the method invocation. + * + * + * @param attr + * @param exception the exception that occurred during the method + * invocation. + * @return {@code true} if the interceptor should rollback the current + * transaction, {@code false} if the interceptor should commit the + * current transaction. + */ + private boolean needsRollback(Transactional attr, Exception exception) { + for (Class cl : attr.dontRollbackOn()) { + if (cl.isInstance(exception)) { + return false; + } + } + for (Class cl : attr.rollbackOn()) { + if (cl.isInstance(exception)) { + return true; + } + } + return exception instanceof RuntimeException; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/FilterLiteral.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/FilterLiteral.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/FilterLiteral.java new file mode 100644 index 0000000..f52e1fd --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/FilterLiteral.java @@ -0,0 +1,35 @@ +/* + * 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.cdi.support; + +import javax.enterprise.util.AnnotationLiteral; + +import org.ops4j.pax.cdi.api2.Filter; + +public final class FilterLiteral extends AnnotationLiteral<Filter> implements Filter { + + private final String filter; + + public FilterLiteral(String filter) { + this.filter = filter; + } + + @Override + public String value() { + return filter; + } +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/ForwardingAnnotatedField.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/ForwardingAnnotatedField.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/ForwardingAnnotatedField.java new file mode 100644 index 0000000..d332b58 --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/ForwardingAnnotatedField.java @@ -0,0 +1,73 @@ +/* + * 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.cdi.support; + +import javax.enterprise.inject.spi.AnnotatedField; +import javax.enterprise.inject.spi.AnnotatedType; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Type; +import java.util.Set; + +public class ForwardingAnnotatedField<X> implements AnnotatedField<X> { + + private final AnnotatedField<X> delegate; + + public ForwardingAnnotatedField(AnnotatedField<X> delegate) { + this.delegate = delegate; + } + + @Override + public Field getJavaMember() { + return delegate.getJavaMember(); + } + + @Override + public boolean isStatic() { + return delegate.isStatic(); + } + + @Override + public AnnotatedType<X> getDeclaringType() { + return delegate.getDeclaringType(); + } + + @Override + public Type getBaseType() { + return delegate.getBaseType(); + } + + @Override + public Set<Type> getTypeClosure() { + return delegate.getTypeClosure(); + } + + @Override + public <T extends Annotation> T getAnnotation(Class<T> annotationType) { + return delegate.getAnnotation(annotationType); + } + + @Override + public Set<Annotation> getAnnotations() { + return delegate.getAnnotations(); + } + + @Override + public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) { + return delegate.isAnnotationPresent(annotationType); + } +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/ForwardingAnnotatedType.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/ForwardingAnnotatedType.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/ForwardingAnnotatedType.java new file mode 100644 index 0000000..6131852 --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/ForwardingAnnotatedType.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.aries.jpa.cdi.support; + +import javax.enterprise.inject.spi.AnnotatedConstructor; +import javax.enterprise.inject.spi.AnnotatedField; +import javax.enterprise.inject.spi.AnnotatedMethod; +import javax.enterprise.inject.spi.AnnotatedType; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.Set; + +public class ForwardingAnnotatedType<X> implements AnnotatedType<X> { + + private final AnnotatedType<X> delegate; + + public ForwardingAnnotatedType(AnnotatedType<X> delegate) { + this.delegate = delegate; + } + + @Override + public Class<X> getJavaClass() { + return delegate.getJavaClass(); + } + + @Override + public Set<AnnotatedConstructor<X>> getConstructors() { + return delegate.getConstructors(); + } + + @Override + public Set<AnnotatedMethod<? super X>> getMethods() { + return delegate.getMethods(); + } + + @Override + public Set<AnnotatedField<? super X>> getFields() { + return delegate.getFields(); + } + + @Override + public Type getBaseType() { + return delegate.getBaseType(); + } + + @Override + public Set<Type> getTypeClosure() { + return delegate.getTypeClosure(); + } + + @Override + public <T extends Annotation> T getAnnotation(Class<T> annotationType) { + return delegate.getAnnotation(annotationType); + } + + @Override + public Set<Annotation> getAnnotations() { + return delegate.getAnnotations(); + } + + @Override + public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) { + return delegate.isAnnotationPresent(annotationType); + } +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/InjectLiteral.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/InjectLiteral.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/InjectLiteral.java new file mode 100644 index 0000000..4fcf6d0 --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/InjectLiteral.java @@ -0,0 +1,26 @@ +/* + * 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.cdi.support; + +import javax.enterprise.util.AnnotationLiteral; +import javax.inject.Inject; + +public final class InjectLiteral extends AnnotationLiteral<Inject> implements Inject { + + public static InjectLiteral INJECT = new InjectLiteral(); + +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/ServiceLiteral.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/ServiceLiteral.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/ServiceLiteral.java new file mode 100644 index 0000000..154c5af --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/ServiceLiteral.java @@ -0,0 +1,27 @@ +/* + * 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.cdi.support; + +import javax.enterprise.util.AnnotationLiteral; + +import org.ops4j.pax.cdi.api2.Service; + +public final class ServiceLiteral extends AnnotationLiteral<Service> implements Service { + + public static final Service SERVICE = new ServiceLiteral(); + +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/SimpleBean.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/SimpleBean.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/SimpleBean.java new file mode 100644 index 0000000..6b302cc --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/SimpleBean.java @@ -0,0 +1,101 @@ +/* + * 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.cdi.support; + +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.InjectionPoint; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.Set; +import java.util.function.Supplier; + +public class SimpleBean<T> implements Bean<T> { + + private final Class clazz; + private final Class<? extends Annotation> scope; + private final Supplier<T> supplier; + private final Set<Type> types; + private final Set<Annotation> qualifiers; + + public SimpleBean(Class clazz, Class<? extends Annotation> scope, InjectionPoint ip, Supplier<T> supplier) { + this(clazz, scope, Collections.singleton(ip.getType()), ip.getQualifiers(), supplier); + } + + public SimpleBean(Class clazz, Class<? extends Annotation> scope, Set<Type> types, Set<Annotation> qualifiers, Supplier<T> supplier) { + this.clazz = clazz; + this.scope = scope; + this.types = Collections.unmodifiableSet(types); + this.qualifiers = Collections.unmodifiableSet(qualifiers); + this.supplier = supplier; + } + + @Override + public Class<?> getBeanClass() { + return clazz; + } + + @Override + public Set<InjectionPoint> getInjectionPoints() { + return Collections.emptySet(); + } + + @Override + public boolean isNullable() { + return false; + } + + @Override + public Set<Type> getTypes() { + return types; + } + + @Override + public Set<Annotation> getQualifiers() { + return qualifiers; + } + + @Override + public Class<? extends Annotation> getScope() { + return scope; + } + + @Override + public String getName() { + return null; + } + + @Override + public Set<Class<? extends Annotation>> getStereotypes() { + return Collections.emptySet(); + } + + @Override + public boolean isAlternative() { + return false; + } + + @Override + public T create(CreationalContext<T> creationalContext) { + return supplier.get(); + } + + @Override + public void destroy(T instance, CreationalContext<T> creationalContext) { + } +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/SyntheticAnnotatedField.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/SyntheticAnnotatedField.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/SyntheticAnnotatedField.java new file mode 100644 index 0000000..092a008 --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/SyntheticAnnotatedField.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.aries.jpa.cdi.support; + +import javax.enterprise.inject.spi.AnnotatedField; +import java.lang.annotation.Annotation; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class SyntheticAnnotatedField<X> extends ForwardingAnnotatedField<X> { + + private final Map<Class<? extends Annotation>, Annotation> annotations = new HashMap<>(); + + public SyntheticAnnotatedField(AnnotatedField<X> delegate) { + this(delegate, Collections.<Annotation>emptyList()); + } + + public SyntheticAnnotatedField(AnnotatedField<X> delegate, Iterable<? extends Annotation> annotations) { + super(delegate); + for (Annotation annotation : annotations) { + addAnnotation(annotation); + } + for (Annotation annotation : delegate.getAnnotations()) { + addAnnotation(annotation); + } + } + + public void addAnnotation(Annotation annotation) { + this.annotations.put(annotation.annotationType(), annotation); + } + + @Override + @SuppressWarnings("unchecked") + public <T extends Annotation> T getAnnotation(Class<T> annotationType) { + return (T) annotations.get(annotationType); + } + + @Override + public Set<Annotation> getAnnotations() { + return Collections.unmodifiableSet(new HashSet<>(annotations.values())); + } + + @Override + public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) { + return annotations.containsKey(annotationType); + } + +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/UniqueIdentifier.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/UniqueIdentifier.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/UniqueIdentifier.java new file mode 100644 index 0000000..399e785 --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/UniqueIdentifier.java @@ -0,0 +1,36 @@ +/* + * 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.cdi.support; + +import javax.inject.Qualifier; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Target({METHOD, FIELD, PARAMETER, TYPE}) +@Retention(RUNTIME) +@Qualifier +public @interface UniqueIdentifier { + + String id(); + +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/UniqueIdentifierLitteral.java ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/UniqueIdentifierLitteral.java b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/UniqueIdentifierLitteral.java new file mode 100644 index 0000000..0fb6805 --- /dev/null +++ b/jpa-cdi/src/main/java/org/apache/aries/jpa/cdi/support/UniqueIdentifierLitteral.java @@ -0,0 +1,38 @@ +/* + * 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.cdi.support; + +import javax.enterprise.util.AnnotationLiteral; +import java.util.UUID; + +public class UniqueIdentifierLitteral extends AnnotationLiteral<UniqueIdentifier> implements UniqueIdentifier { + + private final String id; + + public UniqueIdentifierLitteral(String id) { + this.id = id; + } + + @Override + public String id() { + return id; + } + + public static UniqueIdentifierLitteral random() { + return new UniqueIdentifierLitteral(UUID.randomUUID().toString()); + } +} http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/resources/META-INF/beans.xml ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/resources/META-INF/beans.xml b/jpa-cdi/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000..5a535b3 --- /dev/null +++ b/jpa-cdi/src/main/resources/META-INF/beans.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> +</beans> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension ---------------------------------------------------------------------- diff --git a/jpa-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/jpa-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension new file mode 100644 index 0000000..f5a449c --- /dev/null +++ b/jpa-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension @@ -0,0 +1,2 @@ +org.apache.aries.jpa.cdi.TransactionExtension +org.apache.aries.jpa.cdi.JpaExtension http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/jpa-parent/pom.xml ---------------------------------------------------------------------- diff --git a/jpa-parent/pom.xml b/jpa-parent/pom.xml index 70574a5..1ea4623 100644 --- a/jpa-parent/pom.xml +++ b/jpa-parent/pom.xml @@ -95,6 +95,31 @@ <artifactId>geronimo-jta_1.1_spec</artifactId> <version>1.1.1</version> </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-jta_1.2_spec</artifactId> + <version>1.0-alpha-1</version> + </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-jcdi_1.1_spec</artifactId> + <version>1.0</version> + </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-atinject_1.0_spec</artifactId> + <version>1.0</version> + </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-interceptor_1.2_spec</artifactId> + <version>1.0</version> + </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-annotation_1.2_spec</artifactId> + <version>1.0</version> + </dependency> <dependency> <groupId>org.osgi</groupId> http://git-wip-us.apache.org/repos/asf/aries-jpa/blob/ad5990d4/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 6a4e741..c5fa5a9 100644 --- a/pom.xml +++ b/pom.xml @@ -48,6 +48,7 @@ <module>jpa-container</module> <module>jpa-support</module> <module>jpa-blueprint</module> + <module>jpa-cdi</module> <module>jpa-container-eclipselink-adapter</module> <module>jpa-repository</module> <module>examples</module>
