Skip to content

Commit 4514e8b

Browse files
authored
Pubsub flexible sample (#592)
Pubsub push sample for Flex
1 parent 5b63acb commit 4514e8b

File tree

14 files changed

+715
-0
lines changed

14 files changed

+715
-0
lines changed

flexible/pubsub/README.md

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# App Engine Flexible Environment - Pub/Sub Sample
2+
3+
## Clone the sample app
4+
5+
Copy the sample apps to your local machine, and cd to the pubsub directory:
6+
7+
```
8+
git clone https://github.com/GoogleCloudPlatform/java-docs-samples
9+
cd java-docs-samples/flexible/pubsub
10+
```
11+
12+
## Setup
13+
14+
Make sure [`gcloud`](https://cloud.google.com/sdk/docs/) is installed and authenticated.
15+
16+
Create a topic
17+
```
18+
gcloud beta pubsub topics create <your-topic-name>
19+
```
20+
21+
Create a push subscription, to send messages to a Google Cloud Project URL
22+
such as https://<your-project-id>.appspot.com/push.
23+
```
24+
gcloud beta pubsub subscriptions create <your-subscription-name> \
25+
--topic <your-topic-name> \
26+
--push-endpoint \
27+
https://<your-project-id>.appspot.com/pubsub/push?token=<your-verification-token> \
28+
--ack-deadline 30
29+
```
30+
## Run
31+
32+
Set the following environment variables and run using shown Maven command. You can then
33+
direct your browser to `http://localhost:8080/`
34+
35+
```
36+
export PUBSUB_TOPIC=<your-topic-name>
37+
export PUBSUB_VERIFICATION_TOKEN=<your-verification-token>
38+
mvn jetty:run
39+
```
40+
41+
42+
### Send fake subscription push messages with:
43+
44+
```
45+
curl -H "Content-Type: application/json" -i --data @sample_message.json
46+
"localhost:8080/pubsub/push?token=<your-token>"
47+
```
48+
49+
## Deploy
50+
51+
Update the environment variables `PUBSUB_TOPIC` and `PUBSUB_VERIFICATION_TOKEN` in [`app.yaml`](src/main/appengine/app.yaml),
52+
then:
53+
54+
```
55+
mvn appengine:deploy
56+
```
57+
58+
The home page of this application provides a form to publish messages and also provides a view of the most recent messages
59+
received over the push endpoint and persisted in storage.

flexible/pubsub/pom.xml

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
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>flexible-pubsub</artifactId>
23+
24+
<parent>
25+
<artifactId>doc-samples</artifactId>
26+
<groupId>com.google.cloud</groupId>
27+
<version>1.0.0</version>
28+
<relativePath>../..</relativePath>
29+
</parent>
30+
31+
<properties>
32+
<appengine.maven.plugin>1.3.0</appengine.maven.plugin>
33+
<maven.compiler.target>1.8</maven.compiler.target>
34+
<maven.compiler.source>1.8</maven.compiler.source>
35+
<failOnMissingWebXml>false</failOnMissingWebXml>
36+
<jetty.maven.plugin>9.3.8.v20160314</jetty.maven.plugin>
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.13.0-alpha</version>
53+
</dependency>
54+
<dependency>
55+
<groupId>com.google.cloud</groupId>
56+
<artifactId>google-cloud-datastore</artifactId>
57+
<version>0.13.0-beta</version>
58+
</dependency>
59+
<!-- [END dependencies] -->
60+
61+
<!-- Test Dependencies -->
62+
<dependency>
63+
<groupId>com.google.appengine</groupId>
64+
<artifactId>appengine-api-stubs</artifactId>
65+
<version>1.9.38</version>
66+
<scope>test</scope>
67+
</dependency>
68+
<dependency>
69+
<groupId>com.google.appengine</groupId>
70+
<artifactId>appengine-tools-sdk</artifactId>
71+
<version>1.9.38</version>
72+
<scope>test</scope>
73+
</dependency>
74+
<dependency>
75+
<groupId>org.eclipse.jetty</groupId>
76+
<artifactId>jetty-server</artifactId>
77+
<version>9.4.3.v20170317</version>
78+
</dependency>
79+
<dependency>
80+
<groupId>junit</groupId>
81+
<artifactId>junit</artifactId>
82+
<scope>test</scope>
83+
</dependency>
84+
<dependency>
85+
<groupId>org.mockito</groupId>
86+
<artifactId>mockito-all</artifactId>
87+
<version>1.10.19</version>
88+
<scope>test</scope>
89+
</dependency>
90+
<dependency>
91+
<groupId>org.eclipse.jetty</groupId>
92+
<artifactId>jetty-servlet</artifactId>
93+
<version>9.3.14.v20161028</version>
94+
</dependency>
95+
</dependencies>
96+
<build>
97+
<!-- for hot reload of the web application -->
98+
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
99+
<plugins>
100+
<plugin>
101+
<groupId>com.google.cloud.tools</groupId>
102+
<artifactId>appengine-maven-plugin</artifactId>
103+
<version>${appengine.maven.plugin}</version>
104+
<configuration>
105+
<!-- deploy configuration -->
106+
</configuration>
107+
</plugin>
108+
<plugin>
109+
<groupId>org.eclipse.jetty</groupId>
110+
<artifactId>jetty-maven-plugin</artifactId>
111+
<version>${jetty.maven.plugin}</version>
112+
</plugin>
113+
</plugins>
114+
</build>
115+
</project>
116+
<!-- [END project] -->

flexible/pubsub/sample_message.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"message":{"data":"dGVzdA==","attributes":{},"messageId":"91010751788941","publishTime":"2017-04-05T23:16:42.302Z"}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright 2017 Google Inc.
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+
# [START appyaml]
14+
runtime: java
15+
env: flex
16+
17+
handlers:
18+
- url: /.*
19+
script: this field is required, but ignored
20+
21+
# [START env_variables]
22+
env_variables:
23+
PUBSUB_TOPIC: <your-topic-name>
24+
PUBSUB_VERIFICATION_TOKEN: <your-verification-token>
25+
# [END env_variables]
26+
# [END appyaml]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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+
package com.example.flexible.pubsub;
15+
16+
/**
17+
* A message captures information from the Pubsub message received over the push endpoint and is
18+
* persisted in storage.
19+
*/
20+
public class Message {
21+
private String messageId;
22+
private String publishTime;
23+
private String data;
24+
25+
public Message(String messageId) {
26+
this.messageId = messageId;
27+
}
28+
29+
public String getMessageId() {
30+
return messageId;
31+
}
32+
33+
public void setMessageId(String messageId) {
34+
this.messageId = messageId;
35+
}
36+
37+
public String getPublishTime() {
38+
return publishTime;
39+
}
40+
41+
public void setPublishTime(String publishTime) {
42+
this.publishTime = publishTime;
43+
}
44+
45+
public String getData() {
46+
return data;
47+
}
48+
49+
public void setData(String data) {
50+
this.data = data;
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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+
package com.example.flexible.pubsub;
15+
16+
import java.util.List;
17+
18+
public interface MessageRepository {
19+
20+
/** Save message to persistent storage. */
21+
void save(Message message);
22+
23+
/**
24+
* Retrieve most recent stored messages.
25+
* @param limit number of messages
26+
* @return list of messages
27+
*/
28+
List<Message> retrieve(int limit);
29+
}
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+
package com.example.flexible.pubsub;
15+
16+
import com.google.cloud.datastore.Datastore;
17+
import com.google.cloud.datastore.DatastoreOptions;
18+
import com.google.cloud.datastore.Entity;
19+
import com.google.cloud.datastore.Key;
20+
import com.google.cloud.datastore.KeyFactory;
21+
import com.google.cloud.datastore.Query;
22+
import com.google.cloud.datastore.QueryResults;
23+
import com.google.cloud.datastore.StructuredQuery;
24+
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)