Aries JPA

The Aries JPA project allows allows to use container managed persistence in OSGi in a modular and clean way.

The core is the jpa.container module. It implements the "JPA Service Specification Version 1.0" from the OSGi Enterprise Specification available for public download from the OSGi Alliance. The jpa.blueprint module implements container managed persistence for Aries Blueprint using a programming model like in JEE. The jpa.support module provides support for container managed persistence for DS and other injection frameworks using the JPATemplate interface.

See how it looks like in the See the Aries JPA examples.

Persistence bundles

A bundle is regarded as a persistence bundle if it contains the header Meta-Persistence: in it’s Manifest. The value of the Meta-Persistence: header is a comma separated list of locations where JPA persistence descriptors can be found. If the header value is empty then a default of META-INF/persistence.xml is used. The persistence bundle typically also contains the JPA entities.

For example:

Meta-Persistence:

means that META-INF/persistence.xml will be searched for. For non standard locations:

Meta-Persistence: persistence/myPu.xml, pUnit.jar!/someFolder/anotherPu.xml

means that the locations "persistence/myPu.xml" (relative to the root of the bundle), and "someFolder/anotherPu.xml" (relative to the root of pUnit.jar, which is in the root of the bundle) will be searched.

The Aries JPA 2 modules

Aries JPA consists of four bundles.

Aries JPA container (org.apache.aries.jpa.container)

The Aries JPA container bundle implements the OSGi JPA service specification. It tracks persistence unit bundles and creates an EntityManagerFactory service as soon as all dependencies are met.

Specifying the PersistenceProvider

For each persistence unit jpa container first determines which persistence provider to use by analyzing the "provider" property of persistence.xml. It will track a PersistenceProvider service that matches this name. If no such property is defined then the first PersistenceProvider service found will be used.

Specifying a DataSource

The next step is to configure a DataSource. There are two ways to do this. The spec conform way is to use the database properties to determine which DataSourceFactory service to use and to configure it.

Additionally aries jpa supports refering to a DataSource service using the jta-datasource or non-jta-datasource properties. The syntax is the aries jndi syntax to search for services.

Properties of the published EntityManagerFactory service

The EntityManagerFactory services will be registered with the following properties:

  • osgi.unit.name: this is the name of the persistence unit

  • osgi.unit.provider: this is the class name of the JPA PersistenceProvider that was used to create the EntityManagerFactory

  • org.apache.aries.jpa.container.managed: this property will be set to true, indicating this is a managed EntityManagerFactory.

Useful notes

  • If using a JTA persistence unit keep in mind that you still have to supply a javax.sql.DataSource not an XADataSource. This DataSource must wrap an XADataSource and provide XA resource enlistment. The simplest way to achieve this is to use pax-jdbc.

  • As soon as PersistenceProvider and DataSource are available the EntityManagerFactory service is created. Aries JPA container also supports classpath scanning and load time weaving of JPA entities.

  • You should never call close on the EntityManagerFactory service. This call will be made by the container when the persistence bundle is removed or refreshed. If you do close the EntityManagerFactory service then it will be closed for all users of the service.

Aries JPA API (org.apache.aries.jpa.api)

A set of interfaces to make it easier to use JPA in OSGi. It contains two main interfaces:

  • EmSupplier (deprecated): Allows to get a thread safe EntityManager and mark entry and exit of blocks that access the EntityManager. This is rather low level and meant to be used mainly by frameworks.

  • JpaTemplate: Allows to write closures that can safely access an EntityManager and are executed inside a transaction.

Aries JPA support(org.apache.aries.jpa.support)

For each EntityManagerFactory service this bundle provides additional services not defined in the OSGi spec that make it easier to use JPA without blueprint.

  • EmSuppler (deprectaed): Use the new thread safe EntityManager instead.

  • EntityManager: Thread safe EntityManager. Requires to be run inside a Coordination

  • JPATemplate: Is used similar to the spring JPATemplate. it takes care of the EntityManager lifecycle and transaction handling

Thread safe EntityManager

The plain EntityManager provided by the PersistenceProvider may only be used by one thread at a time. This is ok for EJB where there is a thread pool but not for OSGi where tpyically each class is just instantiated once and meant to be used multi threaded.

So Aries JPA provides a thread safe EntityManager that can be safely used. An OSGi Coordinator service is used to bind the EntityManager to a thread and to manage its lifecycle. So to use the EntityManager service you need to make sure you only call it inside a Coordination. The EntityManager will be created on first access and bound to the Coordination. When the outermost Coordination of the current thread exits the EntityManager will be closed. So typically the EntityManager is created per Request.

Most users will not use the EntityManager service directly and instead either use the blueprint based Annotations or the JPATemplate. Both of these approaches take care of the transaction and Coordination handling transparently.

Aries JPA blueprint extension (org.apache.aries.jpa.blueprint)

Provides a blueprint extension for @PersistenceUnit and @PersistenceContext injection. To use the extension add this namespace to your blueprint

xmlns:jpa="http://aries.apache.org/xmlns/jpa/v2.0.0"

and enable annotation support using the element <jpa:enable> on top level. Typically this namespace is used together with the transaction namespace to also provide annoation based transactions.

For more details see the Aries JPA blueprint example.

Creation of a JPA project using Maven

The first step consist in to create a maven module and make the following modifications to allow to deploy it as OSGI bundle on the platform and reference where the persistence XML file must loaded by the classpath to allow to the JPA container to configure the project accordingly.

Step 1 : Create a bundle

OSGi bundles are mostly regular jars but they need to contain some special OSGi headers in the Manifest. The two changes make sure your maven project creates a valid OSGi bundle.

<packaging>bundle</packaging>

and that you must configure the maven-bundle-plugin (http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html) to generate the MANIFEST.MF file required by OSGI platform.

<plugin>
  <groupId>org.apache.felix</groupId>
  <artifactId>maven-bundle-plugin</artifactId>
  <version>2.5.4</version>
  <extensions>true</extensions>
  <inherited>true</inherited>
  <configuration>
    <instructions>
          <!-- Only needed for the persistence bundle containing the jpa Entities -->
      <Meta-Persistence>META-INF/persistence.xml</Meta-Persistence>
      <!-- Needed for runtime enhancement when using hibernate -->
          <Dynamic-Import-Package>*, org.hibernate.proxy, javassist.util.proxy</Dynamic-Import-Package>
    </instructions>
  </configuration>
</plugin>

Step 2 : Adapt the persistence file

We will cover here how to modify a persistence.xml for OSGi usage. For the most part only the access to the DataSource has to be adapted for OSGi. With J2EE applications, you simply use the jdbc key with the name of the datasource associated (jdbc/reportincidentdb). In OSGi jndi support is provided by aries jndi (http://aries.apache.org/modules/jndiproject.html). It bridges jndi names to OSGi services. We must define two parameters, the "osgi:service" wich will allow to lookup OSGI services, the interface "javax.sql.DataSource" and the name of the service "osgi.jndi.service.name", which is a filter property, with its jndi name associated.

To access to the datasource, you must provide within the <jta-data-source> or <non-jta-data-source> depending if you use transaction type JTA or RESOURCE_LOCAL.

<persistence-unit name="tasklist" transaction-type="JTA">
<jta-data-source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/tasklist)</jta-data-source>

The other elements of the xml file are defined according to JPA specification.

Step 3.1 : Inject EntityManager into a bean and make it transactional

The goal of this step is to provide a DAO layer that looks like JEE code on the java level. For this we need to inject a thread safe EntityManager and ensure the DAO code is run inside a transational context.

Aries JPA 1.x used a xml element inside each DAO bean to inject the EntityManager. This syntax is not suppoerted for Aries JPA 2.x anymore. Instead simply enable standard @PesistenceContext and @PersistenceUnit annotation support with the xml element <jpa:enable> on top level.

The transactional context is established using the xml element <tx:transaction> on the bean level. In the example below we enable transactions for all DAO methods. The scope of the transaction can be defined using the attribute value.

Example blueprint follows showing the full breadth of allowable injection syntax:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
  xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.2.0"
  xmlns:jpa="http://aries.apache.org/xmlns/jpa/v2.0.0">
  <jpa:enable />
  <service ref="taskService" interface="org.apache.aries.jpa.example.tasklist.model.TaskService"/>
  <bean class="org.apache.aries.jpa.example.tasklist.blueprint.impl.TaskServiceImpl"/>
    <tx:transaction method="*"/>
  </bean>
</blueprint>

Make sure you inject the EntityManager in your DAO class like this:

@PersistenceContext(unitName="tasklist")
EntityManager em;

See tasklist-blueprint example for details.

Step 3.2 : Use JPATemplate to work with JPA in declarative services

Inject the JPATemplate using a service reference:

@Reference(target = "(osgi.unit.name=tasklist)")
public void setJpaTemplate(JpaTemplate jpa) { ... }

Use the JPATemplate to work with JPA Entities inside closures.

// txExpr if you need to return an object
return jpa.txExpr(TransactionType.Required, em -> em.find(Task.class, id));

// tx if you just execute code
jpa.tx(em -> em.persist(task));

See the tasklist-ds example for details.

Step 4 : Package the solution

To package the solution, execute a "maven clean install" instruction. Installing Aries JPA and Aries Transaction into arbitrary containers is beyond the scope of this document.

Example

To keep the installation instructions small we only cover installation into Apache Karaf 4.x. Karaf provides features for Aries JPA, Aries Transaction, Hibernate and Pax-jdbc so installation is very easy.