diff --git a/workflows/java/sdk/README.md b/workflows/java/sdk/README.md
new file mode 100644
index 000000000..2566ec1ae
--- /dev/null
+++ b/workflows/java/sdk/README.md
@@ -0,0 +1,109 @@
+# Dapr workflows
+
+In this quickstart, you'll create a simple console application to demonstrate Dapr's workflow programming model and the workflow management API. The console app starts and manages the lifecycle of a workflow that stores and retrieves data in a state store.
+
+This quickstart includes one project:
+
+- Java console app `order-processor`
+
+The quickstart contains 1 workflow to simulate purchasing items from a store, and 5 unique activities within the workflow. These 5 activities are as follows:
+
+- NotifyActivity: This activity utilizes a logger to print out messages throughout the workflow. These messages notify the user when there is insufficient inventory, their payment couldn't be processed, and more.
+- ReserveInventoryActivity: This activity checks the state store to ensure that there is enough inventory present for purchase.
+- RequestApprovalActivity: This activity requests approval for orders over a certain threshold
+- ProcessPaymentActivity: This activity is responsible for processing and authorizing the payment.
+- UpdateInventoryActivity: This activity updates the state store with the new remaining inventory value.
+
+### Run the order processor workflow
+
+1. Open a new terminal window and navigate to `order-processor` directory:
+
+
+
+```bash
+cd ./order-processor
+mvn clean install
+```
+
+
+2. Run the console app with Dapr:
+
+
+
+```bash
+cd ./order-processor
+dapr run --app-id WorkflowConsoleApp --resources-path ../../../components/ --dapr-grpc-port 50001 -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar io.dapr.quickstarts.workflows.WorkflowConsoleApp
+```
+
+
+
+3. Expected output
+
+
+```
+== APP == *** Welcome to the Dapr Workflow console app sample!
+== APP == *** Using this app, you can place orders that start workflows.
+== APP == Start workflow runtime
+== APP == Sep 20, 2023 8:38:30 AM com.microsoft.durabletask.DurableTaskGrpcWorker startAndBlock
+== APP == INFO: Durable Task worker is connecting to sidecar at 127.0.0.1:50001.
+== APP == ==========Begin the purchase of item:==========
+== APP == Starting order workflow, purchasing 10 of cars
+== APP == scheduled new workflow instance of OrderProcessingWorkflow with instance ID: 95d33f7c-3af8-4960-ba11-4ecea83b0509
+== APP == [Thread-0] INFO io.dapr.workflows.WorkflowContext - Starting Workflow: io.dapr.quickstarts.workflows.OrderProcessingWorkflow
+== APP == [Thread-0] INFO io.dapr.workflows.WorkflowContext - Instance ID(order ID): 95d33f7c-3af8-4960-ba11-4ecea83b0509
+== APP == [Thread-0] INFO io.dapr.workflows.WorkflowContext - Current Orchestration Time: 2023-09-20T08:38:33.248Z
+== APP == [Thread-0] INFO io.dapr.workflows.WorkflowContext - Received Order: OrderPayload [itemName=cars, totalCost=150000, quantity=10]
+== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.NotifyActivity - Received Order: OrderPayload [itemName=cars, totalCost=150000, quantity=10]
+== APP == workflow instance 95d33f7c-3af8-4960-ba11-4ecea83b0509 started
+== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.ReserveInventoryActivity - Reserving inventory for order '95d33f7c-3af8-4960-ba11-4ecea83b0509' of 10 cars
+== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.ReserveInventoryActivity - There are 100 cars available for purchase
+== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.ReserveInventoryActivity - Reserved inventory for order '95d33f7c-3af8-4960-ba11-4ecea83b0509' of 10 cars
+== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.RequestApprovalActivity - Requesting approval for order: OrderPayload [itemName=cars, totalCost=150000, quantity=10]
+== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.RequestApprovalActivity - Approved requesting approval for order: OrderPayload [itemName=cars, totalCost=150000, quantity=10]
+== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.ProcessPaymentActivity - Processing payment: 95d33f7c-3af8-4960-ba11-4ecea83b0509 for 10 cars at $150000
+== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.ProcessPaymentActivity - Payment for request ID '95d33f7c-3af8-4960-ba11-4ecea83b0509' processed successfully
+== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.UpdateInventoryActivity - Updating inventory for order '95d33f7c-3af8-4960-ba11-4ecea83b0509' of 10 cars
+== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.UpdateInventoryActivity - Updated inventory for order '95d33f7c-3af8-4960-ba11-4ecea83b0509': there are now 90 cars left in stock
+== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.NotifyActivity - Order completed! : 95d33f7c-3af8-4960-ba11-4ecea83b0509
+== APP == workflow instance 95d33f7c-3af8-4960-ba11-4ecea83b0509 completed, out is: {"processed":true}
+```
+
+### View workflow output with Zipkin
+
+For a more detailed view of the workflow activities (duration, progress etc.), try using Zipkin.
+
+1. Launch Zipkin container - The [openzipkin/zipkin](https://hub.docker.com/r/openzipkin/zipkin/) docker container is launched on running `dapr init`. Check to make sure the container is running. If it's not, launch the Zipkin docker container with the following command.
+
+```bash
+docker run -d -p 9411:9411 openzipkin/zipkin
+```
+
+2. View Traces in Zipkin UI - In your browser go to http://localhost:9411 to view the workflow trace spans in the Zipkin web UI. The order-processor workflow should be viewable with the following output in the Zipkin web UI.
+
+
+
+### What happened?
+
+When you ran `dapr run --app-id WorkflowConsoleApp --resources-path ../../../components/ --dapr-grpc-port 50001 -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar io.dapr.quickstarts.workflows.WorkflowConsoleApp`
+
+1. A unique order ID for the workflow is generated (in the above example, `95d33f7c-3af8-4960-ba11-4ecea83b0509`) and the workflow is scheduled.
+2. The `NotifyActivity` workflow activity sends a notification saying an order for 10 cars has been received.
+3. The `ReserveInventoryActivity` workflow activity checks the inventory data, determines if you can supply the ordered item, and responds with the number of cars in stock.
+4. Your workflow starts and notifies you of its status.
+5. The `RequestApprovalActivity` workflow activity requests approval for order `95d33f7c-3af8-4960-ba11-4ecea83b0509`
+6. The `ProcessPaymentActivity` workflow activity begins processing payment for order `95d33f7c-3af8-4960-ba11-4ecea83b0509` and confirms if successful.
+7. The `UpdateInventoryActivity` workflow activity updates the inventory with the current available cars after the order has been processed.
+8. The `NotifyActivity` workflow activity sends a notification saying that order `95d33f7c-3af8-4960-ba11-4ecea83b0509` has completed and processed.
+9. The workflow terminates as completed and processed.
+
diff --git a/workflows/java/sdk/img/workflow-trace-spans-zipkin.png b/workflows/java/sdk/img/workflow-trace-spans-zipkin.png
new file mode 100644
index 000000000..6564dd4c5
Binary files /dev/null and b/workflows/java/sdk/img/workflow-trace-spans-zipkin.png differ
diff --git a/workflows/java/sdk/makefile b/workflows/java/sdk/makefile
new file mode 100644
index 000000000..e7a8826bf
--- /dev/null
+++ b/workflows/java/sdk/makefile
@@ -0,0 +1,2 @@
+include ../../../docker.mk
+include ../../../validate.mk
\ No newline at end of file
diff --git a/workflows/java/sdk/order-processor/pom.xml b/workflows/java/sdk/order-processor/pom.xml
new file mode 100644
index 000000000..fcf185364
--- /dev/null
+++ b/workflows/java/sdk/order-processor/pom.xml
@@ -0,0 +1,60 @@
+
+
+ 4.0.0
+
+ com.service
+ OrderProcessingService
+ 0.0.1-SNAPSHOT
+ OrderProcessingService
+ Demo for Dapr workflow component
+
+ 11
+ 11
+ 1.6.1
+
+
+
+ io.dapr
+ dapr-sdk-workflows
+ 0.10.0-SNAPSHOT
+
+
+ org.slf4j
+ slf4j-simple
+ 1.7.36
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 2.6.3
+
+
+
+ repackage
+
+
+
+ io.dapr.quickstarts.workflows.WorkflowConsoleApp
+
+
+
+
+
+
+
+
+
+
+ maven-SNAPSHOT
+ https://oss.sonatype.org/content/repositories/snapshots/
+
+ true
+
+
+
+
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/OrderProcessingWorkflow.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/OrderProcessingWorkflow.java
new file mode 100644
index 000000000..79f25c4ad
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/OrderProcessingWorkflow.java
@@ -0,0 +1,111 @@
+package io.dapr.quickstarts.workflows;
+
+import org.slf4j.Logger;
+
+import io.dapr.quickstarts.workflows.activities.NotifyActivity;
+import io.dapr.quickstarts.workflows.activities.ProcessPaymentActivity;
+import io.dapr.quickstarts.workflows.activities.RequestApprovalActivity;
+import io.dapr.quickstarts.workflows.activities.ReserveInventoryActivity;
+import io.dapr.quickstarts.workflows.activities.UpdateInventoryActivity;
+import io.dapr.quickstarts.workflows.models.ApprovalResult;
+import io.dapr.quickstarts.workflows.models.InventoryRequest;
+import io.dapr.quickstarts.workflows.models.InventoryResult;
+import io.dapr.quickstarts.workflows.models.Notification;
+import io.dapr.quickstarts.workflows.models.OrderPayload;
+import io.dapr.quickstarts.workflows.models.OrderResult;
+import io.dapr.quickstarts.workflows.models.PaymentRequest;
+import io.dapr.workflows.Workflow;
+import io.dapr.workflows.WorkflowStub;
+
+public class OrderProcessingWorkflow extends Workflow {
+
+ @Override
+ public WorkflowStub create() {
+ return ctx -> {
+ Logger logger = ctx.getLogger();
+ String orderId = ctx.getInstanceId();
+ logger.info("Starting Workflow: " + ctx.getName());
+ logger.info("Instance ID(order ID): " + orderId);
+ logger.info("Current Orchestration Time: " + ctx.getCurrentInstant());
+
+ OrderPayload order = ctx.getInput(OrderPayload.class);
+ logger.info("Received Order: " + order.toString());
+ OrderResult orderResult = new OrderResult();
+ orderResult.setProcessed(false);
+
+ // Notify the user that an order has come through
+ Notification notification = new Notification();
+ notification.setMessage("Received Order: " + order.toString());
+ ctx.callActivity(NotifyActivity.class.getName(), notification).await();
+
+ // Determine if there is enough of the item available for purchase by checking
+ // the inventory
+ InventoryRequest inventoryRequest = new InventoryRequest();
+ inventoryRequest.setRequestId(orderId);
+ inventoryRequest.setItemName(order.getItemName());
+ inventoryRequest.setQuantity(order.getQuantity());
+ InventoryResult inventoryResult = ctx.callActivity(ReserveInventoryActivity.class.getName(),
+ inventoryRequest, InventoryResult.class).await();
+
+ // If there is insufficient inventory, fail and let the user know
+ if (!inventoryResult.isSuccess()) {
+ notification.setMessage("Insufficient inventory for order : " + order.getItemName());
+ ctx.callActivity(NotifyActivity.class.getName(), notification).await();
+ ctx.complete(orderResult);
+ return;
+ }
+
+ // Require orders over a certain threshold to be approved
+ if (order.getTotalCost() > 5000) {
+ ApprovalResult approvalResult = ctx.callActivity(RequestApprovalActivity.class.getName(),
+ order, ApprovalResult.class).await();
+ if (approvalResult != ApprovalResult.Approved) {
+ notification.setMessage("Order " + order.getItemName() + " was not approved.");
+ ctx.callActivity(NotifyActivity.class.getName(), notification).await();
+ ctx.complete(orderResult);
+ return;
+ }
+ }
+
+ // There is enough inventory available so the user can purchase the item(s).
+ // Process their payment
+ PaymentRequest paymentRequest = new PaymentRequest();
+ paymentRequest.setRequestId(orderId);
+ paymentRequest.setItemBeingPurchased(order.getItemName());
+ paymentRequest.setQuantity(order.getQuantity());
+ paymentRequest.setAmount(order.getTotalCost());
+ boolean isOK = ctx.callActivity(ProcessPaymentActivity.class.getName(),
+ paymentRequest, boolean.class).await();
+ if (!isOK) {
+ notification.setMessage("Payment failed for order : " + orderId);
+ ctx.callActivity(NotifyActivity.class.getName(), notification).await();
+ ctx.complete(orderResult);
+ return;
+ }
+
+ inventoryResult = ctx.callActivity(UpdateInventoryActivity.class.getName(),
+ inventoryRequest, InventoryResult.class).await();
+ if (!inventoryResult.isSuccess()) {
+ // If there is an error updating the inventory, refund the user
+ // paymentRequest.setAmount(-1 * paymentRequest.getAmount());
+ // ctx.callActivity(ProcessPaymentActivity.class.getName(),
+ // paymentRequest).await();
+
+ // Let users know their payment processing failed
+ notification.setMessage("Order failed to update inventory! : " + orderId);
+ ctx.callActivity(NotifyActivity.class.getName(), notification).await();
+ ctx.complete(orderResult);
+ return;
+ }
+
+ // Let user know their order was processed
+ notification.setMessage("Order completed! : " + orderId);
+ ctx.callActivity(NotifyActivity.class.getName(), notification).await();
+
+ // Complete the workflow with order result is processed
+ orderResult.setProcessed(true);
+ ctx.complete(orderResult);
+ };
+ }
+
+}
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/WorkflowConsoleApp.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/WorkflowConsoleApp.java
new file mode 100644
index 000000000..e2d1515ea
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/WorkflowConsoleApp.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2023 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.quickstarts.workflows;
+
+import java.time.Duration;
+import java.util.concurrent.TimeoutException;
+
+import io.dapr.client.DaprClient;
+import io.dapr.client.DaprClientBuilder;
+import io.dapr.quickstarts.workflows.activities.NotifyActivity;
+import io.dapr.quickstarts.workflows.activities.ProcessPaymentActivity;
+import io.dapr.quickstarts.workflows.activities.RequestApprovalActivity;
+import io.dapr.quickstarts.workflows.activities.ReserveInventoryActivity;
+import io.dapr.quickstarts.workflows.activities.UpdateInventoryActivity;
+import io.dapr.quickstarts.workflows.models.InventoryItem;
+import io.dapr.quickstarts.workflows.models.OrderPayload;
+import io.dapr.workflows.client.DaprWorkflowClient;
+import io.dapr.workflows.client.WorkflowInstanceStatus;
+import io.dapr.workflows.runtime.WorkflowRuntime;
+import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
+
+public class WorkflowConsoleApp {
+
+ private static final String STATE_STORE_NAME = "statestore";
+
+ /**
+ * The main method of this console app.
+ *
+ * @param args The port the app will listen on.
+ * @throws Exception An Exception.
+ */
+ public static void main(String[] args) throws Exception {
+ System.out.println("*** Welcome to the Dapr Workflow console app sample!");
+ System.out.println("*** Using this app, you can place orders that start workflows.");
+ // Wait for the sidecar to become available
+ Thread.sleep(5 * 1000);
+
+ // Register the OrderProcessingWorkflow and its activities with the builder.
+ WorkflowRuntimeBuilder builder = new WorkflowRuntimeBuilder().registerWorkflow(OrderProcessingWorkflow.class);
+ builder.registerActivity(NotifyActivity.class);
+ builder.registerActivity(ProcessPaymentActivity.class);
+ builder.registerActivity(RequestApprovalActivity.class);
+ builder.registerActivity(ReserveInventoryActivity.class);
+ builder.registerActivity(UpdateInventoryActivity.class);
+
+ // Build and then start the workflow runtime pulling and executing tasks
+ try (WorkflowRuntime runtime = builder.build()) {
+ System.out.println("Start workflow runtime");
+ runtime.start(false);
+ }
+
+ InventoryItem inventory = prepareInventoryAndOrder();
+
+ DaprWorkflowClient workflowClient = new DaprWorkflowClient();
+ try (workflowClient) {
+ executeWorkflow(workflowClient, inventory);
+ }
+
+ }
+
+ private static void executeWorkflow(DaprWorkflowClient workflowClient, InventoryItem inventory) {
+ System.out.println("==========Begin the purchase of item:==========");
+ String itemName = inventory.getName();
+ int orderQuantity = inventory.getQuantity();
+ int totalcost = orderQuantity * inventory.getPerItemCost();
+ OrderPayload order = new OrderPayload();
+ order.setItemName(itemName);
+ order.setQuantity(orderQuantity);
+ order.setTotalCost(totalcost);
+ System.out.println("Starting order workflow, purchasing " + orderQuantity + " of " + itemName);
+
+ String instanceId = workflowClient.scheduleNewWorkflow(OrderProcessingWorkflow.class, order);
+ System.out.printf("scheduled new workflow instance of OrderProcessingWorkflow with instance ID: %s%n",
+ instanceId);
+
+ try {
+ workflowClient.waitForInstanceStart(instanceId, Duration.ofSeconds(10), false);
+ System.out.printf("workflow instance %s started%n", instanceId);
+ } catch (TimeoutException e) {
+ System.out.printf("workflow instance %s did not start within 10 seconds%n", instanceId);
+ return;
+ }
+
+ try {
+ WorkflowInstanceStatus workflowStatus = workflowClient.waitForInstanceCompletion(instanceId,
+ Duration.ofSeconds(30),
+ true);
+ if (workflowStatus != null) {
+ System.out.printf("workflow instance completed, out is: %s%n",
+ workflowStatus.getSerializedOutput());
+ } else {
+ System.out.printf("workflow instance %s not found%n", instanceId);
+ }
+ } catch (TimeoutException e) {
+ System.out.printf("workflow instance %s did not complete within 30 seconds%n", instanceId);
+ }
+
+ }
+
+ private static InventoryItem prepareInventoryAndOrder() {
+ // prepare 100 cars in inventory
+ InventoryItem inventory = new InventoryItem();
+ inventory.setName("cars");
+ inventory.setPerItemCost(15000);
+ inventory.setQuantity(100);
+ DaprClient daprClient = new DaprClientBuilder().build();
+ restockInventory(daprClient, inventory);
+
+ // prepare order for 10 cars
+ InventoryItem order = new InventoryItem();
+ order.setName("cars");
+ order.setPerItemCost(15000);
+ order.setQuantity(10);
+ return order;
+ }
+
+ private static void restockInventory(DaprClient daprClient, InventoryItem inventory) {
+ String key = inventory.getName();
+ daprClient.saveState(STATE_STORE_NAME, key, inventory).block();
+ }
+}
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/NotifyActivity.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/NotifyActivity.java
new file mode 100644
index 000000000..7c4f71bc7
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/NotifyActivity.java
@@ -0,0 +1,21 @@
+package io.dapr.quickstarts.workflows.activities;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.dapr.quickstarts.workflows.models.Notification;
+import io.dapr.workflows.runtime.WorkflowActivity;
+import io.dapr.workflows.runtime.WorkflowActivityContext;
+
+public class NotifyActivity implements WorkflowActivity {
+ private static Logger logger = LoggerFactory.getLogger(NotifyActivity.class);
+
+ @Override
+ public Object run(WorkflowActivityContext ctx) {
+ Notification notification = ctx.getInput(Notification.class);
+ logger.info(notification.getMessage());
+
+ return "";
+ }
+
+}
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/ProcessPaymentActivity.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/ProcessPaymentActivity.java
new file mode 100644
index 000000000..17dbb8373
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/ProcessPaymentActivity.java
@@ -0,0 +1,29 @@
+package io.dapr.quickstarts.workflows.activities;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.dapr.quickstarts.workflows.models.PaymentRequest;
+import io.dapr.workflows.runtime.WorkflowActivity;
+import io.dapr.workflows.runtime.WorkflowActivityContext;
+
+public class ProcessPaymentActivity implements WorkflowActivity {
+ private static Logger logger = LoggerFactory.getLogger(ProcessPaymentActivity.class);
+
+ @Override
+ public Object run(WorkflowActivityContext ctx) {
+ PaymentRequest req = ctx.getInput(PaymentRequest.class);
+ logger.info("Processing payment: {} for {} {} at ${}",
+ req.getRequestId(), req.getQuantity(), req.getItemBeingPurchased(), req.getAmount());
+
+ // Simulate slow processing
+ try {
+ Thread.sleep(7 * 1000);
+ } catch (InterruptedException e) {
+ }
+ logger.info("Payment for request ID '{}' processed successfully", req.getRequestId());
+
+ return true;
+ }
+
+}
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/RequestApprovalActivity.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/RequestApprovalActivity.java
new file mode 100644
index 000000000..1e24ddd9e
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/RequestApprovalActivity.java
@@ -0,0 +1,24 @@
+package io.dapr.quickstarts.workflows.activities;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.dapr.quickstarts.workflows.models.ApprovalResult;
+import io.dapr.quickstarts.workflows.models.OrderPayload;
+import io.dapr.workflows.runtime.WorkflowActivity;
+import io.dapr.workflows.runtime.WorkflowActivityContext;
+
+public class RequestApprovalActivity implements WorkflowActivity {
+ private static Logger logger = LoggerFactory.getLogger(RequestApprovalActivity.class);
+
+ @Override
+ public Object run(WorkflowActivityContext ctx) {
+ OrderPayload order = ctx.getInput(OrderPayload.class);
+ logger.info("Requesting approval for order: {}", order);
+
+ // hard code to Approved in example
+ logger.info("Approved requesting approval for order: {}", order);
+ return ApprovalResult.Approved;
+ }
+
+}
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/ReserveInventoryActivity.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/ReserveInventoryActivity.java
new file mode 100644
index 000000000..63b05101e
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/ReserveInventoryActivity.java
@@ -0,0 +1,62 @@
+package io.dapr.quickstarts.workflows.activities;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.dapr.client.DaprClient;
+import io.dapr.client.DaprClientBuilder;
+import io.dapr.client.domain.State;
+import io.dapr.quickstarts.workflows.models.InventoryItem;
+import io.dapr.quickstarts.workflows.models.InventoryRequest;
+import io.dapr.quickstarts.workflows.models.InventoryResult;
+import io.dapr.workflows.runtime.WorkflowActivity;
+import io.dapr.workflows.runtime.WorkflowActivityContext;
+
+public class ReserveInventoryActivity implements WorkflowActivity {
+ private static Logger logger = LoggerFactory.getLogger(ReserveInventoryActivity.class);
+
+ private static final String STATE_STORE_NAME = "statestore";
+
+ private DaprClient daprClient;
+
+ public ReserveInventoryActivity() {
+ this.daprClient = new DaprClientBuilder().build();
+ }
+
+ @Override
+ public Object run(WorkflowActivityContext ctx) {
+ InventoryRequest inventoryRequest = ctx.getInput(InventoryRequest.class);
+ logger.info("Reserving inventory for order '{}' of {} {}",
+ inventoryRequest.getRequestId(), inventoryRequest.getQuantity(), inventoryRequest.getItemName());
+
+ State inventoryState = daprClient.getState(STATE_STORE_NAME, inventoryRequest.getItemName(), InventoryItem.class).block();
+ InventoryItem inventory = inventoryState.getValue();
+
+ logger.info("There are {} {} available for purchase",
+ inventory.getQuantity(), inventory.getName());
+
+ // See if there're enough items to purchase
+ if (inventory.getQuantity() >= inventoryRequest.getQuantity()) {
+ // Simulate slow processing
+ try {
+ Thread.sleep(2 * 1000);
+ } catch (InterruptedException e) {
+ }
+ logger.info("Reserved inventory for order '{}' of {} {}",
+ inventoryRequest.getRequestId(), inventoryRequest.getQuantity(), inventoryRequest.getItemName());
+ InventoryResult inventoryResult = new InventoryResult();
+ inventoryResult.setSuccess(true);
+ inventoryResult.setInventoryItem(inventory);
+ return inventoryResult;
+ }
+
+ // Not enough items.
+ logger.info("Not enough items to reserve inventory for order '{}' of {} {}",
+ inventoryRequest.getRequestId(), inventoryRequest.getQuantity(), inventoryRequest.getItemName());
+ InventoryResult inventoryResult = new InventoryResult();
+ inventoryResult.setSuccess(false);
+ inventoryResult.setInventoryItem(inventory);
+ return inventoryResult;
+ }
+
+}
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/UpdateInventoryActivity.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/UpdateInventoryActivity.java
new file mode 100644
index 000000000..a8332441a
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/UpdateInventoryActivity.java
@@ -0,0 +1,70 @@
+package io.dapr.quickstarts.workflows.activities;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.dapr.client.DaprClient;
+import io.dapr.client.DaprClientBuilder;
+import io.dapr.client.domain.State;
+import io.dapr.quickstarts.workflows.models.InventoryItem;
+import io.dapr.quickstarts.workflows.models.InventoryRequest;
+import io.dapr.quickstarts.workflows.models.InventoryResult;
+import io.dapr.quickstarts.workflows.models.OrderPayload;
+import io.dapr.workflows.runtime.WorkflowActivity;
+import io.dapr.workflows.runtime.WorkflowActivityContext;
+
+public class UpdateInventoryActivity implements WorkflowActivity {
+ private static Logger logger = LoggerFactory.getLogger(UpdateInventoryActivity.class);
+
+ private static final String STATE_STORE_NAME = "statestore";
+
+ private DaprClient daprClient;
+
+ public UpdateInventoryActivity() {
+ this.daprClient = new DaprClientBuilder().build();
+ }
+
+ @Override
+ public Object run(WorkflowActivityContext ctx) {
+ InventoryRequest inventoryRequest = ctx.getInput(InventoryRequest.class);
+ logger.info("Updating inventory for order '{}' of {} {}",
+ inventoryRequest.getRequestId(), inventoryRequest.getQuantity(), inventoryRequest.getItemName());
+
+ // Simulate slow processing
+ try {
+ Thread.sleep(2 * 1000);
+ } catch (InterruptedException e) {
+ }
+
+ // Determine if there are enough Items for purchase
+ State inventoryState = daprClient
+ .getState(STATE_STORE_NAME, inventoryRequest.getItemName(), InventoryItem.class).block();
+ InventoryItem inventory = inventoryState.getValue();
+ int newQuantity = inventory.getQuantity() - inventoryRequest.getQuantity();
+ if (newQuantity < 0) {
+ logger.info("Not enough inventory for order '{}' of {} {}, there are only {} {}",
+ inventoryRequest.getRequestId(), inventoryRequest.getQuantity(), inventoryRequest.getItemName(),
+ inventory.getQuantity(), inventory.getName());
+
+ InventoryResult inventoryResult = new InventoryResult();
+ inventoryResult.setSuccess(false);
+ return inventoryResult;
+ }
+
+ // Update the statestore with the new amount of paper clips
+ OrderPayload updatedOrderPayload = new OrderPayload();
+ updatedOrderPayload.setItemName(inventoryRequest.getItemName());
+ updatedOrderPayload.setQuantity(newQuantity);
+ daprClient.saveState(STATE_STORE_NAME, inventoryRequest.getItemName(), inventoryState.getEtag(),
+ updatedOrderPayload, null).block();
+
+ logger.info("Updated inventory for order '{}': there are now {} {} left in stock",
+ inventoryRequest.getRequestId(), newQuantity, inventoryRequest.getItemName());
+ // in addition to print to std out for validation
+ System.out.println("there are now " + newQuantity + " " + inventoryRequest.getItemName() + " left in stock");
+ InventoryResult inventoryResult = new InventoryResult();
+ inventoryResult.setSuccess(true);
+ return inventoryResult;
+ }
+
+}
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/ApprovalRequired.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/ApprovalRequired.java
new file mode 100644
index 000000000..4ee5a45f7
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/ApprovalRequired.java
@@ -0,0 +1,19 @@
+package io.dapr.quickstarts.workflows.models;
+
+public class ApprovalRequired {
+ private boolean approval;
+
+ public boolean isApproval() {
+ return approval;
+ }
+
+ public void setApproval(boolean approval) {
+ this.approval = approval;
+ }
+
+ @Override
+ public String toString() {
+ return "ApprovalRequired [approval=" + approval + "]";
+ }
+
+}
\ No newline at end of file
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/ApprovalResult.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/ApprovalResult.java
new file mode 100644
index 000000000..71ea7d5da
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/ApprovalResult.java
@@ -0,0 +1,7 @@
+package io.dapr.quickstarts.workflows.models;
+
+public enum ApprovalResult {
+ Unspecified,
+ Approved,
+ Rejected
+}
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/InventoryItem.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/InventoryItem.java
new file mode 100644
index 000000000..62261a3e7
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/InventoryItem.java
@@ -0,0 +1,36 @@
+package io.dapr.quickstarts.workflows.models;
+
+public class InventoryItem {
+ private String name;
+ private int perItemCost;
+ private int quantity;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getPerItemCost() {
+ return perItemCost;
+ }
+
+ public void setPerItemCost(int perItemCost) {
+ this.perItemCost = perItemCost;
+ }
+
+ public int getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(int quantity) {
+ this.quantity = quantity;
+ }
+
+ @Override
+ public String toString() {
+ return "InventoryItem [name=" + name + ", perItemCost=" + perItemCost + ", quantity=" + quantity + "]";
+ }
+}
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/InventoryRequest.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/InventoryRequest.java
new file mode 100644
index 000000000..cee70d6ab
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/InventoryRequest.java
@@ -0,0 +1,37 @@
+package io.dapr.quickstarts.workflows.models;
+
+public class InventoryRequest {
+
+ private String requestId;
+ private String itemName;
+ private int quantity;
+
+ public String getRequestId() {
+ return requestId;
+ }
+
+ public void setRequestId(String requestId) {
+ this.requestId = requestId;
+ }
+
+ public String getItemName() {
+ return itemName;
+ }
+
+ public void setItemName(String itemName) {
+ this.itemName = itemName;
+ }
+
+ public int getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(int quantity) {
+ this.quantity = quantity;
+ }
+
+ @Override
+ public String toString() {
+ return "InventoryRequest [requestId=" + requestId + ", itemName=" + itemName + ", quantity=" + quantity + "]";
+ }
+}
\ No newline at end of file
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/InventoryResult.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/InventoryResult.java
new file mode 100644
index 000000000..249bd9b1d
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/InventoryResult.java
@@ -0,0 +1,27 @@
+package io.dapr.quickstarts.workflows.models;
+
+public class InventoryResult {
+ private boolean success;
+ private InventoryItem inventoryItem;
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public void setSuccess(boolean success) {
+ this.success = success;
+ }
+
+ public InventoryItem getInventoryItem() {
+ return inventoryItem;
+ }
+
+ public void setInventoryItem(InventoryItem inventoryItem) {
+ this.inventoryItem = inventoryItem;
+ }
+
+ @Override
+ public String toString() {
+ return "InventoryResult [success=" + success + ", inventoryItem=" + inventoryItem + "]";
+ }
+}
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/Notification.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/Notification.java
new file mode 100644
index 000000000..d77f9d186
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/Notification.java
@@ -0,0 +1,19 @@
+package io.dapr.quickstarts.workflows.models;
+
+public class Notification {
+ private String message;
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ @Override
+ public String toString() {
+ return "Notification [message=" + message + "]";
+ }
+
+}
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/OrderPayload.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/OrderPayload.java
new file mode 100644
index 000000000..01f748519
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/OrderPayload.java
@@ -0,0 +1,38 @@
+package io.dapr.quickstarts.workflows.models;
+
+public class OrderPayload {
+
+ private String itemName;
+ private int totalCost;
+ private int quantity;
+
+ public String getItemName() {
+ return itemName;
+ }
+
+ public void setItemName(String itemName) {
+ this.itemName = itemName;
+ }
+
+ public int getTotalCost() {
+ return totalCost;
+ }
+
+ public void setTotalCost(int totalCost) {
+ this.totalCost = totalCost;
+ }
+
+ public int getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(int quantity) {
+ this.quantity = quantity;
+ }
+
+ @Override
+ public String toString() {
+ return "OrderPayload [itemName=" + itemName + ", totalCost=" + totalCost + ", quantity=" + quantity + "]";
+ }
+
+}
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/OrderResult.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/OrderResult.java
new file mode 100644
index 000000000..a32d12137
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/OrderResult.java
@@ -0,0 +1,19 @@
+package io.dapr.quickstarts.workflows.models;
+
+public class OrderResult {
+ private boolean processed;
+
+ public boolean isProcessed() {
+ return processed;
+ }
+
+ public void setProcessed(boolean processed) {
+ this.processed = processed;
+ }
+
+ @Override
+ public String toString() {
+ return "OrderResult [processed=" + processed + "]";
+ }
+
+}
diff --git a/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/PaymentRequest.java b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/PaymentRequest.java
new file mode 100644
index 000000000..350e354c2
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/models/PaymentRequest.java
@@ -0,0 +1,47 @@
+package io.dapr.quickstarts.workflows.models;
+
+public class PaymentRequest {
+ private String requestId;
+ private String itemBeingPurchased;
+ private int amount;
+ private int quantity;
+
+ public String getRequestId() {
+ return requestId;
+ }
+
+ public void setRequestId(String requestId) {
+ this.requestId = requestId;
+ }
+
+ public String getItemBeingPurchased() {
+ return itemBeingPurchased;
+ }
+
+ public void setItemBeingPurchased(String itemBeingPurchased) {
+ this.itemBeingPurchased = itemBeingPurchased;
+ }
+
+ public int getAmount() {
+ return amount;
+ }
+
+ public void setAmount(int amount) {
+ this.amount = amount;
+ }
+
+ public int getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(int quantity) {
+ this.quantity = quantity;
+ }
+
+ @Override
+ public String toString() {
+ return "PaymentRequest [requestId=" + requestId + ", itemBeingPurchased=" + itemBeingPurchased + ", amount=" + amount
+ + ", quantity=" + quantity + "]";
+ }
+
+}
diff --git a/workflows/java/sdk/order-processor/src/main/resources/simplelogger.properties b/workflows/java/sdk/order-processor/src/main/resources/simplelogger.properties
new file mode 100644
index 000000000..32ca7250a
--- /dev/null
+++ b/workflows/java/sdk/order-processor/src/main/resources/simplelogger.properties
@@ -0,0 +1 @@
+org.slf4j.simpleLogger.logFile=System.out