Um in der Google Cloud Daten zu speichern bietet Google drei API an: JPA, JDO und eine Low-Level-API. Infos dazu gibt liefert http://code.google.com/intl/de/appengine/docs/java/datastore/. JPA und JDO basieren im Kern auf der Low-Level API, die auf die http://en.wikipedia.org/wiki/BigTable zurückgreift.
Für JPA und JDO gibt es selbst von Google viele Beispiele, aber die Low-Level-API ist nicht so gut dokumentiert und selbst das Beispielprogramm in der JavaDoc enthält Fehler. Zeit daher, ein sehr einfaches Beispiel mit einer 1:n Relationen anzugehen.
Im Mittelpunkt der API steht der DatastoreService, der ein bisschen an den EntityManager von JPA erinnert. Er bietet Methoden für die CRUD-Operationen. Mein Beispiel geht schon ein bisschen “pseudo-ORM” an die Aufgabe ran, einer Person Nachrichten zuordnen zu können:
Die Personen-Klasse:
package com.tutego.server.entity;
import java.util.ArrayList;
import java.util.List;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Query;
public class Person
{
private final static String ENTITY_NAME = „Person“;
Entity personEntity;
public enum Gender
{
MALE, FEMALE
}
public Person()
{
personEntity = new Entity( ENTITY_NAME );
}
private Person( Key key )
{
try
{
personEntity = DatastoreServiceFactory.getDatastoreService().get( key );
}
catch ( EntityNotFoundException e )
{
}
}
private Person( Entity entity )
{
personEntity = entity;
}
public static Person get( Key key )
{
return new Person( key );
}
public void setUsername( String username )
{
personEntity.setProperty( „username“, username );
}
public String getUsername()
{
return personEntity.getProperty( „username“ ).toString();
}
public void setGender( Gender gender )
{
personEntity.setProperty( „gender“, gender.toString() );
}
public Gender getGender()
{
return Gender.valueOf( personEntity.getProperty( „gender“ ).toString() );
}
public Key put()
{
return DatastoreServiceFactory.getDatastoreService().put( personEntity );
}
public static void deleteAll()
{
Query deleteAllQuery = new Query( ENTITY_NAME );
for ( Entity entity : DatastoreServiceFactory.getDatastoreService().prepare( deleteAllQuery ).asIterable() )
DatastoreServiceFactory.getDatastoreService().delete( entity.getKey() );
}
private static List<Person> executeQuery( Query query )
{
List<Person> result = new ArrayList<Person>();
for ( Entity entity : DatastoreServiceFactory.getDatastoreService().prepare( query ).asIterable() )
result.add( new Person( entity ) );
return result;
}
public static List<Person> findAllPersons()
{
Query query = new Query( ENTITY_NAME );
return executeQuery( query );
}
public static List<Person> findPersonByGender( Gender gender )
{
Query query = new Query( ENTITY_NAME );
query.addFilter( „gender“, Query.FilterOperator.EQUAL, gender.toString() );
return executeQuery( query );
}
@Override
public String toString()
{
return String.format( „Person[%s,%s]“, getUsername(), getGender() );
}
}
Die Nachrichten-Klasse:
package com.tutego.server.entity;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Query;
public class Message
{
private final static String ENTITY_NAME = „Message“;
private Entity messageEntity;
public Message()
{
messageEntity = new Entity( ENTITY_NAME );
}
private Message( Key key )
{
try
{
messageEntity = DatastoreServiceFactory.getDatastoreService().get( key );
}
catch ( EntityNotFoundException e )
{
}
}
private Message( Entity entity )
{
messageEntity = entity;
}
public static Message get( Key key )
{
return new Message( key );
}
public void setText( String text )
{
messageEntity.setProperty( „text“, text );
}
public String getText()
{
return messageEntity.getProperty( „text“ ).toString();
}
public void setCreationTime( Date d )
{
messageEntity.setProperty( „creationtime“, „“ + d.getTime() );
}
public Date getCreationTime()
{
return new Date( Long.parseLong( messageEntity.getProperty( „creationtime“ ).toString() ) );
}
public void setReceiver( Person p )
{
messageEntity.setProperty( „person_fk“, p.personEntity.getKey() );
}
public Key put()
{
return DatastoreServiceFactory.getDatastoreService().put( messageEntity );
}
private static List<Message> executeQuery( Query query )
{
List<Message> result = new ArrayList<Message>();
for ( Entity entity : DatastoreServiceFactory.getDatastoreService().prepare( query ).asIterable() )
result.add( new Message( entity ) );
return result;
}
public static List<Message> findMessagesForPerson( Person p )
{
Query query = new Query( ENTITY_NAME );
query.addFilter( „person_fk“, Query.FilterOperator.EQUAL, p.personEntity.getKey() );
return executeQuery( query );
}
@Override
public String toString()
{
return String.format( „Message[%s,%s]“, getCreationTime(), getText() );
}
}
Getestet werden soll das ganze in einer einfachen Server-Funktion:
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter( sw );
// Insert new entity
Person p1 = new Person();
p1.setUsername( „chris“ );
p1.setGender( Person.Gender.MALE );
Key key1 = p1.put();
out.println( „* Key für erste Person “ + p1 );
out.println( KeyFactory.keyToString( key1 ) );
Person p2 = new Person();
p2.setUsername( „pallas“ );
p2.setGender( Person.Gender.FEMALE );
p2.put();
Person p3 = new Person();
p3.setUsername( „tina“ );
p3.setGender( Person.Gender.FEMALE );
p3.put();
// Search for entity with a given key
Person p = Person.get( key1 );
out.println( „* Suche mit Schlüssel “ + key1 );
out.println( p.getUsername() );
// Query
List<Person> findAll = Person.findAllPersons();
out.println( „* Alle Personen“ );
out.println( findAll.toString() );
// Query
List<Person> females = Person.findPersonByGender( Gender.FEMALE );
out.println( „* Alle Frauen:“ );
out.println( females.toString() );
Message msg1 = new Message();
msg1.setText( „Hallo Maus“ );
msg1.setCreationTime( new Date(1) );
msg1.setReceiver( p );
msg1.put();
Message msg2 = new Message();
msg2.setText( „Hallo Ratte“ );
msg2.setCreationTime( new Date(2) );
msg2.setReceiver( p );
msg2.put();
out.println( „* Alle Nachrichten für “ + p );
out.println( Message.findMessagesForPerson( p ) );
out.println( „\n“ );
// Clean up
Person.deleteAll();
out.flush();
return sw.toString().replace( „\n“, „<br/>“ );
Als Ergebnis kommt HTML zurück, was der Client zum Testen anschauen kann.