Dynamische Serveranwendungen

Persistenz und JSON APIs

Gunnar Wagenknecht

Nachdem die Persistence Unit erstellt worden ist, geht es mit der Implementierung des Service weiter. Damit Objekte gelesen und geschrieben werden können, ist ein EntityManager-Objekt notwendig. Das kann aus einem EntityManagerFactory-Objekt erstellt werden. Die eigentliche JPA-Serviceimplementierung ist relativ trivial und bedient sich der JPA-Standard-APIs (Listing 2). Interessanter wird die Sache bei der Erstellung der OSGi-DS-Komponente. Der JPA-Provider stellt für jede gefundene Persistence Unit automatisch einen EntityManagerFactoryBuilder-Service zur Verfügung. Mit diesem lassen sich EntityManagerFactory-Objekte erzeugen. Diese Abstraktion erlaubt das Setzen weiterer Properties, falls beispielsweise die Persistence Unit keine Datenbankverbindungseinstellungen enthält. Man spricht bei einer Persistence Unit ohne Datenbankverbindungseinstellungen auch von einer unvollständigen. Bei einer vollständigen Persistence Unit sucht der JPA-Provider automatisch nach einem kompatiblen Data-Source-Provider und stellt zusätzlich ein fertiges EntityManagerFactory-Objekt als OSGi Service zur Verfügung.

Im Beispiel-Bundle wird eine unfertige Persistence Unit definiert, daher muss der EntityManagerFactoryBuilder genutzt werden. Allerdings hat man dadurch auch mehr Freiheit zur Laufzeit, um beispielsweise die Datenbankeinstellungen über OSGi Preference einzulesen. Den richtigen EntityManagerFactoryBuilder-Service erhält man durch die Angabe eines Servicefilters mit dem Namen der Persistence Unit in der DS-Komponentendefinition (Listing 3). Das fertige Projekt ist in Abbildung 1 zu sehen und kann auch online abgerufen werden [1].

Listing 2: JPA-GreetingService-Implementierung

// GreetingService (already defined in hello.service bundle)
public interface GreetingService {
  /** Returns a list of all available greetings. */
  Collection getGreetings() throws Exception;
  /** Adds a new greeting. */
  void sayHello(final String greeting) throws Exception;
}
// JPA Implementation of {@link GreetingService} 
public class JpaGreetingServiceImpl implements GreetingService {
  private final EntityManagerFactory emf;
  public JpaGreetingServiceImpl(EntityManagerFactory emf) {
    this. emf = emf;
  }
  public Collection getGreetings() throws Exception {
    final EntityManager em = emf.createEntityManager();
    final TypedQuery q = em.createQuery(
      "SELECT g FROM GreetingEntity g ORDER BY g.created desc", GreetingEntity.class);
    final List results = q.getResultList();
    final List greetings = new ArrayList(results.size());
    for (final GreetingEntity entity : results) {
      greetings.add(entity.getText());
    }
    em.close();
    return Collections.unmodifiableList(greetings);
  }
  public void sayHello(final String greeting) throws Exception {
    final EntityManager em = emf.createEntityManager();
    final GreetingEntity entity = new GreetingEntity();
    entity.setCreated(System.currentTimeMillis());
    entity.setText(greeting.getText());
    em.getTransaction().begin();
    em.persist(entity);
    em.getTransaction().commit();
    em.close();
  }
}
Listing 3: JPA-GreetingService-OSGi-DS-Komponente

OSGI-INF/jpa-greeting-service.xml:


JpaGreetingServiceComponent.java:
public class JpaGreetingServiceComponent implements GreetingService {
  private GreetingService service;
  public void activate(final ComponentContext context) {
    final EntityManagerFactoryBuilder emfBuilder = (EntityManagerFactoryBuilder) context.locateService("EntityManagerFactoryBuilder");;
    // disable Gemini JPA/EclipseLink data source handling for NoSQL
    final Map props = new HashMap(2);
    props.put("javax.persistence.nonJtaDataSource", "");
    props.put("gemini.jpa.providerConnectedDataSource", Boolean.TRUE);
    // configure MongoDB connection
    props.put("eclipselink.target-database", "org.eclipse.persistence.nosql.adapters.mongo.MongoPlatform");
    props.put("eclipselink.nosql.connection-spec", "org.eclipse.persistence.nosql.adapters.mongo.MongoConnectionSpec");
    props.put("eclipselink.nosql.property.mongo.host", "localhost");
    props.put("eclipselink.nosql.property.mongo.db", "jpamongodb");
    // create EntityManagerFactory and service
    emf = emfBuilder.createEntityManagerFactory(props);
    service = new JpaGreetingServiceImpl(emf);
  }
  public void deactivate(final ComponentContext context) {
    emf.close(); emf = null; // close EMF
    service = null; // dispose real service
  }
  public Collection getGreetings() throws Exception {
    return getService().getGreetings();
  }
  public GreetingService getService() {
    final GreetingService greetingService = service;
    if (greetingService == null)
      throw new IllegalStateException("inactive");
    return greetingService;
  }
  public void sayHello(final String greeting) throws Exception {
    getService().sayHello(greeting);
  }
}

META-INF/MANIFEST.MF:
Manifest-Version: 1.0
Bundle-SymbolicName: hello.jpa
...
Service-Component: OSGI-INF/jpa-greeting-service.xml
Bundle-ActivationPolicy: lazy

build.properties:
bin.includes = META-INF/,
               .,
               OSGI-INF/
...

Abb. 1: JPA-Beispielprojekt
Geschrieben von
Gunnar Wagenknecht
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.