3838/**
3939 * An example of using Google Cloud Datastore.
4040 *
41- * <p>This example adds, display or clear comments for a given user.
41+ * <p>This example adds, displays or clears comments for a given user. This example also sets
42+ * contact information for a user.
4243 *
4344 * <p>Steps needed for running the example:<ol>
4445 * <li>login using gcloud SDK - {@code gcloud auth login}.</li>
4546 * <li>compile using maven - {@code mvn compile}</li>
46- * <li>run using maven - {@code mvn exec:java
47- * -Dexec.mainClass="com.google.cloud.examples.datastore.DatastoreExample"
48- * -Dexec.args="[projectId] [user] [delete|display|add comment]"}</li>
47+ * <li>run using maven -
48+ * <pre>{@code mvn exec:java -Dexec.mainClass="com.google.cloud.examples.datastore.DatastoreExample"
49+ * -Dexec.args="<project_id> <user>
50+ * delete |
51+ * display |
52+ * add <comment> |
53+ * set <email> <phone>}</pre>
54+ * </li>
4955 * </ol>
56+ *
57+ * <p>If no action is provided {@code display} is executed.
5058 */
5159public class DatastoreExample {
5260
@@ -56,15 +64,24 @@ public class DatastoreExample {
5664 private static final String DEFAULT_ACTION = "display" ;
5765 private static final Map <String , DatastoreAction > ACTIONS = new HashMap <>();
5866
59- private interface DatastoreAction {
60- void run (Transaction tx , Key userKey , String ... args );
67+ private abstract static class DatastoreAction <T > {
68+
69+ abstract void run (Transaction tx , Key userKey , T arg ) throws Exception ;
6170
62- String getRequiredParams ();
71+ abstract T parse (String ... args ) throws Exception ;
72+
73+ protected String params () {
74+ return "" ;
75+ }
6376 }
6477
65- private static class DeleteAction implements DatastoreAction {
78+ /**
79+ * This class demonstrates how to delete a user. This action also queries the keys of all comments
80+ * associated with the user and uses them to delete comments.
81+ */
82+ private static class DeleteAction extends DatastoreAction <Void > {
6683 @ Override
67- public void run (Transaction tx , Key userKey , String ... args ) {
84+ public void run (Transaction tx , Key userKey , Void arg ) {
6885 Entity user = tx .get (userKey );
6986 if (user == null ) {
7087 System .out .println ("Nothing to delete, user does not exist." );
@@ -86,19 +103,30 @@ public void run(Transaction tx, Key userKey, String... args) {
86103 }
87104
88105 @ Override
89- public String getRequiredParams () {
90- return "" ;
106+ Void parse ( String ... args ) throws Exception {
107+ return null ;
91108 }
92109 }
93110
94- private static class DisplayAction implements DatastoreAction {
111+ /**
112+ * This class demonstrates how to get a user. The action also queries all comments associated
113+ * with the user.
114+ */
115+ private static class DisplayAction extends DatastoreAction <Void > {
95116 @ Override
96- public void run (Transaction tx , Key userKey , String ... args ) {
117+ public void run (Transaction tx , Key userKey , Void arg ) {
97118 Entity user = tx .get (userKey );
98119 if (user == null ) {
99- System .out .println ( "No comments for '" + userKey .name () + "'." );
120+ System .out .printf ( "User '%s' does not exist.%n" , userKey .name ());
100121 return ;
101122 }
123+ if (user .contains ("contact" )) {
124+ FullEntity <IncompleteKey > contact = user .getEntity ("contact" );
125+ String email = contact .getString ("email" );
126+ String phone = contact .getString ("phone" );
127+ System .out .printf ("User '%s' email is '%s', phone is '%s'.%n" ,
128+ userKey .name (), email , phone );
129+ }
102130 System .out .printf ("User '%s' has %d comment[s].%n" , userKey .name (), user .getLong ("count" ));
103131 int limit = 200 ;
104132 Map <DateTime , String > sortedComments = new TreeMap <>();
@@ -131,25 +159,37 @@ public void run(Transaction tx, Key userKey, String... args) {
131159 }
132160
133161 @ Override
134- public String getRequiredParams () {
135- return "" ;
162+ Void parse ( String ... args ) throws Exception {
163+ return null ;
136164 }
137165 }
138166
139- private static class AddAction implements DatastoreAction {
167+ /**
168+ * This class adds a comment for a user. If the user does not exist its entity is created.
169+ */
170+ private static class AddCommentAction extends DatastoreAction <String > {
140171 @ Override
141- public void run (Transaction tx , Key userKey , String ... args ) {
172+ public void run (Transaction tx , Key userKey , String content ) {
142173 Entity user = tx .get (userKey );
143174 if (user == null ) {
144175 System .out .println ("Adding a new user." );
145- user = Entity .builder (userKey )
146- .set ("count" , 1L )
147- .build ();
176+ user = Entity .builder (userKey ).set ("count" , 1 ).build ();
148177 tx .add (user );
149178 } else {
150179 user = Entity .builder (user ).set ("count" , user .getLong ("count" ) + 1L ).build ();
151180 tx .update (user );
152181 }
182+ IncompleteKey commentKey = IncompleteKey .builder (userKey , COMMENT_KIND ).build ();
183+ FullEntity <IncompleteKey > comment = FullEntity .builder (commentKey )
184+ .set ("content" , content )
185+ .set ("timestamp" , DateTime .now ())
186+ .build ();
187+ tx .addWithDeferredIdAllocation (comment );
188+ System .out .printf ("Adding a comment to user '%s'.%n" , userKey .name ());
189+ }
190+
191+ @ Override
192+ String parse (String ... args ) throws Exception {
153193 String content = "No comment." ;
154194 if (args .length > 0 ) {
155195 StringBuilder stBuilder = new StringBuilder ();
@@ -159,28 +199,98 @@ public void run(Transaction tx, Key userKey, String... args) {
159199 stBuilder .setLength (stBuilder .length () - 1 );
160200 content = stBuilder .toString ();
161201 }
162- IncompleteKey commentKey = IncompleteKey .builder (userKey , COMMENT_KIND ).build ();
163- FullEntity <IncompleteKey > comment = FullEntity .builder (commentKey )
164- .set ("content" , content )
165- .set ("timestamp" , DateTime .now ())
202+ return content ;
203+ }
204+
205+ @ Override
206+ protected String params () {
207+ return "<comment>" ;
208+ }
209+ }
210+
211+ /**
212+ * This class sets contact information (email and phone) for a user. If the user does not exist
213+ * its entity is created. Contact information is saved as an entity embedded in the user entity.
214+ */
215+ private static class SetContactAction extends DatastoreAction <SetContactAction .Contact > {
216+
217+ static final class Contact {
218+
219+ private final String email ;
220+ private final String phone ;
221+
222+ Contact (String email , String phone ) {
223+ this .email = email ;
224+ this .phone = phone ;
225+ }
226+
227+ String email () {
228+ return email ;
229+ }
230+
231+ String phone () {
232+ return phone ;
233+ }
234+ }
235+
236+ @ Override
237+ public void run (Transaction tx , Key userKey , Contact contact ) {
238+ Entity user = tx .get (userKey );
239+ if (user == null ) {
240+ System .out .println ("Adding a new user." );
241+ user = Entity .builder (userKey ).set ("count" , 0L ).build ();
242+ tx .add (user );
243+ }
244+ FullEntity <IncompleteKey > contactEntity = FullEntity .builder ()
245+ .set ("email" , contact .email ())
246+ .set ("phone" , contact .phone ())
166247 .build ();
167- tx .addWithDeferredIdAllocation (comment );
168- System .out .println ("Adding a comment to user '" + userKey .name () + "'." );
248+ tx .update (Entity .builder (user ).set ("contact" , contactEntity ).build ());
249+ System .out .printf ("Setting contact for user '%s'.%n" , userKey .name ());
250+ }
251+
252+ @ Override
253+ Contact parse (String ... args ) throws Exception {
254+ String message ;
255+ if (args .length == 2 ) {
256+ return new Contact (args [0 ], args [1 ]);
257+ } else if (args .length > 2 ) {
258+ message = "Too many arguments." ;
259+ } else {
260+ message = "Missing required email and phone." ;
261+ }
262+ throw new IllegalArgumentException (message );
169263 }
170264
171265 @ Override
172- public String getRequiredParams () {
173- return "comment " ;
266+ protected String params () {
267+ return "<email> <phone> " ;
174268 }
175269 }
176270
177271 static {
178272 ACTIONS .put ("delete" , new DeleteAction ());
179- ACTIONS .put ("add" , new AddAction ());
273+ ACTIONS .put ("add" , new AddCommentAction ());
274+ ACTIONS .put ("set" , new SetContactAction ());
180275 ACTIONS .put ("display" , new DisplayAction ());
181276 }
182277
183- public static void main (String ... args ) {
278+ private static void printUsage () {
279+ StringBuilder actionAndParams = new StringBuilder ();
280+ for (Map .Entry <String , DatastoreAction > entry : ACTIONS .entrySet ()) {
281+ actionAndParams .append ("\n \t " ).append (entry .getKey ());
282+
283+ String param = entry .getValue ().params ();
284+ if (param != null && !param .isEmpty ()) {
285+ actionAndParams .append (' ' ).append (param );
286+ }
287+ }
288+ System .out .printf ("Usage: %s <project_id> <user> operation <args>*%s%n" ,
289+ DatastoreExample .class .getSimpleName (), actionAndParams );
290+ }
291+
292+ @ SuppressWarnings ("unchecked" )
293+ public static void main (String ... args ) throws Exception {
184294 String projectId = args .length > 0 ? args [0 ] : null ;
185295 // If you want to access a local Datastore running via the Google Cloud SDK, do
186296 // DatastoreOptions options = DatastoreOptions.builder()
@@ -197,24 +307,26 @@ public static void main(String... args) {
197307 String actionName = args .length > 2 ? args [2 ].toLowerCase () : DEFAULT_ACTION ;
198308 DatastoreAction action = ACTIONS .get (actionName );
199309 if (action == null ) {
200- StringBuilder actionAndParams = new StringBuilder ();
201- for (Map .Entry <String , DatastoreAction > entry : ACTIONS .entrySet ()) {
202- actionAndParams .append (entry .getKey ());
203- String param = entry .getValue ().getRequiredParams ();
204- if (param != null && !param .isEmpty ()) {
205- actionAndParams .append (' ' ).append (param );
206- }
207- actionAndParams .append ('|' );
208- }
209- actionAndParams .setLength (actionAndParams .length () - 1 );
210- System .out .printf ("Usage: %s [projectId] [user] [%s]%n" ,
211- DatastoreExample .class .getSimpleName (), actionAndParams );
310+ System .out .println ("Unrecognized action." );
311+ printUsage ();
212312 return ;
213313 }
214314 args = args .length > 3 ? Arrays .copyOfRange (args , 3 , args .length ) : new String []{};
215315 Transaction tx = datastore .newTransaction ();
316+ Object request ;
317+ try {
318+ request = action .parse (args );
319+ } catch (IllegalArgumentException ex ) {
320+ System .out .printf ("Invalid input for action '%s'. %s%n" , actionName , ex .getMessage ());
321+ System .out .printf ("Expected: %s%n" , action .params ());
322+ return ;
323+ } catch (Exception ex ) {
324+ System .out .println ("Failed to parse request." );
325+ ex .printStackTrace ();
326+ return ;
327+ }
216328 try {
217- action .run (tx , key , args );
329+ action .run (tx , key , request );
218330 tx .commit ();
219331 } finally {
220332 if (tx .active ()) {
0 commit comments