Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Gemini/JPA/Documentation/OtherTopics

< Gemini‎ | JPA‎ | Documentation
Revision as of 11:29, 13 September 2012 by Michael.keith.oracle.com (Talk | contribs) (Multitenancy and Dynamic EntityManagerFactory Instances)

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

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();

Warning - 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 below) 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 errors, 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”.

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);
    }
}    
...
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 only used 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.

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 symbolic name 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. Thus, a incremental configuration is used when there is already a persistence descriptor in the persistence bundle. If a persistence descriptor does not exist in the persistence bundle then an standalone configuration should be used instead.

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 may be specified with a value of true.

Back to the top