diff --git a/appengine-java8/tasks/pom.xml b/appengine-java8/tasks/pom.xml
new file mode 100644
index 00000000000..34ef6756138
--- /dev/null
+++ b/appengine-java8/tasks/pom.xml
@@ -0,0 +1,97 @@
+
+
+
+ 4.0.0
+ war
+ 1.0-SNAPSHOT
+ com.example.appengine
+ appengine-tasks-j8
+
+
+
+ com.google.cloud.samples
+ shared-configuration
+ 1.0.10
+
+
+
+
+ 1.8
+ 1.8
+ 1.6.0
+
+
+
+
+
+ javax.servlet
+ javax.servlet-api
+ 3.1.0
+ jar
+ provided
+
+
+ com.google.cloud
+ google-cloud-tasks
+ 0.54.0-beta
+
+
+ commons-cli
+ commons-cli
+ 1.4
+ compile
+
+
+
+
+
+ ${project.build.directory}/${project.build.finalName}/WEB-INF/classes
+
+
+
+ com.google.cloud.tools
+ appengine-maven-plugin
+ 1.3.1
+
+ true
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+ 3.1.0
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ ${maven-exec-plugin.version}
+
+ com.example.task.CreateTask
+ false
+
+
+
+
+
diff --git a/appengine-java8/tasks/src/main/java/com/example/task/CreateTask.java b/appengine-java8/tasks/src/main/java/com/example/task/CreateTask.java
new file mode 100644
index 00000000000..3a0f340d07e
--- /dev/null
+++ b/appengine-java8/tasks/src/main/java/com/example/task/CreateTask.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * 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.task;
+
+import com.google.cloud.tasks.v2beta2.AppEngineHttpRequest;
+import com.google.cloud.tasks.v2beta2.CloudTasksClient;
+import com.google.cloud.tasks.v2beta2.HttpMethod;
+import com.google.cloud.tasks.v2beta2.QueueName;
+import com.google.cloud.tasks.v2beta2.Task;
+import com.google.common.base.Strings;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.Timestamp;
+
+import java.nio.charset.Charset;
+import java.time.Clock;
+import java.time.Instant;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+public class CreateTask {
+ private static String GGOGLE_CLOUD_PROJECT_KEY = "GOOGLE_CLOUD_PROJECT";
+
+ private static Option PROJECT_ID_OPTION = Option.builder("pid")
+ .longOpt("project-id")
+ .desc("The Google Cloud Project, if not set as GOOGLE_CLOUD_PROJECT env var.")
+ .hasArg()
+ .argName("project-id")
+ .type(String.class)
+ .build();
+
+ private static Option QUEUE_OPTION = Option.builder("q")
+ .required()
+ .longOpt("queue")
+ .desc("The Cloud Tasks queue.")
+ .hasArg()
+ .argName("queue")
+ .type(String.class)
+ .build();
+
+ private static Option LOCATION_OPTION = Option.builder("l")
+ .required()
+ .longOpt("location")
+ .desc("The region in which your queue is running.")
+ .hasArg()
+ .argName("location")
+ .type(String.class)
+ .build();
+
+ private static Option PAYLOAD_OPTION = Option.builder("p")
+ .longOpt("payload")
+ .desc("The payload string for the task.")
+ .hasArg()
+ .argName("payload")
+ .type(String.class)
+ .build();
+
+ private static Option IN_SECONDS_OPTION = Option.builder("s")
+ .longOpt("in-seconds")
+ .desc("Schedule time for the task to create.")
+ .hasArg()
+ .argName("in-seconds")
+ .type(int.class)
+ .build();
+
+ public static void main(String... args) throws Exception {
+ Options options = new Options();
+ options.addOption(PROJECT_ID_OPTION);
+ options.addOption(QUEUE_OPTION);
+ options.addOption(LOCATION_OPTION);
+ options.addOption(PAYLOAD_OPTION);
+ options.addOption(IN_SECONDS_OPTION);
+
+ if (args.length == 0) {
+ printUsage(options);
+ return;
+ }
+
+ CommandLineParser parser = new DefaultParser();
+ CommandLine params = null;
+ try {
+ params = parser.parse(options, args);
+ } catch (ParseException e) {
+ System.err.println("Invalid command line: " + e.getMessage());
+ printUsage(options);
+ return;
+ }
+
+ String projectId;
+ if (params.hasOption("project-id")) {
+ projectId = params.getOptionValue("project-id");
+ } else {
+ projectId = System.getenv(GGOGLE_CLOUD_PROJECT_KEY);
+ }
+ if (Strings.isNullOrEmpty(projectId)) {
+ printUsage(options);
+ return;
+ }
+
+ String queueName = params.getOptionValue(QUEUE_OPTION.getOpt());
+ String location = params.getOptionValue(LOCATION_OPTION.getOpt());
+ String payload = params.getOptionValue(PAYLOAD_OPTION.getOpt(), "default payload");
+
+ // [START cloud_tasks_appengine_create_task]
+ try (CloudTasksClient client = CloudTasksClient.create()) {
+ Task.Builder taskBuilder = Task
+ .newBuilder()
+ .setAppEngineHttpRequest(AppEngineHttpRequest.newBuilder()
+ .setPayload(ByteString.copyFrom(payload, Charset.defaultCharset()))
+ .setRelativeUrl("/tasks/create")
+ .setHttpMethod(HttpMethod.POST)
+ .build());
+ if (params.hasOption(IN_SECONDS_OPTION.getOpt())) {
+ int seconds = Integer.parseInt(params.getOptionValue(IN_SECONDS_OPTION.getOpt()));
+ taskBuilder.setScheduleTime(Timestamp
+ .newBuilder()
+ .setSeconds(Instant.now(Clock.systemUTC()).plusSeconds(seconds).getEpochSecond()));
+ }
+ Task task = client.createTask(
+ QueueName.of(projectId, location, queueName).toString(), taskBuilder.build());
+ System.out.println("Task created: " + task.getName());
+ }
+ // [END cloud_tasks_appengine_create_task]
+ }
+
+ private static void printUsage(Options options) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp(
+ "client",
+ "A simple Cloud Tasks command line client that triggers a call to an AppEngine "
+ + "endpoint.",
+ options, "", true);
+ throw new RuntimeException();
+ }
+
+}
diff --git a/appengine-java8/tasks/src/main/java/com/example/task/TaskServlet.java b/appengine-java8/tasks/src/main/java/com/example/task/TaskServlet.java
new file mode 100644
index 00000000000..a95de4f85c5
--- /dev/null
+++ b/appengine-java8/tasks/src/main/java/com/example/task/TaskServlet.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * 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.task;
+
+import java.io.IOException;
+import java.util.logging.Logger;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+// [START cloud_tasks_appengine_quickstart]
+@WebServlet(
+ name = "Tasks",
+ description = "Create Cloud Task",
+ urlPatterns = "/tasks/create"
+)
+public class TaskServlet extends HttpServlet {
+ private static Logger log = Logger.getLogger(TaskServlet.class.getName());
+
+ @Override
+ public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ log.info("Received task request: " + req.getServletPath());
+ if (req.getParameter("payload") != null) {
+ String payload = req.getParameter("payload");
+ log.info("Request payload: " + payload);
+ String output = String.format("Received task with payload %s", payload);
+ resp.getOutputStream().write(output.getBytes());
+ log.info("Sending response: " + output);
+ resp.setStatus(HttpServletResponse.SC_OK);
+ } else {
+ log.warning("Null payload received in request to " + req.getServletPath());
+ }
+ }
+}
+// [END cloud_tasks_appengine_quickstart]
diff --git a/appengine-java8/tasks/src/main/webapp/WEB-INF/appengine-web.xml b/appengine-java8/tasks/src/main/webapp/WEB-INF/appengine-web.xml
new file mode 100644
index 00000000000..d64ab6aafb7
--- /dev/null
+++ b/appengine-java8/tasks/src/main/webapp/WEB-INF/appengine-web.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+ java8
+ true
+
diff --git a/tasks/pom.xml b/tasks/pom.xml
new file mode 100644
index 00000000000..9393094817e
--- /dev/null
+++ b/tasks/pom.xml
@@ -0,0 +1,80 @@
+
+
+ 4.0.0
+ com.example
+ tasks-samples
+ jar
+ 1.0
+
+
+
+ com.google.cloud.samples
+ shared-configuration
+ 1.0.10
+
+
+
+
+ UTF-8
+ 1.8
+ 1.8
+
+
+
+
+ com.google.cloud
+ google-cloud-tasks
+ 0.54.0-beta
+
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ com.google.truth
+ truth
+ 0.41
+ test
+
+
+ com.google.api-client
+ google-api-client
+ 1.23.0
+ compile
+
+
+ commons-cli
+ commons-cli
+ 1.4
+ compile
+
+
+
+
+ src/main/java
+
+
+
diff --git a/tasks/src/main/java/com/example/Quickstart.java b/tasks/src/main/java/com/example/Quickstart.java
new file mode 100644
index 00000000000..77040ef8285
--- /dev/null
+++ b/tasks/src/main/java/com/example/Quickstart.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * 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;
+
+// [START tasks_quickstart]
+
+import com.google.cloud.tasks.v2beta2.AcknowledgeTaskRequest;
+import com.google.cloud.tasks.v2beta2.CloudTasksClient;
+import com.google.cloud.tasks.v2beta2.CreateTaskRequest;
+import com.google.cloud.tasks.v2beta2.LeaseTasksRequest;
+import com.google.cloud.tasks.v2beta2.LeaseTasksResponse;
+import com.google.cloud.tasks.v2beta2.PullMessage;
+import com.google.cloud.tasks.v2beta2.QueueName;
+import com.google.cloud.tasks.v2beta2.Task;
+import com.google.common.base.Strings;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.Duration;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+public class Quickstart {
+ private static String GGOGLE_CLOUD_PROJECT_KEY = "GOOGLE_CLOUD_PROJECT";
+
+ private static Option PROJECT_ID_OPTION = Option.builder("project")
+ .longOpt("project-id")
+ .desc("The Google Cloud Project, if not set as GOOGLE_CLOUD_PROJECT env var.")
+ .hasArg()
+ .argName("project-id")
+ .type(String.class)
+ .build();
+
+ private static Option QUEUE_OPTION = Option.builder("queue")
+ .required()
+ .longOpt("queue")
+ .desc("The Cloud Tasks queue.")
+ .hasArg()
+ .argName("queue")
+ .type(String.class)
+ .build();
+
+ private static Option LOCATION_OPTION = Option.builder("location")
+ .required()
+ .longOpt("location")
+ .desc("The region in which your queue is running.")
+ .hasArg()
+ .argName("location")
+ .type(String.class)
+ .build();
+
+ public static void main(String... args) throws Exception {
+ Options options = new Options();
+ options.addOption(PROJECT_ID_OPTION);
+ options.addOption(QUEUE_OPTION);
+ options.addOption(LOCATION_OPTION);
+
+ if (args.length == 0) {
+ printUsage(options);
+ return;
+ }
+
+ CommandLineParser parser = new DefaultParser();
+ CommandLine params;
+ try {
+ params = parser.parse(options, args);
+ } catch (ParseException e) {
+ System.err.println("Invalid command line: " + e.getMessage());
+ printUsage(options);
+ return;
+ }
+
+ String projectId;
+ if (params.hasOption("project-id")) {
+ projectId = params.getOptionValue("project-id");
+ } else {
+ projectId = System.getenv(GGOGLE_CLOUD_PROJECT_KEY);
+ }
+ if (Strings.isNullOrEmpty(projectId)) {
+ printUsage(options);
+ return;
+ }
+
+ String queue = params.getOptionValue(QUEUE_OPTION.getOpt());
+ String location = params.getOptionValue(LOCATION_OPTION.getOpt());
+
+ switch (args[0]) {
+ default:
+ printUsage(options);
+ break;
+ case "create-task":
+ createTask(projectId, queue, location);
+ break;
+ case "lease-and-ack-task":
+ pullAndAckTask(projectId, queue, location);
+ break;
+ }
+ }
+
+ // [START cloud_tasks_create_task]
+ private static void createTask(String projectId, String queueName, String location)
+ throws IOException {
+ try (CloudTasksClient client = CloudTasksClient.create()) {
+ Task.Builder taskBuilder = Task
+ .newBuilder()
+ .setPullMessage(PullMessage.newBuilder().setPayload(
+ ByteString.copyFrom("a message for recipient", Charset.defaultCharset())));
+
+ Task newTask = client.createTask(CreateTaskRequest
+ .newBuilder()
+ .setParent(QueueName.of(projectId, location, queueName).toString())
+ .setTask(taskBuilder)
+ .build());
+ System.out.println("Task created: " + newTask.getName());
+ }
+ }
+ // [END cloud_tasks_create_task]
+
+ // [START cloud_tasks_lease_and_acknowledge_task]
+ private static void pullAndAckTask(String projectId, String queueName, String location) {
+ try (CloudTasksClient client = CloudTasksClient.create()) {
+ LeaseTasksRequest leaseReq = LeaseTasksRequest.newBuilder()
+ .setParent(QueueName.of(projectId, location, queueName).toString())
+ .setLeaseDuration(Duration.newBuilder().setSeconds(600))
+ .setMaxTasks(1)
+ .setResponseView(Task.View.FULL)
+ .build();
+ LeaseTasksResponse response = client.leaseTasks(leaseReq);
+ if (response.getTasksCount() == 0) {
+ System.out.println("No tasks found in queue.");
+ return;
+ }
+ Task task = response.getTasksList().get(0);
+ System.out.println("Leased task: " + task.getName());
+ AcknowledgeTaskRequest ackRequest = AcknowledgeTaskRequest
+ .newBuilder()
+ .setName(task.getName())
+ .setScheduleTime(task.getScheduleTime())
+ .build();
+ client.acknowledgeTask(ackRequest);
+ System.out.println("Acknowledged task: " + task.getName());
+ } catch (Exception e) {
+ System.out.println("Exception during PullAndAckTask: " + e.getMessage());
+ }
+ }
+ // [END cloud_tasks_lease_and_acknowledge_task]
+
+ private static void printUsage(Options options) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp("client",
+ "A simple Cloud Tasks command line client.", options, "", true);
+ }
+}
+// [END tasks_quickstart]
diff --git a/tasks/src/test/java/com/example/QuickstartIT.java b/tasks/src/test/java/com/example/QuickstartIT.java
new file mode 100644
index 00000000000..d0e21e076b0
--- /dev/null
+++ b/tasks/src/test/java/com/example/QuickstartIT.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * 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;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.google.cloud.tasks.v2beta2.CloudTasksClient;
+import com.google.cloud.tasks.v2beta2.QueueName;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Integration (system) tests for {@link Quickstart}.
+ */
+@RunWith(JUnit4.class)
+@SuppressWarnings("checkstyle:abbreviationaswordinname")
+public class QuickstartIT {
+ private static String queue_name = "my-pull-queue";
+ private static String location = "us-east1";
+ private ByteArrayOutputStream bout;
+ private PrintStream out;
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(bout);
+ System.setOut(out);
+ }
+
+ // Purge the task queue when tests done.
+ @AfterClass
+ public static void tearDownClass() throws IOException {
+ try (CloudTasksClient client = CloudTasksClient.create()) {
+ client.purgeQueue(QueueName.of(System.getenv("GOOGLE_CLOUD_PROJECT"), location, queue_name));
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ bout = new ByteArrayOutputStream();
+ out = new PrintStream(bout);
+ System.setOut(out);
+ }
+
+ @Test
+ public void createTaskTest() throws Exception {
+ Quickstart.main("create-task", "--queue", queue_name, "--location", location);
+ assertThat(bout.toString()).contains("Task created: ");
+ }
+
+ @Test
+ public void leaseAndAcknowledge() throws Exception {
+ Quickstart.main("lease-and-ack-task", "--queue", queue_name, "--location", location);
+ assertThat(bout.toString()).contains("Leased task: ");
+ assertThat(bout.toString()).contains("Acknowledged task: ");
+ }
+}