diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/workflows/DaprWorkflowsIT.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/workflows/DaprWorkflowsIT.java index 19fe8f986..4994c237c 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/workflows/DaprWorkflowsIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/workflows/DaprWorkflowsIT.java @@ -147,6 +147,27 @@ public void testSuspendAndResumeWorkflows() throws Exception { } + @Test + public void testNamedActivitiesWorkflows() throws Exception { + TestWorkflowPayload payload = new TestWorkflowPayload(new ArrayList<>()); + String instanceId = workflowClient.scheduleNewWorkflow(TestNamedActivitiesWorkflow.class, payload); + + workflowClient.waitForInstanceStart(instanceId, Duration.ofSeconds(10), false); + + Duration timeout = Duration.ofSeconds(10); + WorkflowInstanceStatus workflowStatus = workflowClient.waitForInstanceCompletion(instanceId, timeout, true); + + assertNotNull(workflowStatus); + + TestWorkflowPayload workflowOutput = deserialize(workflowStatus.getSerializedOutput()); + + assertEquals(3, workflowOutput.getPayloads().size()); + assertEquals("First Activity", workflowOutput.getPayloads().get(0)); + assertEquals("First Activity", workflowOutput.getPayloads().get(1)); + assertEquals("Second Activity", workflowOutput.getPayloads().get(2)); + + assertEquals(instanceId, workflowOutput.getWorkflowId()); + } private TestWorkflowPayload deserialize(String value) throws JsonProcessingException { return OBJECT_MAPPER.readValue(value, TestWorkflowPayload.class); diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/workflows/TestNamedActivitiesWorkflow.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/workflows/TestNamedActivitiesWorkflow.java new file mode 100644 index 000000000..c4b85ae65 --- /dev/null +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/workflows/TestNamedActivitiesWorkflow.java @@ -0,0 +1,45 @@ +/* + * Copyright 2025 The Dapr Authors + * 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 io.dapr.it.testcontainers.workflows; + +import io.dapr.workflows.Workflow; +import io.dapr.workflows.WorkflowStub; +import org.slf4j.Logger; + +public class TestNamedActivitiesWorkflow implements Workflow { + + @Override + public WorkflowStub create() { + return ctx -> { + Logger logger = ctx.getLogger(); + String instanceId = ctx.getInstanceId(); + logger.info("Starting Workflow: " + ctx.getName()); + logger.info("Instance ID: " + instanceId); + logger.info("Current Orchestration Time: " + ctx.getCurrentInstant()); + + TestWorkflowPayload workflowPayload = ctx.getInput(TestWorkflowPayload.class); + workflowPayload.setWorkflowId(instanceId); + + var payloadAfterA = ctx.callActivity("a", workflowPayload, TestWorkflowPayload.class).await(); + + var payloadAfterB = ctx.callActivity("b", payloadAfterA, TestWorkflowPayload.class).await(); + + var payloadAfteC = ctx.callActivity("c", payloadAfterB, TestWorkflowPayload.class) + .await(); + + ctx.complete(payloadAfteC); + }; + } + +} diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/workflows/TestWorkflowsConfiguration.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/workflows/TestWorkflowsConfiguration.java index 78f749e9d..e71bba158 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/workflows/TestWorkflowsConfiguration.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/workflows/TestWorkflowsConfiguration.java @@ -56,8 +56,14 @@ public WorkflowRuntimeBuilder workflowRuntimeBuilder( WorkflowRuntimeBuilder builder = new WorkflowRuntimeBuilder(new Properties(overrides)); builder.registerWorkflow(TestWorkflow.class); + builder.registerWorkflow(TestNamedActivitiesWorkflow.class); + builder.registerActivity(FirstActivity.class); builder.registerActivity(SecondActivity.class); + builder.registerActivity("a",FirstActivity.class); + builder.registerActivity("b",FirstActivity.class); + builder.registerActivity("c", new SecondActivity()); + return builder; } diff --git a/sdk-workflows/src/main/java/io/dapr/workflows/runtime/WorkflowActivityClassWrapper.java b/sdk-workflows/src/main/java/io/dapr/workflows/runtime/WorkflowActivityClassWrapper.java index 2c4c5b17a..bbe97b2d1 100644 --- a/sdk-workflows/src/main/java/io/dapr/workflows/runtime/WorkflowActivityClassWrapper.java +++ b/sdk-workflows/src/main/java/io/dapr/workflows/runtime/WorkflowActivityClassWrapper.java @@ -30,19 +30,28 @@ public class WorkflowActivityClassWrapper implements /** * Constructor for WorkflowActivityWrapper. * + * @param name Name of the activity to wrap. * @param clazz Class of the activity to wrap. */ - public WorkflowActivityClassWrapper(Class clazz) { - this.name = clazz.getCanonicalName(); + public WorkflowActivityClassWrapper(String name, Class clazz) { + this.name = name; try { this.activityConstructor = clazz.getDeclaredConstructor(); } catch (NoSuchMethodException e) { throw new RuntimeException( - String.format("No constructor found for activity class '%s'.", this.name), e - ); + String.format("No constructor found for activity class '%s'.", this.name), e); } } + /** + * Constructor for WorkflowActivityWrapper. + * + * @param clazz Class of the activity to wrap. + */ + public WorkflowActivityClassWrapper(Class clazz) { + this(clazz.getCanonicalName(), clazz); + } + @Override public String getName() { return name; @@ -53,13 +62,12 @@ public TaskActivity create() { return ctx -> { Object result; T activity; - + try { activity = this.activityConstructor.newInstance(); } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new RuntimeException( - String.format("Unable to instantiate instance of activity class '%s'", this.name), e - ); + String.format("Unable to instantiate instance of activity class '%s'", this.name), e); } result = activity.run(new DefaultWorkflowActivityContext(ctx)); diff --git a/sdk-workflows/src/main/java/io/dapr/workflows/runtime/WorkflowActivityInstanceWrapper.java b/sdk-workflows/src/main/java/io/dapr/workflows/runtime/WorkflowActivityInstanceWrapper.java index 537427318..973a90ef9 100644 --- a/sdk-workflows/src/main/java/io/dapr/workflows/runtime/WorkflowActivityInstanceWrapper.java +++ b/sdk-workflows/src/main/java/io/dapr/workflows/runtime/WorkflowActivityInstanceWrapper.java @@ -27,13 +27,23 @@ public class WorkflowActivityInstanceWrapper impleme /** * Constructor for WorkflowActivityWrapper. * + * @param name Name of the activity to wrap. * @param instance Instance of the activity to wrap. */ - public WorkflowActivityInstanceWrapper(T instance) { - this.name = instance.getClass().getCanonicalName(); + public WorkflowActivityInstanceWrapper(String name, T instance) { + this.name = name; this.activity = instance; } + /** + * Constructor for WorkflowActivityWrapper. + * + * @param instance Instance of the activity to wrap. + */ + public WorkflowActivityInstanceWrapper(T instance) { + this(instance.getClass().getCanonicalName(), instance); + } + @Override public String getName() { return name; diff --git a/sdk-workflows/src/main/java/io/dapr/workflows/runtime/WorkflowRuntimeBuilder.java b/sdk-workflows/src/main/java/io/dapr/workflows/runtime/WorkflowRuntimeBuilder.java index 7f1147a0d..23d9884ae 100644 --- a/sdk-workflows/src/main/java/io/dapr/workflows/runtime/WorkflowRuntimeBuilder.java +++ b/sdk-workflows/src/main/java/io/dapr/workflows/runtime/WorkflowRuntimeBuilder.java @@ -147,11 +147,23 @@ public WorkflowRuntimeBuilder registerWorkflow(T instance) * @return the WorkflowRuntimeBuilder */ public WorkflowRuntimeBuilder registerActivity(Class clazz) { - this.builder.addActivity(new WorkflowActivityClassWrapper<>(clazz)); - this.activitySet.add(clazz.getCanonicalName()); - this.activities.add(clazz.getSimpleName()); + return registerActivity(clazz.getCanonicalName(), clazz); + } - this.logger.info("Registered Activity: {}", clazz.getSimpleName()); + /** + * Registers an Activity object. + * + * @param any WorkflowActivity type + * @param name Name of the activity to register. + * @param clazz Class of the activity to register. + * @return the WorkflowRuntimeBuilder + */ + public WorkflowRuntimeBuilder registerActivity(String name, Class clazz) { + this.builder.addActivity(new WorkflowActivityClassWrapper<>(name, clazz)); + this.activitySet.add(name); + this.activities.add(name); + + this.logger.info("Registered Activity: {}", name); return this; } @@ -164,13 +176,23 @@ public WorkflowRuntimeBuilder registerActivity(Clas * @return the WorkflowRuntimeBuilder */ public WorkflowRuntimeBuilder registerActivity(T instance) { - Class clazz = (Class) instance.getClass(); + return this.registerActivity(instance.getClass().getCanonicalName(), instance); + } - this.builder.addActivity(new WorkflowActivityInstanceWrapper<>(instance)); - this.activitySet.add(clazz.getCanonicalName()); - this.activities.add(clazz.getSimpleName()); + /** + * Registers an Activity object. + * + * @param any WorkflowActivity type + * @param name Name of the activity to register. + * @param instance the class instance being registered + * @return the WorkflowRuntimeBuilder + */ + public WorkflowRuntimeBuilder registerActivity(String name, T instance) { + this.builder.addActivity(new WorkflowActivityInstanceWrapper<>(name, instance)); + this.activitySet.add(name); + this.activities.add(name); - this.logger.info("Registered Activity: {}", clazz.getSimpleName()); + this.logger.info("Registered Activity: {}", name); return this; } diff --git a/sdk-workflows/src/test/java/io/dapr/workflows/runtime/WorkflowActivityClassWrapperTest.java b/sdk-workflows/src/test/java/io/dapr/workflows/runtime/WorkflowActivityClassWrapperTest.java index 76a7e07af..687968e22 100644 --- a/sdk-workflows/src/test/java/io/dapr/workflows/runtime/WorkflowActivityClassWrapperTest.java +++ b/sdk-workflows/src/test/java/io/dapr/workflows/runtime/WorkflowActivityClassWrapperTest.java @@ -22,7 +22,7 @@ public Object run(WorkflowActivityContext ctx) { @Test public void getName() { - WorkflowActivityClassWrapper wrapper = new WorkflowActivityClassWrapper<>(TestActivity.class); + WorkflowActivityClassWrapper wrapper = new WorkflowActivityClassWrapper<>( TestActivity.class); assertEquals( "io.dapr.workflows.runtime.WorkflowActivityClassWrapperTest.TestActivity", diff --git a/sdk-workflows/src/test/java/io/dapr/workflows/runtime/WorkflowRuntimeBuilderTest.java b/sdk-workflows/src/test/java/io/dapr/workflows/runtime/WorkflowRuntimeBuilderTest.java index 2b3341fbf..c9e2a5d78 100644 --- a/sdk-workflows/src/test/java/io/dapr/workflows/runtime/WorkflowRuntimeBuilderTest.java +++ b/sdk-workflows/src/test/java/io/dapr/workflows/runtime/WorkflowRuntimeBuilderTest.java @@ -94,6 +94,6 @@ public void loggingOutputTest() { .info(eq("Registered Workflow: {}"), eq("TestWorkflow")); verify(testLogger, times(1)) - .info(eq("Registered Activity: {}"), eq("TestActivity")); + .info(eq("Registered Activity: {}"), eq( "io.dapr.workflows.runtime.WorkflowRuntimeBuilderTest.TestActivity")); } }