Difference between revisions of "Gemini/JPA/Documentation/OtherTopics"

From Eclipsepedia

Jump to: navigation, search
(Start Order)
m (Incremental Configuration)
(37 intermediate revisions by one user not shown)
Line 4: Line 4:
  
 
If there are multiple versions of a persistence bundle that are active at the same time, Gemini JPA will treat them as different bundles. However, if they have the same persistence unit name then the ''EntityManagerFactory'' services that get built by Gemini JPA for each of them will have the same value for its ''osgi.unit.name'' service property. Clients must distinguish between them by first ensuring they control which persistence unit bundle version they get resolved to, and then filtering for that bundle version using the ''osgi.unit.version'' property during the ''EntityManagerFactory'' service lookup. This will avert the possibility of getting resolved to one version of the persistence unit and then looking up a different version and getting a ''ClassCastException'' when operating on an entity class of the same name but from a different persistence unit bundle version.
 
If there are multiple versions of a persistence bundle that are active at the same time, Gemini JPA will treat them as different bundles. However, if they have the same persistence unit name then the ''EntityManagerFactory'' services that get built by Gemini JPA for each of them will have the same value for its ''osgi.unit.name'' service property. Clients must distinguish between them by first ensuring they control which persistence unit bundle version they get resolved to, and then filtering for that bundle version using the ''osgi.unit.version'' property during the ''EntityManagerFactory'' service lookup. This will avert the possibility of getting resolved to one version of the persistence unit and then looking up a different version and getting a ''ClassCastException'' when operating on an entity class of the same name but from a different persistence unit bundle version.
 +
 +
==== Multitenancy and Dynamic EntityManagerFactory Instances ====
 +
 +
There are a number of ways to achieve multitenancy within JPA. See the [http://wiki.eclipse.org/EclipseLink/Examples/JPA/Multitenant EclipseLink multitenancy documentation] for ideas and extensions that may be of use to you.
 +
 +
One approach mentioned there is the "Persistence Unit per Tenant" strategy. This can actually be translated to mean an EntityManagerFactory per tenant, since the persistence unit is often going to be the same one, used as a template to create a new tenant-specific EntityManagerFactory. While there is no allowance within either JPA or OSGi JPA to create multiple EntityManagerFactory instances in the same named persistence unit, the way to do this within Gemini JPA is to pass in the '''eclipselink.session-name''' persistence unit property with a tenant-specific string name when calling the ''EntityManagerFactoryBuilder.createEntityManagerFactory()'' method. Different persistence unit properties, such as JDBC driver properties, etc, may be passed in to the ''createEntityManagerFactory'' method. A new EntityManagerFactory instance will be returned from each call.
 +
 +
Creation of a different EMF for each tenant is not generally the best answer.  More often one would create a separate EntityManager instead and take steps to isolate the shared cached objects in the EMF. See the EclipseLink documentation for more details on available options.
 +
 +
<u>Example of creating multiple EMFs</u>
 +
 +
Assume you have the following persistence descriptor:
 +
 +
<source lang="xml">
 +
<?xml version="1.0" encoding="UTF-8"?>
 +
<persistence version="1.0"
 +
    xmlns="http://java.sun.com/xml/ns/persistence"  ... >
 +
    ...
 +
    <persistence-unit name="MyPU" transaction-type="RESOURCE_LOCAL">
 +
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
 +
        <class>...</class>
 +
        ...
 +
        <properties>
 +
            <property name="eclipselink.logging.level" value="FINE"/>
 +
        </properties>
 +
    </persistence-unit>
 +
</persistence>
 +
</source>
 +
 +
 +
You could then, after obtaining the builder from the service registry, do the following:
 +
 +
<source lang="java">
 +
Map<String,Object> props = new HashMap<String,Object>();
 +
props.put("javax.persistence.jdbc.driver", "org.apache.derby.jdbc.ClientDriver");
 +
props.put("javax.persistence.jdbc.url", "jdbc:derby://localhost:1527/client1DB");
 +
props.put("javax.persistence.jdbc.user", "user1");
 +
props.put("javax.persistence.jdbc.password", "K1H&scD7");
 +
props.put("eclipselink.session-name", "Client1Session");
 +
EntityManagerFactory client1 = emfBuilder.createEntityManagerFactory(props);
 +
...
 +
client1.close();
 +
 +
props.put("javax.persistence.jdbc.url", "jdbc:derby://localhost:1527/client2DB");
 +
props.put("javax.persistence.jdbc.user", "user2");
 +
props.put("javax.persistence.jdbc.password", "L4d32#y2kA");
 +
props.put("eclipselink.session-name", "Client2Session");
 +
EntityManagerFactory client2 = emfBuilder.createEntityManagerFactory(props);
 +
...
 +
client2.close();
 +
</source>
 +
 +
<u>'''Warnings - Please Read'''</u>
 +
 +
1. There is a JPA assumption that a single EMF exists per persistence unit. When this feature is used that assumption no longer holds true and the management of the EMFs is no longer a Gemini JPA responsibility. In other words, if you use this feature and create multiple EMFs (with different session names) from the same persistence unit then all bets are off with respect to Gemini JPA management of the EMF. The returned EMFs will not be managed by Gemini JPA and the caller is responsible, meaning:
 +
 +
* the EMF will not be registered as a service in the service registry
 +
* the caller must close it when done with it
 +
* tracking of its underlying data source may not occur (the client is responsible for tracking if the data source/driver goes away)
 +
 +
2. The '''eclipselink.session-name''' property should ''not'' be specified in a persistence descriptor or in a configuration through the Configuration Admin service support. It should ''only'' be used as a property passed into the ''EntityManagerFactoryBuilder.createEntityManagerFactory()'' method.
 +
 +
3. When creating multiple EMFs from the same persistence unit each of the EMFs must have the same set of managed entities. Ensure that the weaving option (see [[Gemini/JPA/Documentation/OtherTopics#Weaving|Weaving]] section) does not change across any of the EMFs, i.e. they all either use weaving or have it disabled.
  
 
==== Weaving ====
 
==== Weaving ====
Line 70: Line 133:
 
# other application bundles
 
# other application bundles
  
This allows the Gemini infrastructure bundles to already be in place when the persistence unit bundles come along. Failure to do this will not often be catastrophic, but can cause some spurious errors, such as the one mentioned above.
+
This allows the Gemini infrastructure bundles to already be in place when the persistence unit bundles come along. Failure to do this will not often be catastrophic, but can cause some spurious issues, such as the one mentioned above.
  
More commonly, if application bundles are resolved before the Gemini JPA bundle then all that will happen is they will be refreshed by Gemini JPA. (See [[Refreshing]] for more on this.)
+
More commonly, if application bundles are resolved before the Gemini JPA bundle then all that will happen is they will be refreshed by Gemini JPA. (See [[Gemini/JPA/Documentation/OtherTopics#Refreshing|Refreshing]] for more on this.)
  
 
===== Datasource Availability =====
 
===== Datasource Availability =====
Line 80: Line 143:
 
===== Refreshing =====
 
===== Refreshing =====
  
When Gemini JPA starts up it makes the assumption that it is going to be weaving the persistence unit bundles. In order to be able to insert a weaving hook the persistence unit bundle must not already be resolved. If it was found to already be resolved then Gemini JPA will refresh the persistence unit bundle. This means it will stop and unresolve the bundle, and then begin the resolving process again on it. All bundles that are wired to some part if it will also be unresolved and then re-resolved.
+
When Gemini JPA starts up it makes the assumption that EclipseLink is going to be weaving the entities in the persistence unit bundles. In order for EclipseLink to be able to weave the entity classes in a bundle it needs to hook in its classfile weaver before any entity class in that bundle can possibly have been loaded, and the only safe way to do that is to ensure it occurs before the bundle is resolved and has its classloader set up. That means that if Gemini JPA finds a persistence bundle and sees that it has already been resolved then it must push the bundle back into the pre-resolve stage by refreshing it and causing any bundle that may have already been wired to it (and possibly loaded a class from it) to refresh also.
  
If it turns out that weaving is not required then you may want to disable this refreshing behavior. This can be done by disabling the ''GEMINI_REFRESH'' system property that is enabled by default. Use the –D command line option to set this property to ''FALSE'' and cause Gemini JPA to not refresh bundles when it discovers persistence unit bundles that have already been resolved.
+
If refreshing causes problems it may be disabled in one of two cases:
 +
 
 +
# EclipseLink weaving is disabled. See  [http://www.eclipse.org/eclipselink/api/2.4/org/eclipse/persistence/config/PersistenceUnitProperties.html#WEAVING here] for a description of what that implies and how it is done.
 +
# EclipseLink weaving is done statically. See [http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving/Static_Weaving this section] for more information about static weaving. This will essentially perform the weaving beforehand, so by the time you install your bundle it will already have been woven.
 +
 +
If one of these two cases applies to you then Gemini JPA refreshing behavior can be disabled by using the ''REFRESH_BUNDLES'' (see GeminiSystemProperties.GEMINI_REFRESH_BUNDLES) system property. By default it is enabled. Use the –D command line option to set this property to ''FALSE'' and cause Gemini JPA to not refresh bundles when it discovers persistence unit bundles that have already been resolved.
  
 
e.g.  
 
e.g.  
  
:'''java –DGEMINI_REFRESH=FALSE <framework start class>'''
+
:'''java –DREFRESH_BUNDLES=FALSE <framework start class>'''
  
 
If using Eclipse then this property can be included as a VM argument in a “Run Configuration”.
 
If using Eclipse then this property can be included as a VM argument in a “Run Configuration”.
 +
 +
===== Capability Dependency =====
 +
 +
OSGi 4.3 added the ability to provide and require ''capabilities''. A capability is an abstraction of some feature or function that is not necessarily reified as an importable package. It may represent a certain type of extender, for example. In the OSGi JPA case, when a persistence unit bundle is installed it will not function correctly or will not be useful to clients wanting to persist or query for entities unless a suitable OSGi-enabled JPA provider is present. Gemini JPA provides a defined capability that persistence bundles can require in order to ensure the existence of Gemini JPA as a prerequisite to being resolved.
 +
 +
Capabilities will not entirely remove the bootstrap refreshing problem described in the [[Gemini/JPA/Documentation/OtherTopics#Refreshing | Refreshing section]], i.e. the possibility that persistence bundles will get resolved before Gemini JPA and will therefore get refreshed, but it should hopefully at least reduce the size of the window for when this happens.
 +
 +
======Example of requiring a Capability======
 +
 +
To include Gemini JPA as a prerequisite to resolution, add the following line to the manifest.mf file of the persistence unit bundle, and possibly even to the manifest.mf file of the application bundle.
 +
 +
<source lang="text">
 +
Require-Capability: osgi.extender;
 +
filter:="(&(osgi.extender=osgi.jpa)(version>=1.0))"
 +
</source>
 +
 +
While capabilities are standard in the OSGi Core specification, and the ''osgi.extender'' namespace is used by many different specifications, there is not yet a standardized capability attribute value defined in the OSGi JPA specification. ''osgi.jpa'' is currently a Gemini JPA extension based off the best practices used for other specifications. Not all OSGi JPA providers will provide this capability.
 +
 +
To specify a specific dependency on Gemini JPA the filter can be expanded to include the ''provider'' attribute as follows:
 +
 +
<source lang="text">
 +
Require-Capability: osgi.extender;
 +
filter:="(&(osgi.extender=osgi.jpa)(provider=org.eclipse.gemini.jpa))"
 +
</source>
 +
 +
For more information on capabilities please refer to [https://www.osgi.org/members/svn/documents/trunk/project/sp-r4.3/r4.core.pdf the OSGi Core 4.3 specification.]
 +
 +
==== Configuration Admin ====
 +
 +
JPA developers are typically very familiar with JPA persistence descriptors and the configuration that must be contained in them. In OSGi the Configuration Admin service makes dynamic configuration possible. Gemini JPA 1.1 and up has support for integrating certain types of JPA configuration information from OSGi configurations. Two different kinds of configurations are supported: standalone configurations and incremental configurations. These are discussed in the sections below.
 +
 +
An OSGi configuration is created using the ConfigurationAdmin service, obtaining a configuration, setting dictionary properties in it, and then updating it. For Gemini JPA configurations the following rules are mandatory when creating either a standalone or incremental configuration:
 +
 +
 +
# Always create a factory configuration using the ''createFactoryConfiguration()'' method.
 +
#* Always set the first ''createFactoryConfiguration'' parameter (the factory pid) to "gemini.jpa.punit".
 +
#* Always set the second ''createFactoryConfiguration'' parameter (the location) to null.
 +
# Always specify the unit name property, with the key ''GeminiPersistenceUnitProperties.PUNIT_NAME'' ("gemini.jpa.punit.name").
 +
# Only create a single configuration per persistence unit.
 +
 +
 +
The following code snippet assumes that the ''ConfigurationAdmin'' service has been obtained from the service registry. For more information on the config admin service refer to the documentation of the framework you are using.
 +
 +
<source lang="java">
 +
import org.osgi.service.cm.ConfigurationAdmin;
 +
import org.osgi.service.cm.Configuration;
 +
...
 +
 +
void createConfiguration(ConfigurationAdmin configAdmin) {
 +
    try {
 +
        // For Gemini JPA always create a factory config and set the factory pid to "gemini.jpa.punit"
 +
        Configuration config = configAdmin.createFactoryConfiguration("gemini.jpa.punit", null);
 +
 +
        // Create a dictionary and insert config properties (must include the punit name property)
 +
        Dictionary props = new Hashtable();
 +
        props.put("gemini.jpa.punit.name", "Library");
 +
        ...
 +
 +
        // Causes config to be updated, or created if it did not already exist
 +
        config.update(props);
 +
 +
    } catch (Exception ex) {
 +
        ex.printStackTrace();
 +
        throw new RuntimeException(ex);
 +
    }
 +
}   
 +
...
 +
</source>
 +
 +
<u>'''Hint:'''</u>
 +
 +
Do not create configurations in a bundle that has a dependency on anything in the persistence bundle, particularly if the config creation occurs as a result of activation. If the configuration-creating code depends upon (either directly or indirectly) anything in the persistence bundle then it will be refreshed when the persistence bundle gets refreshed and you could end up unknowingly creating the configuration multiple times, or possibly even end up in an infinite refreshing loop.
 +
 +
===== Standalone Configuration =====
 +
 +
A standalone configuration is one that an application creates with the purpose of supplying persistence information that is not present in the persistence bundle. Thus, a standalone configuration is used only when there is no persistence descriptor in the persistence bundle. If a persistence descriptor does exist in the persistence bundle then an incremental configuration should be used instead (see [[Gemini/JPA/Documentation/OtherTopics#Incremental_Configuration | Incremental Configuration]]).
 +
 +
An example of creating a standalone configuration is as follows:
 +
 +
<source lang="java">
 +
import org.osgi.service.cm.ConfigurationAdmin;
 +
import org.osgi.service.cm.Configuration;
 +
...
 +
 +
void createConfiguration(ConfigurationAdmin configAdmin) {
 +
    try {
 +
        // Create a factory config and set the factory pid to "gemini.jpa.punit"
 +
        Configuration config = configAdmin.createFactoryConfiguration("gemini.jpa.punit", null);
 +
 +
        // Config properties
 +
        Dictionary props = new Hashtable();
 +
 +
        // Must include the punit name
 +
        props.put("gemini.jpa.punit.name", "Library");
 +
 +
        // Must include the bsn
 +
        props.put("gemini.jpa.punit.bsn", "com.acme.library.jpa.punit");
 +
 +
        // Specify the classes in the persistent unit
 +
        props.put("gemini.jpa.punit.classes",
 +
                  "com.acme.model.Library, com.acme.model.Book, com.acme.model.Dvd, com.acme.model.CompactDisc");
 +
 +
        // Specify JDBC properties
 +
        props.put("javax.persistence.jdbc.driver", "org.apache.derby.jdbc.ClientDriver");
 +
        props.put("javax.persistence.jdbc.url", "jdbc:derby://localhost:1527/productionDB;create=true");
 +
        props.put("javax.persistence.jdbc.user", "scott");
 +
        props.put("javax.persistence.jdbc.password", "3uZ#hKla");
 +
 +
        // Causes config to be created
 +
        config.update(props);
 +
 +
    } catch (Exception ex) {
 +
        ex.printStackTrace();
 +
        throw new RuntimeException(ex);
 +
    }
 +
}   
 +
...
 +
</source>
 +
 +
 +
The following properties may be specified in standalone configurations:
 +
 +
 +
{| border="1" cellspacing="0" cellpadding="5" align="center"
 +
! Property Name
 +
! Value Description
 +
! Optional/Mandatory
 +
|-
 +
| gemini.jpa.punit.name
 +
| Name of the persistence unit
 +
| Mandatory
 +
|-
 +
| gemini.jpa.punit.bsn
 +
| Bundle-SymbolicName header value of the persistence bundle
 +
| Mandatory
 +
|-
 +
| gemini.jpa.punit.classes
 +
| Comma-separated list of fully qualified class names of entities/managed classes 
 +
| Optional
 +
|-
 +
| gemini.jpa.punit.excludeUnlistedClasses
 +
| When set to false, indicates that classes are to be detected automatically by EclipseLink
 +
| Optional
 +
|-
 +
| gemini.jpa.providerConnectedDataSource
 +
| When set to true, indicates that the data source will be specified using native EclipseLink properties
 +
| Optional
 +
|-
 +
| javax.persistence.jdbc.*
 +
| JPA JDBC driver properties
 +
| Optional
 +
|-
 +
| osgi.jdbc.driver.version
 +
| Additional OSGi JPA property to specify driver version
 +
| Optional
 +
|-
 +
| <EclipseLink native properties>
 +
| Any EclipseLink property
 +
| Optional
 +
|}
 +
 +
 +
Note that when creating a standalone configuration an additional mandatory bsn (bundle symbolic name) property must be included in the configuration to specify the bsn of the persistence bundle to which the persistence configuration should applied.
 +
 +
When Gemini JPA encounters a standalone configuration it will refresh the bundle to which it applies. For this reason, if an application is using only standalone configurations, and no XML persistence descriptors, then it is recommended the refreshing system property be disabled (see [[Gemini/JPA/Documentation/OtherTopics#Refreshing | Refreshing]]) since it will cause redundant refreshing.
 +
 +
===== Incremental Configuration =====
 +
 +
An incremental configuration is one that an application creates with the purpose of incrementing existing persistence information already present in the persistence bundle. It is used, therefore, when a persistence descriptor already exists in the persistence bundle, but the information is not complete or current. If a persistence descriptor does not exist in the persistence bundle then a standalone configuration should be used instead (see [[Gemini/JPA/Documentation/OtherTopics#Standalone_Configuration | Standalone Configuration]]).
 +
 +
An example of creating an incremental configuration is as follows:
 +
 +
<source lang="java">
 +
import org.osgi.service.cm.ConfigurationAdmin;
 +
import org.osgi.service.cm.Configuration;
 +
...
 +
 +
void createConfiguration(ConfigurationAdmin configAdmin) {
 +
    try {
 +
        // Create a factory config and set the factory pid to "gemini.jpa.punit"
 +
        Configuration config = configAdmin.createFactoryConfiguration("gemini.jpa.punit", null);
 +
 +
        // Config properties
 +
        Dictionary props = new Hashtable();
 +
 +
        // Must include the punit name
 +
        props.put("gemini.jpa.punit.name", "Library");
 +
 +
        // Specify JDBC properties for this installation
 +
        props.put("javax.persistence.jdbc.driver", "org.apache.derby.jdbc.ClientDriver");
 +
        props.put("javax.persistence.jdbc.url", "jdbc:derby://localhost:1527/productionDB;create=true");
 +
        props.put("javax.persistence.jdbc.user", "scott");
 +
        props.put("javax.persistence.jdbc.password", "3uZ#hKla");
 +
 +
        // Causes config to be created
 +
        config.update(props);
 +
 +
    } catch (Exception ex) {
 +
        ex.printStackTrace();
 +
        throw new RuntimeException(ex);
 +
    }
 +
}   
 +
...
 +
</source>
 +
 +
 +
The following properties may be specified in incremental configurations:
 +
 +
 +
{| border="1" cellspacing="0" cellpadding="5" align="center"
 +
! Property Name
 +
! Value Description
 +
! Optional/Mandatory
 +
|-
 +
| gemini.jpa.punit.name
 +
| Name of the persistence unit
 +
| Mandatory
 +
|-
 +
| gemini.jpa.providerConnectedDataSource
 +
| When set to true, indicates that the data source will be specified using native EclipseLink properties
 +
| Optional
 +
|-
 +
| gemini.jpa.punit.refresh
 +
| When set to true, indicates the persistence bundle must be refreshed before the config properties are applied to it
 +
| Optional
 +
|-
 +
| javax.persistence.jdbc.*
 +
| JPA JDBC driver properties
 +
| Optional
 +
|-
 +
| osgi.jdbc.driver.version
 +
| Additional OSGi JPA property to specify driver version
 +
| Optional
 +
|-
 +
| <EclipseLink native properties>
 +
| Any EclipseLink property
 +
| Optional
 +
|}
 +
 +
 +
An incremental configuration can basically only include additional properties. The bsn property should never be included in an incremental configuration.
 +
 +
When an incremental configuration is detected by Gemini JPA it will try to create an ''EntityManagerFactory'' service using the additional properties from the configuration. It will attempt to do this without refreshing the persistence bundle. There are certain circumstances, however, when the properties will require that the persistence bundle will need to be refreshed. For example, the ''eclipselink.weaving'' property is set to ''true'' in the configuration. In this case the ''gemini.jpa.punit.refresh'' property might better be specified with a value of ''true''.

Revision as of 16:01, 21 December 2012

Contents

Other Topics

Multiple Persistence Unit Versions

If there are multiple versions of a persistence bundle that are active at the same time, Gemini JPA will treat them as different bundles. However, if they have the same persistence unit name then the EntityManagerFactory services that get built by Gemini JPA for each of them will have the same value for its osgi.unit.name service property. Clients must distinguish between them by first ensuring they control which persistence unit bundle version they get resolved to, and then filtering for that bundle version using the osgi.unit.version property during the EntityManagerFactory service lookup. This will avert the possibility of getting resolved to one version of the persistence unit and then looking up a different version and getting a ClassCastException when operating on an entity class of the same name but from a different persistence unit bundle version.

Multitenancy and Dynamic EntityManagerFactory Instances

There are a number of ways to achieve multitenancy within JPA. See the EclipseLink multitenancy documentation for ideas and extensions that may be of use to you.

One approach mentioned there is the "Persistence Unit per Tenant" strategy. This can actually be translated to mean an EntityManagerFactory per tenant, since the persistence unit is often going to be the same one, used as a template to create a new tenant-specific EntityManagerFactory. While there is no allowance within either JPA or OSGi JPA to create multiple EntityManagerFactory instances in the same named persistence unit, the way to do this within Gemini JPA is to pass in the eclipselink.session-name persistence unit property with a tenant-specific string name when calling the EntityManagerFactoryBuilder.createEntityManagerFactory() method. Different persistence unit properties, such as JDBC driver properties, etc, may be passed in to the createEntityManagerFactory method. A new EntityManagerFactory instance will be returned from each call.

Creation of a different EMF for each tenant is not generally the best answer. More often one would create a separate EntityManager instead and take steps to isolate the shared cached objects in the EMF. See the EclipseLink documentation for more details on available options.

Example of creating multiple EMFs

Assume you have the following persistence descriptor:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" 
    xmlns="http://java.sun.com/xml/ns/persistence"  ... >
    ...
    <persistence-unit name="MyPU" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>...</class>
        ...
        <properties>
            <property name="eclipselink.logging.level" value="FINE"/>
        </properties>
    </persistence-unit>
</persistence>


You could then, after obtaining the builder from the service registry, do the following:

Map<String,Object> props = new HashMap<String,Object>();
props.put("javax.persistence.jdbc.driver", "org.apache.derby.jdbc.ClientDriver");
props.put("javax.persistence.jdbc.url", "jdbc:derby://localhost:1527/client1DB");
props.put("javax.persistence.jdbc.user", "user1");
props.put("javax.persistence.jdbc.password", "K1H&scD7");
props.put("eclipselink.session-name", "Client1Session");
EntityManagerFactory client1 = emfBuilder.createEntityManagerFactory(props);
...
client1.close();
 
props.put("javax.persistence.jdbc.url", "jdbc:derby://localhost:1527/client2DB");
props.put("javax.persistence.jdbc.user", "user2");
props.put("javax.persistence.jdbc.password", "L4d32#y2kA");
props.put("eclipselink.session-name", "Client2Session");
EntityManagerFactory client2 = emfBuilder.createEntityManagerFactory(props);
...
client2.close();

Warnings - Please Read

1. There is a JPA assumption that a single EMF exists per persistence unit. When this feature is used that assumption no longer holds true and the management of the EMFs is no longer a Gemini JPA responsibility. In other words, if you use this feature and create multiple EMFs (with different session names) from the same persistence unit then all bets are off with respect to Gemini JPA management of the EMF. The returned EMFs will not be managed by Gemini JPA and the caller is responsible, meaning:

  • the EMF will not be registered as a service in the service registry
  • the caller must close it when done with it
  • tracking of its underlying data source may not occur (the client is responsible for tracking if the data source/driver goes away)

2. The eclipselink.session-name property should not be specified in a persistence descriptor or in a configuration through the Configuration Admin service support. It should only be used as a property passed into the EntityManagerFactoryBuilder.createEntityManagerFactory() method.

3. When creating multiple EMFs from the same persistence unit each of the EMFs must have the same set of managed entities. Ensure that the weaving option (see Weaving section) does not change across any of the EMFs, i.e. they all either use weaving or have it disabled.

Weaving

Certain kinds of lazy mappings make weaving of the entity classes necessary. In other cases, turning on weaving can be a way to optimize performance. Weaving is used by EclipseLink for various kinds of state management, from fetch groups to change tracking. The relevant documented EclipseLink weaving properties apply similarly in a Gemini JPA environment, except that by default they are all disabled in Gemini JPA. In general, to enable weaving the eclipselink.weaving persistence unit property should be set to true in the persistence unit.

For example:

...
    <properties>
        ...
        <property name="eclipselink.weaving" value="true"/>
        ...
    </properties>
...

For more information on EclipseLink weaving properties refer to the section of the EclipseLink documentation on weaving properties.

Non-relational Databases

EclipseLink provides support for a number of NoSQL databases, EIS connectors, and other kinds of backend data sources. These features are enabled within Gemini JPA by setting a special Gemini JPA property in addition to the connection properties needed to connect to the data source.

The gemini.jpa.providerConnectedDataSource property is a persistence unit level property that can be specified either in the persistence descriptor or as a property passed to the EntityManagerFactoryBuilder createEntityManagerFactory method. The property value may be anything. Defining the property name will be enough to cause it to be in force. Setting the value to true is considered good style, though.

Once this property is set, Gemini JPA will not try to look up the usual JDBC properties, but leave it to EclipseLink to do the connecting. It assumes that EclipseLink can access and load the driver classes if a driver class is necessary. If the usual JDBC properties are specified then EclipseLink will use them and look up the JDBC driver, but the driver will be accessed directly, not tracked through an OSGi service so, again, it must be accessible to EclipseLink bundles.

An example of configuring for a MongoDB database is as follows:

...
    <properties>
        ...
        <property name="gemini.jpa.providerConnectedDataSource" value="true"/>
        <property name="eclipselink.target-database" 
                  value="org.eclipse.persistence.nosql.adapters.mongo.MongoPlatform"/>
        <property name="eclipselink.nosql.connection-spec" 
                  value="org.eclipse.persistence.nosql.adapters.mongo.MongoConnectionSpec"/>
        <property name="eclipselink.nosql.property.mongo.host" value="localhost"/>
        <property name="eclipselink.nosql.property.mongo.port" value="27017"/>
        <property name="eclipselink.nosql.property.mongo.db" value="myDB"/>        
        ...
    </properties>
...

Depending upon the data source being used, additional EclipseLink bundles may be necessary. See the EclipseLink documentation for configuring different types of data sources, and how they can be used in combination with JPA applications. The Gemini JPA part of the equation is just the gemini.jpa.providerConnectedDataSource property.

Installing and Starting Applications

One of the hard parts of starting a dynamic environment like OSGi is the ordering of the bundles that are being “deployed”. In theory, and when developed correctly, an OSGi bundle should be able to adapt to the coming and going of bundles that it relies upon. In practice, however, it may be more difficult, and unless your application goes the extra mile, it may be less resilient than you thought. Applications often have some base expectations that make it difficult, and possibly not even worth the effort, to handle complete dynamism. Here are some hints to help you start your application.

Start Order

While having a start order is not absolutely necessary, if no start order is specified then the door is open to the possibility of a certain class of timing problems. While small in number, there are a couple of things that could happen. For example, when the javax.persistence bundle is started, its activator sets its resolver (that it uses to find persistence providers) to be a special resolver that makes use of the OSGi service registry to find providers. If an application invokes the Persistence.createEntityManagerFactory() method before the javax.persistence bundle has been started then the correct resolver will not be set and the provider lookup will fail.

If a start order can be appropriately imposed, the following bundle order is recommended:

  1. javax.persistence
  2. osgi.enterprise
  3. JDBC driver bundle
  4. DBAccess bundle(s) (org.eclipse.gemini.dbaccess.<database>)
  5. org.eclipse.gemini.jpa
  6. application persistence unit bundle
  7. other application bundles

This allows the Gemini infrastructure bundles to already be in place when the persistence unit bundles come along. Failure to do this will not often be catastrophic, but can cause some spurious issues, such as the one mentioned above.

More commonly, if application bundles are resolved before the Gemini JPA bundle then all that will happen is they will be refreshed by Gemini JPA. (See Refreshing for more on this.)

Datasource Availability

A related side effect of start ordering is the availability of the DataSourceFactory service that Gemini DBAccess registers. When using Gemini DBAccess the JDBC driver will be assumed to be exported as a service from the service registry and Gemini JPA will try to look it up. If the service is not available because the Gemini DBAccess bundle has not started yet then Gemini JPA will not register the EMF service, only the EMFBuilder service. When the DataSourceFactory does eventually come online then the EMF service will get registered. If, in the meantime, before the DataSourceFactory is registered, the EMF Builder is used by an application to try to create an EMF then it will fail because the datasource is not yet available. Once again, the moral is that even though there is no resolved dependency on the datasource, its presence is rather critical unless direct JDBC driver access is being assumed.

Refreshing

When Gemini JPA starts up it makes the assumption that EclipseLink is going to be weaving the entities in the persistence unit bundles. In order for EclipseLink to be able to weave the entity classes in a bundle it needs to hook in its classfile weaver before any entity class in that bundle can possibly have been loaded, and the only safe way to do that is to ensure it occurs before the bundle is resolved and has its classloader set up. That means that if Gemini JPA finds a persistence bundle and sees that it has already been resolved then it must push the bundle back into the pre-resolve stage by refreshing it and causing any bundle that may have already been wired to it (and possibly loaded a class from it) to refresh also.

If refreshing causes problems it may be disabled in one of two cases:

  1. EclipseLink weaving is disabled. See here for a description of what that implies and how it is done.
  2. EclipseLink weaving is done statically. See this section for more information about static weaving. This will essentially perform the weaving beforehand, so by the time you install your bundle it will already have been woven.

If one of these two cases applies to you then Gemini JPA refreshing behavior can be disabled by using the REFRESH_BUNDLES (see GeminiSystemProperties.GEMINI_REFRESH_BUNDLES) system property. By default it is enabled. Use the –D command line option to set this property to FALSE and cause Gemini JPA to not refresh bundles when it discovers persistence unit bundles that have already been resolved.

e.g.

java –DREFRESH_BUNDLES=FALSE <framework start class>

If using Eclipse then this property can be included as a VM argument in a “Run Configuration”.

Capability Dependency

OSGi 4.3 added the ability to provide and require capabilities. A capability is an abstraction of some feature or function that is not necessarily reified as an importable package. It may represent a certain type of extender, for example. In the OSGi JPA case, when a persistence unit bundle is installed it will not function correctly or will not be useful to clients wanting to persist or query for entities unless a suitable OSGi-enabled JPA provider is present. Gemini JPA provides a defined capability that persistence bundles can require in order to ensure the existence of Gemini JPA as a prerequisite to being resolved.

Capabilities will not entirely remove the bootstrap refreshing problem described in the Refreshing section, i.e. the possibility that persistence bundles will get resolved before Gemini JPA and will therefore get refreshed, but it should hopefully at least reduce the size of the window for when this happens.

Example of requiring a Capability

To include Gemini JPA as a prerequisite to resolution, add the following line to the manifest.mf file of the persistence unit bundle, and possibly even to the manifest.mf file of the application bundle.

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

While capabilities are standard in the OSGi Core specification, and the osgi.extender namespace is used by many different specifications, there is not yet a standardized capability attribute value defined in the OSGi JPA specification. osgi.jpa is currently a Gemini JPA extension based off the best practices used for other specifications. Not all OSGi JPA providers will provide this capability.

To specify a specific dependency on Gemini JPA the filter can be expanded to include the provider attribute as follows:

Require-Capability: osgi.extender;
 filter:="(&(osgi.extender=osgi.jpa)(provider=org.eclipse.gemini.jpa))"

For more information on capabilities please refer to the OSGi Core 4.3 specification.

Configuration Admin

JPA developers are typically very familiar with JPA persistence descriptors and the configuration that must be contained in them. In OSGi the Configuration Admin service makes dynamic configuration possible. Gemini JPA 1.1 and up has support for integrating certain types of JPA configuration information from OSGi configurations. Two different kinds of configurations are supported: standalone configurations and incremental configurations. These are discussed in the sections below.

An OSGi configuration is created using the ConfigurationAdmin service, obtaining a configuration, setting dictionary properties in it, and then updating it. For Gemini JPA configurations the following rules are mandatory when creating either a standalone or incremental configuration:


  1. Always create a factory configuration using the createFactoryConfiguration() method.
    • Always set the first createFactoryConfiguration parameter (the factory pid) to "gemini.jpa.punit".
    • Always set the second createFactoryConfiguration parameter (the location) to null.
  2. Always specify the unit name property, with the key GeminiPersistenceUnitProperties.PUNIT_NAME ("gemini.jpa.punit.name").
  3. Only create a single configuration per persistence unit.


The following code snippet assumes that the ConfigurationAdmin service has been obtained from the service registry. For more information on the config admin service refer to the documentation of the framework you are using.

import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.cm.Configuration;
...
 
void createConfiguration(ConfigurationAdmin configAdmin) {
    try {
        // For Gemini JPA always create a factory config and set the factory pid to "gemini.jpa.punit" 
        Configuration config = configAdmin.createFactoryConfiguration("gemini.jpa.punit", null);
 
        // Create a dictionary and insert config properties (must include the punit name property)
        Dictionary props = new Hashtable();
        props.put("gemini.jpa.punit.name", "Library");
        ...
 
        // Causes config to be updated, or created if it did not already exist
        config.update(props);
 
    } catch (Exception ex) {
        ex.printStackTrace();
        throw new RuntimeException(ex);
    }
}    
...

Hint:

Do not create configurations in a bundle that has a dependency on anything in the persistence bundle, particularly if the config creation occurs as a result of activation. If the configuration-creating code depends upon (either directly or indirectly) anything in the persistence bundle then it will be refreshed when the persistence bundle gets refreshed and you could end up unknowingly creating the configuration multiple times, or possibly even end up in an infinite refreshing loop.

Standalone Configuration

A standalone configuration is one that an application creates with the purpose of supplying persistence information that is not present in the persistence bundle. Thus, a standalone configuration is used only when there is no persistence descriptor in the persistence bundle. If a persistence descriptor does exist in the persistence bundle then an incremental configuration should be used instead (see Incremental Configuration).

An example of creating a standalone configuration is as follows:

import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.cm.Configuration;
...
 
void createConfiguration(ConfigurationAdmin configAdmin) {
    try {
        // Create a factory config and set the factory pid to "gemini.jpa.punit" 
        Configuration config = configAdmin.createFactoryConfiguration("gemini.jpa.punit", null);
 
        // Config properties
        Dictionary props = new Hashtable();
 
        // Must include the punit name
        props.put("gemini.jpa.punit.name", "Library");
 
        // Must include the bsn
        props.put("gemini.jpa.punit.bsn", "com.acme.library.jpa.punit");
 
        // Specify the classes in the persistent unit
        props.put("gemini.jpa.punit.classes", 
                  "com.acme.model.Library, com.acme.model.Book, com.acme.model.Dvd, com.acme.model.CompactDisc");
 
        // Specify JDBC properties 
        props.put("javax.persistence.jdbc.driver", "org.apache.derby.jdbc.ClientDriver");
        props.put("javax.persistence.jdbc.url", "jdbc:derby://localhost:1527/productionDB;create=true");
        props.put("javax.persistence.jdbc.user", "scott");
        props.put("javax.persistence.jdbc.password", "3uZ#hKla");
 
        // Causes config to be created
        config.update(props);
 
    } catch (Exception ex) {
        ex.printStackTrace();
        throw new RuntimeException(ex);
    }
}    
...


The following properties may be specified in standalone configurations:


Property Name Value Description Optional/Mandatory
gemini.jpa.punit.name Name of the persistence unit Mandatory
gemini.jpa.punit.bsn Bundle-SymbolicName header value of the persistence bundle Mandatory
gemini.jpa.punit.classes Comma-separated list of fully qualified class names of entities/managed classes Optional
gemini.jpa.punit.excludeUnlistedClasses When set to false, indicates that classes are to be detected automatically by EclipseLink Optional
gemini.jpa.providerConnectedDataSource When set to true, indicates that the data source will be specified using native EclipseLink properties Optional
javax.persistence.jdbc.* JPA JDBC driver properties Optional
osgi.jdbc.driver.version Additional OSGi JPA property to specify driver version Optional
<EclipseLink native properties> Any EclipseLink property Optional


Note that when creating a standalone configuration an additional mandatory bsn (bundle symbolic name) property must be included in the configuration to specify the bsn of the persistence bundle to which the persistence configuration should applied.

When Gemini JPA encounters a standalone configuration it will refresh the bundle to which it applies. For this reason, if an application is using only standalone configurations, and no XML persistence descriptors, then it is recommended the refreshing system property be disabled (see Refreshing) since it will cause redundant refreshing.

Incremental Configuration

An incremental configuration is one that an application creates with the purpose of incrementing existing persistence information already present in the persistence bundle. It is used, therefore, when a persistence descriptor already exists in the persistence bundle, but the information is not complete or current. If a persistence descriptor does not exist in the persistence bundle then a standalone configuration should be used instead (see Standalone Configuration).

An example of creating an incremental configuration is as follows:

import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.cm.Configuration;
...
 
void createConfiguration(ConfigurationAdmin configAdmin) {
    try {
        // Create a factory config and set the factory pid to "gemini.jpa.punit" 
        Configuration config = configAdmin.createFactoryConfiguration("gemini.jpa.punit", null);
 
        // Config properties
        Dictionary props = new Hashtable();
 
        // Must include the punit name
        props.put("gemini.jpa.punit.name", "Library");
 
        // Specify JDBC properties for this installation
        props.put("javax.persistence.jdbc.driver", "org.apache.derby.jdbc.ClientDriver");
        props.put("javax.persistence.jdbc.url", "jdbc:derby://localhost:1527/productionDB;create=true");
        props.put("javax.persistence.jdbc.user", "scott");
        props.put("javax.persistence.jdbc.password", "3uZ#hKla");
 
        // Causes config to be created
        config.update(props);
 
    } catch (Exception ex) {
        ex.printStackTrace();
        throw new RuntimeException(ex);
    }
}    
...


The following properties may be specified in incremental configurations:


Property Name Value Description Optional/Mandatory
gemini.jpa.punit.name Name of the persistence unit Mandatory
gemini.jpa.providerConnectedDataSource When set to true, indicates that the data source will be specified using native EclipseLink properties Optional
gemini.jpa.punit.refresh When set to true, indicates the persistence bundle must be refreshed before the config properties are applied to it Optional
javax.persistence.jdbc.* JPA JDBC driver properties Optional
osgi.jdbc.driver.version Additional OSGi JPA property to specify driver version Optional
<EclipseLink native properties> Any EclipseLink property Optional


An incremental configuration can basically only include additional properties. The bsn property should never be included in an incremental configuration.

When an incremental configuration is detected by Gemini JPA it will try to create an EntityManagerFactory service using the additional properties from the configuration. It will attempt to do this without refreshing the persistence bundle. There are certain circumstances, however, when the properties will require that the persistence bundle will need to be refreshed. For example, the eclipselink.weaving property is set to true in the configuration. In this case the gemini.jpa.punit.refresh property might better be specified with a value of true.