Mittwoch, 9. Januar 2013

JDO 3.0 in der Google App Engine

Es ist nicht gerade ganz neu, aber ich habe es nun einmal bis jetzt aufgeschoben, meine Google App Engine nutzenden Anwendungen auf JDO 3 zu heben, obwohl das ja nun angeblich möglich ist. 
Das wichtigste dabei wären die "unowned relationsships" (was ein Wort-Ungetüm), da sie der Grund sind, daß wir bisher keine referenzielle Integrität auf Datenebene haben und diese merkwürdigen Umwege über die IDs als Strings in in den Datenfeldern nutzen müssen. In Tangram gibt es da einen Haufen Methoden (getIds, getContent(), getContents()), die einem das Leben einfach machen, aber eigentlich sollte das alle ersatzlos gestrichen werden.
Google beschreibt die Umstellung als manuellen Weg, die Anwendung zu modifizieren.
An andere Stelle kursieren immer wieder Anleitetungen, wie man das mit dem Eclipse Plugin für die Google App Engine bewerkstelligen soll. Nur genau dieses Plugin nutze ich natürlich in einem Projekt nicht, das ich auch anderen Menschen zur Verfügung stellen will, da dort mein Anspruch ist, daß man einfach ein Build-Systam hat, das alles genauso zusammenbaut wie ich bei mir.
Mit einer IDE habe ich so etwas noch nie erreicht, also bleibe ich nach make, ant, maven nun bei gradle und will hier einmal für mich und andere Aufzählen, was man zu Umstellung machen muß:
Schritt eins ist, die Abhängigkeit der JDO API zu ändern. In Gradle-Notation wird
javax.jdo:jdo2-api:2.3-eb zu
javax.jdo:jdo2-api:3.0.1
(Die letzten Maven-Nutzer werde das auch lesen können)
Und dann brauch noch die jdoconfig.xml ein paar kleinere Anpassungen:
<property name="javax.jdo.PersistenceManagerFactoryClass"
          value="org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/>
wird zu
<property name="javax.jdo.PersistenceManagerFactoryClass"
          value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/>

Außerdem kommen noch zwei kleine Zeile dazu
<property name="datanucleus.appengine.query.inMemoryWhenUnsupported" value="true"/>
<property name="datanucleus.appengine.relationDefault" value="unowned"/>
Die obere Zeile ergibt sich aus den geänderten Paketen für die aktuelle datanucleus Version und die beiden anderen Zeilen versuchen, die performance zu erhöhen und die "unowned relationsships" als default zu setzen, wie es auch bei allen anderen Stores außer der Appengine der Falle ist.
Wenn man das getan hat, funktioniert bis auf die paar Semantik-Änderungen alles wie gehabt und man kann beginnen die Model-Klassen umzuschreiben.
Google beschreibt, daß auch noch die JPA-Anbindung in datanucleus hinzugefügt werden sollte, aber die nutzen ich nicht und so entsteht die Abhängigkeit nicht. Desweitere fehlt noch geronimo-jpa_2.0_spec-1.0, was aber für JDO wieder keine Rolle spielen sollte..
Aus 
package org.tangram.gae.solution;
 
import java.util.List;

import org.tangram.jdo.JdoContent

import javax.jdo.annotations.PersistenceCapable;

@PersistenceCapable
public class Container extends JdoContent {

    private List<String> contentIds;


    public List<Topic> getContents() {
        return getContents(Topic.class, contentIds);
    }


    public void setContents(List<Topic> contents) {
        contentIds = getIds(contents);
    }

} // Container
wird dann das deutlich lesbarere
package org.tangram.rdbms.solution;

import java.util.List;

import javax.jdo.annotations.PersistenceCapable;

@PersistenceCapable
public class Container extends Linkable {

    @Unowned
    private List<Topic> contents;


    public List<Topic> getContents() {
        return contents;
    }


    public void setContents(List<Topic> contents) {
        this.contents = contents;
    }

} // Container

wie wir es schon in der rdbms Variante nutzen. Endlich...
(Daß ich dabei Probleme in der rdbms-Variante entdecken mußte steht auf einem anderen Blatt und damit in einem späteres Posting ;-) )