From 85c23c262e1c337731750d900ac3687a0f51e81c Mon Sep 17 00:00:00 2001 From: Les Vogel Date: Wed, 20 Apr 2016 18:47:29 -0700 Subject: [PATCH] Oauth2 updates, Guestbook (#172) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Oauth2 - Tim and Brett’s comments - Mostly nits - HelloServlet now uses User GuestBook - Initial checkin, updated README remove .gitignore * Check style changes * rename guestbook -> guestbook-objectify --- appengine/guestbook-objectify/README.md | 17 +++ appengine/guestbook-objectify/pom.xml | 96 ++++++++++++++++ .../java/com/example/guestbook/Greeting.java | 80 +++++++++++++ .../java/com/example/guestbook/Guestbook.java | 33 ++++++ .../java/com/example/guestbook/OfyHelper.java | 37 ++++++ .../guestbook/SignGuestbookServlet.java | 62 ++++++++++ .../src/main/webapp/WEB-INF/appengine-web.xml | 10 ++ .../main/webapp/WEB-INF/logging.properties | 13 +++ .../src/main/webapp/WEB-INF/web.xml | 35 ++++++ .../src/main/webapp/guestbook.jsp | 106 ++++++++++++++++++ .../src/main/webapp/stylesheets/main.css | 4 + appengine/helloworld/.gitignore | 7 -- appengine/oauth2/pom.xml | 16 ++- .../com/example/appengine/HelloServlet.java | 21 +++- .../com/example/appengine/Oauth2Filter.java | 22 ++-- appengine/oauth2/src/main/webapp/index.html | 19 +++- pom.xml | 3 +- 17 files changed, 554 insertions(+), 27 deletions(-) create mode 100644 appengine/guestbook-objectify/README.md create mode 100644 appengine/guestbook-objectify/pom.xml create mode 100644 appengine/guestbook-objectify/src/main/java/com/example/guestbook/Greeting.java create mode 100644 appengine/guestbook-objectify/src/main/java/com/example/guestbook/Guestbook.java create mode 100644 appengine/guestbook-objectify/src/main/java/com/example/guestbook/OfyHelper.java create mode 100644 appengine/guestbook-objectify/src/main/java/com/example/guestbook/SignGuestbookServlet.java create mode 100644 appengine/guestbook-objectify/src/main/webapp/WEB-INF/appengine-web.xml create mode 100644 appengine/guestbook-objectify/src/main/webapp/WEB-INF/logging.properties create mode 100644 appengine/guestbook-objectify/src/main/webapp/WEB-INF/web.xml create mode 100644 appengine/guestbook-objectify/src/main/webapp/guestbook.jsp create mode 100644 appengine/guestbook-objectify/src/main/webapp/stylesheets/main.css delete mode 100644 appengine/helloworld/.gitignore diff --git a/appengine/guestbook-objectify/README.md b/appengine/guestbook-objectify/README.md new file mode 100644 index 00000000000..2a7ee9cd289 --- /dev/null +++ b/appengine/guestbook-objectify/README.md @@ -0,0 +1,17 @@ +# appengine/guestbook-objectify + +An App Engine guestbook using Java, Maven, and Objectify. + +Data access using [Objectify](https://github.com/objectify/objectify) + +Please ask questions on [Stackoverflow](http://stackoverflow.com/questions/tagged/google-app-engine) + +## Running Locally + +How do I, as a developer, start working on the project? + +1. `mvn clean appengine:devserver` + +## Deploying + +1. `mvn clean appengine:update -Dappengine.appId=PROJECT -Dappengine.version=VERSION` diff --git a/appengine/guestbook-objectify/pom.xml b/appengine/guestbook-objectify/pom.xml new file mode 100644 index 00000000000..ee44bb44325 --- /dev/null +++ b/appengine/guestbook-objectify/pom.xml @@ -0,0 +1,96 @@ + + + + 4.0.0 + war + 1.0-SNAPSHOT + + com.example.appengine + guestbook + + 5.1.5 + 18.0 + + + com.google.cloud + doc-samples + 1.0.0 + ../.. + + + + + 3.3.9 + + + + + + + com.google.appengine + appengine-api-1.0-sdk + ${appengine.sdk.version} + + + javax.servlet + servlet-api + 2.5 + provided + + + jstl + jstl + 1.2 + + + + + com.google.guava + guava + ${guava.version} + + + com.googlecode.objectify + objectify + ${objectify.version} + + + + + + com.google.appengine + appengine-testing + ${appengine.sdk.version} + test + + + com.google.appengine + appengine-api-stubs + ${appengine.sdk.version} + test + + + + + + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes + + + com.google.appengine + appengine-maven-plugin + ${appengine.sdk.version} + + false + + + + + + + + + diff --git a/appengine/guestbook-objectify/src/main/java/com/example/guestbook/Greeting.java b/appengine/guestbook-objectify/src/main/java/com/example/guestbook/Greeting.java new file mode 100644 index 00000000000..29c37d066ce --- /dev/null +++ b/appengine/guestbook-objectify/src/main/java/com/example/guestbook/Greeting.java @@ -0,0 +1,80 @@ +/** + * Copyright 2014-2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//[START all] +package com.example.guestbook; + +import com.googlecode.objectify.Key; +import com.googlecode.objectify.annotation.Entity; +import com.googlecode.objectify.annotation.Id; +import com.googlecode.objectify.annotation.Index; +import com.googlecode.objectify.annotation.Parent; + +import java.lang.String; +import java.util.Date; + +/** + * The @Entity tells Objectify about our entity. We also register it in {@link OfyHelper} + * Our primary key @Id is set automatically by the Google Datastore for us. + * + * We add a @Parent to tell the object about its ancestor. We are doing this to support many + * guestbooks. Objectify, unlike the AppEngine library requires that you specify the fields you + * want to index using @Index. Only indexing the fields you need can lead to substantial gains in + * performance -- though if not indexing your data from the start will require indexing it later. + * + * NOTE - all the properties are PUBLIC so that can keep the code simple. + **/ +@Entity +public class Greeting { + @Parent Key theBook; + @Id public Long id; + + public String authorEmail; + public String authorId; + public String content; + @Index public Date date; + + /** + * Simple constructor just sets the date. + **/ + public Greeting() { + date = new Date(); + } + + /** + * A convenience constructor. + **/ + public Greeting(String book, String content) { + this(); + if ( book != null ) { + theBook = Key.create(Guestbook.class, book); // Creating the Ancestor key + } else { + theBook = Key.create(Guestbook.class, "default"); + } + this.content = content; + } + + /** + * Takes all important fields. + **/ + public Greeting(String book, String content, String id, String email) { + this(book, content); + authorEmail = email; + authorId = id; + } + +} +//[END all] diff --git a/appengine/guestbook-objectify/src/main/java/com/example/guestbook/Guestbook.java b/appengine/guestbook-objectify/src/main/java/com/example/guestbook/Guestbook.java new file mode 100644 index 00000000000..73786e00249 --- /dev/null +++ b/appengine/guestbook-objectify/src/main/java/com/example/guestbook/Guestbook.java @@ -0,0 +1,33 @@ +/** + * Copyright 2014-2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//[START all] +package com.example.guestbook; + +import com.googlecode.objectify.annotation.Entity; +import com.googlecode.objectify.annotation.Id; + +/** + * The @Entity tells Objectify about our entity. We also register it in + * OfyHelper.java -- very important. + * + * This is never actually created, but gives a hint to Objectify about our Ancestor key. + */ +@Entity +public class Guestbook { + @Id public String book; +} +//[END all] diff --git a/appengine/guestbook-objectify/src/main/java/com/example/guestbook/OfyHelper.java b/appengine/guestbook-objectify/src/main/java/com/example/guestbook/OfyHelper.java new file mode 100644 index 00000000000..a5837295656 --- /dev/null +++ b/appengine/guestbook-objectify/src/main/java/com/example/guestbook/OfyHelper.java @@ -0,0 +1,37 @@ +/** + * Copyright 2014-2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +//[START all] +package com.example.guestbook; + +import com.googlecode.objectify.ObjectifyService; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +/** + * OfyHelper, a ServletContextListener, is setup in web.xml to run before a JSP is run. This is + * required to let JSP's access Ofy. + **/ +public class OfyHelper implements ServletContextListener { + public void contextInitialized(ServletContextEvent event) { + // This will be invoked as part of a warmup request, or the first user request if no warmup + // request. + ObjectifyService.register(Guestbook.class); + ObjectifyService.register(Greeting.class); + } + + public void contextDestroyed(ServletContextEvent event) { + // App Engine does not currently invoke this method. + } +} +//[END all] diff --git a/appengine/guestbook-objectify/src/main/java/com/example/guestbook/SignGuestbookServlet.java b/appengine/guestbook-objectify/src/main/java/com/example/guestbook/SignGuestbookServlet.java new file mode 100644 index 00000000000..2b7d368642a --- /dev/null +++ b/appengine/guestbook-objectify/src/main/java/com/example/guestbook/SignGuestbookServlet.java @@ -0,0 +1,62 @@ +/** + * Copyright 2014-2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//[START all] +package com.example.guestbook; + +import com.google.appengine.api.users.User; +import com.google.appengine.api.users.UserService; +import com.google.appengine.api.users.UserServiceFactory; + +import com.googlecode.objectify.ObjectifyService; + +import java.io.IOException; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Form Handling Servlet - most of the action for this sample is in webapp/guestbook.jsp, + * which displays the {@link Greeting}'s. + */ +public class SignGuestbookServlet extends HttpServlet { + + // Process the http POST of the form + @Override + public void doPost(HttpServletRequest req, HttpServletResponse resp) + throws IOException { + Greeting greeting; + + UserService userService = UserServiceFactory.getUserService(); + User user = userService.getCurrentUser(); // Find out who the user is. + + String guestbookName = req.getParameter("guestbookName"); + String content = req.getParameter("content"); + if (user != null) { + greeting = new Greeting(guestbookName, content, user.getUserId(), user.getEmail()); + } else { + greeting = new Greeting(guestbookName, content); + } + + // Use Objectify to save the greeting and now() is used to make the call synchronously as we + // will immediately get a new page using redirect and we want the data to be present. + ObjectifyService.ofy().save().entity(greeting).now(); + + resp.sendRedirect("/guestbook.jsp?guestbookName=" + guestbookName); + } +} +//[END all] diff --git a/appengine/guestbook-objectify/src/main/webapp/WEB-INF/appengine-web.xml b/appengine/guestbook-objectify/src/main/webapp/WEB-INF/appengine-web.xml new file mode 100644 index 00000000000..8bf645d1013 --- /dev/null +++ b/appengine/guestbook-objectify/src/main/webapp/WEB-INF/appengine-web.xml @@ -0,0 +1,10 @@ + + + your-app-id + ${appengine.app.version} + true + + + + + diff --git a/appengine/guestbook-objectify/src/main/webapp/WEB-INF/logging.properties b/appengine/guestbook-objectify/src/main/webapp/WEB-INF/logging.properties new file mode 100644 index 00000000000..a17206681f0 --- /dev/null +++ b/appengine/guestbook-objectify/src/main/webapp/WEB-INF/logging.properties @@ -0,0 +1,13 @@ +# A default java.util.logging configuration. +# (All App Engine logging is through java.util.logging by default). +# +# To use this configuration, copy it into your application's WEB-INF +# folder and add the following to your appengine-web.xml: +# +# +# +# +# + +# Set the default logging level for all loggers to WARNING +.level = WARNING diff --git a/appengine/guestbook-objectify/src/main/webapp/WEB-INF/web.xml b/appengine/guestbook-objectify/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..d5a23626f0c --- /dev/null +++ b/appengine/guestbook-objectify/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,35 @@ + + + + + + sign + com.example.guestbook.SignGuestbookServlet + + + + sign + /sign + + + + guestbook.jsp + + + + + + ObjectifyFilter + com.googlecode.objectify.ObjectifyFilter + + + ObjectifyFilter + /* + + + com.example.guestbook.OfyHelper + + + diff --git a/appengine/guestbook-objectify/src/main/webapp/guestbook.jsp b/appengine/guestbook-objectify/src/main/webapp/guestbook.jsp new file mode 100644 index 00000000000..481274ceb84 --- /dev/null +++ b/appengine/guestbook-objectify/src/main/webapp/guestbook.jsp @@ -0,0 +1,106 @@ +<%-- //[START all]--%> +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ page import="com.google.appengine.api.users.User" %> +<%@ page import="com.google.appengine.api.users.UserService" %> +<%@ page import="com.google.appengine.api.users.UserServiceFactory" %> + +<%-- //[START imports]--%> +<%@ page import="com.example.guestbook.Greeting" %> +<%@ page import="com.example.guestbook.Guestbook" %> +<%@ page import="com.googlecode.objectify.Key" %> +<%@ page import="com.googlecode.objectify.ObjectifyService" %> +<%-- //[END imports]--%> + +<%@ page import="java.util.List" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> + + + + + + + + +<% + String guestbookName = request.getParameter("guestbookName"); + if (guestbookName == null) { + guestbookName = "default"; + } + pageContext.setAttribute("guestbookName", guestbookName); + UserService userService = UserServiceFactory.getUserService(); + User user = userService.getCurrentUser(); + if (user != null) { + pageContext.setAttribute("user", user); +%> + +

Hello, ${fn:escapeXml(user.nickname)}! (You can + sign out.)

+<% + } else { +%> +

Hello! + Sign in + to include your name with greetings you post.

+<% + } +%> + +<%-- //[START datastore]--%> +<% + // Create the correct Ancestor key + Key theBook = Key.create(Guestbook.class, guestbookName); + + // Run an ancestor query to ensure we see the most up-to-date + // view of the Greetings belonging to the selected Guestbook. + List greetings = ObjectifyService.ofy() + .load() + .type(Greeting.class) // We want only Greetings + .ancestor(theBook) // Anyone in this book + .order("-date") // Most recent first - date is indexed. + .limit(5) // Only show 5 of them. + .list(); + + if (greetings.isEmpty()) { +%> +

Guestbook '${fn:escapeXml(guestbookName)}' has no messages.

+<% + } else { +%> +

Messages in Guestbook '${fn:escapeXml(guestbookName)}'.

+<% + // Look at all of our greetings + for (Greeting greeting : greetings) { + pageContext.setAttribute("greeting_content", greeting.content); + String author; + if (greeting.authorEmail == null) { + author = "An anonymous person"; + } else { + author = greeting.authorEmail; + String author_id = greeting.authorId; + if (user != null && user.getUserId().equals(author_id)) { + author += " (You)"; + } + } + pageContext.setAttribute("greeting_user", author); +%> +

${fn:escapeXml(greeting_user)} wrote:

+
${fn:escapeXml(greeting_content)}
+<% + } + } +%> + +
+
+
+ +
+<%-- //[END datastore]--%> +
+
+
+
+ + + +<%-- //[END all]--%> diff --git a/appengine/guestbook-objectify/src/main/webapp/stylesheets/main.css b/appengine/guestbook-objectify/src/main/webapp/stylesheets/main.css new file mode 100644 index 00000000000..05d72d5536d --- /dev/null +++ b/appengine/guestbook-objectify/src/main/webapp/stylesheets/main.css @@ -0,0 +1,4 @@ +body { + font-family: Verdana, Helvetica, sans-serif; + background-color: #FFFFCC; +} diff --git a/appengine/helloworld/.gitignore b/appengine/helloworld/.gitignore deleted file mode 100644 index 471339729ae..00000000000 --- a/appengine/helloworld/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Eclipse files -.project -.classpath -.settings - -# Target folders -target/ diff --git a/appengine/oauth2/pom.xml b/appengine/oauth2/pom.xml index b29ab18dad4..b520b4a4f46 100644 --- a/appengine/oauth2/pom.xml +++ b/appengine/oauth2/pom.xml @@ -1,5 +1,9 @@ + + appengine-oauth2 sample