Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[eclipselink-dev] Classloader problem using OSGi JPA bundles

I've been playing with the bundles in the "osgi" branch and have come
across a problem.

I am trying to keep the database separated from the persistence code. I
have two bundles. The motivation is that the bundle that's providing my
domain classes and the persistence mapping, should be able to work
against an arbitrary database that I can dynamically swap at deploy- or
even run-time. 

The first bundle, org.eclipse.persistence.demo.core, contains my domain
class, Person, an Activator that exercises things, and an IDatabase
interface that provides some handy methods for figuring out how to
access the database.

My activator, looks for an OSGi service that implements IDatabase and
uses it to configure EclipseLink properties when I create the
EntityManagerFactory. Here's a snippet:

---
ServiceReference reference =
context.getServiceReference(IDatabase.class.getName());
		IDatabase database = (IDatabase) context.getService(reference);

		HashMap<String, Object> properties = new HashMap<String, Object>();
		properties.put(PersistenceUnitProperties.JDBC_URL, database.getUrl());
		properties.put(PersistenceUnitProperties.TARGET_DATABASE,
database.getName()); 
		properties.put(PersistenceUnitProperties.JDBC_DRIVER,
database.getDriver().getName()); 
		properties.put(PersistenceUnitProperties.JDBC_USER,
database.getUserId()); 
		properties.put(PersistenceUnitProperties.JDBC_PASSWORD,
database.getPassword());
		
		EntityManagerFactory entityManagerFactory = new
PersistenceProvider().createEntityManagerFactory("demo", properties,
this.getClass().getClassLoader());
---

I've created a second bundle,
org.eclipse.persistence.demo.database.derby, with an Activator that does
two things. First, it starts the Derby 'net' server (it has a dependency
on the org.apache.derby bundle) and second it creates a service that
implements the aforementioned IDatabase interface. The IDatabase
interface, as shown in the above snippet, has a method, getDriver(),
that--in the case of the DerbyDatabase class--returns Derby's
ClientDriver.

Unfortunately, org.eclipse.persistence.demo.database.derby and
org.apache.derby bundles are not in the class loading path for
org.eclipse.persistence.demo.core and so the driver, ClientDriver, is
not found by EclipseLink and I get a driver not found exception.

One work around I've used successfully (which is shown in the attached
file) is to add Buddy Classloading to org.eclipse.persistence.demo.core.
Specifically, I've added "Eclipse-BuddyPolicy: global" to the
MANIFEST.MF file.

What this does, is it tells Equinox to first do the normal thing while
looking for the class and, if that fails, look everywhere else for it.
This workaround is more of a "bad practice" pattern than a solution, but
it does work. One potential problem is that it is unclear where the
class will actually come from should there be multiple bundles
contributing classes with that name. It also just plain breaks down key
benefits of using OSGi in the first place.

It should also work to set the buddy policy to "dependent" which tells
the classloader to first work it's way up the chain, and--should it not
find the class--work it's way down the chain (more of a tree). This
still falls into the category of "bad practice" pattern rather than
solution. Besides, it wouldn't work in the real case that I'm facing
where the "derby database" bundle has no direct dependency on the bundle
that leverages EclipseLink (I can provide more info and a better example
if necessary).

This problem should disappear if I can, instead of passing in the name
of the driver, pass in the actual class of the driver. This would work
in my case where I'm passing the value in programmatically. The
declarative approach would still need to be able to handle the name.
However, in the declarative approach, I'm introducing a soft dependency
by hard-coding the name of the driver anyway, so requiring an explicit
dependency on the org.apache.derby bundle shouldn't be unreasonable.

Let me know if I'm mumbling. I'm sure that I can explain this better if
I need to.

Wayne

Attachment: demo.zip
Description: Zip archive


Back to the top