Jump to: navigation, search

Difference between revisions of "EclipseLink/Development/OSGi"

m (EclipseLink OSGi)
 
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
This page is focussed on capturing how EclipseLink will be developed and used for an OSGi (Equinox) environment and is motivated by [https://bugs.eclipse.org/bugs/show_bug.cgi?id=210979 Bug 210979].
+
This page is focussed on capturing how EclipseLink can be used in OSGi. The goal of this effort is to produce OSGi bundles for use in any OSGi application, other Eclipse projects, and RCP applications. While the focus is on OSGi it is understood that Equinox extensions may also be provided.
 
+
The goal of this effort is to produce OSGi bundles for use in other Eclipse projects and RCP applications. While the focus is on OSGi it is understood that Equinox extensions may be required.
+
  
 
== Requirements ==
 
== Requirements ==
  
# Provide EclipseLink bundles that are easy to use within other Eclipse projects and RCP applications  
+
# Provide EclipseLink bundles that are easy to use within other OSGi applications, Eclipse projects, and RCP applications.
# Provide EclipseLink JAR files that enabled Java SE and EE usage
+
# Provide EclipseLink bundle jars that can be used in both OSGi and in Java SE and EE environments.
# Ensure that the bundles offer flexibility in their independent usage. The usage of EclipseLink JPA should not force the usage of EclipseLink's JAXB
+
# Ensure that the bundles offer flexibility in their independent usage. For example, the usage of EclipseLink JPA should not force the usage of EclipseLink's JAXB implementation.
  
 
== Rationale ==
 
== Rationale ==
Line 13: Line 11:
 
# Enable other Eclipse projects and those building Eclipse RCP applications to more easily consume EclipseLink (project MayInstall, EMF Teneo)
 
# Enable other Eclipse projects and those building Eclipse RCP applications to more easily consume EclipseLink (project MayInstall, EMF Teneo)
 
# Address our stated project goal to define a blue-print for persistence services usage in OSGi
 
# Address our stated project goal to define a blue-print for persistence services usage in OSGi
# As a member project of the proposed top level runtime project centered around Equinox we must be usable in an Equinox environment
+
# As a member project of the proposed top level Runtime project centered around Equinox we must be usable in an Equinox environment
  
 
== Current Status ==
 
== Current Status ==
  
As of 1.0M3 EclipseLink does not make OSGi/Equinox bundles available. This page is tracking the requirements, proposals, and discussion as to how EclipseLink can most effectively be bundled.
+
As of release 1.0 EclipseLink is packaged as a set of bundles for use in OSGi as well as a set of jars for Java SE/EE usage. They can be downloaded from the [http://www.eclipse.org/eclipselink/downloads EclipseLink Download page].
  
Here is the [EclipseLink/Development/EclipseLinkPDEConversionPLan | Detailed PDE Conversion Plan]
+
== Features ==
 +
* An implementation of javax.persistence.Persistence that provides a pluggable mechanism for JPA Provider resolution.  This mechanism is open and supports the use of JPA providers other than EclipseLink in an OSGi environment.
 +
* Applications requiring JPA only require the javax.persistence bundle, not EclipseLink (unless using EclipseLink extensions).  EclipseLink JPA is discovered through the OSGi Service Registry.
 +
* JAXB and SDO implementations are available as OSGi bundles.
  
== Proposal ==
+
== Future ==
 
+
* To avoid EclipseLink foundation having compile time dependencies on specific database or server platform APIs, such classes are contained in separate bundles.  For example, in SVN, Oracle database platform classes are housed in the eclipselink.extension.oracle project.  In OSGi, classloader restrictions mean that EclipseLink foundation classes cannot directly load database platform classes identified in persistence.xml properties.  Through a service based approach, EclipseLink will obtain the identified platform classes from a service.
To explore the packaging of EclipseLink as OSGi bundles, a branch should be created in the SVN repository.  This branch will provide a safe "sandbox" in which to experiment with different packaging and integration strategies.  It will also provide a way for EclipseLink developers and community members to access, try, and provide feedback on the approach.
+
 
+
The approach to supporting OSGi being proposed includes:
+
* Conversion of all EclipseLink projects to PDE projects to support development, debugging, and testing in an OSGi environment.
+
** This would require all developers of EclipseLink to be aware of how to develop using PDE rather than directly in JDT (e.g., classpath's defined through required bundles instead of require projects).
+
* A bundle containing the JPA specification classes contained in javax.persistence.
+
** Modification of javax.persistence.Persistence to introduce a pluggable mechanism for JPA Provider resolution.  The spec provided implementation relies on classpath scanning which doesn't work in an OSGi container.  This would support the use of JPA providers other than EclipseLink in an OSGi environment.
+
** Applications requiring JPA would require the javax.persistence bundle, not EclipseLink (unless using EclipseLink extensions).  EclipseLink JPA would be discovered through the OSGi Service Registry.
+
* A bundle containing the JAXB specification classes contained in javax.xml.bind.
+
** It's expected that a modification to the spec classes similar to those proposed for JPA would be necessary to deal with classloader issues.
+
* A service based approach to extending EclipseLink with database and server platforms.
+
** To avoid EclipseLink foundation having compile time dependencies on specific database or server platform APIs, such classes are contained in separate bundles.  For example, in SVN, Oracle database platform classes are housed in the eclipselink.extension.oracle project.  In OSGi, classloader restrictions mean that EclipseLink foundation classes cannot directly load database platform classes identified in persistence.xml properties.  Through a service based approach, EclipseLink will obtain the identified platform classes from a service.
+
 
* A service based approach to obtaining JDBC Drivers.
 
* A service based approach to obtaining JDBC Drivers.
 
** The rationale is similar to that for database and server platforms--classloader limitations do not make it possible for EclipseLink to see classes unless it explicitly pre-reqs the bundle containing a driver.  This is not extensible.  The OSGi solution to this problem (see OSGi RFC 122) is for the drivers to be registered as services and to look them up when needed.
 
** The rationale is similar to that for database and server platforms--classloader limitations do not make it possible for EclipseLink to see classes unless it explicitly pre-reqs the bundle containing a driver.  This is not extensible.  The OSGi solution to this problem (see OSGi RFC 122) is for the drivers to be registered as services and to look them up when needed.
  
=== Proposed Bundles ===
+
=== EclipseLink Bundles ===
  
*'''javax.xml.bind'''
+
There are a number of Java standard API libraries packaged as bundles and included with EclipseLink. EclipseLink is itself packaged into the following bundles:
** Spec classes and interfaces augmented with support for discovering JAXB provider services.
+
 
* '''org.eclipse.persistence.foundation'''
+
* '''org.eclipse.persistence.core'''
** Native object-relational persistence using ElcipseLink-ORM.XML or API
+
** Native object-relational persistence API(underlies JPA implementation)
** Native Object-XML API using native XML mapping file or API configuration
+
** Native Object-XML API (underlies JAXB and SDO implementations)
* '''org.eclipse.persistence.foundation.lib'''
+
** Contains various libraries required by EclipseLink.  Likely this bundle will eventually be unnecessary as the required Java libraries are either bundled separately or obtained from Orbit.  The focus of this work is on packaging EclipseLink so the packaging of all the required libraries will not be addressed by this investigation.
+
 
* '''org.eclipse.persistence.jpa'''
 
* '''org.eclipse.persistence.jpa'''
 
** JPA 1.0 functionality
 
** JPA 1.0 functionality
** Extended JPA support using EclipseLink's annotations, PU properties, and query hints
+
** Extended JPA support using EclipseLink's annotations, PU properties, mapping file extensions, and query hints
** Support for partial and complete EclipseLink-ORM.XML extensions of JPA
+
 
* '''org.eclipse.persistence.moxy'''
 
* '''org.eclipse.persistence.moxy'''
 
** JAXB 2.0 using annotations
 
** JAXB 2.0 using annotations
Line 56: Line 42:
 
* '''org.eclipse.persistence.sdo'''
 
* '''org.eclipse.persistence.sdo'''
 
** SDO 2.1 support
 
** SDO 2.1 support
* '''org.eclipse.persistence.eis'''
+
* '''org.eclipse.persistence.antlr'''
** Native Object-EIS/JCA using native XML mapping file or API configuration
+
** Repackaged ANTLR library for JP QL parsing.
 
+
* '''org.eclipse.persistence.asm'''
=== Proposed Persistence Service and Extensions ===
+
** Repackaged ASM library for byte code weaving.
 
+
* '''org.eclipse.persistence.oracle'''
* For the details on the proposed persistence service, see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=226421
+
** Oracle database platform classes.
* For the details on the proposed entity extension point, see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=226425
+
 
+
This is an example of an Eclipse (RCP) application for a library.  The first part of the example is from the point of view of the application developer.  The second part is what goes on behind the scenes to make it all work. 
+
 
+
==== Part 1: The Developer ====
+
 
+
The domain consists of one class: Book which is defined in the plugin '''org.acme.library'''.
+
 
+
<source lang="java">
+
package org.acme.library.entity;
+
 
+
@Entity
+
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
+
public class Book
+
{
+
  @Id
+
  @Generated
+
  private long id;
+
  private String title;
+
  private String abstract;
+
  ...
+
}
+
</source>
+
 
+
The entity is declared as an extension in the '''plugin.xml''' (look Ma', no persistence.xml)
+
 
+
<source lang="xml">
+
<plugin>
+
  <extension point="org.eclipse.persistence.jpa.persistenceContext">
+
      <context name="org.acme.library">
+
        <entity class="org.acme.library.entity.Book"/>
+
      </context>
+
  </extension>
+
</plugin>
+
</source>
+
 
+
Here is how a Book would be accessed using the proposed persistence service
+
 
+
<source lang="java">
+
IPersistenceService persistenceService = Activator().getDefault().getPersistenceService();
+
EntityManager em = persistenceService.createEntityManager("org.acme.library");
+
Book book = em.find(Book.class, 4368);
+
em.close();
+
</source>
+
 
+
Now, consider the library expanding and adding audio books.  The class AudioBook is defined in the plugin '''org.acme.library.audio'''.
+
 
+
<source lang="java">
+
package org.acme.library.entity;
+
 
+
import org.acme.library.Book;
+
 
+
@Entity
+
public class AudioBook entends Book
+
{
+
  private boolean abridged;
+
  private String storyteller;
+
  ...
+
}
+
</source>
+
 
+
The entity is declared as an extension in the '''plugin.xml'''
+
 
+
<source lang="xml">
+
<plugin>
+
  <extension point="org.eclipse.persistence.jpa.persistenceContext">
+
      <context name="org.acme.library">
+
        <entity class="org.acme.library.audio.entity.AudioBook"/>
+
      </context>
+
  </extension>
+
</plugin>
+
</source>
+
 
+
At runtime, the declared entities from the two plugins are combined into a single persistence context.
+
 
+
<source lang="java">
+
IPersistenceService persistenceService = Activator().getDefault().getPersistenceService();
+
EntityManager em = persistenceService.createEntityManager("org.acme.library");
+
Book book = em.find(Book.class, 4368);
+
AudioBook audioBook = em.find(AudioBook.class, 148905);
+
em.close();
+
</source>
+
 
+
==== Part 2: The Black Magic ====
+
 
+
When the persistence service starts, it loads various extensions.  The first is loading of the IPersistenceConfigurationFactory.  The factory takes the database connection information and creates a mapping of parameters specific to the JPA provider.  My current implementation only allows for a single provider to be active for the application.  To support multiple providers in the same application, the factories could be associated with some sort of provider id.
+
 
+
<source lang = "java">
+
public interface IPersistenceConfigurationFactory
+
{
+
  Map<String, String> createConfiguration(DatabaseConnectionInfo connectionInfo);
+
}
+
</source>
+
 
+
Here is the code for the Hibernate provider.  This factory only support MySQL and DB2.  Some additional work is needed to make database support generic.
+
 
+
<source lang="java">
+
public class PersistenceConfigurationFactory implements IPersistenceConfigurationFactory
+
{
+
  public Map<String, String> createConfiguration(DatabaseConnectionInfo connectionInfo)
+
  {
+
    StringBuilder uri = new StringBuilder();
+
    uri.append("jdbc:");
+
    uri.append(connectionInfo.getType());
+
    uri.append("://");
+
    uri.append(connectionInfo.getServer());
+
+
    if(connectionInfo.getPort() > 0)
+
    {
+
      uri.append(':');
+
      uri.append(connectionInfo.getPort());
+
    }
+
+
  uri.append('/');
+
+
    if(connectionInfo.getDatabase() != null)
+
      uri.append(connectionInfo.getDatabase());
+
+
    final HashMap<String, String> config = new HashMap<String, String>();
+
    config.put("hibernate.dialect", getDialect(connectionInfo.getType()));
+
    config.put("hibernate.connection.driver_class", getDriver(connectionInfo.getType()));
+
    config.put("hibernate.connection.url", uri.toString());
+
    config.put("hibernate.connection.username", connectionInfo.getUser());
+
    config.put("hibernate.connection.password", connectionInfo.getPassword());
+
+
    return config;
+
  }
+
 
+
  private String getDialect(String type)
+
  {
+
    if (type.equals("mysql"))
+
      return "org.hibernate.dialect.MySQLDialect";
+
    else
+
      return "org.hibernate.dialect.DB2Dialect";
+
  }
+
 
+
  private String getDriver(String type)
+
  {
+
    // TODO better driver support
+
    if (type.equals("mysql"))
+
      return "com.mysql.jdbc.Driver";
+
    else
+
      return "com.ibm.db2.jcc.DB2Driver";
+
  }
+
}
+
</source>
+
 
+
Here is the declaration of the extension:
+
 
+
<source lang="xml">
+
  <extension point="com.ibm.hdwb.core.persistence.ejb.configurationFactory">
+
    <factory class="com.ibm.hdwb.core.internal.persistence.ejb.hibernate.PersistenceConfigurationFactory">
+
    </factory>
+
  </extension>
+
</source>
+
 
+
The second extension point loaded is the declaration of the entities.  The class names of the entities are stored in a map keyed on the persistence context.
+
 
+
<source lang="java">
+
private final HashMap<String, HashSet<String>> entities;
+
</source>
+
 
+
There is a third extension point that maps the persistence context to a database URI. These entries are stored in a map keyed on the persistence context.
+
 
+
<source lang="java">
+
private final HashMap<String, URI> configuration;
+
</source>
+
 
+
When a client requests an EntityManager, the context name is used to locate the EntityManagerFactory from the cache of factories.  If the factory is found in the cache, it is used to create and return the EntityManger.  If the factory does not yet exist, The persistence context name is used to locate the database URI from the configuration.  From the database URI, the DatabaseConnectionInfo is obtained via an extension point.  Once the DatabaseConnectionInfo is available, the IPersistenceConfigurationFactory is used to create the JPA provider specific configuration info for the persistence context.  From the persistence context configuration, a PersistenceFactory is created that is a proxy for the EntityManagerFactory.  The PersistenceFactory is responsible for working around context classloader issues (present in Hibernate) and creating the persistence.xml.
+
 
+
<source lang="java">
+
public EntityManager createEntityManager(String instance, IProgressMonitor monitor, Map<String, String> config) throws PersistenceServiceException
+
{
+
monitor.beginTask("Connect to database", 4);
+
 
+
PersistenceFactory factory = factories.get(instance);
+
monitor.worked(1);
+
 
+
if (factory == null)
+
{
+
if (entities.containsKey(instance))
+
{
+
final Map<String, String> conf = createConfiguration(instance);
+
+
if(conf == null)
+
{
+
final Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, PersistenceService.STATUS_ERROR, "The datasource for the instance '" + instance + "' could not be found", null);
+
Activator.getDefault().getLog().log(status);
+
throw new PersistenceServiceException(status);
+
}
+
+
conf.putAll(config);
+
factory = new PersistenceFactory(instance, entities.get(instance), conf);
+
factories.put(instance, factory);
+
}
+
else
+
{
+
final Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, PersistenceService.STATUS_ERROR, "The persistence context instance '" + instance + "' could not be found", null);
+
Activator.getDefault().getLog().log(status);
+
throw new PersistenceServiceException(status);
+
}
+
}
+
+
monitor.worked(1);
+
factory.connectToDatabase();
+
monitor.worked(1);
+
 
+
return factory.createEntityManager();
+
}
+
 
+
private Map<String, String> createConfiguration(String persistenceContext)
+
{
+
final URI datasource = configuration.get(persistenceContext);
+
 
+
if (datasource == null)
+
return null;
+
+
final DatabaseConnectionInfo connectionInfo = Activator.getDefault().getConnectionService().getConnectionInfo(datasource);
+
return configurationFactory.createConfiguration(connectionInfo);
+
}
+
</source>
+
 
+
<source lang="java">
+
public class PersistenceFactory
+
{
+
public PersistenceFactory(String context, Set<String> entities, Map<String, String> properties)
+
{
+
active = false;
+
persistenceContext = context;
+
contextProperties = properties;
+
this.entities = entities;
+
}
+
 
+
public synchronized void connectToDatabase() throws PersistenceServiceException
+
{
+
if (factory != null)
+
return;
+
 
+
try
+
{
+
final ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
+
final ClassLoader parentLoader = PersistenceActivator.class.getClassLoader();
+
final PersistenceClassLoader newLoader = new PersistenceClassLoader(parentLoader, getPersistenceXML());
+
Thread.currentThread().setContextClassLoader(newLoader);
+
factory = Persistence.createEntityManagerFactory(persistenceContext, contextProperties);
+
Thread.currentThread().setContextClassLoader(oldLoader);
+
active = true;
+
}
+
catch (final Exception e)
+
{
+
final Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, PersistenceService.STATUS_ERROR, "Failed to construct EntityManagerFactory for persistence context: '" + persistenceContext
+
+ "'", e);
+
Activator.getDefault().getLog().log(status);
+
throw new PersistenceServiceException(status);
+
}
+
}
+
 
+
public EntityManager createEntityManager() throws PersistenceServiceException
+
{
+
if (factory == null)
+
{
+
final Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, PersistenceService.STATUS_ERROR, "Attempted to access the persistence context: '" + persistenceContext
+
+ "' when it is off-line", null);
+
Activator.getDefault().getLog().log(status);
+
throw new PersistenceServiceException(status);
+
}
+
 
+
return factory.createEntityManager();
+
}
+
 
+
public synchronized void disconnectFromDatabase()
+
{
+
if (factory == null)
+
return;
+
 
+
factory.close();
+
factory = null;
+
}
+
 
+
public String getPersistenceContext()
+
{
+
return persistenceContext;
+
}
+
 
+
public byte[] getPersistenceXML()
+
{
+
final StringBuilder xml = new StringBuilder();
+
xml.append("<persistence>");
+
xml.append(System.getProperty("line.separator"));
+
 
+
xml.append("<persistence-unit name=\"");
+
xml.append(persistenceContext);
+
xml.append("\" transaction-type=\"RESOURCE_LOCAL\">");
+
xml.append(System.getProperty("line.separator"));
+
 
+
for (final String entity : entities)
+
{
+
xml.append("<class>");
+
xml.append(entity);
+
xml.append("</class>");
+
xml.append(System.getProperty("line.separator"));
+
}
+
 
+
xml.append("</persistence-unit>");
+
 
+
xml.append(System.getProperty("line.separator"));
+
xml.append("</persistence>");
+
 
+
return xml.toString().getBytes();
+
}
+
 
+
public boolean isActive()
+
{
+
return active;
+
}
+
 
+
Map<String, String> contextProperties;
+
Set<String> entities;
+
private boolean active;
+
private final String persistenceContext;
+
private EntityManagerFactory factory;
+
}
+
</source>
+
 
+
The loading of the persistence.xml is handled via a specialized ClassLoader, URLStreamHandler, and URLConnection:
+
 
+
<source lang="java">
+
public class PersistenceClassLoader extends ClassLoader
+
{
+
PersistenceClassLoader(ClassLoader delegate, byte[] xmlData)
+
{
+
super(delegate);
+
 
+
urls = new Vector<URL>();
+
 
+
try
+
{
+
urls.add(new URL("bundleresource", Long.toString(Activator.getDefault().getBundle().getBundleId()), -1, "/META-INF/persistence.xml", new Handler(xmlData)));
+
}
+
catch (final MalformedURLException e)
+
{
+
e.printStackTrace();
+
}
+
}
+
 
+
@Override
+
public Enumeration<URL> getResources(String name) throws IOException
+
{
+
if (name.equals("META-INF/persistence.xml"))
+
return urls.elements();
+
 
+
return super.getResources(name);
+
}
+
 
+
Vector<URL> urls;
+
}
+
 
+
public class Handler extends URLStreamHandler
+
{
+
public Handler(byte[] xmlData)
+
{
+
this.xmlData = xmlData;
+
}
+
 
+
@Override
+
protected URLConnection openConnection(URL arg0) throws IOException
+
{
+
return new PersistenceURLConnection(arg0, xmlData);
+
}
+
 
+
byte[] xmlData;
+
}
+
 
+
public class PersistenceURLConnection extends URLConnection
+
{
+
protected PersistenceURLConnection(URL arg0, byte[] xmlData)
+
{
+
super(arg0);
+
this.xmlData = xmlData;
+
}
+
 
+
@Override
+
public void connect() throws IOException
+
{
+
}
+
 
+
@Override
+
public InputStream getInputStream() throws IOException
+
{
+
final ByteArrayInputStream stream = new ByteArrayInputStream(xmlData);
+
return stream;
+
}
+
 
+
private byte[] xmlData;
+
}
+
</source>
+
 
+
== Dependent Bundles ==
+
 
+
=== JPA ===
+
 
+
# ''QUESTION'': Is there any value in having JPA (persistence.jar) available as a separate bundle or is this just part of the API exposed from the '''org.eclipse.persistence.jpa''' bundle?
+
#* Having the javax.persistence classes available in a separate bundle would support the use of multiple persistence providers in a single application--having multiple copies of these classes can (as practical experience has shown me--Shaun) lead to nasty ClassCastExceptions.
+
#* Separating spec classes from the impl classes would support multiple spec versions independent of impl versions
+
#* Specification versions and implementations should probably be decoupled to be consistent with the expectations of OSGi users.
+
 
+
=== JAXB ===
+
 
+
# ''QUESTION: Should JAXB be a bundle or should it be advertised API from EclipseLink's MOXy bundle?''
+
#* If we take the same approach to JAXB as is proposed for JPA then JAXB would be its own bundle and be extended to support resolving specific JAXB implementations through a service registry.
+
# ''QUESTION: If it is a separate bundle should the RI be included with the API to make it functionally useful on its own?''
+
 
+
=== SDO ===
+
 
+
#''NOTE: SDO's vendor implementation approach of customizing a class from the public API (Helper) will make bundling it interesting.''
+
#* The SDO 2.1 spec classes contain a single static variable that holds a single SDO implementation class.  This effectively makes it impossible to have two SDO implementations on your classpath.  Also the way in which SDO bootstraps to find this sole implementation makes it impossible to have more than one.  Given this is the case there is no motivation to make the SDO classes available in a separate bundle.  They should be included in the EclipseLink SDO bundle.
+
  
== Issues ==
+
== Open Issues/Areas of Development ==
  
# Current Proof-of-Concept packaging of EclipseLink into bundles has relied upon the Equinox Buddy Classloader extension.  This approach is not portable to other OSGi containers and is therefore not a long term solution.  In his blog, [http://www.aqute.biz/Blog/HomePage Peter Kriens], OSGi Director of Technology, [http://www.osgi.org/blog/2007/06/osgi-and-hibernate.html describes his efforts] to address classloader issues with Hibernate that are similar to those facing EclipseLink in an OSGi environment.  Unfortunately he concludes that future versions of OSGi would require new features to solve the problem elegantly and portably.
+
* Dynamic Byte Code Weaving
#* '''Jan. 8, 2008''' -- Further investigation has lead to an approach that does not require Equinox Buddy Classloaders.  The solution is for EclipseLink to use the classloader of the bundle containing the JPA client code to perform class and resource loading.  The challenge is in obtaining the classloader.  One approach that has been prototyped is to use an Activator class in the the client application bundle to obtain the bundle classloader.  This class can be identified through the Manifest.mf of a JPA client bundle.  EclipseLink can listen for bundle events to identify JPA client bundles and obtain their classloader.
+
** When dynamic byte code weaving is enabled, EclipseLink will alter Entity classes as they are loaded to introduce a proxy (ValueHolder) for lazy OneToOne  and ManyToOne relationships as well as fetch-groups and change tracking.  
# Does packaging EclipseLink into OSGi bundles require the use of an OSGi service approach or is the JPA sufficient?  Bryan Hunt, on the eclipselink-users mailing, list has [http://dev.eclipse.org/mhonarc/lists/eclipselink-users/msg00046.html described what a service based approach would look like].
+
** As of EclipseLink 1.0 there is some support for byte code weaving in Equinox. An example will be put up on the wiki.
#* '''Jan. 8, 2008''' -- Prototyping has resulted in a fleshing out of the issue of using the Spec API vs. Services.  The current thinking is that a hybrid of both is the way to go.  The idea is that JPA client code would us the JPA spec API to obtain an EntityManagerFactory from javax.persistence.Persistence, but behind the scenes it would use a service approach to locate JPA providers.  This approach would allow client code to ignore the underlying OSGi service mechanism and just use JPA as they would in an SE environment.  It would also allow for the using of multiple JPA providers in the same OSGi container and even application.
+
** Discussions have been had with the team providing [http://www.eclipse.org/equinox/incubator/aspects/index.php AspectJ in OSGi and Equinox] to see if EclipseLink can leverage their work. Initial investigations suggest it may be possible but it would require significant engineering work.
# When dynamic weaving is enabled, EclipseLink will alter Entity classes as they are loaded to introduce a ValueHolder (proxy) for lazy OneToOne  and ManyToOne relationships as well as fetch-groups and change tracking. How can byte code weaving work in an OSGi container? Support for [http://www.eclipse.org/equinox/incubator/aspects/index.php AspectJ in OSGi and Equinox] may provide some insight into this, and may even provide an API at some point.
+
# It is not uncommon for EclipseLink customers to actually modify the EclipseLink framework by either subclassing an EclipseLink class or adding another implementation of an EclipseLink interface. We need to work with the OSGi group to see what mechanism would best accomplish the case where some of the EclipseLink code is actually defined in the client bundle, i.e. when clients add EclipseLink extension code.
+
  
== Obtaining Proof of Concept ==
+
== Other Initiatives ==
  
The OSGi proof of concept is being developed in a branch of the EclipseLink Subversion Repository based on EclipseLink 1.0M3. Check out the [http://wiki.eclipse.org/EclipseLink/Development/OSGi_Proof_of_Concept Proof of Concept] page for details on obtaining and running the POC.
+
* Proposed Persistence Service and Extensions
 +
** There is a proposal to provide support for configuring EclipseLink JPA using the Equinox plugin extension framework
 +
** [http://wiki.eclipse.org/EclipseLink/Development/OSGi/ServiceProposal Proposal Page]
  
 
[[Category:EclipseLink|OSGi]]
 
[[Category:EclipseLink|OSGi]]

Latest revision as of 11:19, 3 November 2008

This page is focussed on capturing how EclipseLink can be used in OSGi. The goal of this effort is to produce OSGi bundles for use in any OSGi application, other Eclipse projects, and RCP applications. While the focus is on OSGi it is understood that Equinox extensions may also be provided.

Requirements

  1. Provide EclipseLink bundles that are easy to use within other OSGi applications, Eclipse projects, and RCP applications.
  2. Provide EclipseLink bundle jars that can be used in both OSGi and in Java SE and EE environments.
  3. Ensure that the bundles offer flexibility in their independent usage. For example, the usage of EclipseLink JPA should not force the usage of EclipseLink's JAXB implementation.

Rationale

  1. Enable other Eclipse projects and those building Eclipse RCP applications to more easily consume EclipseLink (project MayInstall, EMF Teneo)
  2. Address our stated project goal to define a blue-print for persistence services usage in OSGi
  3. As a member project of the proposed top level Runtime project centered around Equinox we must be usable in an Equinox environment

Current Status

As of release 1.0 EclipseLink is packaged as a set of bundles for use in OSGi as well as a set of jars for Java SE/EE usage. They can be downloaded from the EclipseLink Download page.

Features

  • An implementation of javax.persistence.Persistence that provides a pluggable mechanism for JPA Provider resolution. This mechanism is open and supports the use of JPA providers other than EclipseLink in an OSGi environment.
  • Applications requiring JPA only require the javax.persistence bundle, not EclipseLink (unless using EclipseLink extensions). EclipseLink JPA is discovered through the OSGi Service Registry.
  • JAXB and SDO implementations are available as OSGi bundles.

Future

  • To avoid EclipseLink foundation having compile time dependencies on specific database or server platform APIs, such classes are contained in separate bundles. For example, in SVN, Oracle database platform classes are housed in the eclipselink.extension.oracle project. In OSGi, classloader restrictions mean that EclipseLink foundation classes cannot directly load database platform classes identified in persistence.xml properties. Through a service based approach, EclipseLink will obtain the identified platform classes from a service.
  • A service based approach to obtaining JDBC Drivers.
    • The rationale is similar to that for database and server platforms--classloader limitations do not make it possible for EclipseLink to see classes unless it explicitly pre-reqs the bundle containing a driver. This is not extensible. The OSGi solution to this problem (see OSGi RFC 122) is for the drivers to be registered as services and to look them up when needed.

EclipseLink Bundles

There are a number of Java standard API libraries packaged as bundles and included with EclipseLink. EclipseLink is itself packaged into the following bundles:

  • org.eclipse.persistence.core
    • Native object-relational persistence API(underlies JPA implementation)
    • Native Object-XML API (underlies JAXB and SDO implementations)
  • org.eclipse.persistence.jpa
    • JPA 1.0 functionality
    • Extended JPA support using EclipseLink's annotations, PU properties, mapping file extensions, and query hints
  • org.eclipse.persistence.moxy
    • JAXB 2.0 using annotations
    • JAXB 2.0 using native XML mapping file
  • org.eclipse.persistence.sdo
    • SDO 2.1 support
  • org.eclipse.persistence.antlr
    • Repackaged ANTLR library for JP QL parsing.
  • org.eclipse.persistence.asm
    • Repackaged ASM library for byte code weaving.
  • org.eclipse.persistence.oracle
    • Oracle database platform classes.

Open Issues/Areas of Development

  • Dynamic Byte Code Weaving
    • When dynamic byte code weaving is enabled, EclipseLink will alter Entity classes as they are loaded to introduce a proxy (ValueHolder) for lazy OneToOne and ManyToOne relationships as well as fetch-groups and change tracking.
    • As of EclipseLink 1.0 there is some support for byte code weaving in Equinox. An example will be put up on the wiki.
    • Discussions have been had with the team providing AspectJ in OSGi and Equinox to see if EclipseLink can leverage their work. Initial investigations suggest it may be possible but it would require significant engineering work.

Other Initiatives

  • Proposed Persistence Service and Extensions
    • There is a proposal to provide support for configuring EclipseLink JPA using the Equinox plugin extension framework
    • Proposal Page