diff --git a/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml b/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml
index 3ef3eecbd..16df49076 100644
--- a/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml
+++ b/dapr-spring/dapr-spring-boot-autoconfigure/pom.xml
@@ -27,6 +27,12 @@
${project.parent.version}
true
+
+ io.dapr.spring
+ dapr-spring-workflows
+ ${project.parent.version}
+ true
+
org.springframework.boot
spring-boot-starter
diff --git a/dapr-spring/dapr-spring-boot-autoconfigure/src/main/java/io/dapr/spring/boot/autoconfigure/client/DaprClientAutoConfiguration.java b/dapr-spring/dapr-spring-boot-autoconfigure/src/main/java/io/dapr/spring/boot/autoconfigure/client/DaprClientAutoConfiguration.java
index f77683424..7e10c1f8f 100644
--- a/dapr-spring/dapr-spring-boot-autoconfigure/src/main/java/io/dapr/spring/boot/autoconfigure/client/DaprClientAutoConfiguration.java
+++ b/dapr-spring/dapr-spring-boot-autoconfigure/src/main/java/io/dapr/spring/boot/autoconfigure/client/DaprClientAutoConfiguration.java
@@ -16,12 +16,17 @@ package io.dapr.spring.boot.autoconfigure.client;
import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;
import io.dapr.config.Properties;
+import io.dapr.workflows.client.DaprWorkflowClient;
+import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
+import java.util.HashMap;
+import java.util.Map;
+
@AutoConfiguration
@ConditionalOnClass(DaprClient.class)
@EnableConfigurationProperties(DaprClientProperties.class)
@@ -58,4 +63,29 @@ public class DaprClientAutoConfiguration {
return daprClientBuilder.build();
}
+ @Bean
+ @ConditionalOnMissingBean
+ DaprWorkflowClient daprWorkflowClient(DaprConnectionDetails daprConnectionDetails) {
+ Properties properties = createPropertiesFromConnectionDetails(daprConnectionDetails);
+ return new DaprWorkflowClient(properties);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ WorkflowRuntimeBuilder daprWorkflowRuntimeBuilder(DaprConnectionDetails daprConnectionDetails) {
+ Properties properties = createPropertiesFromConnectionDetails(daprConnectionDetails);
+ return new WorkflowRuntimeBuilder(properties);
+ }
+
+ private Properties createPropertiesFromConnectionDetails(DaprConnectionDetails daprConnectionDetails) {
+ final Map propertyOverrides = new HashMap<>();
+ propertyOverrides.put(Properties.HTTP_ENDPOINT.getName(), daprConnectionDetails.httpEndpoint());
+ propertyOverrides.put(Properties.HTTP_PORT.getName(), String.valueOf(daprConnectionDetails.httpPort()));
+ propertyOverrides.put(Properties.GRPC_ENDPOINT.getName(), daprConnectionDetails.grpcEndpoint());
+ propertyOverrides.put(Properties.GRPC_PORT.getName(), String.valueOf(daprConnectionDetails.grpcPort()));
+ return new Properties(propertyOverrides);
+ }
+
+
+
}
diff --git a/dapr-spring/dapr-spring-boot-autoconfigure/src/test/java/io/dapr/spring/boot/autoconfigure/client/DaprWorkflowsRegistrationTests.java b/dapr-spring/dapr-spring-boot-autoconfigure/src/test/java/io/dapr/spring/boot/autoconfigure/client/DaprWorkflowsRegistrationTests.java
new file mode 100644
index 000000000..78a99cc34
--- /dev/null
+++ b/dapr-spring/dapr-spring-boot-autoconfigure/src/test/java/io/dapr/spring/boot/autoconfigure/client/DaprWorkflowsRegistrationTests.java
@@ -0,0 +1,44 @@
+package io.dapr.spring.boot.autoconfigure.client;
+
+import io.dapr.spring.boot.autoconfigure.client.workflows.TestActivity;
+import io.dapr.spring.boot.autoconfigure.client.workflows.TestWorkflow;
+import io.dapr.workflows.client.DaprWorkflowClient;
+import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+@SpringBootTest(classes = {WorkflowTestApplication.class, DaprClientAutoConfiguration.class, TestActivity.class, TestWorkflow.class})
+public class DaprWorkflowsRegistrationTests {
+
+ @Autowired
+ private DaprWorkflowClient daprWorkflowClient;
+
+ @Autowired
+ private WorkflowRuntimeBuilder workflowRuntimeBuilder;
+
+ @Autowired
+ private TestActivity testActivity;
+
+ @Autowired
+ private TestWorkflow testWorkflow;
+
+ @Test
+ public void testWorkflowInjection(){
+
+ //I cannot test here if the client works, as it needs the runtime
+ assertNotNull(daprWorkflowClient);
+
+ //@TODO: there is no way to assert the runtime and its registered workflows and activities
+ assertNotNull(workflowRuntimeBuilder);
+
+ //Check that both Activities and Workflows are managed beans
+ assertNotNull(testActivity);
+ assertNotNull(testWorkflow);
+ assertNotNull(testActivity.getRestTemplate());
+ assertNotNull(testWorkflow.getRestTemplate());
+
+ }
+}
diff --git a/dapr-spring/dapr-spring-boot-autoconfigure/src/test/java/io/dapr/spring/boot/autoconfigure/client/WorkflowTestApplication.java b/dapr-spring/dapr-spring-boot-autoconfigure/src/test/java/io/dapr/spring/boot/autoconfigure/client/WorkflowTestApplication.java
new file mode 100644
index 000000000..2f9fc27f4
--- /dev/null
+++ b/dapr-spring/dapr-spring-boot-autoconfigure/src/test/java/io/dapr/spring/boot/autoconfigure/client/WorkflowTestApplication.java
@@ -0,0 +1,24 @@
+package io.dapr.spring.boot.autoconfigure.client;
+
+import io.dapr.spring.workflows.config.EnableDaprWorkflows;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+@SpringBootApplication
+@EnableDaprWorkflows
+public class WorkflowTestApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(WorkflowTestApplication.class, args);
+ }
+
+ @Configuration
+ static class Config {
+ @Bean
+ RestTemplate restTemplate(){
+ return new RestTemplate();
+ }
+ }
+}
diff --git a/dapr-spring/dapr-spring-boot-autoconfigure/src/test/java/io/dapr/spring/boot/autoconfigure/client/workflows/TestActivity.java b/dapr-spring/dapr-spring-boot-autoconfigure/src/test/java/io/dapr/spring/boot/autoconfigure/client/workflows/TestActivity.java
new file mode 100644
index 000000000..67e6715f0
--- /dev/null
+++ b/dapr-spring/dapr-spring-boot-autoconfigure/src/test/java/io/dapr/spring/boot/autoconfigure/client/workflows/TestActivity.java
@@ -0,0 +1,21 @@
+package io.dapr.spring.boot.autoconfigure.client.workflows;
+
+import io.dapr.workflows.runtime.WorkflowActivity;
+import io.dapr.workflows.runtime.WorkflowActivityContext;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.client.RestTemplate;
+
+public class TestActivity implements WorkflowActivity {
+
+ @Autowired
+ private RestTemplate restTemplate;
+
+ @Override
+ public Object run(WorkflowActivityContext ctx) {
+ return "OK";
+ }
+
+ public RestTemplate getRestTemplate() {
+ return restTemplate;
+ }
+}
diff --git a/dapr-spring/dapr-spring-boot-autoconfigure/src/test/java/io/dapr/spring/boot/autoconfigure/client/workflows/TestWorkflow.java b/dapr-spring/dapr-spring-boot-autoconfigure/src/test/java/io/dapr/spring/boot/autoconfigure/client/workflows/TestWorkflow.java
new file mode 100644
index 000000000..97e94b1e7
--- /dev/null
+++ b/dapr-spring/dapr-spring-boot-autoconfigure/src/test/java/io/dapr/spring/boot/autoconfigure/client/workflows/TestWorkflow.java
@@ -0,0 +1,23 @@
+package io.dapr.spring.boot.autoconfigure.client.workflows;
+
+import io.dapr.workflows.Workflow;
+import io.dapr.workflows.WorkflowStub;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.client.RestTemplate;
+
+public class TestWorkflow extends Workflow {
+
+ @Autowired
+ private RestTemplate restTemplate;
+
+ @Override
+ public WorkflowStub create() {
+ return ctx -> {
+ ctx.callActivity(TestActivity.class.getName(), null).await();
+ };
+ }
+
+ public RestTemplate getRestTemplate() {
+ return restTemplate;
+ }
+}
diff --git a/dapr-spring/dapr-spring-boot-starters/dapr-spring-boot-starter/pom.xml b/dapr-spring/dapr-spring-boot-starters/dapr-spring-boot-starter/pom.xml
index e2ce4bf1b..682ce450e 100644
--- a/dapr-spring/dapr-spring-boot-starters/dapr-spring-boot-starter/pom.xml
+++ b/dapr-spring/dapr-spring-boot-starters/dapr-spring-boot-starter/pom.xml
@@ -40,6 +40,11 @@
dapr-spring-messaging
${project.parent.version}
+
+ io.dapr.spring
+ dapr-spring-workflows
+ ${project.parent.version}
+
diff --git a/dapr-spring/dapr-spring-workflows/pom.xml b/dapr-spring/dapr-spring-workflows/pom.xml
new file mode 100644
index 000000000..1b9776943
--- /dev/null
+++ b/dapr-spring/dapr-spring-workflows/pom.xml
@@ -0,0 +1,24 @@
+
+
+ 4.0.0
+
+
+ io.dapr.spring
+ dapr-spring-parent
+ 0.14.0-SNAPSHOT
+
+
+ dapr-spring-workflows
+ dapr-spring-workflows
+ Dapr Spring Workflows
+ jar
+
+
+
+ io.dapr
+ dapr-sdk-workflows
+ ${project.version}
+
+
+
diff --git a/dapr-spring/dapr-spring-workflows/src/main/java/io/dapr/spring/workflows/config/DaprWorkflowsConfiguration.java b/dapr-spring/dapr-spring-workflows/src/main/java/io/dapr/spring/workflows/config/DaprWorkflowsConfiguration.java
new file mode 100644
index 000000000..35753fb47
--- /dev/null
+++ b/dapr-spring/dapr-spring-workflows/src/main/java/io/dapr/spring/workflows/config/DaprWorkflowsConfiguration.java
@@ -0,0 +1,55 @@
+package io.dapr.spring.workflows.config;
+
+import io.dapr.workflows.Workflow;
+import io.dapr.workflows.runtime.WorkflowActivity;
+import io.dapr.workflows.runtime.WorkflowRuntime;
+import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Map;
+
+@Configuration
+public class DaprWorkflowsConfiguration implements ApplicationContextAware {
+ private static final Logger LOGGER = LoggerFactory.getLogger(DaprWorkflowsConfiguration.class);
+
+ private WorkflowRuntimeBuilder workflowRuntimeBuilder;
+
+ public DaprWorkflowsConfiguration(WorkflowRuntimeBuilder workflowRuntimeBuilder) {
+ this.workflowRuntimeBuilder = workflowRuntimeBuilder;
+ }
+
+ /**
+ * Register workflows and activities to the workflowRuntimeBuilder.
+ * @param applicationContext Spring Application Context
+ */
+ private void registerWorkflowsAndActivities(ApplicationContext applicationContext) {
+ LOGGER.info("Registering Dapr Workflows and Activities");
+ Map workflowBeans = applicationContext.getBeansOfType(Workflow.class);
+ for (Workflow w : workflowBeans.values()) {
+ LOGGER.info("Dapr Workflow: '{}' registered", w.getClass().getName());
+ workflowRuntimeBuilder.registerWorkflow(w.getClass());
+ }
+
+ Map workflowActivitiesBeans = applicationContext.getBeansOfType(WorkflowActivity.class);
+ for (WorkflowActivity a : workflowActivitiesBeans.values()) {
+ LOGGER.info("Dapr Workflow Activity: '{}' registered", a.getClass().getName());
+ workflowRuntimeBuilder.registerActivity(a.getClass());
+ }
+
+ try (WorkflowRuntime runtime = workflowRuntimeBuilder.build()) {
+ LOGGER.info("Starting workflow runtime ... ");
+ runtime.start(false);
+ }
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ registerWorkflowsAndActivities(applicationContext);
+ }
+}
diff --git a/dapr-spring/dapr-spring-workflows/src/main/java/io/dapr/spring/workflows/config/EnableDaprWorkflows.java b/dapr-spring/dapr-spring-workflows/src/main/java/io/dapr/spring/workflows/config/EnableDaprWorkflows.java
new file mode 100644
index 000000000..e5572f6f7
--- /dev/null
+++ b/dapr-spring/dapr-spring-workflows/src/main/java/io/dapr/spring/workflows/config/EnableDaprWorkflows.java
@@ -0,0 +1,16 @@
+package io.dapr.spring.workflows.config;
+
+
+import org.springframework.context.annotation.Import;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Retention(RUNTIME)
+@Target(TYPE)
+@Import(DaprWorkflowsConfiguration.class)
+public @interface EnableDaprWorkflows {
+}
diff --git a/dapr-spring/pom.xml b/dapr-spring/pom.xml
index 553c9aab4..ffbb736f3 100644
--- a/dapr-spring/pom.xml
+++ b/dapr-spring/pom.xml
@@ -20,6 +20,7 @@
dapr-spring-data
dapr-spring-messaging
+ dapr-spring-workflows
dapr-spring-boot-autoconfigure
dapr-spring-boot-tests
dapr-spring-boot-starters/dapr-spring-boot-starter