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/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);