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: "); + } +}