Skip to content

Commit 89c85be

Browse files
jabubakelesv
authored andcommitted
Adding Pub/Sub App engine Java 8 sample (#865)
* Adding Pub/Sub app engine sample * updating README * removing unit tests updating README based on review
1 parent 4632179 commit 89c85be

File tree

12 files changed

+563
-0
lines changed

12 files changed

+563
-0
lines changed

appengine-java8/pom.xml

+2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@
7272

7373
<module>postgres</module>
7474

75+
<module>pubsub</module>
76+
7577
<module>requests</module>
7678

7779
<module>remote-client</module>

appengine-java8/pubsub/README.md

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Using Google Cloud Pub/Sub on App Engine Standard Java 8 Environment
2+
3+
This sample demonstrates how to use [Google Cloud Pub/Sub][pubsub]
4+
from [Google App Engine standard environment][ae-docs].
5+
6+
[pubsub]: https://cloud.google.com/pubsub/docs/
7+
[ae-docs]: https://cloud.google.com/appengine/docs/java/
8+
9+
The home page of this application provides a form to publish messages using Google/Cloud PubSub. The application
10+
then receives these published messages over a push subscription endpoint and then stores in Google Cloud Datastore.
11+
The home page provides a view of the most recent messages persisted in storage.
12+
13+
## Clone the sample app
14+
15+
Copy the sample apps to your local machine, and cd to the pubsub directory:
16+
17+
```
18+
git clone https://github.com/GoogleCloudPlatform/java-docs-samples
19+
cd java-docs-samples/appengine-java8/pubsub
20+
```
21+
22+
## Setup
23+
24+
- Make sure [`gcloud`](https://cloud.google.com/sdk/docs/) is installed and initialized:
25+
```
26+
gcloud init
27+
```
28+
- If this is the first time you are creating an App Engine project
29+
```
30+
gcloud app create
31+
```
32+
- For local development, [set up](https://cloud.google.com/docs/authentication/getting-started) authentication
33+
- [Enable](https://console.cloud.google.com/launcher/details/google/pubsub.googleapis.com) Pub/Sub API
34+
35+
- Create a topic
36+
```
37+
gcloud beta pubsub topics create <your-topic-name>
38+
```
39+
40+
- Create a push subscription, to send messages to a Google Cloud Project URL such as https://<your-project-id>.appspot.com/push.
41+
42+
The verification token is used to ensure that the end point only handles requests that are sent matching the verification token.
43+
You can use `uuidgen` on MacOS X, Windows, and Linux to generate a unique verification token.
44+
45+
```
46+
gcloud beta pubsub subscriptions create <your-subscription-name> \
47+
--topic <your-topic-name> \
48+
--push-endpoint \
49+
https://<your-project-id>.appspot.com/pubsub/push?token=<your-verification-token> \
50+
--ack-deadline 30
51+
```
52+
53+
## Run locally
54+
Set the following environment variables and run using shown Maven command. You can then
55+
direct your browser to `http://localhost:8080/`
56+
57+
```
58+
export PUBSUB_TOPIC=<your-topic-name>
59+
export PUBSUB_VERIFICATION_TOKEN=<your-verification-token>
60+
mvn appengine:run
61+
```
62+
63+
## Send fake subscription push messages with:
64+
65+
```
66+
curl -H "Content-Type: application/json" -i --data @sample_message.json
67+
"localhost:8080/pubsub/push?token=<your-token>"
68+
```
69+
70+
## Deploy
71+
72+
Update the environment variables `PUBSUB_TOPIC` and `PUBSUB_VERIFICATION_TOKEN` in
73+
[`appengine-web.xml`](src/main/webapp/WEB-INF/appengine-web.xml),
74+
then:
75+
76+
```
77+
mvn appengine:deploy
78+
```
79+
80+
Direct your browser to `https://project-id.appspot.com`.

appengine-java8/pubsub/pom.xml

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<!--
2+
Copyright 2017 Google Inc.
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+
<!-- [START project] -->
17+
<project>
18+
<modelVersion>4.0.0</modelVersion>
19+
<packaging>war</packaging>
20+
<version>1.0-SNAPSHOT</version>
21+
<groupId>com.example.flexible</groupId>
22+
<artifactId>appengine-pubsub</artifactId>
23+
24+
<parent>
25+
<artifactId>appengine-java8-samples</artifactId>
26+
<groupId>com.google.cloud</groupId>
27+
<version>1.0.0</version>
28+
<relativePath>..</relativePath>
29+
</parent>
30+
31+
<properties>
32+
<maven.compiler.target>1.8</maven.compiler.target>
33+
<maven.compiler.source>1.8</maven.compiler.source>
34+
<failOnMissingWebXml>false</failOnMissingWebXml> <!-- REQUIRED -->
35+
<appengine.maven.plugin>1.3.1</appengine.maven.plugin>
36+
<jetty>9.4.4.v20170414</jetty>
37+
</properties>
38+
39+
<dependencies>
40+
<dependency>
41+
<groupId>javax.servlet</groupId>
42+
<artifactId>javax.servlet-api</artifactId>
43+
<version>3.1.0</version>
44+
<type>jar</type>
45+
<scope>provided</scope>
46+
</dependency>
47+
48+
<!-- [START dependencies] -->
49+
<dependency>
50+
<groupId>com.google.cloud</groupId>
51+
<artifactId>google-cloud-pubsub</artifactId>
52+
<version>0.24.0-beta</version>
53+
</dependency>
54+
<dependency>
55+
<groupId>com.google.cloud</groupId>
56+
<artifactId>google-cloud-datastore</artifactId>
57+
<version>1.6.0</version>
58+
</dependency>
59+
<!-- [END dependencies] -->
60+
</dependencies>
61+
<build>
62+
<!-- for hot reload of the web application -->
63+
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
64+
<plugins>
65+
<plugin>
66+
<groupId>com.google.cloud.tools</groupId>
67+
<artifactId>appengine-maven-plugin</artifactId>
68+
<version>${appengine.maven.plugin}</version>
69+
<configuration>
70+
<!-- deploy configuration -->
71+
</configuration>
72+
</plugin>
73+
</plugins>
74+
</build>
75+
</project>
76+
<!-- [END project] -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"message":{"data":"dGVzdA==","attributes":{},"messageId":"91010751788941","publishTime":"2017-09-25T23:16:42.302Z"}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* Copyright 2017 Google Inc.
3+
*
4+
* <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* <p>http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
* express or implied. See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
15+
package com.example.appengine.pubsub;
16+
17+
/**
18+
* A message captures information from the Pubsub message received over the push endpoint and is
19+
* persisted in storage.
20+
*/
21+
public class Message {
22+
private String messageId;
23+
private String publishTime;
24+
private String data;
25+
26+
public Message(String messageId) {
27+
this.messageId = messageId;
28+
}
29+
30+
public String getMessageId() {
31+
return messageId;
32+
}
33+
34+
public void setMessageId(String messageId) {
35+
this.messageId = messageId;
36+
}
37+
38+
public String getPublishTime() {
39+
return publishTime;
40+
}
41+
42+
public void setPublishTime(String publishTime) {
43+
this.publishTime = publishTime;
44+
}
45+
46+
public String getData() {
47+
return data;
48+
}
49+
50+
public void setData(String data) {
51+
this.data = data;
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Copyright 2017 Google Inc.
3+
*
4+
* <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* <p>http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
* express or implied. See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
15+
package com.example.appengine.pubsub;
16+
17+
import java.util.List;
18+
19+
public interface MessageRepository {
20+
21+
/** Save message to persistent storage. */
22+
void save(Message message);
23+
24+
/**
25+
* Retrieve most recent stored messages.
26+
* @param limit number of messages
27+
* @return list of messages
28+
*/
29+
List<Message> retrieve(int limit);
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* Copyright 2017 Google Inc.
3+
*
4+
* <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* <p>http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
* express or implied. See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
15+
package com.example.appengine.pubsub;
16+
17+
import com.google.cloud.datastore.Datastore;
18+
import com.google.cloud.datastore.DatastoreOptions;
19+
import com.google.cloud.datastore.Entity;
20+
import com.google.cloud.datastore.Key;
21+
import com.google.cloud.datastore.KeyFactory;
22+
import com.google.cloud.datastore.Query;
23+
import com.google.cloud.datastore.QueryResults;
24+
import com.google.cloud.datastore.StructuredQuery;
25+
import java.util.ArrayList;
26+
import java.util.List;
27+
28+
/** Storage for Message objects using Cloud Datastore. */
29+
public class MessageRepositoryImpl implements MessageRepository {
30+
31+
private static MessageRepositoryImpl instance;
32+
33+
private String messagesKind = "messages";
34+
private KeyFactory keyFactory = getDatastoreInstance().newKeyFactory().setKind(messagesKind);
35+
36+
@Override
37+
public void save(Message message) {
38+
// Save message to "messages"
39+
Datastore datastore = getDatastoreInstance();
40+
Key key = datastore.allocateId(keyFactory.newKey());
41+
42+
Entity.Builder messageEntityBuilder = Entity.newBuilder(key)
43+
.set("messageId", message.getMessageId());
44+
45+
if (message.getData() != null) {
46+
messageEntityBuilder = messageEntityBuilder.set("data", message.getData());
47+
}
48+
49+
if (message.getPublishTime() != null) {
50+
messageEntityBuilder = messageEntityBuilder.set("publishTime", message.getPublishTime());
51+
}
52+
datastore.put(messageEntityBuilder.build());
53+
}
54+
55+
@Override
56+
public List<Message> retrieve(int limit) {
57+
// Get Message saved in Datastore
58+
Datastore datastore = getDatastoreInstance();
59+
Query<Entity> query =
60+
Query.newEntityQueryBuilder()
61+
.setKind(messagesKind)
62+
.setLimit(limit)
63+
.addOrderBy(StructuredQuery.OrderBy.desc("publishTime"))
64+
.build();
65+
QueryResults<Entity> results = datastore.run(query);
66+
67+
List<Message> messages = new ArrayList<>();
68+
while (results.hasNext()) {
69+
Entity entity = results.next();
70+
Message message = new Message(entity.getString("messageId"));
71+
String data = entity.getString("data");
72+
if (data != null) {
73+
message.setData(data);
74+
}
75+
String publishTime = entity.getString("publishTime");
76+
if (publishTime != null) {
77+
message.setPublishTime(publishTime);
78+
}
79+
messages.add(message);
80+
}
81+
return messages;
82+
}
83+
84+
private Datastore getDatastoreInstance() {
85+
return DatastoreOptions.getDefaultInstance().getService();
86+
}
87+
88+
private MessageRepositoryImpl() {
89+
}
90+
91+
// retrieve a singleton instance
92+
public static synchronized MessageRepositoryImpl getInstance() {
93+
if (instance == null) {
94+
instance = new MessageRepositoryImpl();
95+
}
96+
return instance;
97+
}
98+
}

0 commit comments

Comments
 (0)