127 JPA Service Specification

127.1 Introduction

The Java Persistence API (JPA) is a specification that sets a standard for persistently storing objects in enterprise and non-enterprise Java based environments. JPA provides an Object Relational Mapping (ORM) model that is configured through persistence descriptors. This Java Persistence Service specification defines how persistence units can be published in an OSGi framework, how client bundles can find these persistence units, how database drivers are found with the Data Service Specification for JDBC™ Technology, as well as how JPA providers can be made available within an OSGi framework.

Applications can be managed or they can be unmanaged. Managed applications run inside a Java EE Container and unmanaged applications run in a Java SE environment. The managed case requires a provider interface that can be used by the container, while in the unmanaged case the JPA provider is responsible for supporting the client directly. This specification is about the unmanaged model of JPA except in the areas where the managed model is explicitly mentioned. Additionally, multiple concurrent providers for the unmanaged case are not supported.

127.1.1 Essentials

  • Dependencies - There must be a way for persistence clients, if they so require, to manage their dependencies on a compatible persistence unit.

  • Compatibility - The Persistence Unit service must be able to function in non-managed mode according to existing standards and interfaces outlined in the JPA specification.

  • Modularity - Persistent classes and their accompanying configuration can exist in a separate bundle from the client that is operating on them using the Persistence Unit service.

  • JDBC - Leverage the Data Service Specification for JDBC™ Technology for access to the database.

127.1.2 Entities

  • JPA - The Java Persistence API, [3] JPA 2.1.

  • JPA Provider - An implementation of JPA, providing the Persistence Provider and JPA Services to Java EE Containers and Client Bundles.

  • Interface Bundle - A bundle containing the interfaces and classes in the javax.persistence namespace (and its sub-namespaces) that are defined by the JPA specification.

  • Persistence Bundle - A bundle that includes, a Meta-Persistence header, one or more Persistence Descriptor resources, and the entity classes specified by the Persistence Units in those resources.

  • Client Bundle - The bundle that uses the Persistence Bundle to retrieve and store objects.

  • Persistence Descriptor - A resource describing one or more Persistence Units.

  • Persistence Unit - A named configuration for the object-relational mappings and database access as defined in a Persistence Descriptor.

  • Entity Manager - The interface that provides the control point of retrieving and persisting objects in a relational database based on a single Persistence Unit for a single session.

  • Entity Manager Factory - A service that can create Entity Managers based on a Persistence Unit for different sessions.

  • Entity Manager Factory Builder - A service that can build an Entity Manager Factory for a specific Persistence Unit with extra configuration parameters.

  • Managed Client - A Client Bundle that is managed by a Container

  • Static Client - A Client that uses the static factory methods in the Persistence class instead of services.

  • Static Persistence - The actor that enables the use of the Persistence class static factory methods to obtain an Entity Manager Factory.

  • JDBC Provider - The bundle providing a Data Source Factory service.

Figure 127.1 JPA Service overview

JPA Service overview

127.1.3 Dependencies

This specification requires a minimum JPA version of 2.1. Implementations may choose to support newer versions of JPA, for example version 2.2, but must offer the JavaJPA contract at version 2.1 as well as any future versions that they support.

127.1.4 Synopsis

A JPA Provider tracks Persistence Bundles; a Persistence Bundle contains a Meta-Persistence manifest header. This manifest header enumerates the Persistence Descriptor resources in the Persistence Bundle. Each resource's XML schema is defined by the JPA specification. The JPA Provider reads the resource accordingly and extracts the information for one or more Persistence Units. For each found Persistence Unit, the JPA Provider registers an Entity Manager Factory Builder service. If the database is defined in the Persistence Unit, then the JPA Provider registers an Entity Manager Factory service during the availability of the corresponding Data Source Factory.

The identification of these services is handled through a number of service properties. The Entity Manager Factory service is named by the standard JPA interface, the Builder version is OSGi specific; it is used when the Client Bundle needs to create an Entity Manager Factory based on configuration properties.

A Client Bundle that wants to persist or retrieve its entity classes depends on an Entity Manager Factory (Builder) service that corresponds to a Persistence Unit that lists the entity classes. If such a service is available, the client can use this service to get an Entity Manager, allowing the client to retrieve and persist objects as long as the originating Entity Manager Factory (Builder) service is registered.

In a non-OSGi environment, it is customary to get an Entity Manager Factory through the Persistence class. This Persistence class provides a number of static methods that give access to any locally available JPA providers. This approach is not recommended in an OSGi environment due to class loading and start ordering issues. However, OSGi environments can support access through this static factory with a Static Persistence bundle.

127.2 JPA Overview

Java Persistence API (JPA) is a specification that is part of [4] Java EE 5. This OSGi Specification is based on [1] JPA 1.0, [2] JPA 2.0 and [3] JPA 2.1. This section provides an overview of JPA as specified in the JCP. The purpose of this section is to introduce the concepts behind JPA and define the terminology that will be used in the remainder of the chapter.

The purpose of JPA is to simplify access to relational databases for applications on the object-oriented Java platform. JPA provides support for storing and retrieving objects in a relational database. The JPA specification defines in detail how objects are mapped to tables and columns under the full control of the application. The core classes involved are depicted in Figure 127.2.

Figure 127.2 JPA Client View

JPA Client View

The JPA specifications define a number of concepts that are defined in this section for the purpose of this OSGi specification. However, the full syntax and semantics are defined in the JPA specifications.

127.2.1 Persistence

Classes that are stored and retrieved through JPA are called the entity classes. In this specification, the concept of entity classes includes the embeddable classes, which are classes that do not have any persistent identity, and mapped super classes that allow mappings, but are not themselves persistent. Entity classes are not required to implement any interface or extend a specific superclass, they are Plain Old Java Objects (POJOs). It is the responsibility of the JPA Provider to connect to a database and map the store and retrieve operations of the entity classes to their tables and columns. For performance reasons, the entity classes are sometimes enhanced. This enhancement can take place during build time, deploy time, or during class loading time. Some enhancements use byte code weaving, some enhancements are based on sub-classing.

The JPA Provider cannot automatically perform its persistence tasks; it requires configuration information. This configuration information is stored in the Persistence Descriptor. A Persistence Descriptor is an XML file according of one of the two following namespaces:

http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd

The JPA standard Persistence Descriptor must be stored in META-INF/persistence.xml. It is usually in the same class path entry (like a JAR or directory) as the entity classes.

The JPA Provider parses the Persistence Descriptor and extracts one or more Persistence Units. A Persistence Unit includes the following aspects:

  • Name - Every Persistence Unit must have a name to identify it to clients. For example: Accounting.

  • Provider Selection - Restriction to a specific JPA Provider, usually because there are dependencies in the application code on provider specific functionality.

  • JDBC Driver Selection - Selects the JDBC driver, the principal and the credentials for selecting and accessing a relational database. See JDBC Access in JPA.

  • Properties - Standard and JPA Provider specific properties.

The object-relational mappings are stored in special mapping resources or are specified in annotations.

A Persistence Unit can be complete or incomplete. A complete Persistence Unit identifies the database driver that is needed for the Persistence Unit, though it does not have to contain the credentials. An incomplete Persistence Unit lacks this information.

The relations between the class path, its entries, the entity classes, the Persistence Descriptor and the Persistence Unit is depicted in Figure 127.3 on page .

Figure 127.3 JPA Configuration

JPA Configuration

JPA recognizes the concept of a persistence root. The persistence root is the root of the JAR (or directory) on the class path that contains the META-INF/persistence.xml resource.

127.2.2 JPA Provider

The JPA specifications provide support for multiple JPA Providers in the same application. An Application selects a JPA Provider through the Persistence class, using static factory methods. One of these methods accepts a map with configuration properties. Configuration properties can override information specified in a Persistence Unit or these properties add new information to the Persistence Unit.

The default implementation of the Persistence class discovers providers through the Java EE services model, this model requires a text resource in the class path entry called:

 META-INF/services/javax.persistence.PersistenceProvider 

This text resource contains the name of the JPA Provider implementation class.

The Persistence class createEntityManagerFactory method provides the JPA Provider with the name of a Persistence Unit. The JPA Provider must then scan the class path for any META-INF/persistence.xml entries, these are the available Persistence Descriptors. It then extracts the Persistence Units to find the requested Persistence Unit. If no such Persistence Unit can be found, or the JPA Provider is restricted from servicing this Persistence Unit, then null is returned. The Persistence class will then continue to try the next found or registered JPA Provider.

A Persistence Unit can restrict JPA Providers by specifying a JPA Provider class, this introduces a provider dependency. The specified JPA Provider class must implement the PersistenceProvider interface. This implementation class name must be available from the JPA Provider's documentation. JPA Providers that do not own the specified JPA Provider class must ignore such a Persistence Unit.

Otherwise, if the Persistence Unit is not restricted, the JPA Provider is assigned to this Persistence Unit; it must be ready to provide an EntityManagerFactory object when the application requests one.

The JPA Provider uses the Persistence Unit, together with any additional configuration properties, to construct an Entity Manager Factory. The application then uses this Entity Manager Factory to construct an Entity Manager, optionally providing additional configuration properties. The Entity Manager then provides the operations for the application to store and retrieve entity classes from the database.

The additional configuration properties provided with the creation of the Entity Manager Factory or the Entity Manager are often used to specify the database driver and the credentials. This allows the Persistence Unit to be specified without committing to a specific database, leaving the choice to the application at runtime.

The relations between the application, Entity Manager, Entity Manager Factory and the JPA Provider are depicted in Figure 127.4 on page .

Figure 127.4 JPA Dynamic Model

JPA Dynamic Model

127.2.3 Managed and Unmanaged

The JPA specifications make a distinction between a managed and an unmanaged mode. In the managed mode the presence of a Java EE Container is assumed. Such a container provides many services for its contained applications like transaction handling, dependency injection, etc. One of these aspects can be the interface to the relational database. The JPA specifications therefore have defined a special method for Java EE Containers to manage the persistence aspects of their Managed Clients. This method is the createContainerEntityManagerFactory method on the PersistenceProvider interface. This method is purely intended for Java EE Containers and should not be used in other environments.

The other method on the PersistenceProvider interface is intended to be used by the Persistence class static factory methods. The Persistence class searches for an appropriate JPA Provider by asking all available JPA Providers to create an Entity Manager Factory based on configuration properties. The first JPA Provider that is capable of providing an Entity Manager Factory wins. The use of these static factory methods is called the unmanaged mode. It requires a JPA Provider to scan the class path to find the assigned Persistence Units.

127.2.4 JDBC Access in JPA

A Persistence Unit is configured to work with a relational database. JPA Providers communicate with a relational database through compliant JDBC database drivers. The database and driver parameters are specified in the Persistence Unit or configured during Entity Manager Factory or Entity Manager creation with the configuration properties. The configuration properties for selecting a database in non-managed mode were proprietary in JPA 1.0 but have been standardized in version 2.0 of JPA:

  • javax.persistence.jdbc.driver - Fully-qualified name of the driver class

  • javax.persistence.jdbc.url - Driver-specific URL to indicate database information

  • javax.persistence.jdbc.user - User name to use when obtaining connections

  • javax.persistence.jdbc.password - Password to use when obtaining connections

127.3 Bundles with Persistence

The primary goal of this specification is to simplify the programming model for bundles that need persistence. In this specification there are two application roles:

  • Persistence Bundle - A Persistence Bundle contains the entity classes and one or more Persistence Descriptors, each providing one or more Persistence Units.

  • Client Bundle -A Client Bundle contains the code that manipulates the entity classes and uses an Entity Manager to store and retrieve these entity classes with a relational database. The Client Bundle obtains the required Entity Manager(s) via a service based model.

These roles can be combined in a single bundle.

127.3.1 Services

A JPA Provider uses Persistence Units to provide Client Bundles with a configured Entity Manager Factory service and/or an Entity Manager Factory Builder service for each assigned Persistence Unit:

  • Entity Manager Factory service - Provides an EntityManagerFactory object that depends on a complete Persistence Unit. That is, it is associated with a registered Data Source Factory service.

  • Entity Manager Factory Builder service - The Entity Manager Factory Builder service provides the capability of creating an EntityManagerFactory object with additional configuration properties. The Entity Manager Factory Builder service also provides information about the JPA Provider that will be used to create the EntityManagerFactory object.

These services are collectively called the JPA Services. Entity Managers obtained from such JPA Services can only be used to operate on entity classes associated with their corresponding Persistence Unit.

127.3.2 Persistence Bundle

A Persistence Bundle is a bundle that specifies the Meta-Persistence header, see Meta Persistence Header. This header refers to one or more Persistence Descriptors in the Persistence Bundle. Commonly, this is the META-INF/persistence.xml resource. This location is the standard for non-OSGi environments, however an OSGi bundle can also use other locations as well as multiple resources.

For example, the contents of a simple Persistence Bundle with a single Person entity class could look like:

META-INF/
META-INF/MANIFEST.MF
OSGI-INF/address.xml
com/acme/Person.class

The corresponding manifest would then look like:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Meta-Persistence: OSGI-INF/address.xml
Bundle-SymbolicName: com.acme.simple.persistence
Bundle-Version: 3.2.4.200912231004

A Persistence Bundle is a normal bundle; it must follow all the rules of OSGi and can use all OSGi constructs like Bundle-ClassPath, fragment bundles, import packages, export packages, etc. However, there is one limitation: any entity classes must originate in the bundle's JAR, it cannot come from a fragment. This requirement is necessary to simplify enhancing entity classes.

127.3.3 Client Bundles

A Client Bundle uses the entity classes from a Persistence Bundle to provide its required functionality. To store and retrieve these entity classes a Client Bundle requires an Entity Manager that is configured for the corresponding Persistence Unit.

An Entity Manager is intended to be used by a single session, it is not thread safe. Therefore, a client needs an Entity Manager Factory to create an Entity Manager. In an OSGi environment, there are multiple routes to obtain an Entity Manager Factory.

A JPA Provider must register an Entity Manager Factory service for each assigned Persistence Unit that is complete. Complete means that it is a configured Persistence Unit, including the reference to the relational database. The Entity Manager Factory service is therefore bound to a Data Source Factory service and Client Bundles should not attempt to rebind the Data Source Factory with the configuration properties of the createEntityManager(Map) method. See Rebinding for the consequences. If the Data Source Factory must be bound by the Client Bundle then the Client Bundle should use the Custom Configured Entity Manager.

The Entity Manager Factory service must be registered with the service properties as defined in Service Registrations. These are:

  • osgi.unit.name - (String) The name of the Persistence Unit

  • osgi.unit.version - (String) The version of the associated Persistence Bundle

  • osgi.unit.provider - (String) The implementation class name of the JPA Provider

The life cycle of the Entity Manager Factory service is bound to the Persistence Bundle, the JPA Provider, and the selected Data Source Factory service.

A Client Bundle that wants to use an Entity Manager Factory service should therefore use an appropriate filter to select the Entity Manager Factory service that corresponds to its required Persistence Unit. For example, the following snippet uses Declarative Services, see Declarative Services Specification, to statically depend on such a service:

<reference name="accounting"
   target="(&amp;(osgi.unit.name=Accounting)(osgi.unit.version=3.2.*))"
    interface="javax.persistence.EntityManagerFactory"/>

127.3.4 Custom Configured Entity Manager

If a Client Bundle needs to provide configuration properties for the creation of an Entity Manager Factory it should use the Entity Manager Factory Builder service. This can for example be used to provide the database selection properties when the Persistence Unit is incomplete or if the database selection needs to be overridden. The Entity Manager Factory Builder service also provides information about the JPA Provider that will be used to create the Entity Manager Factory. This information can be used by the Client Bundle when determining what (if any) JPA Provider implementation specific configuration that the Client Bundle will provide.

The Entity Manager Factory Builder service's life cycle must not depend on the availability of any Data Source Factory, even if a JDBC driver class name is specified in the Persistence Descriptor. The Entity Manager Factory Builder service is registered with the same service properties as the corresponding Entity Factory service, see Service Registrations.

The following methods are defined on the EntityManagerFactoryBuilder interface:

  • createEntityManagerFactory(Map) - Returns a custom configured EntityManagerFactory instance for the Persistence Unit associated with the service. Accepts a map with the configuration properties to be applied during Entity Manager Factory creation. The method must return a proper Entity Manager Factory or throw an Exception.

  • getPersistenceProviderName() - Returns the name of the PersistenceProvider implementation class used in Entity Manager Factory creation. This name will be the same as the value of the JPA_UNIT_PROVIDER service property.

  • getPersistenceProviderBundle() - Returns the bundle JPA Provider implementation bundle which provides the PersistenceProvider. If the Persistence Provider was provided as an OSGi service then this method must return the bundle which registered the service. Otherwise this method must return the bundle which loaded the PersistenceProvider implementation class.

The createEntityManagerFactory method allows standard and vendor-specific properties to be passed in and applied to the Entity Manager Factory being created. However, some properties cannot be honored by the aforementioned method. For example, the javax.persistence.provider JPA property, as a means to specify a specific JPA Provider at runtime, cannot be supported because the JPA Provider has already been decided; it is the JPA Provider that registered the Entity Manager Factory Builder service. A JPA Provider should throw an Exception if it recognizes the property but it cannot use the property when specified through the builder. Unrecognized properties must be ignored.

Once an Entity Manager Factory is created the specified Data Source becomes associated with the Entity Manager Factory. It is therefore not possible to re-associate an Entity Manager Factory with another Data Source by providing different properties. A JPA Provider must throw an Exception when an attempt is made to re-specify the database properties. See Rebinding for further information.

As an example, a sample snippet of a client that wants to operate on a persistence unit named Accounting and pass in the JDBC user name and password properties is:

ServiceReference[] refs = context.getServiceReferences(
    EntityManagerFactoryBuilder.class.getName(),
    "(osgi.unit.name=Accounting)");
if ( refs != null ) {
    EntityManagerFactoryBuilder emfBuilder = 
        (EntityManagerFactoryBuilder) context.getService(refs[0]);
    if ( emfBuilder != null ) {
      Map<String,Object> props = new HashMap<String,Object>();
      props.put("javax.persistence.jdbc.user", userString);
      props.put("javax.persistence.jdbc.password",passwordString);
      EntityManagerFactory emf = emfBuilder.createEntityManagerFactory(props);
      EntityManager em = emf.createEntityManager();
     ...
}

The example does not handle the dynamic dependencies on the associated Data Source Factory service.

127.3.4.1 Supported configuration properties

The [3] JPA 2.1 specification adds a significant number of standard property names. These properties are used both for runtime control, and also for configuring JPA persistence units as they are created.

The EntityManagerFactoryBuilder service must support the defined property names as per the JPA specification. In most cases this will be accomplished by passing the values directly to the Persistence Provider, but in some cases it may require further action from the JPA Service implementation.

127.4 Extending a Persistence Bundle

A Persistence Bundle is identified by its Meta-Persistence manifest header that references a number of Persistence Descriptor resources. Persistence bundles must be detected by a JPA Provider. The JPA Provider must parse any Persistence Descriptors in these bundles and detect the assigned Persistence Units. For each assigned Persistence Unit, the JPA Provider must register an Entity Manager Factory Builder service when the Persistence Bundle is ready, see Ready Phase.

For complete and assigned Persistence Units, the JPA Provider must find the required Data Source Factory service based on the driver name. When the Persistence Bundle is ready and the selected Data Source Factory is available, the JPA Provider must have an Entity Manager Factory service registered that is linked to that Data Source Factory.

When the Persistence Bundle is stopped (or the JPA Provider stops), the JPA Provider must close all connections and cleanup any resources associated with the Persistence Bundle.

This process is outlined in detail in the following sections.

127.4.1 Class Space Consistency

A JPA Provider must ignore Persistence Bundles that are in another class space for the javax.persistence.* packages. Such a JPA Provider cannot create JPA Services that would be visible and usable by the Client Bundles.

127.4.2 Meta Persistence Header

A Persistence Bundle is a bundle that contains the Meta-Persistence header. If this header is not present, then this specification does not apply and a JPA Provider should ignore the corresponding bundle.

The persistence root of a Persistence Unit is the root of the Persistence Bundle's JAR

The Meta-Persistence header has a syntax of:

Meta-Persistence ::= ( jar-path ( ',' jar-path)* )?
jar-path         ::= path ( '!/' spath )? 
spath            ::= path   // must not start with solidus ('/' \u002F)

The header may include zero or more comma-separated jar-paths, each a path to a Persistence Descriptor resource in the bundle. Paths may optionally be prefixed with the solidus ('/' \u002F) character. The JPA Provider must always include the META-INF/persistence.xml first if it is not one of the listed paths. Wildcards in directories are not supported. The META-INF/persistence.xml is therefore the default location for an empty header.

For example:

Meta-Persistence: META-INF/jpa.xml, persistence/jpa.xml

The previous example will instruct the JPA Provider to process the META-INF/persistence.xml resource first, even though it is not explicitly listed. The JPA Provider must then subsequently process META-INF/jpa.xml and the persistence/jpa.xml resources.

The paths in the Meta-Persistence header must be used with the Bundle.getEntry() method, or a mechanism with similar semantics, to obtain the corresponding resource. The getEntry method does not force the bundle to resolve when still unresolved; resolving might interfere with the efficiency of any required entity class enhancements. However, the use of the getEntry method implies that fragment bundles cannot be used to contain Persistence Descriptors nor entity classes.

Paths in the Meta-Persistence header can reference JAR files that are nested in the bundle by using the !/ jar: URL syntax to separate the JAR file from the path within the JAR, for example:

Meta-Persistence: embedded.jar!/META-INF/persistence.xml

This example refers to a resource in the embedded.jar resource, located in the META-INF directory of embedded.jar.

The !/ splits the jar-path in a prefix and a suffix:

  • Prefix - The prefix is a path to a JAR resource in the bundle.

  • Suffix - The suffix is a path to a resource in the JAR identified by the prefix.

For example:

embedded.jar!/META-INF/persistence.xml
prefix:     embedded.jar
suffix:     META-INF/persistence.xml

It is not required that all listed or implied resources are present in the bundle's JAR. For example, it is valid that the default META-INF/persistence.xml resource is absent. However, if no Persistence Units are found at all then the absence of any Persistence Unit is regarded as an error that should be logged. In this case, the Persistence Bundle is further ignored.

127.4.3 Processing

A JPA Provider can detect a Persistence Bundle as early as its installation time. This early detection allows the JPA Provider to validate the Persistence Bundle as well as prepare any mechanisms to enhance the classes for better performance. However, this process can also be delayed until the bundle is started.

The JPA Provider must validate the Persistence Bundle. A valid Persistence Bundle must:

  • Have no parsing errors of the Persistence Descriptors

  • Validate all Persistence Descriptors against their schemas

  • Have at least one assigned Persistence Unit

  • Have all entity classes mentioned in the assigned Persistence Units on the Persistence Bundle's JAR.

A Persistence Bundle that uses multiple providers for its Persistence Units could become incompatible with future versions of this specification.

If any validation fails, then this is an error and should be logged. Such a bundle is ignored completely even if it also contains valid assigned Persistence Units. Only a bundle update can recover from this state.

Persistence Units can restrict JPA Providers by specifying a provider dependency. JPA Providers that do not own this JPA Provider implementation class must ignore such a Persistence Unit completely. Otherwise, if the JPA Provider can service a Persistence Unit, it assigns itself to this Persistence Unit.

If after the processing of all Persistence Descriptors, the JPA Provider has no assigned Persistence Units, then the JPA Provider must further ignore the Persistence Bundle.

127.4.4 Ready Phase

A Persistence Bundle is ready when its state is ACTIVE or, when a lazy activation policy is used, STARTING. A JPA Provider must track the ready state of Persistence Bundles that contain assigned Persistence Units.

While a Persistence Bundle is ready, the JPA Provider must have, for each assigned Persistence Unit, an Entity Manager Factory Builder service registered to allow Client Bundles to create new EntityManagerFactory objects. The JPA Provider must also register an Entity Manager Factory for each assigned and complete Persistence Unit that has its corresponding Data Source available in the service registry.

The service registration process is asynchronous with the Persistence Bundle start because a JPA Provider could start after a Persistence Bundle became ready.

127.4.5 Service Registrations

The JPA Services must be registered through the Bundle Context of the corresponding Persistence Bundle to ensure proper class space consistency checks by the OSGi Framework.

JPA Services are always related to an assigned Persistence Unit. To identify this Persistence Unit and the assigned JPA Provider, each JPA Service must have the following service properties:

  • osgi.unit.name - (String) The name of the Persistence Unit. This property corresponds to the name attribute of the persistence-unit element in the Persistence Descriptor. It is used by Client Bundles as the primary filter criterion to obtain a JPA Service for a required Persistence Unit. There can be multiple JPA Services registered under the same osgi.unit.name, each representing a different version of the Persistence Unit.

  • osgi.unit.version - (String) The version of the Persistence Bundle, as specified in Bundle-Version header, that provides the corresponding Persistence Unit. Client Bundles can filter their required JPA Services based on a particular Persistence Unit version.

  • osgi.unit.provider - (String) The JPA Provider implementation class name that registered the service. The osgi.unit.provider property allows Client Bundles to know the JPA Provider that is servicing the Persistence Unit. Client Bundles should be careful when filtering on this property, however, since the JPA Provider that is assigned a Persistence Unit may not be known by the Client Bundle ahead of time. If there is a JPA Provider dependency, it is better to specify this dependency in the Persistence Unit because other JPA Providers are then not allowed to assign such a Persistence Unit and will therefore not register a service.

127.4.6 Registering the Entity Manager Factory Builder Service

Once the Persistence Bundle is ready, a JPA Provider must register an Entity Manager Factory Builder service for each assigned Persistence Unit from that Persistence Bundle.

The Entity Manager Factory Builder service must be registered with the service properties listed in Service Registrations. The Entity Manager Factory Builder service is registered under the org.osgi.service.jpa.EntityManagerFactoryBuilder name. This interface is using the JPA packages and is therefore bound to one of the two supported versions, see Dependencies.

The Entity Manager Factory Builder service enables the creation of a parameterized version of an Entity Factory Manager by allowing the caller to specify configuration properties. This approach is necessary if, for example, the Persistence Unit is not complete.

127.4.7 Registering the Entity Manager Factory

A complete Persistence Unit is configured with a specific relational database driver, see JDBC Access in JPA. A JPA Provider must have an Entity Manager Factory service registered for each assigned and complete Persistence Unit when:

  • The originating Persistence Bundle is ready, and

  • A matching Data Source Factory service is available. Matching a Data Source Factory service to a Persistence Unit is discussed in Database Access.

A JPA Provider must track the life cycle of the matching Data Source Factory service; while this service is unavailable the Entity Manager Factory service must also be unavailable. Any active Entity Managers created by the Entity Manager Factory service become invalid to use at that time.

The Entity Manager Factory service must be registered with the same service properties as described for the Entity Manager Factory Builder service, see Service Registrations. It should be registered under the following name:

 javax.persistence.EntityManagerFactory

The EntityManagerFactory interface is from the JPA packages and is therefore bound to one of the two supported versions, see Dependencies.

An Entity Manager Factory is bound to a Data Source Factory service because its assigned Persistence Unit was complete. However, a Client Bundle could still provide JDBC configuration properties for the createEntityManager(Map) method. This not always possible, see Rebinding.

In the case of an incomplete Persistence Unit no Entity Manager Factory can be initially registered, however once configured using an Entity Manager Factory Builder service the JPA Service must register the created Entity Manager Factory as a service. The registered service must include any supplied configuration properties that match the recommended OSGi service property types as service properties. The javax.persistence.jdbc.password property must be omitted from these service properties.

If the Entity Manager Factory Builder service is later used to change the configuration being used by the Entity Manager Factory Service then the registered Entity Manager Factory service must be unregistered and closed. The newly created Entity Manager Factory object must then be registered as a service.

127.4.8 Stopping

If a Persistence Bundle is being stopped, then the JPA Provider must ensure that any resources allocated on behalf of the Persistence Bundle are cleaned up and all open connections are closed. This cleanup must happen synchronously with the STOPPING event. Any Exceptions being thrown while cleaning up should be logged but must not stop any further clean up.

If the JPA Provider is being stopped, the JPA Provider must unregister all JPA Services that it registered through the Persistence Bundles and clean up as if those bundles were stopped.

127.4.9 Entity Manager Factory Life Cycle

The Entity Manager Factory object has a close method. This method closes the EntityManagerFactory and all associated Entity Manager instances. As an OSGi framework is a multi-tenant environment it should not be possible for one user of an Entity Manager Factory service to break the valid usage of another. Therefore calls to the close method of the EntityManagerFactory registered in the service registry must not close the Entity Manager Factory.

When an Entity Manager Factory Builder service is used to create an Entity Manager Factory the same rules apply to the resulting Entity Manager Factory service, however the object returned by the Entity Manager Factory Builder behaves differently. This object has a working close method which must unregister the Entity Manager Factory service and close the Entity Manager Factory. This allows callers of the Entity Manager Factory Builder to invalidate the Entity Manager Factories that they create if, for example, a configuration changes, or a Data Source becomes invalid.

127.5 JPA Provider

JPA Providers supply the implementation of the JPA Services and the Persistence Provider service. It is the responsibility of a JPA Provider to store and retrieve the entity classes from a relational database. It is the responsibility of the JPA Provider to register a Persistence Provider and start tracking Persistence Bundles, see Extending a Persistence Bundle.

127.5.1 Managed Model

A JPA Provider that supports running in managed mode should register a specific service for the Java EE Containers: the Persistence Provider service. The interface is the standard JPA PersistenceProvider interface. See Dependencies for the issues around the multiple versions that this specification supports.

The service must be registered with the following service property:

  • javax.persistence.provider - The JPA Provider implementation class name, a documented name for all JPA Providers.

The Persistence Provider service enables a Java EE Container to find a particular JPA Provider. This service is intended for containers only, not for Client Bundles because there are implicit assumptions in the JPA Providers about the Java EE environment. A Java EE Container must obey the life cycle of the Persistence Provider service. If this service is unregistered then it must close all connections and clean up the corresponding resources.

127.5.2 Database Access

A Persistence Unit is configured to work with a relational database. JPA Providers must communicate with a relational database through a compliant JDBC database driver. The database and driver parameters are specified with properties in the Persistence Unit or the configuration properties when a Entity Manager Factory Builder is used to build an Entity Manager Factory. All JPA Providers, regardless of version, in an OSGi environment must support the following properties for database access:

  • javax.persistence.jdbc.driver - Fully-qualified name of the driver class.

  • javax.persistence.jdbc.url - Driver-specific URL to indicate database information

  • javax.persistence.jdbc.user - User name to use when obtaining connections

  • javax.persistence.jdbc.password - Password to use when obtaining connections

There are severe limitations in specifying these properties after the Entity Manager Factory is created for the first time, see Rebinding.

127.5.3 Data Source Factory Service Matching

Providers must use the javax.persistence.jdbc.driver property, as defined in JDBC Access in JPA, to obtain a Data Source Factory service. The Data Source Factory is specified in Data Service Specification for JDBC™ Technology. The javax.persistence.jdbc.driver property must be matched with the value of the Data Source Factory service property named osgi.jdbc.driver.class.

The Data Source Factory service is registered with the osgi.jdbc.driver.class service property that holds the class name of the driver. This property must match the javax.persistence.jdbc.driver service property of the Persistence Unit.

For example, if the Persistence Unit specifies the com.acme.db.Driver database driver in the javax.persistence.jdbc.driver property (or in the Persistence Descriptor property element), then the following filter would select an appropriate Data Source Factory:

(&(objectClass=org.osgi.service.jdbc.DataSourceFactory)
   (osgi.jdbc.driver.class=com.acme.db.Driver))

Once the Data Source Factory is obtained, the JPA Provider must obtain a DataSource object. This Data Source object must then be used for all relational database access.

In [1] JPA 1.0 the JPA JDBC properties were not standardized. JPA Providers typically defined a set of JDBC properties, similar to those defined in JPA 2.0, to configure JDBC driver access. JPA 1.0 JPA Providers must look up the Data Source Factory service first using the JPA 2.0 JDBC properties. If these properties are not defined then they should fall back to their proprietary driver properties.

127.5.4 Rebinding

In this specification, the Entity Manager Factory service is only registered when the Persistence Unit is complete and a matching Data Source Factory service is available. However, the API of the Entity Manager Factory Builder allows the creation of an Entity Manager Factory with configuration properties. Those configuration properties could contain the JDBC properties to bind to another Data Source Factory service than it had already selected.

This case must not be supported by a JPA Provider, an Illegal Argument Exception must be thrown. If such a case would be supported then the life cycle of the Entity Manager Factory service would still be bound to the first Data Source Factory. There would be no way for the JPA Provider to signal to the Client Bundle that the returned Entity Manager Factory is no longer valid because the rebound Data Source Factory was unregistered.

Therefore, when an Entity Manager Factory is being created using the Entity Manager Factory Builder, a JPA Provider must verify that the new properties are compatible with the properties of the already created Entity Manager Factory. If no, then an Exception must be thrown. If they are compatible, then an instance of the previous Entity Manager Factory should be returned.

127.5.5 Enhancing Entity Classes

JPA Providers may choose to implement the JPA specifications using various implementation approaches and techniques. This promotes innovation in the area, but also opens the door to limitations and constraints arising due to implementation choices. For example, there are JPA Providers that perform byte code weaving during the entity class loading. Dynamic byte code weaving requires that the entity classes are not loaded until the JPA Provider is first able to intercept the loading of the entity class and be given an opportunity to do its weaving. It also implies that the Persistence Bundle and any other bundles that import packages from that bundle must be refreshed if the JPA Provider needs to be changed.

This is necessary because the JPA Services are registered against the Bundle Contexts of the Persistence Bundles and not the Bundle Context of the JPA Providers. Client Bundles must then unget the service to unbind themselves from the uninstalled JPA Provider. However, since most JPA Providers perform some kind of weaving or class transformation on the entity classes, the Persistence Bundle will likely need to be refreshed. This will cause the Client Bundles to be refreshed also because they depend on the packages of the entity classes.

127.5.6 Class Loading

JPA Providers cannot have package dependencies on entity classes in Persistence Bundles because they cannot know at install time what Persistence Bundles they will be servicing. However, when a JPA Provider is servicing a Persistence Bundle, it must be able to load classes and resources from that Persistence Bundle according to the OSGi bundle rules. To do this class loading it must obtain a class loader that has the same visibility as the Persistence Bundle's bundle class loader. This will also allow it to load and manage metadata for the entity classes and resources for that Persistence Bundle's assigned Persistence Units. These resources and entity classes must reside directly in the Persistence Bundle, they must be accessed using the getEntry method. Entity classes and resources must not reside in fragments.

127.5.7 Validation

There is not yet an OSGi service specification defined for validation providers. If validation is required, the validation implementation will need to be included with the JPA Provider bundle.

127.6 Static Access

Non-managed client usage of JPA has traditionally been achieved through the Persistence class. Invoking a static method on the Persistence class is a dependency on the returned JPA Provider that cannot be managed by the OSGi framework.

However, such an unmanaged dependency is supported in this specification by the Static Persistence bundle. This bundle provides backwards compatibility for programs that use existing JPA access patterns. However, usage of this static model requires that the deployer ensures that the actors needed are in place at the appropriate times by controlling the life cycles of all participating bundles. The normal OSGi safe-guards and dependency handling do not work in the case of static access.

A Static Persistence Bundle must provide static access from the Persistence class to the JPA Services.

127.6.1 Access

There are two methods on the Persistence class:

  • createEntityManagerFactory(String)

  • createEntityManagerFactory(String,Map)

Both methods take the name of a Persistence Unit. The last method also takes a map that contains extra configuration properties. To support the usage of the static methods on the Persistence class, the implementation of the Persistence.createEntityManagerFactory method family must do a lookup of one of the JPA Services associated with the selected Persistence Unit.

If no configuration properties are specified, the Static Persistence Bundle must look for an Entity Manager Factory service with the osgi.unit.name property set to the given name. The default service should be used because no selector for a version is provided. If no such service is available, null must be returned. Provisioning of multiple versioned Persistence Units is not supported. Deployers should ensure only a single version of a Persistence Unit with the same name is present in an OSGi framework at any moment in time.

Otherwise, if configuration properties are provided, the Static Access implementation must look for an Entity Manager Factory Builder service with the osgi.unit.name property set to the given Persistence Unit name. If no such service exists, null must be returned. Otherwise, the default service must be used to create an Entity Manager Factory with the given configuration properties. The result must be returned to the caller.

For service lookups, the Static Persistence Bundle must use its own Bundle Context, it must not attempt to use the Bundle Context of the caller. All exceptions should be passed to the caller.

The class space of the Entity Manager Factory and the class space of the client cannot be enforced to be consistent by the framework because it is the Persistence class that is doing the lookup of the service, and not the actual calling Client Bundle that will be using the Entity Manager Factory. The framework cannot make the connection and therefore cannot enforce that the class spaces correspond. Deployers should therefore ensure that the involved class spaces are correctly wired.

127.7 Capabilities

The JPA Service Implementation must supply a number of capabilities for use by client bundles and Deployers.

127.7.1 The Extender Capability

A JPA Service implementation must provide an extender which finds and extends persistence bundles. The bundle providing this extender must provide a capability in the osgi.extender namespace declaring an extender with the name JPA_CAPABILITY_NAME. This capability must also declare a uses constraint for the org.osgi.service.jpa and javax.persistence packages. For example:

Provide-Capability: osgi.extender;
    osgi.extender="osgi.jpa";
    version:Version="1.1";
    uses:="org.osgi.service.jpa,javax.persistence"

This capability must follow the rules defined for the osgi.extender Namespace.

All persistence bundles should require the osgi.extender capability from the JPA Service. This requirement will wire the persistence bundle to the JPA Service implementation and ensure that the JPA service is using the same API packages as the persistence bundle.

Require-Capability: osgi.extender;
  filter:="(&(osgi.extender=osgi.jpa)(version>=1.1)(!(version>=2.0)))"

This requirement can be easily generated using the RequireJPAExtender annotation.

The JPA extender must only process a persistence bundle's persistence units if the following is true:

  • The bundle's wiring has a required wire for at least one osgi.extender capability with the name osgi.jpa and the first of these required wires is wired to the JPA extender.

  • The bundle's wiring has no required wire for an osgi.extender capability with the name osgi.jpa.

Otherwise, the JPA Service extender must not process the persistence bundle

127.7.2 The JPA Contract Capability

Previous versions of this specification recommended that the JPA API packages were versioned using the OSGi recommended semantic versioning policy. Whilst this would have been an excellent way to ensure compatibility between JPA persistence bundles, client bundles, and JPA providers, in practice few bundles followed this versioning policy. As a result the various actors in the JPA service can easily be created with have clashing version ranges.

This problem is not isolated to JPA, and so a general solution was created called [5] Portable Java Contract Definitions. These define a capability namespace called osgi.contract

In order to permit JPA clients to reliably work when paired with newer versions of JPA there needs to be a defined contract upon which the clients and persistence units can rely, otherwise a JPA 1.0 compatible client cannot declare a dependency which also accepts the backward compatible JPA 2.0 API. For JPA the following three contracts exist:

osgi.contract;osgi.contract=JavaJPA;version:Version=1;
    uses:="javax.persistence,javax.persistence.spi"
      
osgi.contract;osgi.contract=JavaJPA;version:Version=2;
    uses:="javax.persistence,javax.persistence.criteria,
    javax.persistence.metamodel,javax.persistence.spi"
      
osgi.contract;osgi.contract=JavaJPA;version:Version=2.1;
          uses:="javax.persistence,javax.persistence.criteria,
          javax.persistence.metamodel,javax.persistence.spi"
      

JPA API providers must declare the full set of API contract versions with which they are compatible. As JPA API versions are backward compatible this will typically result in the provider exposing all versions of a contract. Note that when a provider offers multiple versions of a contract then all of the contract versions must be offered by a single capability. For example:

Export-Package: javax.persistence,javax.persistence.criteria,
 javax.persistence.metamodel,javax.persistence.spi
Provide-Capability: osgi.contract;osgi.contract=JavaJPA;
 version:List>Version<="2.1,2,1"; uses:="javax.persistence,
 javax.persistence.criteria,javax.persistence.metamodel,javax.persistence.spi"

The contract capability means that clients can safely import the API using the contract and no import version. For example:

Import-Package: javax.persistence,javax.persistence.criteria
Require-Capability: osgi.contract;
 filter:="(&(osgi.contract=JavaJPA)(version=2.1))"

127.7.3 Service capabilities

The JPA Service implementation is responsible for registering both an EntityManagerFactoryBuilder service and a EntityManagerFactory service on behalf of the persistence bundle. The persistence bundle should therefore provide two capabilities in the osgi.service namespace, one representing the EntityManagerFactoryBuilder service, and another representing the javax.persistence.EntityManagerFactory service. These capabilities must also declare uses constraints for the packages that they expose. For example:

Provide-Capability: osgi.service;
    objectClass:List<String>=
      "org.osgi.service.jpa.EntityManagerFactoryBuilder";
    uses:="org.osgi.service.jpa",
    osgi.service;objectClass:List<String>=
      "javax.persistence.EntityManagerFactory";
    uses:="javax.persistence"

This capability must follow the rules defined for the osgi.service Namespace.

127.8 Security

When Java permissions are enabled, the JPA service must perform the following security procedures.

127.8.1 Service Permissions

The JPA service is built upon the existing OSGi service infrastructure. This means that Service Permission applies regarding the ability to publish services. A persistence bundle therefore must have ServicePermission[<interface>, REGISTER] for both the EntityManagerFactory and EntityManagerFactoryBuilder services.

If a persistence bundle specifies a complete persistence unit then the persistence bundle must either have ServicePermission[<org.osgi.service.jdbc.DataSourceFactory>, GET], or be able to directly load the configured database driver.

Client bundles that wish to configure a persistence unit using the EntityManagerFactoryBuilder service must have ServicePermission[<org.osgi.service.jpa.EntityManagerFactoryBuilder>, GET]. Furthermore, if this service is used to configure an incomplete persistence unit with a database driver name then it is the getter of the EntityManagerFactoryBuilder service whose permissions must be checked when obtaining the DataSourceFactory service. If the caller of the EntityManagerFactory Builder passes a ready constructed database Driver or DataSource then no permission check is required.

127.8.2 Required Admin Permission

The JPA service implementation requires AdminPermission[*,CONTEXT] because it needs access to the bundle's Bundle Context object with the Bundle.getBundleContext() method.

127.9 org.osgi.service.jpa

Version 1.1

JPA Package Version 1.1.

Bundles wishing to use this package must list the package in the Import-Package header of the bundle's manifest. This package has two types of users: the consumers that use the API in this package and the providers that implement the API in this package.

Example import for consumers using the API in this package:

Import-Package: org.osgi.service.jpa; version="[1.1,2.0)"

Example import for providers implementing the API in this package:

Import-Package: org.osgi.service.jpa; version="[1.1,1.2)"

127.9.1 Summary

  • EntityManagerFactoryBuilder - This service interface offers JPA clients the ability to create instances of EntityManagerFactory for a given named persistence unit.

127.9.2 public interface EntityManagerFactoryBuilder

This service interface offers JPA clients the ability to create instances of EntityManagerFactory for a given named persistence unit. A service instance will be created for each named persistence unit and can be filtered by comparing the value of the osgi.unit.name property containing the persistence unit name. This service is used specifically when the caller wants to pass in factory-scoped properties as arguments. If no properties are being used in the creation of the EntityManagerFactory then the basic EntityManagerFactory service should be used.

Consumers of this API must not implement this type

127.9.2.1 public static final String JPA_CAPABILITY_NAME = "osgi.jpa"

The name of the JPA extender capability.

1.1

127.9.2.2 public static final String JPA_SPECIFICATION_VERSION = "1.1"

The version of the extender capability for the JPA Service specification

1.1

127.9.2.3 public static final String JPA_UNIT_NAME = "osgi.unit.name"

The name of the persistence unit.

127.9.2.4 public static final String JPA_UNIT_PROVIDER = "osgi.unit.provider"

The class name of the provider that registered the service and implements the JPA javax.persistence.PersistenceProvider interface.

127.9.2.5 public static final String JPA_UNIT_VERSION = "osgi.unit.version"

The version of the persistence unit bundle.

127.9.2.6 public EntityManagerFactory createEntityManagerFactory(Map<String, Object> props)

Properties to be used, in addition to those in the persistence descriptor, for configuring the EntityManagerFactory for the persistence unit.

Return an EntityManagerFactory instance configured according to the properties defined in the corresponding persistence descriptor, as well as the properties passed into the method.

An EntityManagerFactory for the persistence unit associated with this service. Must not be null.

127.9.2.7 public Bundle getPersistenceProviderBundle()

This method returns the Bundle which provides the PersistenceProvider implementation that is used by this EntityManagerFactoryBuilder.

If the PersistenceProvider is provided as an OSGi service then this method must return the bundle which registered the service. Otherwise this method must return the bundle which loaded the PersistenceProvider implementation class.

The Bundle which provides the PersistenceProvider implementation used by this EntityManagerFactoryBuilder.

1.1

127.9.2.8 public String getPersistenceProviderName()

This method returns the name of the PersistenceProvider implementation that is used by this EntityManagerFactoryBuilder. The returned value will be the same as the value of the JPA_UNIT_PROVIDER service property.

the name of the PersistenceProvider implementation

1.1

127.10 org.osgi.service.jpa.annotations

Version 1.1

JPA Service Annotations Package Version 1.1.

This package contains annotations that can be used to require the JPA Service implementation.

Bundles should not normally need to import this package as the annotations are only used at build-time.

127.10.1 Summary

127.10.2 @RequireJPAExtender

This annotation can be used to require the JPA extender. It can be used directly, or as a meta-annotation.

CLASS

TYPE, PACKAGE

127.12 Changes