Tuesday, April 8, 2008

Passing DataSources to EclipseLink JPA

When you hear the same question twice it's time to blog the answer so the third time it comes up you can point to the blog. ;-) This time it's whether you can pass a DataSource to EclipseLink JPA and have it use that instead of what's configured in persistence.xml (or perhaps not configured in persistence.xml).

Yes, you can pass a DataSource. Here's a code sample that illustrates creating a Derby DataSource and passing it as a property to createEntityManagerFactory. Works like a charm.

--Shaun

private DataSource createDataSource() {
   ClientDataSource dataSource = new ClientDataSource();
   dataSource.setServerName("localhost");
   dataSource.setPortNumber(1527);
   dataSource.setDatabaseName("sample");
   dataSource.setUser("app");
   dataSource.setPassword("app");
   return dataSource;
}

private EntityManagerFactory getEntityManagerFactory() {
   if (emf == null) {
      Map properties = new HashMap();
      properties
         .put(PersistenceUnitProperties.NON_JTA_DATASOURCE,createDataSource());
      emf = Persistence.createEntityManagerFactory(PU_NAME, properties);
   }
   return emf;
}

6 comments:

sib said...

Very useful tip.

Could I ask, would you know if EclipseLink should respond in the same way as TopLink to using the property:

java -Djava.persistence.setup.config=myConfigClass
....

I understand that you can use this property with Toplink to specify the classname of a configuration class that enables 'out-of-container' testing as outlined in the Oracle tech-note:

"Out-of-Container EJB 3.0 Testing with Oracle Entity Test Harness"
http://www.oracle.com/technology/pub/articles/debu_testability_of_ejb.html


If this is no longer possible with EclipseLink, would you know if there is a recommended alternative method to specify the List of Entity classes from within the JUnit test instead of adding them to the META-INF/persistence.xml file.

Cheers


Steven

Shaun Smith said...

Hi Steven,

The article you referenced is really old--pre JPA 1.0. It should probably be taken down.

In terms of passing the list of entities to EclipseLink, it isn't straightforward. The standard approach is to either have them listed in the persistence.xml or to have EclipseLink scan the classpath to find them (as it does in-container).

This is a good candidate for an Enhancement Request against EclipseLink. Anyone can file one in the project Bugzilla. :-) What I think you'd like to be able to do is pass in a list of entities in the properties map used to create the EntityManagerFactory.

--Shaun

sib said...

Thanks Shaun,


Really appreciate your quick response.
That's a pity that we can't do this with Eclipselink.

Would I be correct in thinking that we might try using
the method:

public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map properties)

from the "org.eclipse.persistence.jpa.PersistenceProvider" class
and setting up the "PersistenceUnitInfo" arg ourselves
as an alternative route to achieving the same ends.


Kind Regards,


Steven

Shaun Smith said...

createContainerEntityManagerFactory is called when an EntityManagerFactory is being created inside an EE 5 container. You can certainly try to use it. You'll probably need to ensure you have byte code weaving disabled.

--Shaun

Unknown said...

Hi. When I try something similar to the original post, using an OracleDataSource, I get the following:

ul
java.lang.IllegalArgumentException: EntityManager properties conflict: eclipselink.jdbc.driver and/or eclipselink.jdbc.url require DefaultConnector, but javax.persistence.jtaDataSource and/or javax.persistence.nonjtaDataSource require JNDIConnector.
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.processConnectionPolicyProperties(EntityManagerImpl.java:1070)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.processProperties(EntityManagerImpl.java:961)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.(EntityManagerImpl.java:165)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImplInternal(EntityManagerFactoryImpl.java:126)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:121)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:108)

Any hints would be appreciated!

Thanks.

- DAP

Unknown said...

Ah, it seems to work if I put only the datasource into the prop map - I guess it was getting confused with the other parameters.