{"id":376,"date":"2009-07-28T14:33:00","date_gmt":"2009-07-28T14:33:00","guid":{"rendered":"http:\/\/www.tutego.de\/blog\/javainsel\/?p=376"},"modified":"2009-07-28T14:33:00","modified_gmt":"2009-07-28T14:33:00","slug":"java-datastore-api-fur-die-google-app-engine","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2009\/07\/java-datastore-api-fur-die-google-app-engine\/","title":{"rendered":"Java Datastore API f\u00fcr die Google App Engine"},"content":{"rendered":"<p>Um in der Google Cloud Daten zu speichern bietet Google drei API an: JPA, JDO und eine Low-Level-API. Infos dazu gibt liefert <a title=\"http:\/\/code.google.com\/intl\/de\/appengine\/docs\/java\/datastore\/\" href=\"http:\/\/code.google.com\/intl\/de\/appengine\/docs\/java\/datastore\/. JPA\">http:\/\/code.google.com\/intl\/de\/appengine\/docs\/java\/datastore\/. JPA<\/a> und JDO basieren im Kern auf der Low-Level API, die auf die <a title=\"http:\/\/en.wikipedia.org\/wiki\/BigTable\" href=\"http:\/\/en.wikipedia.org\/wiki\/BigTable\">http:\/\/en.wikipedia.org\/wiki\/BigTable<\/a> zur\u00fcckgreift.<\/p>\n<p>F\u00fcr 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\u00e4lt Fehler. Zeit daher, ein sehr einfaches Beispiel mit einer 1:n Relationen anzugehen.<\/p>\n<p>Im Mittelpunkt der API steht der DatastoreService, der ein bisschen an den EntityManager von JPA erinnert. Er bietet Methoden f\u00fcr die CRUD-Operationen. Mein Beispiel geht schon ein bisschen \u201cpseudo-ORM\u201d an die Aufgabe ran, einer Person Nachrichten zuordnen zu k\u00f6nnen:<\/p>\n<p>Die Personen-Klasse: <\/p>\n<p>package com.tutego.server.entity;  <\/p>\n<p>import java.util.ArrayList;<br \/>import java.util.List;  <\/p>\n<p>import com.google.appengine.api.datastore.DatastoreServiceFactory;<br \/>import com.google.appengine.api.datastore.Entity;<br \/>import com.google.appengine.api.datastore.EntityNotFoundException;<br \/>import com.google.appengine.api.datastore.Key;<br \/>import com.google.appengine.api.datastore.Query;  <\/p>\n<p>public class Person<br \/>{<br \/>&nbsp; private final static String ENTITY_NAME = &#8222;Person&#8220;;<br \/>&nbsp; Entity personEntity;  <\/p>\n<p>&nbsp; public enum Gender<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; MALE, FEMALE<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public Person()<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; personEntity = new Entity( ENTITY_NAME );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; private Person( Key key )<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; try<br \/>&nbsp;&nbsp;&nbsp; {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; personEntity = DatastoreServiceFactory.getDatastoreService().get( key );<br \/>&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp; catch ( EntityNotFoundException e )<br \/>&nbsp;&nbsp;&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; }<br \/>&nbsp; }  <\/p>\n<p>&nbsp; private Person( Entity entity )<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; personEntity = entity;<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public static Person get( Key key )<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; return new Person( key );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public void setUsername( String username )<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; personEntity.setProperty( &#8222;username&#8220;, username );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public String getUsername()<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; return personEntity.getProperty( &#8222;username&#8220; ).toString();<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public void setGender( Gender gender )<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; personEntity.setProperty( &#8222;gender&#8220;, gender.toString() );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public Gender getGender()<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; return Gender.valueOf( personEntity.getProperty( &#8222;gender&#8220; ).toString() );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public Key put()<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; return DatastoreServiceFactory.getDatastoreService().put( personEntity );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public static void deleteAll()<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; Query deleteAllQuery = new Query( ENTITY_NAME );  <\/p>\n<p>&nbsp;&nbsp;&nbsp; for ( Entity entity : DatastoreServiceFactory.getDatastoreService().prepare( deleteAllQuery ).asIterable() )<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DatastoreServiceFactory.getDatastoreService().delete( entity.getKey() );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; private static List&lt;Person&gt; executeQuery( Query query )<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; List&lt;Person&gt; result = new ArrayList&lt;Person&gt;();<br \/>&nbsp;&nbsp;&nbsp; for ( Entity entity : DatastoreServiceFactory.getDatastoreService().prepare( query ).asIterable() )<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result.add( new Person( entity ) );<br \/>&nbsp;&nbsp;&nbsp; return result;&nbsp; <br \/>&nbsp; }  <\/p>\n<p>&nbsp; public static List&lt;Person&gt; findAllPersons()<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; Query query = new Query( ENTITY_NAME );  <\/p>\n<p>&nbsp;&nbsp;&nbsp; return executeQuery( query );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public static List&lt;Person&gt; findPersonByGender( Gender gender )<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; Query query = new Query( ENTITY_NAME );<br \/>&nbsp;&nbsp;&nbsp; query.addFilter( &#8222;gender&#8220;, Query.FilterOperator.EQUAL, gender.toString() );  <\/p>\n<p>&nbsp;&nbsp;&nbsp; return executeQuery( query );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; @Override<br \/>&nbsp; public String toString()<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; return String.format( &#8222;Person[%s,%s]&#8220;, getUsername(), getGender() );<br \/>&nbsp; }<br \/>} <\/p>\n<p>Die Nachrichten-Klasse:<\/p>\n<p>package com.tutego.server.entity;  <\/p>\n<p>import java.util.ArrayList;<br \/>import java.util.Date;<br \/>import java.util.List;  <\/p>\n<p>import com.google.appengine.api.datastore.DatastoreServiceFactory;<br \/>import com.google.appengine.api.datastore.Entity;<br \/>import com.google.appengine.api.datastore.EntityNotFoundException;<br \/>import com.google.appengine.api.datastore.Key;<br \/>import com.google.appengine.api.datastore.Query;  <\/p>\n<p>public class Message<br \/>{<br \/>&nbsp; private final static String ENTITY_NAME = &#8222;Message&#8220;;  <\/p>\n<p>&nbsp; private Entity messageEntity;  <\/p>\n<p>&nbsp; public Message()<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; messageEntity = new Entity( ENTITY_NAME );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; private Message( Key key )<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; try<br \/>&nbsp;&nbsp;&nbsp; {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; messageEntity = DatastoreServiceFactory.getDatastoreService().get( key );<br \/>&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp; catch ( EntityNotFoundException e )<br \/>&nbsp;&nbsp;&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; }<br \/>&nbsp; }  <\/p>\n<p>&nbsp; private Message( Entity entity )<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; messageEntity = entity;<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public static Message get( Key key )<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; return new Message( key );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public void setText( String text )<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; messageEntity.setProperty( &#8222;text&#8220;, text );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public String getText()<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; return messageEntity.getProperty( &#8222;text&#8220; ).toString();<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public void setCreationTime( Date d )<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; messageEntity.setProperty( &#8222;creationtime&#8220;, &#8222;&#8220; + d.getTime() );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public Date getCreationTime()<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; return new Date( Long.parseLong( messageEntity.getProperty( &#8222;creationtime&#8220; ).toString() ) );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public void setReceiver( Person p )<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; messageEntity.setProperty( &#8222;person_fk&#8220;, p.personEntity.getKey() );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; public Key put()<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; return DatastoreServiceFactory.getDatastoreService().put( messageEntity );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; private static List&lt;Message&gt; executeQuery( Query query )<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; List&lt;Message&gt; result = new ArrayList&lt;Message&gt;();  <\/p>\n<p>&nbsp;&nbsp;&nbsp; for ( Entity entity : DatastoreServiceFactory.getDatastoreService().prepare( query ).asIterable() )<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result.add( new Message( entity ) );<br \/>&nbsp;&nbsp;&nbsp; return result;&nbsp; <br \/>&nbsp; }  <\/p>\n<p>&nbsp; public static List&lt;Message&gt; findMessagesForPerson( Person p )<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; Query query = new Query( ENTITY_NAME );<br \/>&nbsp;&nbsp;&nbsp; query.addFilter( &#8222;person_fk&#8220;, Query.FilterOperator.EQUAL, p.personEntity.getKey() );  <\/p>\n<p>&nbsp;&nbsp;&nbsp; return executeQuery( query );<br \/>&nbsp; }  <\/p>\n<p>&nbsp; @Override<br \/>&nbsp; public String toString()<br \/>&nbsp; {<br \/>&nbsp;&nbsp;&nbsp; return String.format( &#8222;Message[%s,%s]&#8220;, getCreationTime(), getText() );<br \/>&nbsp; }<br \/>} <\/p>\n<p>Getestet werden soll das ganze in einer einfachen Server-Funktion: <\/p>\n<p>StringWriter sw = new StringWriter();<br \/>PrintWriter out = new PrintWriter( sw );  <\/p>\n<p>\/\/ Insert new entity  <\/p>\n<p>Person p1 = new Person();<br \/>p1.setUsername( &#8222;chris&#8220; );<br \/>p1.setGender( Person.Gender.MALE );<br \/>Key key1 = p1.put();  <\/p>\n<p>out.println( &#8222;* Key f\u00fcr erste Person &#8220; + p1 );<br \/>out.println( KeyFactory.keyToString( key1 ) );  <\/p>\n<p>Person p2 = new Person();<br \/>p2.setUsername( &#8222;pallas&#8220; );<br \/>p2.setGender( Person.Gender.FEMALE );<br \/>p2.put();  <\/p>\n<p>Person p3 = new Person();<br \/>p3.setUsername( &#8222;tina&#8220; );<br \/>p3.setGender( Person.Gender.FEMALE );<br \/>p3.put();  <\/p>\n<p>\/\/ Search for entity with a given key  <\/p>\n<p>Person p = Person.get( key1 );<br \/>out.println( &#8222;* Suche mit Schl\u00fcssel &#8220; + key1 );<br \/>out.println( p.getUsername() );  <\/p>\n<p>\/\/ Query  <\/p>\n<p>List&lt;Person&gt; findAll = Person.findAllPersons();<br \/>out.println( &#8222;* Alle Personen&#8220; );<br \/>out.println( findAll.toString() );  <\/p>\n<p>\/\/ Query  <\/p>\n<p>List&lt;Person&gt; females = Person.findPersonByGender( Gender.FEMALE );<br \/>out.println( &#8222;* Alle Frauen:&#8220; );<br \/>out.println( females.toString() );  <\/p>\n<p>Message msg1 = new Message();<br \/>msg1.setText( &#8222;Hallo Maus&#8220; );<br \/>msg1.setCreationTime( new Date(1) );<br \/>msg1.setReceiver( p );<br \/>msg1.put();  <\/p>\n<p>Message msg2 = new Message();<br \/>msg2.setText( &#8222;Hallo Ratte&#8220; );<br \/>msg2.setCreationTime( new Date(2) );<br \/>msg2.setReceiver( p );<br \/>msg2.put();  <\/p>\n<p>out.println( &#8222;* Alle Nachrichten f\u00fcr &#8220; + p );<br \/>out.println( Message.findMessagesForPerson( p ) );<br \/>out.println( &#8222;\\n&#8220; );  <\/p>\n<p>\/\/ Clean up  <\/p>\n<p>Person.deleteAll();  <\/p>\n<p>out.flush();  <\/p>\n<p>return sw.toString().replace( &#8222;\\n&#8220;, &#8222;&lt;br\/&gt;&#8220; ); <\/p>\n<p>Als Ergebnis kommt HTML zur\u00fcck, was der Client zum Testen anschauen kann.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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\u00fcckgreift. F\u00fcr JPA und JDO gibt es selbst von Google viele Beispiele, aber die Low-Level-API ist nicht so [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","_links_to":"","_links_to_target":""},"categories":[16],"tags":[],"class_list":["post-376","post","type-post","status-publish","format-standard","hentry","category-gwt"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/376","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/comments?post=376"}],"version-history":[{"count":0,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/376\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=376"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=376"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=376"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}