Cleaning up
This commit is contained in:
95
order/order-worker/pom.xml
Normal file
95
order/order-worker/pom.xml
Normal file
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>order-worker</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>order-worker</name>
|
||||
|
||||
<parent>
|
||||
<groupId>org.kbastani</groupId>
|
||||
<artifactId>order</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-hateoas</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-integration</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.statemachine</groupId>
|
||||
<artifactId>spring-statemachine-core</artifactId>
|
||||
<version>${spring-statemachine-core.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.kbastani</groupId>
|
||||
<artifactId>spring-boot-starter-aws-lambda</artifactId>
|
||||
<version>${spring-boot-starter-aws-lambda.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-java-sdk-sts</artifactId>
|
||||
<version>${aws-java-sdk-sts.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-java-sdk-lambda</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.jayway.jsonpath</groupId>
|
||||
<artifactId>json-path</artifactId>
|
||||
<version>${json-path.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-java-sdk-bom</artifactId>
|
||||
<version>${aws-java-sdk-sts.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,16 @@
|
||||
package demo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.hateoas.config.EnableHypermediaSupport;
|
||||
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableHypermediaSupport(type = {HypermediaType.HAL})
|
||||
public class OrderWorkerApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(OrderWorkerApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
92
order/order-worker/src/main/java/demo/address/Address.java
Normal file
92
order/order-worker/src/main/java/demo/address/Address.java
Normal file
@@ -0,0 +1,92 @@
|
||||
package demo.address;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class Address implements Serializable {
|
||||
|
||||
private String street1, street2, state, city, country;
|
||||
private Integer zipCode;
|
||||
private AddressType addressType;
|
||||
|
||||
public Address() {
|
||||
}
|
||||
|
||||
public Address(String street1, String street2, String state,
|
||||
String city, String country, Integer zipCode) {
|
||||
this.street1 = street1;
|
||||
this.street2 = street2;
|
||||
this.state = state;
|
||||
this.city = city;
|
||||
this.country = country;
|
||||
this.zipCode = zipCode;
|
||||
}
|
||||
|
||||
public String getStreet1() {
|
||||
return street1;
|
||||
}
|
||||
|
||||
public void setStreet1(String street1) {
|
||||
this.street1 = street1;
|
||||
}
|
||||
|
||||
public String getStreet2() {
|
||||
return street2;
|
||||
}
|
||||
|
||||
public void setStreet2(String street2) {
|
||||
this.street2 = street2;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return country;
|
||||
}
|
||||
|
||||
public void setCountry(String country) {
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
public Integer getZipCode() {
|
||||
return zipCode;
|
||||
}
|
||||
|
||||
public void setZipCode(Integer zipCode) {
|
||||
this.zipCode = zipCode;
|
||||
}
|
||||
|
||||
public AddressType getAddressType() {
|
||||
return addressType;
|
||||
}
|
||||
|
||||
public void setAddressType(AddressType addressType) {
|
||||
this.addressType = addressType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Address{" +
|
||||
"street1='" + street1 + '\'' +
|
||||
", street2='" + street2 + '\'' +
|
||||
", state='" + state + '\'' +
|
||||
", city='" + city + '\'' +
|
||||
", country='" + country + '\'' +
|
||||
", zipCode=" + zipCode +
|
||||
", addressType=" + addressType +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package demo.address;
|
||||
|
||||
public enum AddressType {
|
||||
SHIPPING,
|
||||
BILLING
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package demo.config;
|
||||
|
||||
import amazon.aws.AWSLambdaConfigurerAdapter;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import demo.function.LambdaFunctions;
|
||||
import demo.util.LambdaUtil;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
|
||||
@Configuration
|
||||
@Profile("cloud")
|
||||
public class AwsLambdaConfig {
|
||||
|
||||
@Bean
|
||||
public LambdaFunctions lambdaInvoker(AWSLambdaConfigurerAdapter configurerAdapter) {
|
||||
return configurerAdapter
|
||||
.getFunctionInstance(LambdaFunctions.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LambdaUtil lambdaUtil(ObjectMapper objectMapper) {
|
||||
return new LambdaUtil(objectMapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package demo.config;
|
||||
|
||||
import demo.event.OrderEvent;
|
||||
import demo.event.OrderEventType;
|
||||
import demo.function.OrderFunction;
|
||||
import demo.order.Order;
|
||||
import demo.order.OrderStatus;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.EnableStateMachineFactory;
|
||||
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* A configuration adapter for describing a {@link StateMachine} factory that maps actions to functional
|
||||
* expressions. Actions are executed during transitions between a source state and a target state.
|
||||
* <p>
|
||||
* A state machine provides a robust declarative language for describing the state of an {@link Order}
|
||||
* resource given a sequence of ordered {@link demo.event.OrderEvents}. When an event is received
|
||||
* in {@link demo.event.OrderEventStream}, an in-memory state machine is fully replicated given the
|
||||
* {@link demo.event.OrderEvents} attached to an {@link Order} resource.
|
||||
*
|
||||
* @author kbastani
|
||||
*/
|
||||
@Configuration
|
||||
@EnableStateMachineFactory
|
||||
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderStatus, OrderEventType> {
|
||||
|
||||
final private Logger log = Logger.getLogger(StateMachineConfig.class);
|
||||
|
||||
/**
|
||||
* Configures the initial conditions of a new in-memory {@link StateMachine} for {@link Order}.
|
||||
*
|
||||
* @param states is the {@link StateMachineStateConfigurer} used to describe the initial condition
|
||||
*/
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<OrderStatus, OrderEventType> states) {
|
||||
try {
|
||||
// Describe the initial condition of the order state machine
|
||||
states.withStates()
|
||||
.initial(OrderStatus.PENDING)
|
||||
.states(EnumSet.allOf(OrderStatus.class));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("State machine configuration failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link StateMachine} that describes how {@link OrderEventType} drives the state
|
||||
* of an {@link Order}. Events are applied as transitions from a source {@link OrderStatus} to
|
||||
* a target {@link OrderStatus}. An {@link Action} is attached to each transition, which maps to a
|
||||
* function that is executed in the context of an {@link OrderEvent}.
|
||||
*
|
||||
* @param transitions is the {@link StateMachineTransitionConfigurer} used to describe state transitions
|
||||
*/
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderEventType> transitions) {
|
||||
try {
|
||||
// Describe state machine transitions for orders
|
||||
// TODO: Configure state machine
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not configure state machine transitions", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Functions are mapped to actions that are triggered during the replication of a state machine. Functions
|
||||
* should only be executed after the state machine has completed replication. This method checks the state
|
||||
* context of the machine for an {@link OrderEvent}, which signals that the state machine is finished
|
||||
* replication.
|
||||
* <p>
|
||||
* The {@link OrderFunction} argument is only applied if an {@link OrderEvent} is provided as a
|
||||
* message header in the {@link StateContext}.
|
||||
*
|
||||
* @param context is the state machine context that may include an {@link OrderEvent}
|
||||
* @param orderFunction is the order function to apply after the state machine has completed replication
|
||||
* @return an {@link OrderEvent} only if this event has not yet been processed, otherwise returns null
|
||||
*/
|
||||
private OrderEvent applyEvent(StateContext<OrderStatus, OrderEventType> context,
|
||||
OrderFunction orderFunction) {
|
||||
OrderEvent orderEvent = null;
|
||||
|
||||
// Log out the progress of the state machine replication
|
||||
log.info("Replicate event: " + context.getMessage().getPayload());
|
||||
|
||||
// The machine is finished replicating when an OrderEvent is found in the message header
|
||||
if (context.getMessageHeader("event") != null) {
|
||||
orderEvent = (OrderEvent) context.getMessageHeader("event");
|
||||
log.info("State machine replicated: " + orderEvent.getType());
|
||||
|
||||
// Apply the provided function to the OrderEvent
|
||||
orderFunction.apply(orderEvent);
|
||||
}
|
||||
|
||||
return orderEvent;
|
||||
}
|
||||
}
|
||||
|
||||
36
order/order-worker/src/main/java/demo/domain/BaseEntity.java
Normal file
36
order/order-worker/src/main/java/demo/domain/BaseEntity.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package demo.domain;
|
||||
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
|
||||
public class BaseEntity extends ResourceSupport {
|
||||
|
||||
private Long createdAt;
|
||||
private Long lastModified;
|
||||
|
||||
public BaseEntity() {
|
||||
}
|
||||
|
||||
public Long getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(Long createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public Long getLastModified() {
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
public void setLastModified(Long lastModified) {
|
||||
this.lastModified = lastModified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BaseEntity{" +
|
||||
"createdAt=" + createdAt +
|
||||
", lastModified=" + lastModified +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package demo.event;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v1")
|
||||
public class EventController {
|
||||
|
||||
private EventService eventService;
|
||||
|
||||
public EventController(EventService eventService) {
|
||||
this.eventService = eventService;
|
||||
}
|
||||
|
||||
@PostMapping(path = "/events")
|
||||
public ResponseEntity handleEvent(@RequestBody OrderEvent event) {
|
||||
return Optional.ofNullable(eventService.apply(event))
|
||||
.map(e -> new ResponseEntity<>(e, HttpStatus.CREATED))
|
||||
.orElseThrow(() -> new RuntimeException("Apply event failed"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package demo.event;
|
||||
|
||||
import demo.order.Order;
|
||||
import demo.order.OrderStatus;
|
||||
import demo.state.StateMachineService;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.hateoas.client.Traverson;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class EventService {
|
||||
|
||||
final private Logger log = Logger.getLogger(EventService.class);
|
||||
final private StateMachineService stateMachineService;
|
||||
|
||||
public EventService(StateMachineService stateMachineService) {
|
||||
this.stateMachineService = stateMachineService;
|
||||
}
|
||||
|
||||
public Order apply(OrderEvent orderEvent) {
|
||||
|
||||
Order result;
|
||||
|
||||
log.info("Order event received: " + orderEvent.getLink("self").getHref());
|
||||
|
||||
// Generate a state machine for computing the state of the order resource
|
||||
StateMachine<OrderStatus, OrderEventType> stateMachine =
|
||||
stateMachineService.getStateMachine();
|
||||
|
||||
// Follow the hypermedia link to fetch the attached order
|
||||
Traverson traverson = new Traverson(
|
||||
URI.create(orderEvent.getLink("order").getHref()),
|
||||
MediaTypes.HAL_JSON
|
||||
);
|
||||
|
||||
// Get the event log for the attached order resource
|
||||
OrderEvents events = traverson.follow("events")
|
||||
.toEntity(OrderEvents.class)
|
||||
.getBody();
|
||||
|
||||
// Prepare order event message headers
|
||||
Map<String, Object> headerMap = new HashMap<>();
|
||||
headerMap.put("event", orderEvent);
|
||||
|
||||
// Replicate the current state of the order resource
|
||||
events.getContent()
|
||||
.stream()
|
||||
.sorted((a1, a2) -> a1.getCreatedAt().compareTo(a2.getCreatedAt()))
|
||||
.forEach(e -> {
|
||||
MessageHeaders headers = new MessageHeaders(null);
|
||||
|
||||
// Check to see if this is the current event
|
||||
if (e.getLink("self").equals(orderEvent.getLink("self"))) {
|
||||
headers = new MessageHeaders(headerMap);
|
||||
}
|
||||
|
||||
// Send the event to the state machine
|
||||
stateMachine.sendEvent(MessageBuilder.createMessage(e.getType(), headers));
|
||||
});
|
||||
|
||||
|
||||
// Get result
|
||||
Map<Object, Object> context = stateMachine.getExtendedState()
|
||||
.getVariables();
|
||||
|
||||
// Get the order result
|
||||
result = (Order) context.getOrDefault("order", null);
|
||||
|
||||
// Destroy the state machine
|
||||
stateMachine.stop();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
30
order/order-worker/src/main/java/demo/event/OrderEvent.java
Normal file
30
order/order-worker/src/main/java/demo/event/OrderEvent.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package demo.event;
|
||||
|
||||
import demo.domain.BaseEntity;
|
||||
|
||||
public class OrderEvent extends BaseEntity {
|
||||
|
||||
private OrderEventType type;
|
||||
|
||||
public OrderEvent() {
|
||||
}
|
||||
|
||||
public OrderEvent(OrderEventType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public OrderEventType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(OrderEventType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AccountEvent{" +
|
||||
"type=" + type +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package demo.event;
|
||||
|
||||
import demo.order.Order;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.annotation.StreamListener;
|
||||
import org.springframework.cloud.stream.messaging.Sink;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
|
||||
/**
|
||||
* The {@link OrderEventStream} monitors for a variety of {@link OrderEvent} domain
|
||||
* events for an {@link Order}.
|
||||
*
|
||||
* @author kbastani
|
||||
*/
|
||||
@EnableAutoConfiguration
|
||||
@EnableBinding(Sink.class)
|
||||
@Profile({ "cloud", "development" })
|
||||
public class OrderEventStream {
|
||||
|
||||
private EventService eventService;
|
||||
|
||||
public OrderEventStream(EventService eventService) {
|
||||
this.eventService = eventService;
|
||||
}
|
||||
|
||||
@StreamListener(Sink.INPUT)
|
||||
public void streamListerner(OrderEvent orderEvent) {
|
||||
eventService.apply(orderEvent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package demo.event;
|
||||
|
||||
public enum OrderEventType {
|
||||
// TODO: Add event types
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package demo.event;
|
||||
|
||||
import org.springframework.hateoas.Resources;
|
||||
|
||||
public class OrderEvents extends Resources<OrderEvent> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package demo.function;
|
||||
|
||||
public interface LambdaFunctions {
|
||||
// TODO: Implement
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package demo.function;
|
||||
|
||||
import demo.order.Order;
|
||||
import demo.order.OrderStatus;
|
||||
import demo.event.OrderEvent;
|
||||
import demo.event.OrderEventType;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* The {@link OrderFunction} is an abstraction used to map actions that are triggered by
|
||||
* state transitions on a {@link demo.order.Order} resource on to a function. Mapped functions
|
||||
* can take multiple forms and reside either remotely or locally on the classpath of this application.
|
||||
*
|
||||
* @author kbastani
|
||||
*/
|
||||
public abstract class OrderFunction {
|
||||
|
||||
final private Logger log = Logger.getLogger(OrderFunction.class);
|
||||
final protected StateContext<OrderStatus, OrderEventType> context;
|
||||
final protected Function<OrderEvent, Order> lambda;
|
||||
|
||||
/**
|
||||
* Create a new instance of a class that extends {@link OrderFunction}, supplying
|
||||
* a state context and a lambda function used to apply {@link OrderEvent} to a provided
|
||||
* action.
|
||||
*
|
||||
* @param context is the {@link StateContext} for a replicated state machine
|
||||
* @param lambda is the lambda function describing an action that consumes an {@link OrderEvent}
|
||||
*/
|
||||
public OrderFunction(StateContext<OrderStatus, OrderEventType> context,
|
||||
Function<OrderEvent, Order> lambda) {
|
||||
this.context = context;
|
||||
this.lambda = lambda;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply an {@link OrderEvent} to the lambda function that was provided through the
|
||||
* constructor of this {@link OrderFunction}.
|
||||
*
|
||||
* @param event is the {@link OrderEvent} to apply to the lambda function
|
||||
*/
|
||||
public Order apply(OrderEvent event) {
|
||||
// Execute the lambda function
|
||||
Order result = lambda.apply(event);
|
||||
context.getExtendedState().getVariables().put("order", result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
74
order/order-worker/src/main/java/demo/order/LineItem.java
Normal file
74
order/order-worker/src/main/java/demo/order/LineItem.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package demo.order;
|
||||
|
||||
/**
|
||||
* A simple domain class for the {@link LineItem} concept in the order context.
|
||||
*
|
||||
* @author Kenny Bastani
|
||||
* @author Josh Long
|
||||
*/
|
||||
public class LineItem {
|
||||
|
||||
private String name, productId;
|
||||
private Integer quantity;
|
||||
private Double price, tax;
|
||||
|
||||
public LineItem(String name, String productId, Integer quantity,
|
||||
Double price, Double tax) {
|
||||
this.name = name;
|
||||
this.productId = productId;
|
||||
this.quantity = quantity;
|
||||
this.price = price;
|
||||
this.tax = tax;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getProductId() {
|
||||
return productId;
|
||||
}
|
||||
|
||||
public void setProductId(String productId) {
|
||||
this.productId = productId;
|
||||
}
|
||||
|
||||
public Integer getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public void setQuantity(Integer quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
public Double getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(Double price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public Double getTax() {
|
||||
return tax;
|
||||
}
|
||||
|
||||
public void setTax(Double tax) {
|
||||
this.tax = tax;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LineItem{" +
|
||||
"name='" + name + '\'' +
|
||||
", productId='" + productId + '\'' +
|
||||
", quantity=" + quantity +
|
||||
", price=" + price +
|
||||
", tax=" + tax +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
97
order/order-worker/src/main/java/demo/order/Order.java
Normal file
97
order/order-worker/src/main/java/demo/order/Order.java
Normal file
@@ -0,0 +1,97 @@
|
||||
package demo.order;
|
||||
|
||||
import demo.address.Address;
|
||||
import demo.address.AddressType;
|
||||
import demo.domain.BaseEntity;
|
||||
import demo.event.OrderEvent;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Order extends BaseEntity {
|
||||
|
||||
private Long orderId;
|
||||
private String accountNumber;
|
||||
|
||||
private OrderStatus status;
|
||||
|
||||
private Set<OrderEvent> events = new HashSet<>();
|
||||
|
||||
private Set<LineItem> lineItems = new HashSet<>();
|
||||
|
||||
private Address shippingAddress;
|
||||
|
||||
public Order() {
|
||||
}
|
||||
|
||||
public Order(String accountNumber, Address shippingAddress) {
|
||||
this();
|
||||
this.accountNumber = accountNumber;
|
||||
this.shippingAddress = shippingAddress;
|
||||
if (shippingAddress.getAddressType() == null)
|
||||
this.shippingAddress.setAddressType(AddressType.SHIPPING);
|
||||
}
|
||||
|
||||
public Long getOrderId() {
|
||||
return orderId;
|
||||
}
|
||||
|
||||
public void setOrderId(Long id) {
|
||||
this.orderId = orderId;
|
||||
}
|
||||
|
||||
public String getAccountNumber() {
|
||||
return accountNumber;
|
||||
}
|
||||
|
||||
public void setAccountNumber(String accountNumber) {
|
||||
this.accountNumber = accountNumber;
|
||||
}
|
||||
|
||||
public OrderStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(OrderStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Set<OrderEvent> getEvents() {
|
||||
return events;
|
||||
}
|
||||
|
||||
public void setEvents(Set<OrderEvent> events) {
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
public Set<LineItem> getLineItems() {
|
||||
return lineItems;
|
||||
}
|
||||
|
||||
public void setLineItems(Set<LineItem> lineItems) {
|
||||
this.lineItems = lineItems;
|
||||
}
|
||||
|
||||
public Address getShippingAddress() {
|
||||
return shippingAddress;
|
||||
}
|
||||
|
||||
public void setShippingAddress(Address shippingAddress) {
|
||||
this.shippingAddress = shippingAddress;
|
||||
}
|
||||
|
||||
public void addLineItem(LineItem lineItem) {
|
||||
lineItems.add(lineItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Order{" +
|
||||
"orderId='" + orderId + '\'' +
|
||||
", accountNumber='" + accountNumber + '\'' +
|
||||
", status=" + status +
|
||||
", lineItems=" + lineItems +
|
||||
", shippingAddress=" + shippingAddress +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
||||
14
order/order-worker/src/main/java/demo/order/OrderStatus.java
Normal file
14
order/order-worker/src/main/java/demo/order/OrderStatus.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package demo.order;
|
||||
|
||||
/**
|
||||
* Describes the state of an {@link Order}.
|
||||
*
|
||||
* @author Kenny Bastani
|
||||
* @author Josh Long
|
||||
*/
|
||||
public enum OrderStatus {
|
||||
PENDING,
|
||||
CONFIRMED,
|
||||
SHIPPED,
|
||||
DELIVERED
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package demo.state;
|
||||
|
||||
import demo.order.OrderStatus;
|
||||
import demo.event.OrderEventType;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.config.StateMachineFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* The {@link StateMachineService} provides factory access to get new state machines for
|
||||
* replicating the state of an {@link demo.order.Order} from {@link demo.event.OrderEvents}.
|
||||
*
|
||||
* @author kbastani
|
||||
*/
|
||||
@Service
|
||||
public class StateMachineService {
|
||||
|
||||
private final StateMachineFactory<OrderStatus, OrderEventType> factory;
|
||||
|
||||
public StateMachineService(StateMachineFactory<OrderStatus, OrderEventType> factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new state machine that is initially configured and ready for replicating
|
||||
* the state of an {@link demo.order.Order} from a sequence of {@link demo.event.OrderEvent}.
|
||||
*
|
||||
* @return a new instance of {@link StateMachine}
|
||||
*/
|
||||
public StateMachine<OrderStatus, OrderEventType> getStateMachine() {
|
||||
// Create a new state machine in its initial state
|
||||
StateMachine<OrderStatus, OrderEventType> stateMachine =
|
||||
factory.getStateMachine(UUID.randomUUID().toString());
|
||||
|
||||
// Start the new state machine
|
||||
stateMachine.start();
|
||||
|
||||
return stateMachine;
|
||||
}
|
||||
}
|
||||
29
order/order-worker/src/main/java/demo/util/LambdaUtil.java
Normal file
29
order/order-worker/src/main/java/demo/util/LambdaUtil.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package demo.util;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
@Component
|
||||
public class LambdaUtil {
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
public LambdaUtil(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
public HashMap objectToMap(Object object) {
|
||||
HashMap result = null;
|
||||
|
||||
try {
|
||||
result = objectMapper.readValue(objectMapper.writeValueAsString(object), HashMap.class);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
24
order/order-worker/src/main/resources/application.yml
Normal file
24
order/order-worker/src/main/resources/application.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
spring:
|
||||
profiles:
|
||||
active: development
|
||||
---
|
||||
spring:
|
||||
profiles: development
|
||||
cloud:
|
||||
stream:
|
||||
bindings:
|
||||
input:
|
||||
destination: account
|
||||
group: account-group
|
||||
contentType: 'application/json'
|
||||
consumer:
|
||||
durableSubscription: true
|
||||
server:
|
||||
port: 8081
|
||||
amazon:
|
||||
aws:
|
||||
access-key-id: replace
|
||||
access-key-secret: replace
|
||||
---
|
||||
spring:
|
||||
profiles: test
|
||||
4
order/order-worker/src/main/resources/bootstrap.yml
Normal file
4
order/order-worker/src/main/resources/bootstrap.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
spring:
|
||||
application:
|
||||
name: account-worker
|
||||
---
|
||||
@@ -0,0 +1,18 @@
|
||||
package demo;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
|
||||
@ActiveProfiles("test")
|
||||
public class AccountStreamModuleApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user