Skip to content

Commit 48473a5

Browse files
authored
Merge branch 'master' into wsh/standard-guestbook-sans-objectify
2 parents dee5c71 + 237e3aa commit 48473a5

File tree

62 files changed

+2150
-96
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+2150
-96
lines changed

appengine/cloudsql/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
<dependency>
4545
<groupId>mysql</groupId>
4646
<artifactId>mysql-connector-java</artifactId>
47-
<version>6.0.4</version>
47+
<version>6.0.5</version>
4848
</dependency>
4949
<!-- Parent POM defines ${appengine.sdk.version} (updates frequently). -->
5050
<dependency>

appengine/endpoints-frameworks-v2/backend/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
<properties>
3232
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
3333

34-
<endpoints.framework.version>2.0.0-beta.7</endpoints.framework.version>
35-
<endpoints.management.version>1.0.0-beta.7</endpoints.management.version>
34+
<endpoints.framework.version>2.0.0-beta.8</endpoints.framework.version>
35+
<endpoints.management.version>1.0.0-beta.10</endpoints.management.version>
3636

3737
<endpoints.project.id>YOUR_PROJECT_ID</endpoints.project.id>
3838
</properties>

appengine/firebase-event-proxy/gae-firebase-event-proxy/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@
6262
<dependency>
6363
<groupId>com.fasterxml.jackson.core</groupId>
6464
<artifactId>jackson-core</artifactId>
65-
<version>2.8.3</version>
65+
<version>2.8.4</version>
6666
</dependency>
6767
<dependency>
6868
<groupId>com.fasterxml.jackson.core</groupId>
6969
<artifactId>jackson-databind</artifactId>
70-
<version>2.8.3</version>
70+
<version>2.8.4</version>
7171
</dependency>
7272

7373
<!-- Test Dependencies -->

appengine/firebase-tictactoe/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<packaging>war</packaging>
1919
<version>1.0-SNAPSHOT</version>
2020
<groupId>com.example.appengine</groupId>
21-
<artifactId>appengine-firebase</artifactId>
21+
<artifactId>appengine-firebase-tictactoe</artifactId>
2222
<parent>
2323
<groupId>com.google.cloud</groupId>
2424
<artifactId>doc-samples</artifactId>

appengine/firebase-tictactoe/src/main/java/com/example/appengine/firetactoe/DeleteServlet.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public void doPost(HttpServletRequest request, HttpServletResponse response)
4141
UserService userService = UserServiceFactory.getUserService();
4242
String currentUserId = userService.getCurrentUser().getUserId();
4343

44+
// TODO(you): In practice, first validate that the user has permission to delete the Game
4445
game.deleteChannel(currentUserId);
4546
}
4647
}

appengine/firebase-tictactoe/src/main/java/com/example/appengine/firetactoe/FirebaseChannel.java

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.example.appengine.firetactoe;
1818

19+
import com.google.api.client.auth.oauth2.Credential;
1920
import com.google.api.client.extensions.appengine.http.UrlFetchTransport;
2021
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
2122
import com.google.api.client.http.ByteArrayContent;
@@ -31,6 +32,7 @@
3132

3233
import java.io.FileInputStream;
3334
import java.io.IOException;
35+
import java.io.InputStream;
3436
import java.io.InputStreamReader;
3537
import java.nio.charset.StandardCharsets;
3638
import java.util.Arrays;
@@ -46,16 +48,18 @@
4648
*/
4749
public class FirebaseChannel {
4850
private static final String FIREBASE_SNIPPET_PATH = "WEB-INF/view/firebase_config.jspf";
51+
static InputStream firebaseConfigStream = null;
4952
private static final Collection FIREBASE_SCOPES = Arrays.asList(
5053
"https://www.googleapis.com/auth/firebase.database",
5154
"https://www.googleapis.com/auth/userinfo.email"
5255
);
5356
private static final String IDENTITY_ENDPOINT =
5457
"https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit";
55-
static final HttpTransport HTTP_TRANSPORT = new UrlFetchTransport();
5658

5759
private String firebaseDbUrl;
5860
private GoogleCredential credential;
61+
// Keep this a package-private member variable, so that it can be mocked for unit tests
62+
HttpTransport httpTransport;
5963

6064
private static FirebaseChannel instance;
6165

@@ -79,11 +83,17 @@ public static FirebaseChannel getInstance() {
7983
*/
8084
private FirebaseChannel() {
8185
try {
86+
// This variables exist primarily so it can be stubbed out in unit tests.
87+
if (null == firebaseConfigStream) {
88+
firebaseConfigStream = new FileInputStream(FIREBASE_SNIPPET_PATH);
89+
}
90+
8291
String firebaseSnippet = CharStreams.toString(new InputStreamReader(
83-
new FileInputStream(FIREBASE_SNIPPET_PATH), StandardCharsets.UTF_8));
92+
firebaseConfigStream, StandardCharsets.UTF_8));
8493
firebaseDbUrl = parseFirebaseUrl(firebaseSnippet);
8594

8695
credential = GoogleCredential.getApplicationDefault().createScoped(FIREBASE_SCOPES);
96+
httpTransport = UrlFetchTransport.getDefaultInstance();
8797
} catch (IOException e) {
8898
throw new RuntimeException(e);
8999
}
@@ -109,7 +119,7 @@ private static String parseFirebaseUrl(String firebaseSnippet) {
109119
public void sendFirebaseMessage(String channelKey, Game game)
110120
throws IOException {
111121
// Make requests auth'ed using Application Default Credentials
112-
HttpRequestFactory requestFactory = HTTP_TRANSPORT.createRequestFactory(credential);
122+
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);
113123
GenericUrl url = new GenericUrl(
114124
String.format("%s/channels/%s.json", firebaseDbUrl, channelKey));
115125
HttpResponse response = null;
@@ -163,4 +173,63 @@ public String createFirebaseToken(Game game, String userId) {
163173
AppIdentityService.SigningResult result = appIdentity.signForApp(toSign.getBytes());
164174
return String.format("%s.%s", toSign, base64.encode(result.getSignature()));
165175
}
176+
177+
// The following methods are to illustrate making various calls to Firebase from App Engine
178+
// Standard
179+
180+
public HttpResponse firebasePut(String path, Object object) throws IOException {
181+
// Make requests auth'ed using Application Default Credentials
182+
Credential credential = GoogleCredential.getApplicationDefault().createScoped(FIREBASE_SCOPES);
183+
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);
184+
185+
String json = new Gson().toJson(object);
186+
GenericUrl url = new GenericUrl(path);
187+
188+
return requestFactory.buildPutRequest(
189+
url, new ByteArrayContent("application/json", json.getBytes())).execute();
190+
}
191+
192+
public HttpResponse firebasePatch(String path, Object object) throws IOException {
193+
// Make requests auth'ed using Application Default Credentials
194+
Credential credential = GoogleCredential.getApplicationDefault().createScoped(FIREBASE_SCOPES);
195+
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);
196+
197+
String json = new Gson().toJson(object);
198+
GenericUrl url = new GenericUrl(path);
199+
200+
return requestFactory.buildPatchRequest(
201+
url, new ByteArrayContent("application/json", json.getBytes())).execute();
202+
}
203+
204+
public HttpResponse firebasePost(String path, Object object) throws IOException {
205+
// Make requests auth'ed using Application Default Credentials
206+
Credential credential = GoogleCredential.getApplicationDefault().createScoped(FIREBASE_SCOPES);
207+
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);
208+
209+
String json = new Gson().toJson(object);
210+
GenericUrl url = new GenericUrl(path);
211+
212+
return requestFactory.buildPostRequest(
213+
url, new ByteArrayContent("application/json", json.getBytes())).execute();
214+
}
215+
216+
public HttpResponse firebaseGet(String path) throws IOException {
217+
// Make requests auth'ed using Application Default Credentials
218+
Credential credential = GoogleCredential.getApplicationDefault().createScoped(FIREBASE_SCOPES);
219+
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);
220+
221+
GenericUrl url = new GenericUrl(path);
222+
223+
return requestFactory.buildGetRequest(url).execute();
224+
}
225+
226+
public HttpResponse firebaseDelete(String path) throws IOException {
227+
// Make requests auth'ed using Application Default Credentials
228+
Credential credential = GoogleCredential.getApplicationDefault().createScoped(FIREBASE_SCOPES);
229+
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);
230+
231+
GenericUrl url = new GenericUrl(path);
232+
233+
return requestFactory.buildDeleteRequest(url).execute();
234+
}
166235
}

appengine/firebase-tictactoe/src/main/java/com/example/appengine/firetactoe/Game.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public void setMoveX(boolean moveX) {
104104
this.moveX = moveX;
105105
}
106106

107-
//[START send_updates]
107+
// [START send_updates]
108108
public String getChannelKey(String userId) {
109109
return userId + id;
110110
}
@@ -130,7 +130,7 @@ public void sendUpdateToClients()
130130
sendUpdateToUser(userX);
131131
sendUpdateToUser(userO);
132132
}
133-
//[END send_updates]
133+
// [END send_updates]
134134

135135
public void checkWin() {
136136
final Pattern[] wins;
@@ -152,7 +152,6 @@ public void checkWin() {
152152
}
153153
}
154154

155-
//[START make_move]
156155
public boolean makeMove(int position, String userId) {
157156
String currentMovePlayer;
158157
char value;
@@ -181,5 +180,4 @@ public boolean makeMove(int position, String userId) {
181180

182181
return false;
183182
}
184-
//[END make_move]
185183
}

appengine/firebase-tictactoe/src/main/java/com/example/appengine/firetactoe/MoveServlet.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public void doPost(HttpServletRequest request, HttpServletResponse response)
4444

4545
int cell = new Integer(request.getParameter("cell"));
4646
if (!game.makeMove(cell, currentUserId)) {
47-
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
47+
response.sendError(HttpServletResponse.SC_FORBIDDEN);
4848
} else {
4949
ofy.save().entity(game).now();
5050
}

appengine/firebase-tictactoe/src/main/java/com/example/appengine/firetactoe/OpenedServlet.java

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.example.appengine.firetactoe;
1818

19-
import com.googlecode.objectify.NotFoundException;
2019
import com.googlecode.objectify.Objectify;
2120
import com.googlecode.objectify.ObjectifyService;
2221

@@ -32,19 +31,10 @@ public class OpenedServlet extends HttpServlet {
3231
@Override
3332
public void doPost(HttpServletRequest request, HttpServletResponse response)
3433
throws IOException {
34+
// TODO(you): In practice, you should validate the user has permission to post to the given Game
3535
String gameId = request.getParameter("gameKey");
3636
Objectify ofy = ObjectifyService.ofy();
37-
try {
38-
Game game = ofy.load().type(Game.class).id(gameId).safe();
39-
if (gameId != null && request.getUserPrincipal() != null) {
40-
game.sendUpdateToClients();
41-
response.setContentType("text/plain");
42-
response.getWriter().println("ok");
43-
} else {
44-
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
45-
}
46-
} catch (NotFoundException e) {
47-
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
48-
}
37+
Game game = ofy.load().type(Game.class).id(gameId).safe();
38+
game.sendUpdateToClients();
4939
}
5040
}

appengine/firebase-tictactoe/src/main/java/com/example/appengine/firetactoe/TicTacToeServlet.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.example.appengine.firetactoe;
1818

19-
import com.google.appengine.api.users.UserService;
2019
import com.google.appengine.api.users.UserServiceFactory;
2120
import com.google.gson.Gson;
2221
import com.googlecode.objectify.Objectify;
@@ -60,20 +59,18 @@ private String getGameUriWithGameParam(HttpServletRequest request, String gameKe
6059
@Override
6160
public void doGet(HttpServletRequest request, HttpServletResponse response)
6261
throws ServletException, IOException {
63-
final UserService userService = UserServiceFactory.getUserService();
6462
String gameKey = request.getParameter("gameKey");
65-
if (userService.getCurrentUser() == null) {
66-
response.getWriter().println("<p>Please <a href=\"" + userService.createLoginURL(
67-
getGameUriWithGameParam(request, gameKey)) + "\">sign in</a>.</p>");
68-
return;
69-
}
7063

7164
// 1. Create or fetch a Game object from the datastore
7265
Objectify ofy = ObjectifyService.ofy();
7366
Game game = null;
74-
String userId = userService.getCurrentUser().getUserId();
67+
String userId = UserServiceFactory.getUserService().getCurrentUser().getUserId();
7568
if (gameKey != null) {
76-
game = ofy.load().type(Game.class).id(gameKey).safe();
69+
game = ofy.load().type(Game.class).id(gameKey).now();
70+
if (null == game) {
71+
response.sendError(HttpServletResponse.SC_NOT_FOUND);
72+
return;
73+
}
7774
if (game.getUserO() == null && !userId.equals(game.getUserX())) {
7875
game.setUserO(userId);
7976
}
@@ -91,6 +88,7 @@ public void doGet(HttpServletRequest request, HttpServletResponse response)
9188

9289
// 3. Inject a secure token into the client, so it can get game updates
9390

91+
// [START pass_token]
9492
// The 'Game' object exposes a method which creates a unique string based on the game's key
9593
// and the user's id.
9694
String token = FirebaseChannel.getInstance().createFirebaseToken(game, userId);
@@ -102,6 +100,7 @@ public void doGet(HttpServletRequest request, HttpServletResponse response)
102100
request.setAttribute("channel_id", game.getChannelKey(userId));
103101
request.setAttribute("initial_message", new Gson().toJson(game));
104102
request.setAttribute("game_link", getGameUriWithGameParam(request, gameKey));
105-
getServletContext().getRequestDispatcher("/WEB-INF/view/index.jsp").forward(request, response);
103+
request.getRequestDispatcher("/WEB-INF/view/index.jsp").forward(request, response);
104+
// [END pass_token]
106105
}
107106
}

0 commit comments

Comments
 (0)