` tag in src/main/webapp/WEB-INF/appengine-web.xml
+ with a valid version number.
+
+
+You will now be able to run
+
+ $ mvn appengine:update
+
+without the need for any additional parameters.
diff --git a/appengine/taskqueue-push/pom.xml b/appengine/taskqueue-push/pom.xml
new file mode 100644
index 00000000000..197dd0b3ef5
--- /dev/null
+++ b/appengine/taskqueue-push/pom.xml
@@ -0,0 +1,98 @@
+
+
+
+ 4.0.0
+ war
+ 1.0-SNAPSHOT
+ com.example.appengine
+ taskqueue-push
+
+
+ com.google.cloud
+ doc-samples
+ 1.0.0
+ ../..
+
+
+
+ com.google.appengine
+ appengine-maven-plugin
+ ${appengine.sdk.version}
+
+
+ javax.servlet
+ servlet-api
+ 2.5
+ jar
+ provided
+
+
+ org.json
+ json
+ 20151123
+
+
+
+ junit
+ junit
+ 4.10
+ test
+
+
+ org.mockito
+ mockito-all
+ 1.10.19
+ test
+
+
+ com.google.appengine
+ appengine-testing
+ ${appengine.sdk.version}
+ test
+
+
+ com.google.appengine
+ appengine-api-stubs
+ ${appengine.sdk.version}
+ test
+
+
+ com.google.appengine
+ appengine-tools-sdk
+ ${appengine.sdk.version}
+ test
+
+
+ com.google.truth
+ truth
+ 0.28
+ test
+
+
+
+
+
+ ${project.build.directory}/${project.build.finalName}/WEB-INF/classes
+
+
+ com.google.appengine
+ appengine-maven-plugin
+ ${appengine.sdk.version}
+
+
+
+
diff --git a/appengine/taskqueue-push/src/main/java/com/example/appengine/taskqueue/push/Enqueue.java b/appengine/taskqueue-push/src/main/java/com/example/appengine/taskqueue/push/Enqueue.java
new file mode 100644
index 00000000000..7076b04fc3a
--- /dev/null
+++ b/appengine/taskqueue-push/src/main/java/com/example/appengine/taskqueue/push/Enqueue.java
@@ -0,0 +1,42 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.appengine.taskqueue.push;
+
+import com.google.appengine.api.taskqueue.Queue;
+import com.google.appengine.api.taskqueue.QueueFactory;
+import com.google.appengine.api.taskqueue.TaskOptions;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+// [START enqueue]
+// The Enqueue servlet should be mapped to the "/enqueue" URL.
+public class Enqueue extends HttpServlet {
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String key = request.getParameter("key");
+
+ // Add the task to the default queue.
+ Queue queue = QueueFactory.getDefaultQueue();
+ queue.add(TaskOptions.Builder.withUrl("/worker").param("key", key));
+
+ response.sendRedirect("/");
+ }
+}
+// [END enqueue]
diff --git a/appengine/taskqueue-push/src/main/java/com/example/appengine/taskqueue/push/Worker.java b/appengine/taskqueue-push/src/main/java/com/example/appengine/taskqueue/push/Worker.java
new file mode 100644
index 00000000000..5bc298be1db
--- /dev/null
+++ b/appengine/taskqueue-push/src/main/java/com/example/appengine/taskqueue/push/Worker.java
@@ -0,0 +1,40 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.appengine.taskqueue.push;
+
+import java.io.IOException;
+import java.util.logging.Logger;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+// [START worker]
+// The Worker servlet should be mapped to the "/worker" URL.
+public class Worker extends HttpServlet {
+ private static final Logger log = Logger.getLogger(Worker.class.getName());
+
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String key = request.getParameter("key");
+
+ // Do something with key.
+ // [START_EXCLUDE]
+ log.info("Worker is processing " + key);
+ // [END_EXCLUDE]
+ }
+}
+// [END worker]
diff --git a/appengine/taskqueue-push/src/main/webapp/WEB-INF/appengine-web.xml b/appengine/taskqueue-push/src/main/webapp/WEB-INF/appengine-web.xml
new file mode 100644
index 00000000000..878132f8813
--- /dev/null
+++ b/appengine/taskqueue-push/src/main/webapp/WEB-INF/appengine-web.xml
@@ -0,0 +1,21 @@
+
+
+
+ YOUR-PROJECT-ID
+ YOUR-VERSION-ID
+ true
+
diff --git a/appengine/taskqueue-push/src/main/webapp/WEB-INF/web.xml b/appengine/taskqueue-push/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 00000000000..c7c7ab97bc4
--- /dev/null
+++ b/appengine/taskqueue-push/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,39 @@
+
+
+
+
+ index.html
+
+
+ enqueue
+ com.example.appengine.taskqueue.push.Enqueue
+
+
+ worker
+ com.example.appengine.taskqueue.push.Worker
+
+
+ enqueue
+ /enqueue
+
+
+ worker
+ /worker
+
+
diff --git a/appengine/taskqueue-push/src/main/webapp/index.html b/appengine/taskqueue-push/src/main/webapp/index.html
new file mode 100644
index 00000000000..f03eaa5f8a8
--- /dev/null
+++ b/appengine/taskqueue-push/src/main/webapp/index.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+Enqueue a value, to be processed by a worker.
+
+
+
+
diff --git a/appengine/taskqueue-push/src/test/java/com/example/appengine/taskqueue/push/WorkerTest.java b/appengine/taskqueue-push/src/test/java/com/example/appengine/taskqueue/push/WorkerTest.java
new file mode 100644
index 00000000000..9dec78c9700
--- /dev/null
+++ b/appengine/taskqueue-push/src/test/java/com/example/appengine/taskqueue/push/WorkerTest.java
@@ -0,0 +1,79 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.appengine.taskqueue.push;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Unit tests for {@link Worker}.
+ */
+@RunWith(JUnit4.class)
+public class WorkerTest {
+ private static final String FAKE_KEY_VALUE = "KEY";
+
+ // To capture and restore stderr
+ private final ByteArrayOutputStream stderr = new ByteArrayOutputStream();
+ private static final PrintStream REAL_ERR = System.err;
+
+ @Mock
+ private HttpServletRequest mockRequest;
+ @Mock
+ private HttpServletResponse mockResponse;
+ private Worker servletUnderTest;
+
+ @Before
+ public void setUp() throws Exception {
+ // Capture stderr to examine messages written to it
+ System.setErr(new PrintStream(stderr));
+
+ MockitoAnnotations.initMocks(this);
+
+ when(mockRequest.getParameter("key")).thenReturn(FAKE_KEY_VALUE);
+
+ servletUnderTest = new Worker();
+ }
+
+ @After
+ public void tearDown() {
+ // Restore stderr
+ System.setErr(WorkerTest.REAL_ERR);
+ }
+
+ @Test
+ public void doPost_writesResponse() throws Exception {
+ servletUnderTest.doPost(mockRequest, mockResponse);
+
+ String out = stderr.toString();
+ // We expect a log message to be created
+ // with the following message.
+ assertThat(out).contains("Worker is processing " + FAKE_KEY_VALUE);
+
+ }
+}
diff --git a/pom.xml b/pom.xml
index f0800083dab..e37c1554d2d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,6 +61,7 @@
appengine/remote/remote-client
appengine/remote/remote-server
appengine/static-files
+ appengine/taskqueue-push
appengine/twilio
appengine/urlfetch
appengine/users