Skip to content

Commit 9f7d910

Browse files
authored
Add guestbook sample for Java 11 (GoogleCloudPlatform#1381)
* Add guestbook sample * update parent pom.xml * draft * Add firestore * clean up * Firestore sample * Update pom * Update licenses and comments * Add path to dependency * Fix pom
1 parent 663a40b commit 9f7d910

File tree

9 files changed

+590
-0
lines changed

9 files changed

+590
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Guestbook sample for Google App Engine Java 11
2+
3+
<a href="https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/java-docs-samples&page=editor&open_in_editor=appengine-java11/guestbook/README.md">
4+
<img alt="Open in Cloud Shell" src ="http://gstatic.com/cloudssh/images/open-btn.png"></a>
5+
6+
This sample demonstrates how to handle form data using
7+
[Cloud Firestore](https://cloud.google.com/firestore/) on Google App Engine
8+
Standard.
9+
10+
This sample also uses packages from [Guava](https://github.com/google/guava),
11+
which provides some basic utility libraries and collections from Google's core
12+
libraries.
13+
14+
## Setup
15+
16+
* Download and initialize the [Cloud SDK](https://cloud.google.com/sdk/)
17+
18+
`gcloud init`
19+
20+
* If this is your first time creating an App Engine application:
21+
```
22+
gcloud app create
23+
```
24+
25+
* Setup [Application Default Credentials](https://developers.google.com/identity/protocols/application-default-credentials) by
26+
[creating a service account](https://cloud.google.com/docs/authentication/production#creating_a_service_account) and downloading the JSON key file.
27+
28+
* Provide authentication credentials to your application code by setting the
29+
environment variable `GOOGLE_APPLICATION_CREDENTIALS` to the path of your
30+
JSON key file.
31+
32+
`export GOOGLE_APPLICATION_CREDENTIALS="[PATH]"`
33+
34+
* Replace `YOUR-PROJECT-ID` in [`Persistence.java`](/src/main/java/com/example/guestbook/Persistence.java) with your project Id you created.
35+
36+
* Create a [Cloud Firestore in Native mode](https://cloud.google.com/firestore/docs/firestore-or-datastore) database by going to the
37+
[Cloud Firestore UI](https://console.cloud.google.com/firestore/data) and
38+
from the Select a database service screen:
39+
* Choose Cloud Firestore in Native mode.
40+
* Select a Cloud Firestore location.
41+
* Click Create Database.
42+
43+
**Cloud Firestore and App Engine:** You can't use both Cloud Firestore and Cloud Datastore in the same project, which might affect apps using App Engine. Try using Cloud Firestore with a different project if you need to use Cloud Datastore.
44+
45+
## Deploying
46+
47+
Deploy your application using the maven plugin:
48+
49+
```
50+
mvn clean package appengine:deploy -Dapp.deploy.projectId=<your-project-id>
51+
```
52+
53+
View your application:
54+
```
55+
gcloud app browse
56+
```
57+
or by visiting `https://<your-project-id>.appspot.com`.
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Copyright 2019 Google LLC
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
Unless required by applicable law or agreed to in writing, software
9+
distributed under the License is distributed on an "AS IS" BASIS,
10+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
See the License for the specific language governing permissions and
12+
limitations under the License.
13+
-->
14+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
15+
16+
<modelVersion>4.0.0</modelVersion>
17+
<packaging>war</packaging>
18+
<version>1.0-SNAPSHOT</version>
19+
<groupId>com.example.guestbook</groupId>
20+
<artifactId>guestbook-cloud-firestore</artifactId>
21+
22+
<properties>
23+
<maven.compiler.source>11</maven.compiler.source>
24+
<maven.compiler.target>11</maven.compiler.target>
25+
</properties>
26+
27+
<!-- All dependencies are scoped as provided.
28+
Dependent-jars are created and added to
29+
${project.build.directory}/appengine-staging -->
30+
<dependencies>
31+
<!-- Dependency from folder `../appengine-simple-jetty-main` -->
32+
<!-- See README for instructions for more information -->
33+
<dependency>
34+
<groupId>com.google.appengine.demo</groupId>
35+
<artifactId>simple-jetty-main</artifactId>
36+
<version>1</version>
37+
<scope>system</scope>
38+
<systemPath>${project.basedir}/../appengine-simple-jetty-main/target/simple-jetty-main-1.jar</systemPath>
39+
</dependency>
40+
41+
<dependency>
42+
<groupId>com.google.cloud</groupId>
43+
<artifactId>google-cloud-firestore</artifactId>
44+
<version>0.81.0-beta</version>
45+
<scope>provided</scope>
46+
</dependency>
47+
48+
<dependency>
49+
<groupId>com.google.guava</groupId>
50+
<artifactId>guava</artifactId>
51+
<version>27.1-jre</version>
52+
</dependency>
53+
54+
<dependency>
55+
<groupId>javax.servlet</groupId>
56+
<artifactId>javax.servlet-api</artifactId>
57+
<version>3.1.0</version>
58+
<type>jar</type>
59+
<scope>provided</scope>
60+
</dependency>
61+
<dependency>
62+
<groupId>jstl</groupId>
63+
<artifactId>jstl</artifactId>
64+
<version>1.2</version>
65+
</dependency>
66+
</dependencies>
67+
68+
<build>
69+
<finalName>guestbook</finalName>
70+
<plugins>
71+
<plugin>
72+
<groupId>com.google.cloud.tools</groupId>
73+
<artifactId>appengine-maven-plugin</artifactId>
74+
<version>2.0.0-rc5</version>
75+
<configuration>
76+
<version>guestbook</version>
77+
</configuration>
78+
</plugin>
79+
80+
<plugin>
81+
<groupId>org.eclipse.jetty</groupId>
82+
<artifactId>jetty-maven-plugin</artifactId>
83+
<version>9.4.2.v20170220</version>
84+
</plugin>
85+
86+
<plugin>
87+
<groupId>org.apache.maven.plugins</groupId>
88+
<artifactId>maven-dependency-plugin</artifactId>
89+
<version>3.1.1</version>
90+
<executions>
91+
<execution>
92+
<id>copy</id>
93+
<phase>prepare-package</phase>
94+
<goals>
95+
<goal>copy-dependencies</goal>
96+
</goals>
97+
<configuration>
98+
<outputDirectory>
99+
${project.build.directory}/appengine-staging
100+
</outputDirectory>
101+
</configuration>
102+
</execution>
103+
</executions>
104+
</plugin>
105+
</plugins>
106+
</build>
107+
</project>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Copyright 2019 Google LLC
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
runtime: java11
15+
instance_class: F2
16+
entrypoint: 'java -cp * com.google.appengine.demo.jettymain.Main guestbook.war'
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright 2019 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.guestbook;
18+
19+
20+
import com.google.common.base.MoreObjects;
21+
import java.util.Date;
22+
import java.util.HashMap;
23+
import java.util.Map;
24+
import java.util.Objects;
25+
26+
/** Greeting model. */
27+
@SuppressWarnings("JavadocMethod")
28+
public class Greeting {
29+
30+
private Guestbook book;
31+
32+
public String id;
33+
public String authorName;
34+
public String content;
35+
public Date date;
36+
37+
public Greeting() {
38+
date = new Date();
39+
}
40+
41+
public Greeting(String book, String content) {
42+
this();
43+
this.book = new Guestbook(book);
44+
this.content = content;
45+
}
46+
47+
public Greeting(String book, String content, String name) {
48+
this(book, content);
49+
authorName = name;
50+
}
51+
52+
/** Save the Greeting in the guestbook */
53+
public void save() {
54+
// Construct a Greeting.
55+
Map<String, Object> greetingData = new HashMap<>();
56+
greetingData.put("date", date);
57+
greetingData.put("content", content);
58+
greetingData.put("authorName", authorName);
59+
60+
// Add Greeting to Guestbook with random id.
61+
book.getBookRef().collection("Greetings").add(greetingData);
62+
}
63+
64+
@Override
65+
public boolean equals(Object obj) {
66+
if (this == obj) {
67+
return true;
68+
}
69+
if (obj == null || getClass() != obj.getClass()) {
70+
return false;
71+
}
72+
Greeting greeting = (Greeting) obj;
73+
return Objects.equals(id, greeting.id)
74+
&& Objects.equals(authorName, greeting.authorName)
75+
&& Objects.equals(content, greeting.content)
76+
&& Objects.equals(date, greeting.date);
77+
}
78+
79+
@Override
80+
public int hashCode() {
81+
return Objects.hash(id, authorName, content, date);
82+
}
83+
84+
@Override
85+
public String toString() {
86+
return MoreObjects.toStringHelper(this)
87+
.add("id", id)
88+
.add("authorName", authorName)
89+
.add("content", content)
90+
.add("date", date)
91+
.add("book", book)
92+
.toString();
93+
}
94+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright 2019 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.guestbook;
18+
19+
import static com.example.guestbook.Persistence.getFirestore;
20+
21+
import com.google.api.core.ApiFuture;
22+
import com.google.cloud.firestore.DocumentReference;
23+
import com.google.cloud.firestore.Query.Direction;
24+
import com.google.cloud.firestore.QueryDocumentSnapshot;
25+
import com.google.cloud.firestore.QuerySnapshot;
26+
import com.google.common.base.MoreObjects;
27+
import com.google.common.collect.ImmutableList;
28+
import java.util.HashMap;
29+
import java.util.List;
30+
import java.util.Map;
31+
import java.util.Objects;
32+
33+
/** Guestbook model. */
34+
@SuppressWarnings("JavadocMethod")
35+
public class Guestbook {
36+
37+
private static final long TIMEOUT_SECONDS = 5;
38+
39+
private final DocumentReference bookRef;
40+
41+
public final String book;
42+
43+
public Guestbook(String book) {
44+
this.book = book == null ? "default" : book;
45+
46+
// Construct the Guestbook data.
47+
Map<String, Object> bookData = new HashMap<>();
48+
bookData.put("name", this.book);
49+
50+
// Get Guestbook reference in the collection.
51+
bookRef = getFirestore().collection("Guestbooks").document(this.book);
52+
// Add Guestbook to collection.
53+
bookRef.set(bookData);
54+
}
55+
56+
public DocumentReference getBookRef() {
57+
return bookRef;
58+
}
59+
60+
/** Get greetings for the Guestbook */
61+
public List<Greeting> getGreetings() {
62+
// Initialize a List for Greetings.
63+
ImmutableList.Builder<Greeting> greetings = new ImmutableList.Builder<Greeting>();
64+
// Construct query.
65+
ApiFuture<QuerySnapshot> query =
66+
bookRef.collection("Greetings").orderBy("date", Direction.DESCENDING).get();
67+
68+
try {
69+
// Get query documents.
70+
QuerySnapshot querySnapshot = query.get();
71+
for (QueryDocumentSnapshot greeting : querySnapshot.getDocuments()) {
72+
greetings.add(greeting.toObject(Greeting.class));
73+
}
74+
} catch (Exception InterruptedException) {
75+
System.out.println("Nothing to query.");
76+
}
77+
78+
return greetings.build();
79+
}
80+
81+
@Override
82+
public boolean equals(Object obj) {
83+
if (!(obj instanceof Guestbook)) {
84+
return false;
85+
}
86+
Guestbook guestbook = (Guestbook) obj;
87+
return Objects.equals(book, guestbook.book) && Objects.equals(bookRef, guestbook.bookRef);
88+
}
89+
90+
@Override
91+
public int hashCode() {
92+
return Objects.hash(book, bookRef);
93+
}
94+
95+
@Override
96+
public String toString() {
97+
return MoreObjects.toStringHelper(this).add("book", book).add("bookRef", bookRef).toString();
98+
}
99+
}

0 commit comments

Comments
 (0)