2

I'm looking for the cleanest way to inject (or otherwise best initialize) JDO PersistenceManager and/or PersistenceManagerFactory to RESTful web application resources based on JAX-RS / Jersey 2 and EJB 3.1 Lite, preferably without adding too many extra dependencies. The project uses DataNucleus and is built with Maven 3.

Here are some pointers that I found. Maybe you've already tried some of these and found which approach works best:

The current solution is based on JPA and the injection works as usual. The following code has been simplified and unfortunately I can't post the original.

In main/java/project/ws/rs/TestResource.java:

@Path("/test")
@Stateless
public class TestResource {

    @PersistenceContext(unitName = "project-webapi")
    private EntityManager em;

    @GET
    @Path("/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response test(@PathParam("id") UUID id) {
        return Response.status(
                Response.Status.OK).entity(em.find(type, id)).build();
    }
}

As you can see above, the persistent JAX-RS resources are annotated as @Stateless EJB's.

All the Java EE and Jersey dependencies are provided by GlassFish 4.0 that is my target platform. DataNucleus libraries are included in the runtime deployable war artifact in WEB-INF/lib.

The project has a standard persistence unit described by the main/resources/META-INF/persistence.xml file.

<persistence>
  <persistence-unit name="project-webapi"/>
</persistence>

(XML namespaces and schema references have been omitted for simplicity.)

The deployment descriptor is in main/webapp/WEB-INF/web.xml:

<web-app version="3.0" metadata-complete="false" />

The goal

I would like to switch from JPA to JDO without losing clean dependency injection like above. An ideal solution would of course be similar to just replacing the EntityManager with PersistenceManager above, but how to achieve that or perhaps there are better ways? It doesn't have to be injection, if some other way is more efficient for this purpose.

The reason I'm switching is to be able to use also non-SQL persistence with the help of DataNucleus and to have a full ORM implementation available to my Java EE web applications.

I'm sure there are many others who would be interested in this. Any ideas?

Edit: Finding the most efficient way for web apps like above to obtain a reference to a PersistenceManager is the point of this question.

With JPA it's done by injection. Obviously we know that the Java EE spec and application servers do not support this directly with JDO. Otherwise we wouldn't be asking this. So we are after the cleanest and the "most deployable" way to do it for web apps.

Community
  • 1
  • 1
SAM
  • 1,431
  • 1
  • 10
  • 6
  • I haven't used this before but have you thought about using this ? http://www.datanucleus.org/products/accessplatform_3_3/rest/api.html – Muhammad Gelbana Aug 19 '13 at 15:35
  • @MuhammadGelbana, thanks. I did scan through it, but this is also a general question. In some cases the access platform would work for me, but I have other cases where I need more manual control. Perhaps the answer I'm looking for is somewhere in the sources. I will continue researching as soon as I can spend some more time on this, but for now I have to continue with JPA. Meanwhile, if someone already has the answer that would save time for all of us. – SAM Aug 19 '13 at 16:42
  • 1
    There is no PersistenceContext/PersistenceUnit injection in JDO since it would rely on the JavaEE server implementing that (this is not part of DataNucleus JPA ... it's in Glassfish/JBoss etc). JDO doesn't specify what the container does since the politicians decreed that it wasn't allowed to (other than using JCA to allow use in a container). The "container" has to do injection ... so looking at Spring or Guice are your best bets – DataNucleus Aug 19 '13 at 17:16
  • @DataNucleus Thank you very much for your time and expert opinion. – SAM Aug 19 '13 at 23:32

1 Answers1

0

I use CDI interceptors to create and tear down JDO PMs in our web apps.

You can define an interceptor method relying on ThreadLocal in a helper class. I'm simplifying my code here (read: untested :) ) as you may have to deal with multiple data sources, re-entrances, etc., but as illustration:

public class MyJDO_Helper {

    private static ThreadLocal<PersistenceManager> localPM = new ThreadLocal<>();

    @AroundInvoke
    public Object allocatePersistenceManager(InvocationContext ctx) throws Exception {
        PersistenceManager pm = localPM.get();
        if (pm == null) {
            pm = getNewPersistenceManager();
            localPM.set(pm);
        }
        try {
            return ctx.proceed();
        }
        catch(Error err) { // to log them before Jersey blows casting them to Ex
            log.log(Level.SEVERE, "Caught " + err, err);
            throw err;
        }
        finally {
            try {
                if (pm.currentTransaction().isActive()) {
                    pm.currentTransaction().rollback();
                }
                pm.close();   
            }
            catch(Exception ex) {
                log.log(Level.SEVERE, "Error closing JDO PM: " + ex, ex);
            }
        }
    }

    public static PersistenceManager getPersistenceManager() {
        return localPM.get();
    }

Then you can decalre this interceptor on Jersey resource methods needing JDO access:

@ManagedBean // for interceptors
@Path("/my")
public class MyResource {

    @GET
    @Interceptors({MyJDO_Helper.class})
    public String get() {
        PersistenceManager pm = MyJDO_Helper.getPersistenceManager();

At that point you can call MyJDO_Helper.getPersistenceManager() from anywhere in your code (even not Jersey classes) anytime and you'll always get the right PM without the need to pass it around. :)

TheArchitect
  • 2,161
  • 1
  • 12
  • 16
  • I need to take a closer look at CDI for this purpose when I have time to return to this. Thanks for the pointer, @TheArchitect. I'll confirm it once I've had the opportunity to test it in practice. – SAM Aug 23 '13 at 10:41