Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1ec2907

Browse files
authoredSep 25, 2017
Fixes Firebase tic tac on App Engine sample (GoogleCloudPlatform#862)
1 parent 4932176 commit 1ec2907

File tree

15 files changed

+162
-196
lines changed

15 files changed

+162
-196
lines changed
 

‎appengine/firebase-tictactoe/README.md

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,48 +7,48 @@ for realtime notifications when the board changes.
77
[Firebase]: https://firebase.google.com
88
[standard]: https://cloud.google.com/appengine/docs/about-the-standard-environment
99

10-
## Prerequisites
10+
## Setup
1111

1212
* Install [Apache Maven][maven] 3.0.5 or later
13-
* Install the [Google Cloud SDK][sdk]
1413
* Create a project in the [Firebase Console][fb-console]
14+
* Download and install the [Cloud SDK](https://cloud.google.com/sdk/)
15+
16+
Initialize the `gcloud` configuration to use your new project:
17+
```
18+
gcloud init
19+
```
1520
* In the [Overview section][fb-overview] of the Firebase console, click 'Add
1621
Firebase to your web app' and replace the contents of the file
1722
`src/main/webapp/WEB-INF/view/firebase_config.jspf` with that code snippet.
18-
* If using the development appserver to run the app locally, you must supply
19-
credentials that would otherwise be inferred from the App Engine environment.
20-
Download [service account credentials][creds] and set the
21-
`GOOGLE_APPLICATION_CREDENTIALS` environment variable to its path:
22-
23-
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/your/credentials.json
24-
23+
* [Enable the Identity API](https://console.cloud.google.com/apis/api/identitytoolkit.googleapis.com/overview)
24+
* If you haven't already, Create an App Engine app within the current Google Cloud Project
25+
```
26+
gcloud app create
27+
```
28+
* Setup [Application Default Credentials](https://developers.google.com/identity/protocols/application-default-credentials)
29+
to run your application locally:
30+
Download [service account credentials][creds] and set the `GOOGLE_APPLICATION_CREDENTIALS`
31+
environment variable to its path:
32+
```
33+
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/your/credentials.json
34+
```
2535

2636
[fb-console]: https://console.firebase.google.com
2737
[sdk]: https://cloud.google.com/sdk
2838
[creds]: https://console.firebase.google.com/iam-admin/serviceaccounts/project?project=_&consoleReturnUrl=https:%2F%2Fconsole.firebase.google.com%2Fproject%2F_%2Fsettings%2Fgeneral%2F
2939
[fb-overview]: https://console.firebase.google.com/project/_/overview
3040
[maven]: https://maven.apache.org
3141

42+
## Running locally
3243

33-
## Run the sample
34-
35-
* To run the app locally using the development appserver:
36-
37-
```sh
3844
$ mvn appengine:run
39-
```
4045

41-
## Troubleshooting
46+
When running locally, the page does not automatically refresh,
47+
please reload the page manually after each move.
4248

43-
* If you see the error `Google Cloud SDK path was not provided ...`:
44-
* Make sure you've installed the [Google Cloud SDK][sdk]
45-
* Make sure the Google Cloud SDK's `bin/` directory is in your `PATH`. If
46-
you prefer it not to be, you can also set the environment variable
47-
`GOOGLE_CLOUD_SDK_HOME` to point to where you installed the SDK:
49+
## Deploying to App Engine Standard
4850

49-
```sh
50-
export GOOGLE_CLOUD_SDK_HOME=/path/to/google-cloud-sdk
51-
```
51+
$ mvn appengine:deploy
5252

5353
## Contributing changes
5454

‎appengine/firebase-tictactoe/pom.xml

Lines changed: 45 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -25,92 +25,50 @@
2525
<version>1.0.0</version>
2626
<relativePath>..</relativePath>
2727
</parent>
28-
<properties>
29-
<objectify.version>5.1.21</objectify.version>
30-
<servlet-api.version>2.5</servlet-api.version>
31-
<gson.version>2.7</gson.version>
32-
<guava.version>20.0</guava.version>
33-
<google-api-client.version>1.22.0</google-api-client.version>
34-
<junit.version>4.12</junit.version>
35-
<mockito.version>1.10.19</mockito.version>
36-
<google-truth.version>0.35</google-truth.version>
37-
<appengine-maven.version>1.3.1</appengine-maven.version>
38-
</properties>
39-
<!-- [START set_versions] -->
40-
<!-- [END set_versions] -->
41-
<dependencies>
42-
<dependency>
43-
<groupId>com.google.appengine</groupId>
44-
<artifactId>appengine-api-1.0-sdk</artifactId>
45-
<version>${appengine.sdk.version}</version>
46-
</dependency>
47-
<dependency>
48-
<groupId>javax.servlet</groupId>
49-
<artifactId>servlet-api</artifactId>
50-
<version>${servlet-api.version}</version>
51-
<type>jar</type>
52-
<scope>provided</scope>
53-
</dependency>
54-
<dependency>
55-
<groupId>com.google.code.gson</groupId>
56-
<artifactId>gson</artifactId>
57-
<version>2.8.1</version>
58-
</dependency>
59-
<dependency>
60-
<groupId>com.googlecode.objectify</groupId>
61-
<artifactId>objectify</artifactId>
62-
<version>${objectify.version}</version>
63-
</dependency>
64-
<dependency>
65-
<groupId>com.google.guava</groupId>
66-
<artifactId>guava</artifactId>
67-
<version>${guava.version}</version>
68-
</dependency>
69-
<dependency>
70-
<groupId>com.google.api-client</groupId>
71-
<artifactId>google-api-client-appengine</artifactId>
72-
<version>${google-api-client.version}</version>
73-
</dependency>
74-
75-
76-
<!-- Test Dependencies -->
77-
<dependency>
78-
<groupId>junit</groupId>
79-
<artifactId>junit</artifactId>
80-
<version>${junit.version}</version>
81-
<scope>test</scope>
82-
</dependency>
83-
<dependency>
84-
<groupId>org.mockito</groupId>
85-
<artifactId>mockito-all</artifactId>
86-
<version>${mockito.version}</version>
87-
<scope>test</scope>
88-
</dependency>
89-
<dependency>
90-
<groupId>com.google.appengine</groupId>
91-
<artifactId>appengine-testing</artifactId>
92-
<version>${appengine.sdk.version}</version>
93-
<scope>test</scope>
94-
</dependency>
95-
<dependency>
96-
<groupId>com.google.appengine</groupId>
97-
<artifactId>appengine-api-stubs</artifactId>
98-
<version>${appengine.sdk.version}</version>
99-
<scope>test</scope>
100-
</dependency>
101-
<dependency>
102-
<groupId>com.google.appengine</groupId>
103-
<artifactId>appengine-tools-sdk</artifactId>
104-
<version>${appengine.sdk.version}</version>
105-
<scope>test</scope>
106-
</dependency>
107-
<dependency>
108-
<groupId>com.google.truth</groupId>
109-
<artifactId>truth</artifactId>
110-
<version>${google-truth.version}</version>
111-
<scope>test</scope>
112-
</dependency>
113-
</dependencies>
28+
<dependencies>
29+
<dependency>
30+
<groupId>com.googlecode.objectify</groupId>
31+
<artifactId>objectify</artifactId>
32+
<version>5.1.21</version>
33+
</dependency>
34+
<dependency>
35+
<groupId>com.google.appengine</groupId>
36+
<artifactId>appengine-api-1.0-sdk</artifactId>
37+
<version>1.9.56</version>
38+
</dependency>
39+
<dependency>
40+
<groupId>com.google.api-client</groupId>
41+
<artifactId>google-api-client-appengine</artifactId>
42+
<version>1.22.0</version>
43+
</dependency>
44+
<dependency>
45+
<groupId>com.google.code.gson</groupId>
46+
<artifactId>gson</artifactId>
47+
<version>2.8.1</version>
48+
</dependency>
49+
<!-- Test dependences -->
50+
<dependency>
51+
<groupId>junit</groupId>
52+
<artifactId>junit</artifactId>
53+
<version>4.12</version>
54+
</dependency>
55+
<dependency>
56+
<groupId>org.mockito</groupId>
57+
<artifactId>mockito-core</artifactId>
58+
<version>2.9.0</version>
59+
</dependency>
60+
<dependency>
61+
<groupId>com.google.appengine</groupId>
62+
<artifactId>appengine-api-stubs</artifactId>
63+
<version>1.9.56</version>
64+
<scope>test</scope>
65+
</dependency>
66+
<dependency>
67+
<groupId>com.google.appengine</groupId>
68+
<artifactId>appengine-testing</artifactId>
69+
<version>1.9.56</version>
70+
</dependency>
71+
</dependencies>
11472
<build>
11573
<!-- for hot reload of the web application -->
11674
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes
@@ -119,7 +77,7 @@
11977
<plugin>
12078
<groupId>com.google.cloud.tools</groupId>
12179
<artifactId>appengine-maven-plugin</artifactId>
122-
<version>${appengine-maven.version}</version>
80+
<version>1.3.1</version>
12381
</plugin>
12482
</plugins>
12583
</build>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ public void doPost(HttpServletRequest request, HttpServletResponse response)
4242
String currentUserId = userService.getCurrentUser().getUserId();
4343

4444
// TODO(you): In practice, first validate that the user has permission to delete the Game
45-
game.deleteChannel(currentUserId);
45+
game.deleteChannel(getServletContext(), currentUserId);
4646
}
4747
}

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@
2424
import com.google.api.client.http.HttpRequestFactory;
2525
import com.google.api.client.http.HttpResponse;
2626
import com.google.api.client.http.HttpTransport;
27+
import com.google.api.client.util.Preconditions;
2728
import com.google.appengine.api.appidentity.AppIdentityService;
2829
import com.google.appengine.api.appidentity.AppIdentityServiceFactory;
2930
import com.google.common.io.BaseEncoding;
3031
import com.google.common.io.CharStreams;
3132
import com.google.gson.Gson;
3233

33-
import java.io.FileInputStream;
3434
import java.io.IOException;
3535
import java.io.InputStream;
3636
import java.io.InputStreamReader;
@@ -39,6 +39,7 @@
3939
import java.util.Collection;
4040
import java.util.HashMap;
4141
import java.util.Map;
42+
import javax.servlet.ServletContext;
4243

4344
/**
4445
* Utility functions for communicating with the realtime communication channel using Firebase.
@@ -47,7 +48,7 @@
4748
* Firebase.
4849
*/
4950
public class FirebaseChannel {
50-
private static final String FIREBASE_SNIPPET_PATH = "WEB-INF/view/firebase_config.jspf";
51+
private static final String FIREBASE_SNIPPET_PATH = "/WEB-INF/view/firebase_config.jspf";
5152
static InputStream firebaseConfigStream = null;
5253
private static final Collection FIREBASE_SCOPES = Arrays.asList(
5354
"https://www.googleapis.com/auth/firebase.database",
@@ -67,9 +68,9 @@ public class FirebaseChannel {
6768
* FirebaseChannel is a singleton, since it's just utility functions.
6869
* The class derives auth information when first instantiated.
6970
*/
70-
public static FirebaseChannel getInstance() {
71+
public static FirebaseChannel getInstance(ServletContext servletContext) {
7172
if (instance == null) {
72-
instance = new FirebaseChannel();
73+
instance = new FirebaseChannel(servletContext);
7374
}
7475
return instance;
7576
}
@@ -81,11 +82,13 @@ public static FirebaseChannel getInstance() {
8182
* communicate with Firebase is derived from App Engine's default credentials, and given
8283
* Firebase's OAuth scopes.
8384
*/
84-
private FirebaseChannel() {
85+
private FirebaseChannel(ServletContext servletContext) {
8586
try {
8687
// This variables exist primarily so it can be stubbed out in unit tests.
8788
if (null == firebaseConfigStream) {
88-
firebaseConfigStream = new FileInputStream(FIREBASE_SNIPPET_PATH);
89+
Preconditions.checkNotNull(servletContext,
90+
"Servlet context expected to initialize Firebase channel");
91+
firebaseConfigStream = servletContext.getResourceAsStream(FIREBASE_SNIPPET_PATH);
8992
}
9093

9194
String firebaseSnippet = CharStreams.toString(new InputStreamReader(
@@ -176,7 +179,6 @@ public String createFirebaseToken(Game game, String userId) {
176179

177180
// The following methods are to illustrate making various calls to Firebase from App Engine
178181
// Standard
179-
180182
public HttpResponse firebasePut(String path, Object object) throws IOException {
181183
// Make requests auth'ed using Application Default Credentials
182184
Credential credential = GoogleCredential.getApplicationDefault().createScoped(FIREBASE_SCOPES);

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424
import java.util.logging.Level;
2525
import java.util.logging.Logger;
2626
import java.util.regex.Pattern;
27+
import javax.servlet.ServletContext;
2728

2829
/**
2930
* The datastore-persisted Game object. This holds the entire game state - from a representation of
3031
* the board, to the players are and whose turn it is, and who the winner is and how they won.
31-
*
3232
* It also contains some convenience functions for communicating updates to the board to the
3333
* clients, via Firebase.
3434
*/
@@ -109,26 +109,26 @@ public String getChannelKey(String userId) {
109109
return userId + id;
110110
}
111111

112-
public void deleteChannel(String userId)
112+
public void deleteChannel(ServletContext servletContext, String userId)
113113
throws IOException {
114114
if (userId != null) {
115115
String channelKey = getChannelKey(userId);
116-
FirebaseChannel.getInstance().sendFirebaseMessage(channelKey, null);
116+
FirebaseChannel.getInstance(servletContext).sendFirebaseMessage(channelKey, null);
117117
}
118118
}
119119

120-
private void sendUpdateToUser(String userId)
120+
private void sendUpdateToUser(ServletContext servletContext, String userId)
121121
throws IOException {
122122
if (userId != null) {
123123
String channelKey = getChannelKey(userId);
124-
FirebaseChannel.getInstance().sendFirebaseMessage(channelKey, this);
124+
FirebaseChannel.getInstance(servletContext).sendFirebaseMessage(channelKey, this);
125125
}
126126
}
127127

128-
public void sendUpdateToClients()
128+
public void sendUpdateToClients(ServletContext servletContext)
129129
throws IOException {
130-
sendUpdateToUser(userX);
131-
sendUpdateToUser(userO);
130+
sendUpdateToUser(servletContext, userX);
131+
sendUpdateToUser(servletContext, userO);
132132
}
133133
// [END send_updates]
134134

@@ -152,7 +152,7 @@ public void checkWin() {
152152
}
153153
}
154154

155-
public boolean makeMove(int position, String userId) {
155+
public boolean makeMove(ServletContext servletContext, int position, String userId) {
156156
String currentMovePlayer;
157157
char value;
158158
if (getMoveX()) {
@@ -170,7 +170,7 @@ public boolean makeMove(int position, String userId) {
170170
checkWin();
171171
setMoveX(!getMoveX());
172172
try {
173-
sendUpdateToClients();
173+
sendUpdateToClients(servletContext);
174174
} catch (IOException e) {
175175
LOGGER.log(Level.SEVERE, "Error sending Game update to Firebase", e);
176176
throw new RuntimeException(e);

‎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
@@ -43,7 +43,7 @@ public void doPost(HttpServletRequest request, HttpServletResponse response)
4343
String currentUserId = userService.getCurrentUser().getUserId();
4444

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

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
1617
package com.example.appengine.firetactoe;
1718

1819
import com.googlecode.objectify.ObjectifyService;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@ public void doPost(HttpServletRequest request, HttpServletResponse response)
3535
String gameId = request.getParameter("gameKey");
3636
Objectify ofy = ObjectifyService.ofy();
3737
Game game = ofy.load().type(Game.class).id(gameId).safe();
38-
game.sendUpdateToClients();
38+
game.sendUpdateToClients(getServletContext());
3939
}
4040
}
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.