Advanced topics

Integrating with JPA

Updated: October 16, 2020

The following paragraphs explain the specific part of integrating a nuxeo service with JPA.

Let say we want to put in place a document rating service that persist information using JPA. For this, we need these three modules :

  • nuxeo-samples-persistence-api
  • nuxeo-samples-persistence-core
  • nuxeo-samples-persistence-facade

The API would be something like


interface DocumentRating {
DocumentRating createRating(DocumentModel doc, String name, short maxRating);
DocumentRating getRating(DocumentModel doc, String name);
DocumentRating saveRating(DocumentMOdel doc, String name, int rating);
}

with an entity bean


...
@Entity(name="DocRating"
class DocumentRating {

   @Id
   @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="DOCRATING_SEQ")
   @SequenceGenerator(name="DOCRATING_SEQ", sequenceName="DOCRATING_SEQ", allocationSize=100)
   @Column(name = "RATING_ID", nullable = false, columnDefinition = "integer")
   private long id;

   String docUUID;

   short rating;

   short maxRating;

   long created;

   long modified;
}
...

Nuxeo's data providers should support deployment inside or outside an EJB container. The following describe what should be achieved for each use case.

Outside an EJB container

In that case, the framework resolves the service as the document rating provider. A persistence provider is lazy obtained using nuxeo persistence core services and used for getting access to the entity manager.


class DocumentRatingProvider implements DocumentRating {

protected PersistenceProvider persistenceProvider;

public PersistenceProvider persistenceProvider() {
if (persistenceProvider == null) {
     persistenceProvider = Framework.getService(PersistenceProviderFactory.class).newProvider("doc-rating");
    }
return persistenceProvider;
}

...
public DocumentRating saveRating(DocumentModel doc, String name, short rating) {
persistenceProvider.run(true, new RunCallback<DocumentRating>() {
public DocumentRating runWith(EntityManager em) {
         return this.saveRating(em, doc, name, rating);
      }
});
}

public DocumentRating saveRating(EntityManager em, DocumentModel doc, String name, short rating) {
    ...
  }
...
}

A minimal configuration should named the persistence unit and specify the data source to be used.


...
  <extension target="org.nuxeo.ecm.core.persistence.PersistenceComponent"
        point="hibernate">
        <hibernateConfiguration name="doc-rating">
            <datasource>doc-rating</datasource>
            <properties>
               <property name="hibernate.hbm2ddl.auto">update</property>
            </properties>
        </hibernateConfiguration>
  </extension
...

Inside an EJB container

In that case, the framework is resolving the service using the document rating bean. The persistence unit is initialized by the container himself, and an entity manager is automatically injected into the bean. The entity manager is transmitted by the bean to the core provider using a call parameter (thread safe).


@Stateless
@Local(DocumentRatingLocal)
@Remote(DocumentRating)
class DocumentRatingBean implements DocumentRating {

@PersistenceContext(unitName = "doc-rating")
private EntityManager em;

...

public DocumentRating saveRating(DocumentModel doc, String name, short rating) {
    DocumentRatingProvider provider = Framework.getLocalService(DocumentRatingProvider)
    return provider.saveRating(em, doc, name, rating);
  }

...

The persistence unit should be registered in the JPA container by providing a META-INF/persistence.xml descriptor in the core module.


<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
    version="1.0">

    <persistence-unit name="doc-rating">
        <jta-data-source>java:/doc-rating</jta-data-source>
        <class>...DocumentRating</class>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="update" />
        </properties>
    </persistence-unit>
</persistence>