From c0cc36a3de77633d30bd77acb6cca9718d545342 Mon Sep 17 00:00:00 2001 From: pjgg Date: Sun, 4 Aug 2019 11:51:14 +0200 Subject: [PATCH] Implement activity helpers As a developer I would like to be able to define or even implements commons methods (default methods) that could be extended by an activity method interface. This methods, should not be consider as an activity method. This feature will gives an upper level of abstraction allowing commons behavior between activity methods. In order to support this feature, an annotation named 'ActivityHelper' was developed. You must add this annotation to all those interfaces that gives some kind of support or gives an upper level of abstraction to an activity method interface. --- CONTRIBUTING.md | 3 +- .../uber/cadence/activity/ActivityHelper.java | 34 +++++++++++ .../uber/cadence/client/WorkflowClient.java | 4 +- .../sync/POJOActivityTaskHandler.java | 8 +++ .../internal/testing/WorkflowTestingTest.java | 60 +++++++++++++++++++ 5 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/uber/cadence/activity/ActivityHelper.java diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 000d8fdfa..859892b2c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,8 +7,9 @@ This doc is intended for contributors to `cadence-java-client` (hopefully that's ## Development Environment * Java 8. -* Gradle build tool +* Gradle build tool 4.5.1 * Docker +* Apache Thrift 0.9.3 ## Licence headers diff --git a/src/main/java/com/uber/cadence/activity/ActivityHelper.java b/src/main/java/com/uber/cadence/activity/ActivityHelper.java new file mode 100644 index 000000000..ec143345b --- /dev/null +++ b/src/main/java/com/uber/cadence/activity/ActivityHelper.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not + * use this file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.uber.cadence.activity; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that this class is an activity helper. This annotation applies only to parent activity + * interfaces, where activity methods are defined. Not required. By default all methods owned by an + * Activity, are {@link ActivityMethod}, even if is not annotated. Use it to avoid this behavior and + * be able to define or implement some commons behavior that could be extended by an Activity Method + * interface. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ActivityHelper {} diff --git a/src/main/java/com/uber/cadence/client/WorkflowClient.java b/src/main/java/com/uber/cadence/client/WorkflowClient.java index bc503728a..412650c4e 100644 --- a/src/main/java/com/uber/cadence/client/WorkflowClient.java +++ b/src/main/java/com/uber/cadence/client/WorkflowClient.java @@ -729,8 +729,6 @@ static CompletableFuture execute( return WorkflowClientInternal.execute(workflow, arg1, arg2, arg3, arg4, arg5, arg6); } - /** - * Closes the workflow client and the underlying IWorkflowService when this method is called. - */ + /** Closes the workflow client and the underlying IWorkflowService when this method is called. */ void close(); } diff --git a/src/main/java/com/uber/cadence/internal/sync/POJOActivityTaskHandler.java b/src/main/java/com/uber/cadence/internal/sync/POJOActivityTaskHandler.java index dfb1c8b60..9bb382165 100644 --- a/src/main/java/com/uber/cadence/internal/sync/POJOActivityTaskHandler.java +++ b/src/main/java/com/uber/cadence/internal/sync/POJOActivityTaskHandler.java @@ -22,6 +22,7 @@ import com.uber.cadence.PollForActivityTaskResponse; import com.uber.cadence.RespondActivityTaskCompletedRequest; import com.uber.cadence.RespondActivityTaskFailedRequest; +import com.uber.cadence.activity.ActivityHelper; import com.uber.cadence.activity.ActivityMethod; import com.uber.cadence.client.ActivityCancelledException; import com.uber.cadence.common.MethodRetry; @@ -92,9 +93,16 @@ private void addActivityImplementation( if (i.getType().getTypeName().startsWith("org.mockito")) { continue; } + for (Method method : i.getRawType().getMethods()) { ActivityMethod annotation = method.getAnnotation(ActivityMethod.class); String activityType; + + ActivityHelper helper = i.getRawType().getAnnotation(ActivityHelper.class); + if (helper != null) { + continue; + } + if (annotation != null && !annotation.name().isEmpty()) { activityType = annotation.name(); } else { diff --git a/src/test/java/com/uber/cadence/internal/testing/WorkflowTestingTest.java b/src/test/java/com/uber/cadence/internal/testing/WorkflowTestingTest.java index a1843eef3..fdb4d7f9e 100644 --- a/src/test/java/com/uber/cadence/internal/testing/WorkflowTestingTest.java +++ b/src/test/java/com/uber/cadence/internal/testing/WorkflowTestingTest.java @@ -36,6 +36,7 @@ import com.uber.cadence.WorkflowExecution; import com.uber.cadence.WorkflowExecutionInfo; import com.uber.cadence.activity.Activity; +import com.uber.cadence.activity.ActivityHelper; import com.uber.cadence.activity.ActivityMethod; import com.uber.cadence.activity.ActivityOptions; import com.uber.cadence.client.WorkflowClient; @@ -151,6 +152,53 @@ public void testFailure() { } } + @ActivityHelper + public interface TestParentActivity { + String execute(String input); + } + + public interface TestChild1Activity extends TestParentActivity { + + @ActivityMethod(scheduleToCloseTimeoutSeconds = 3600) + @Override + String execute(String input); + } + + public interface TestChild2Activity extends TestParentActivity { + + @ActivityMethod(scheduleToCloseTimeoutSeconds = 3600) + @Override + String execute(String input); + } + + private static class ActivityChild1Impl implements TestChild1Activity { + + @Override + public String execute(String input) { + return Activity.getTask().getActivityType() + "-" + input; + } + } + + private static class ActivityChild2Impl implements TestChild2Activity { + + @Override + public String execute(String input) { + return Activity.getTask().getActivityType() + "-" + input; + } + } + + @Test + public void testChildActivity() { + Worker worker = testEnvironment.newWorker(TASK_LIST); + worker.registerWorkflowImplementationTypes(ChildActivityWorkflow.class); + worker.registerActivitiesImplementations(new ActivityChild1Impl(), new ActivityChild2Impl()); + testEnvironment.start(); + WorkflowClient client = testEnvironment.newWorkflowClient(); + TestWorkflow workflow = client.newWorkflowStub(TestWorkflow.class); + String result = workflow.workflow1("input1"); + assertEquals("TestChild1Activity::execute-input1-TestChild2Activity::execute-input1", result); + } + public interface TestActivity { @ActivityMethod(scheduleToCloseTimeoutSeconds = 3600) @@ -176,6 +224,18 @@ public String workflow1(String input) { } } + public static class ChildActivityWorkflow implements TestWorkflow { + + private final TestChild1Activity activity1 = Workflow.newActivityStub(TestChild1Activity.class); + private final TestChild2Activity activity2 = Workflow.newActivityStub(TestChild2Activity.class); + + @Override + public String workflow1(String input) { + Workflow.sleep(Duration.ofHours(1)); // test time skipping + return activity1.execute(input) + "-" + activity2.execute(input); + } + } + @Test public void testActivity() { Worker worker = testEnvironment.newWorker(TASK_LIST);