Finish payment workflow
This commit is contained in:
@@ -49,7 +49,8 @@ public class AccountController {
|
|||||||
|
|
||||||
@RequestMapping(path = "/accounts/{id}")
|
@RequestMapping(path = "/accounts/{id}")
|
||||||
public ResponseEntity getAccount(@PathVariable Long id) {
|
public ResponseEntity getAccount(@PathVariable Long id) {
|
||||||
return Optional.ofNullable(getAccountResource(id))
|
return Optional.ofNullable(accountService.get(id))
|
||||||
|
.map(this::getAccountResource)
|
||||||
.map(e -> new ResponseEntity<>(e, HttpStatus.OK))
|
.map(e -> new ResponseEntity<>(e, HttpStatus.OK))
|
||||||
.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
|
.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
|
||||||
}
|
}
|
||||||
@@ -91,57 +92,48 @@ public class AccountController {
|
|||||||
|
|
||||||
@RequestMapping(path = "/accounts/{id}/commands/confirm")
|
@RequestMapping(path = "/accounts/{id}/commands/confirm")
|
||||||
public ResponseEntity confirm(@PathVariable Long id) {
|
public ResponseEntity confirm(@PathVariable Long id) {
|
||||||
return Optional.ofNullable(getAccountResource(accountService.get(id)
|
return Optional.ofNullable(accountService.get(id))
|
||||||
.confirm()))
|
.map(Account::confirm)
|
||||||
|
.map(this::getAccountResource)
|
||||||
.map(e -> new ResponseEntity<>(e, HttpStatus.OK))
|
.map(e -> new ResponseEntity<>(e, HttpStatus.OK))
|
||||||
.orElseThrow(() -> new RuntimeException("The command could not be applied"));
|
.orElseThrow(() -> new RuntimeException("The command could not be applied"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(path = "/accounts/{id}/commands/activate")
|
@RequestMapping(path = "/accounts/{id}/commands/activate")
|
||||||
public ResponseEntity activate(@PathVariable Long id) {
|
public ResponseEntity activate(@PathVariable Long id) {
|
||||||
return Optional.ofNullable(getAccountResource(accountService.get(id)
|
return Optional.ofNullable(accountService.get(id))
|
||||||
.activate()))
|
.map(Account::activate)
|
||||||
|
.map(this::getAccountResource)
|
||||||
.map(e -> new ResponseEntity<>(e, HttpStatus.OK))
|
.map(e -> new ResponseEntity<>(e, HttpStatus.OK))
|
||||||
.orElseThrow(() -> new RuntimeException("The command could not be applied"));
|
.orElseThrow(() -> new RuntimeException("The command could not be applied"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(path = "/accounts/{id}/commands/suspend")
|
@RequestMapping(path = "/accounts/{id}/commands/suspend")
|
||||||
public ResponseEntity suspend(@PathVariable Long id) {
|
public ResponseEntity suspend(@PathVariable Long id) {
|
||||||
return Optional.ofNullable(getAccountResource(accountService.get(id)
|
return Optional.ofNullable(accountService.get(id))
|
||||||
.suspend()))
|
.map(Account::suspend)
|
||||||
|
.map(this::getAccountResource)
|
||||||
.map(e -> new ResponseEntity<>(e, HttpStatus.OK))
|
.map(e -> new ResponseEntity<>(e, HttpStatus.OK))
|
||||||
.orElseThrow(() -> new RuntimeException("The command could not be applied"));
|
.orElseThrow(() -> new RuntimeException("The command could not be applied"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(path = "/accounts/{id}/commands/archive")
|
@RequestMapping(path = "/accounts/{id}/commands/archive")
|
||||||
public ResponseEntity archive(@PathVariable Long id) {
|
public ResponseEntity archive(@PathVariable Long id) {
|
||||||
return Optional.ofNullable(getAccountResource(accountService.get(id)
|
return Optional.ofNullable(accountService.get(id))
|
||||||
.archive()))
|
.map(Account::archive)
|
||||||
|
.map(this::getAccountResource)
|
||||||
.map(e -> new ResponseEntity<>(e, HttpStatus.OK))
|
.map(e -> new ResponseEntity<>(e, HttpStatus.OK))
|
||||||
.orElseThrow(() -> new RuntimeException("The command could not be applied"));
|
.orElseThrow(() -> new RuntimeException("The command could not be applied"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(path = "/accounts/{id}/commands/postOrder", method = RequestMethod.POST)
|
@RequestMapping(path = "/accounts/{id}/commands/postOrder", method = RequestMethod.POST)
|
||||||
public ResponseEntity postOrder(@PathVariable Long id, @RequestBody Order order) {
|
public ResponseEntity postOrder(@PathVariable Long id, @RequestBody Order order) {
|
||||||
return Optional.ofNullable(accountService.get(id)
|
return Optional.ofNullable(accountService.get(id))
|
||||||
.postOrder(order))
|
.map(a -> a.postOrder(order))
|
||||||
.map(e -> new ResponseEntity<>(e, HttpStatus.OK))
|
.map(o -> new ResponseEntity<>(o, HttpStatus.CREATED))
|
||||||
.orElseThrow(() -> new RuntimeException("The command could not be applied"));
|
.orElseThrow(() -> new RuntimeException("The command could not be applied"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves a hypermedia resource for {@link Account} with the specified identifier.
|
|
||||||
*
|
|
||||||
* @param id is the unique identifier for looking up the {@link Account} entity
|
|
||||||
* @return a hypermedia resource for the fetched {@link Account}
|
|
||||||
*/
|
|
||||||
private Resource<Account> getAccountResource(Long id) {
|
|
||||||
// Get the account for the provided id
|
|
||||||
Account account = accountService.get(id);
|
|
||||||
|
|
||||||
return getAccountResource(account);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link Account} entity and persists the result to the repository.
|
* Creates a new {@link Account} entity and persists the result to the repository.
|
||||||
*
|
*
|
||||||
@@ -247,17 +239,17 @@ public class AccountController {
|
|||||||
private Resource<Account> getAccountResource(Account account) {
|
private Resource<Account> getAccountResource(Account account) {
|
||||||
Assert.notNull(account, "Account must not be null");
|
Assert.notNull(account, "Account must not be null");
|
||||||
|
|
||||||
if(account.getLink("commands") == null) {
|
if (!account.hasLink("commands")) {
|
||||||
// Add command link
|
// Add command link
|
||||||
account.add(linkBuilder("getCommands", account.getIdentity()).withRel("commands"));
|
account.add(linkBuilder("getCommands", account.getIdentity()).withRel("commands"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(account.getLink("events") == null) {
|
if (!account.hasLink("events")) {
|
||||||
// Add get events link
|
// Add get events link
|
||||||
account.add(linkBuilder("getAccountEvents", account.getIdentity()).withRel("events"));
|
account.add(linkBuilder("getAccountEvents", account.getIdentity()).withRel("events"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(account.getLink("orders") == null) {
|
if (!account.hasLink("orders")) {
|
||||||
// Add orders link
|
// Add orders link
|
||||||
account.add(linkBuilder("getAccountOrders", account.getIdentity()).withRel("orders"));
|
account.add(linkBuilder("getAccountOrders", account.getIdentity()).withRel("orders"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,11 @@
|
|||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.jayway.jsonpath</groupId>
|
||||||
|
<artifactId>json-path</artifactId>
|
||||||
|
<version>${json-path.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
<artifactId>h2</artifactId>
|
<artifactId>h2</artifactId>
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
package demo.order.action;
|
package demo.order.action;
|
||||||
|
|
||||||
import demo.domain.Action;
|
import demo.domain.Action;
|
||||||
import demo.order.event.OrderEvent;
|
|
||||||
import demo.order.event.OrderEventType;
|
|
||||||
import demo.order.domain.Order;
|
import demo.order.domain.Order;
|
||||||
import demo.order.domain.OrderModule;
|
import demo.order.domain.OrderModule;
|
||||||
import demo.order.domain.OrderService;
|
import demo.order.domain.OrderService;
|
||||||
import demo.order.domain.OrderStatus;
|
import demo.order.domain.OrderStatus;
|
||||||
|
import demo.order.event.OrderEvent;
|
||||||
|
import demo.order.event.OrderEventType;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connects an {@link Order} to an Account.
|
* Connects an {@link Order} to an Account.
|
||||||
@@ -18,19 +20,33 @@ import java.util.function.BiConsumer;
|
|||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class ConnectAccount extends Action<Order> {
|
public class ConnectAccount extends Action<Order> {
|
||||||
|
private final Logger log = Logger.getLogger(this.getClass());
|
||||||
|
|
||||||
public BiConsumer<Order, Long> getConsumer() {
|
public BiFunction<Order, Long, Order> getFunction() {
|
||||||
return (order, accountId) -> {
|
return (order, accountId) -> {
|
||||||
OrderService orderService = order.getModule(OrderModule.class)
|
Assert.isTrue(order.getStatus() == OrderStatus.ORDER_CREATED, "Order must be in a created state");
|
||||||
.getDefaultService();
|
|
||||||
|
Order result;
|
||||||
|
OrderService orderService = order.getModule(OrderModule.class).getDefaultService();
|
||||||
|
|
||||||
// Connect the account
|
// Connect the account
|
||||||
order.setAccountId(accountId);
|
order.setAccountId(accountId);
|
||||||
order.setStatus(OrderStatus.ACCOUNT_CONNECTED);
|
order.setStatus(OrderStatus.ACCOUNT_CONNECTED);
|
||||||
order = orderService.update(order);
|
order = orderService.update(order);
|
||||||
|
|
||||||
// Trigger the account connected event
|
try {
|
||||||
order.sendAsyncEvent(new OrderEvent(OrderEventType.ACCOUNT_CONNECTED, order));
|
// Trigger the account connected event
|
||||||
|
result = order.sendEvent(new OrderEvent(OrderEventType.ACCOUNT_CONNECTED, order)).getEntity();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.error("Could not connect order to account", ex);
|
||||||
|
order.setAccountId(null);
|
||||||
|
order.setStatus(OrderStatus.ORDER_CREATED);
|
||||||
|
orderService.update(order);
|
||||||
|
throw new IllegalStateException("Could not connect order to account", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
package demo.order.action;
|
package demo.order.action;
|
||||||
|
|
||||||
import demo.domain.Action;
|
import demo.domain.Action;
|
||||||
import demo.order.event.OrderEvent;
|
|
||||||
import demo.order.event.OrderEventType;
|
|
||||||
import demo.order.domain.Order;
|
import demo.order.domain.Order;
|
||||||
import demo.order.domain.OrderModule;
|
import demo.order.domain.OrderModule;
|
||||||
import demo.order.domain.OrderService;
|
import demo.order.domain.OrderService;
|
||||||
import demo.order.domain.OrderStatus;
|
import demo.order.domain.OrderStatus;
|
||||||
|
import demo.order.event.OrderEvent;
|
||||||
|
import demo.order.event.OrderEventType;
|
||||||
import demo.payment.domain.Payment;
|
import demo.payment.domain.Payment;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connects a {@link Payment} to an {@link Order}.
|
* Connects a {@link Payment} to an {@link Order}.
|
||||||
@@ -19,19 +21,33 @@ import java.util.function.BiConsumer;
|
|||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class ConnectPayment extends Action<Order> {
|
public class ConnectPayment extends Action<Order> {
|
||||||
public BiConsumer<Order, Long> getConsumer() {
|
private final Logger log = Logger.getLogger(this.getClass());
|
||||||
|
|
||||||
|
public BiFunction<Order, Long, Order> getFunction() {
|
||||||
return (order, paymentId) -> {
|
return (order, paymentId) -> {
|
||||||
|
Assert.isTrue(order
|
||||||
|
.getStatus() == OrderStatus.PAYMENT_CREATED, "Order must be in a payment created state");
|
||||||
|
|
||||||
OrderService orderService = order.getModule(OrderModule.class)
|
Order result;
|
||||||
.getDefaultService();
|
OrderService orderService = order.getModule(OrderModule.class).getDefaultService();
|
||||||
|
|
||||||
// Connect the account
|
// Connect the payment
|
||||||
order.setPaymentId(paymentId);
|
order.setPaymentId(paymentId);
|
||||||
order.setStatus(OrderStatus.PAYMENT_CONNECTED);
|
order.setStatus(OrderStatus.PAYMENT_CONNECTED);
|
||||||
order = orderService.update(order);
|
order = orderService.update(order);
|
||||||
|
|
||||||
// Trigger the account connected event
|
try {
|
||||||
order.sendAsyncEvent(new OrderEvent(OrderEventType.PAYMENT_CONNECTED, order));
|
// Trigger the payment connected event
|
||||||
|
result = order.sendEvent(new OrderEvent(OrderEventType.PAYMENT_CONNECTED, order)).getEntity();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.error("Could not connect payment to order", ex);
|
||||||
|
order.setPaymentId(null);
|
||||||
|
order.setStatus(OrderStatus.ORDER_CREATED);
|
||||||
|
orderService.update(order);
|
||||||
|
throw new IllegalStateException("Could not connect payment to order", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,20 @@
|
|||||||
package demo.order.action;
|
package demo.order.action;
|
||||||
|
|
||||||
import demo.domain.Action;
|
import demo.domain.Action;
|
||||||
import demo.order.event.OrderEvent;
|
|
||||||
import demo.order.event.OrderEventType;
|
|
||||||
import demo.order.domain.Order;
|
import demo.order.domain.Order;
|
||||||
import demo.order.domain.OrderModule;
|
import demo.order.domain.OrderModule;
|
||||||
import demo.order.domain.OrderService;
|
import demo.order.domain.OrderService;
|
||||||
import demo.order.domain.OrderStatus;
|
import demo.order.domain.OrderStatus;
|
||||||
|
import demo.order.event.OrderEvent;
|
||||||
|
import demo.order.event.OrderEventType;
|
||||||
import demo.payment.domain.Payment;
|
import demo.payment.domain.Payment;
|
||||||
import demo.payment.domain.PaymentMethod;
|
import demo.payment.domain.PaymentMethod;
|
||||||
|
import demo.payment.domain.PaymentService;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.springframework.hateoas.MediaTypes;
|
|
||||||
import org.springframework.hateoas.Resource;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.http.RequestEntity;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
|
|
||||||
import java.net.URI;
|
import java.util.function.Function;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link Payment} for an {@link Order}.
|
* Creates a {@link Payment} for an {@link Order}.
|
||||||
@@ -29,54 +24,54 @@ import java.util.function.Consumer;
|
|||||||
@Service
|
@Service
|
||||||
public class CreatePayment extends Action<Order> {
|
public class CreatePayment extends Action<Order> {
|
||||||
|
|
||||||
private final Logger log = Logger.getLogger(CreatePayment.class);
|
private final Logger log = Logger.getLogger(this.getClass());
|
||||||
|
private final PaymentService paymentService;
|
||||||
|
|
||||||
private RestTemplate restTemplate;
|
public CreatePayment(PaymentService paymentService) {
|
||||||
|
this.paymentService = paymentService;
|
||||||
public CreatePayment(RestTemplate restTemplate) {
|
|
||||||
this.restTemplate = restTemplate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Consumer<Order> getConsumer() {
|
public Function<Order, Order> getFunction() {
|
||||||
return order -> {
|
return order -> {
|
||||||
Assert.isTrue(order.getPaymentId() == null, "Payment has already been created");
|
Assert.isTrue(order.getPaymentId() == null, "Payment has already been created");
|
||||||
Assert.isTrue(order.getStatus() == OrderStatus.ACCOUNT_CONNECTED, "Account must be connected first");
|
Assert.isTrue(order.getStatus() == OrderStatus.ACCOUNT_CONNECTED, "Account must be connected first");
|
||||||
|
|
||||||
OrderService orderService = order.getModule(OrderModule.class)
|
// Get entity services
|
||||||
.getDefaultService();
|
OrderService orderService = order.getModule(OrderModule.class).getDefaultService();
|
||||||
|
Order result;
|
||||||
|
|
||||||
Payment payment = new Payment();
|
Payment payment = new Payment();
|
||||||
|
|
||||||
// Calculate payment amount
|
|
||||||
payment.setAmount(order.calculateTotal());
|
payment.setAmount(order.calculateTotal());
|
||||||
|
|
||||||
// Set payment method
|
|
||||||
payment.setPaymentMethod(PaymentMethod.CREDIT_CARD);
|
payment.setPaymentMethod(PaymentMethod.CREDIT_CARD);
|
||||||
|
payment = paymentService.create(payment);
|
||||||
|
|
||||||
// Create a new request entity
|
log.info(payment);
|
||||||
RequestEntity<Resource<Payment>> requestEntity = RequestEntity.post(
|
|
||||||
URI.create("http://payment-web/v1/payments"))
|
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
|
||||||
.accept(MediaTypes.HAL_JSON)
|
|
||||||
.body(new Resource<>(payment), Resource.class);
|
|
||||||
|
|
||||||
// Update the order entity's status
|
// Update the order status
|
||||||
Resource paymentResource = restTemplate
|
|
||||||
.exchange(requestEntity, Resource.class)
|
|
||||||
.getBody();
|
|
||||||
|
|
||||||
log.info(paymentResource);
|
|
||||||
|
|
||||||
// Update the status
|
|
||||||
order.setStatus(OrderStatus.PAYMENT_CREATED);
|
order.setStatus(OrderStatus.PAYMENT_CREATED);
|
||||||
order = orderService.update(order);
|
order = orderService.update(order);
|
||||||
|
|
||||||
OrderEvent event = new OrderEvent(OrderEventType.PAYMENT_CREATED, order);
|
try {
|
||||||
event.add(paymentResource.getLink("self")
|
OrderEvent event = new OrderEvent(OrderEventType.PAYMENT_CREATED, order);
|
||||||
.withRel("payment"));
|
event.add(payment.getLink("self").withRel("payment"));
|
||||||
|
|
||||||
// Trigger the payment created
|
// Trigger payment created event
|
||||||
order.sendAsyncEvent(event);
|
result = order.sendEvent(event).getEntity();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.error("The order's payment could not be created", ex);
|
||||||
|
|
||||||
|
// Rollback the payment creation
|
||||||
|
if (payment.getIdentity() != null)
|
||||||
|
paymentService.delete(payment.getIdentity());
|
||||||
|
|
||||||
|
order.setPaymentId(null);
|
||||||
|
order.setStatus(OrderStatus.ACCOUNT_CONNECTED);
|
||||||
|
orderService.update(order);
|
||||||
|
|
||||||
|
throw new IllegalStateException("Payment creation failed", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ import demo.domain.Action;
|
|||||||
import demo.order.domain.Order;
|
import demo.order.domain.Order;
|
||||||
import demo.order.domain.OrderModule;
|
import demo.order.domain.OrderModule;
|
||||||
import demo.payment.domain.Payment;
|
import demo.payment.domain.Payment;
|
||||||
|
import demo.payment.domain.PaymentService;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@@ -17,19 +18,18 @@ import java.util.function.Consumer;
|
|||||||
@Service
|
@Service
|
||||||
public class DeleteOrder extends Action<Order> {
|
public class DeleteOrder extends Action<Order> {
|
||||||
|
|
||||||
private RestTemplate restTemplate;
|
private final Logger log = Logger.getLogger(this.getClass());
|
||||||
|
private final PaymentService paymentService;
|
||||||
|
|
||||||
public DeleteOrder(RestTemplate restTemplate) {
|
public DeleteOrder(PaymentService paymentService) {
|
||||||
this.restTemplate = restTemplate;
|
this.paymentService = paymentService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Consumer<Order> getConsumer() {
|
public Consumer<Order> getConsumer() {
|
||||||
return (order) -> {
|
return (order) -> {
|
||||||
// Delete payment
|
// Delete payment
|
||||||
if (order.getPaymentId() != null) {
|
if (order.getPaymentId() != null)
|
||||||
String href = "http://payment-web/v1/payments/" + order.getPaymentId();
|
paymentService.delete(order.getPaymentId());
|
||||||
restTemplate.delete(href);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete order
|
// Delete order
|
||||||
order.getModule(OrderModule.class)
|
order.getModule(OrderModule.class)
|
||||||
|
|||||||
@@ -2,10 +2,21 @@ package demo.order.action;
|
|||||||
|
|
||||||
import demo.domain.Action;
|
import demo.domain.Action;
|
||||||
import demo.order.domain.Order;
|
import demo.order.domain.Order;
|
||||||
|
import demo.order.domain.OrderModule;
|
||||||
|
import demo.order.domain.OrderService;
|
||||||
|
import demo.order.domain.OrderStatus;
|
||||||
|
import demo.order.event.OrderEvent;
|
||||||
|
import demo.order.event.OrderEventType;
|
||||||
import demo.payment.domain.Payment;
|
import demo.payment.domain.Payment;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.springframework.hateoas.MediaTypes;
|
||||||
|
import org.springframework.hateoas.client.Traverson;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.net.URI;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes a {@link Payment} for an {@link Order}.
|
* Processes a {@link Payment} for an {@link Order}.
|
||||||
@@ -14,7 +25,51 @@ import java.util.function.Consumer;
|
|||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class ProcessPayment extends Action<Order> {
|
public class ProcessPayment extends Action<Order> {
|
||||||
public Consumer<Order> getConsumer() {
|
|
||||||
return (order) -> {};
|
private final Logger log = Logger.getLogger(this.getClass());
|
||||||
|
|
||||||
|
public Function<Order, Order> getFunction() {
|
||||||
|
return order -> {
|
||||||
|
Assert.isTrue(!Arrays
|
||||||
|
.asList(OrderStatus.PAYMENT_SUCCEEDED, OrderStatus.PAYMENT_PENDING, OrderStatus.PAYMENT_FAILED)
|
||||||
|
.contains(order.getStatus()), "Payment has already been processed");
|
||||||
|
Assert.isTrue(order.getStatus() == OrderStatus.PAYMENT_CONNECTED, "Payment must be connected to an order");
|
||||||
|
|
||||||
|
Order result = order;
|
||||||
|
|
||||||
|
// Get entity services
|
||||||
|
OrderService orderService = order.getModule(OrderModule.class).getDefaultService();
|
||||||
|
|
||||||
|
// Get the payment
|
||||||
|
Payment payment = order.getPayment();
|
||||||
|
|
||||||
|
// Update the order status
|
||||||
|
order.setStatus(OrderStatus.PAYMENT_PENDING);
|
||||||
|
order = orderService.update(order);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create traverson for the new order
|
||||||
|
Traverson traverson = new Traverson(URI.create(payment.getLink("self").getHref()), MediaTypes.HAL_JSON);
|
||||||
|
payment = traverson.follow("commands", "processPayment").toObject(Payment.class);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.error("The order's payment could not be processed", ex);
|
||||||
|
|
||||||
|
OrderEvent event = new OrderEvent(OrderEventType.PAYMENT_FAILED, order);
|
||||||
|
event.add(payment.getLink("self").withRel("payment"));
|
||||||
|
|
||||||
|
// Trigger payment failed event
|
||||||
|
result = order.sendEvent(event).getEntity();
|
||||||
|
} finally {
|
||||||
|
if (result.getStatus() != OrderStatus.PAYMENT_FAILED) {
|
||||||
|
OrderEvent event = new OrderEvent(OrderEventType.PAYMENT_SUCCEEDED, result);
|
||||||
|
event.add(payment.getLink("self").withRel("payment"));
|
||||||
|
|
||||||
|
// Trigger payment created event
|
||||||
|
result = order.sendEvent(event).getEntity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,23 +212,27 @@ public class OrderController {
|
|||||||
* @return is a hypermedia enriched resource for the supplied {@link Order} entity
|
* @return is a hypermedia enriched resource for the supplied {@link Order} entity
|
||||||
*/
|
*/
|
||||||
private Resource<Order> getOrderResource(Order order) {
|
private Resource<Order> getOrderResource(Order order) {
|
||||||
if(order == null) return null;
|
if (order == null) return null;
|
||||||
|
|
||||||
// Add command link
|
if (order.getLink("commands") == null) {
|
||||||
order.add(linkBuilder("getCommands", order.getIdentity()).withRel("commands"));
|
// Add command link
|
||||||
|
order.add(linkBuilder("getCommands", order.getIdentity()).withRel("commands"));
|
||||||
|
}
|
||||||
|
|
||||||
// Add get events link
|
if (order.getLink("events") == null) {
|
||||||
order.add(linkBuilder("getOrderEvents", order.getIdentity()).withRel("events"));
|
// Add get events link
|
||||||
|
order.add(linkBuilder("getOrderEvents", order.getIdentity()).withRel("events"));
|
||||||
|
}
|
||||||
|
|
||||||
// Add remote account link
|
// Add remote account link
|
||||||
if (order.getAccountId() != null) {
|
if (order.getAccountId() != null && order.getLink("account") == null) {
|
||||||
Link result = getRemoteLink("account-web", "/v1/accounts/{id}", order.getAccountId(), "account");
|
Link result = getRemoteLink("account-web", "/v1/accounts/{id}", order.getAccountId(), "account");
|
||||||
if (result != null)
|
if (result != null)
|
||||||
order.add(result);
|
order.add(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add remote payment link
|
// Add remote payment link
|
||||||
if (order.getPaymentId() != null) {
|
if (order.getPaymentId() != null && order.getLink("payment") == null) {
|
||||||
Link result = getRemoteLink("payment-web", "/v1/payments/{id}", order.getPaymentId(), "payment");
|
Link result = getRemoteLink("payment-web", "/v1/payments/{id}", order.getPaymentId(), "payment");
|
||||||
if (result != null)
|
if (result != null)
|
||||||
order.add(result);
|
order.add(result);
|
||||||
|
|||||||
@@ -3,10 +3,13 @@ package demo.order.domain;
|
|||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import demo.domain.AbstractEntity;
|
import demo.domain.AbstractEntity;
|
||||||
|
import demo.domain.Aggregate;
|
||||||
import demo.domain.Command;
|
import demo.domain.Command;
|
||||||
import demo.order.event.OrderEvent;
|
import demo.domain.Module;
|
||||||
import demo.order.action.*;
|
import demo.order.action.*;
|
||||||
import demo.order.controller.OrderController;
|
import demo.order.controller.OrderController;
|
||||||
|
import demo.order.event.OrderEvent;
|
||||||
|
import demo.payment.domain.Payment;
|
||||||
import org.springframework.hateoas.Link;
|
import org.springframework.hateoas.Link;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
@@ -97,34 +100,30 @@ public class Order extends AbstractEntity<OrderEvent, Long> {
|
|||||||
|
|
||||||
@Command(method = "connectAccount", controller = OrderController.class)
|
@Command(method = "connectAccount", controller = OrderController.class)
|
||||||
public Order connectAccount(Long accountId) {
|
public Order connectAccount(Long accountId) {
|
||||||
getAction(ConnectAccount.class)
|
return getAction(ConnectAccount.class)
|
||||||
.getConsumer()
|
.getFunction()
|
||||||
.accept(this, accountId);
|
.apply(this, accountId);
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(method = "connectPayment", controller = OrderController.class)
|
@Command(method = "connectPayment", controller = OrderController.class)
|
||||||
public Order connectPayment(Long paymentId) {
|
public Order connectPayment(Long paymentId) {
|
||||||
getAction(ConnectPayment.class)
|
return getAction(ConnectPayment.class)
|
||||||
.getConsumer()
|
.getFunction()
|
||||||
.accept(this, paymentId);
|
.apply(this, paymentId);
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(method = "createPayment", controller = OrderController.class)
|
@Command(method = "createPayment", controller = OrderController.class)
|
||||||
public Order createPayment() {
|
public Order createPayment() {
|
||||||
getAction(CreatePayment.class)
|
return getAction(CreatePayment.class)
|
||||||
.getConsumer()
|
.getFunction()
|
||||||
.accept(this);
|
.apply(this);
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(method = "processPayment", controller = OrderController.class)
|
@Command(method = "processPayment", controller = OrderController.class)
|
||||||
public Order processPayment() {
|
public Order processPayment() {
|
||||||
getAction(ProcessPayment.class)
|
return getAction(ProcessPayment.class)
|
||||||
.getConsumer()
|
.getFunction()
|
||||||
.accept(this);
|
.apply(this);
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(method = "reserveInventory", controller = OrderController.class)
|
@Command(method = "reserveInventory", controller = OrderController.class)
|
||||||
@@ -151,6 +150,24 @@ public class Order extends AbstractEntity<OrderEvent, Long> {
|
|||||||
.sum();
|
.sum();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public Payment getPayment() {
|
||||||
|
Payment result = null;
|
||||||
|
|
||||||
|
if (paymentId != null)
|
||||||
|
result = getModule(OrderModule.class).getPaymentService().get(paymentId);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T extends Module<A>, A extends Aggregate<OrderEvent, Long>> T getModule() throws
|
||||||
|
IllegalArgumentException {
|
||||||
|
OrderModule orderModule = getModule(OrderModule.class);
|
||||||
|
return (T) orderModule;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link Link} with a rel of {@link Link#REL_SELF}.
|
* Returns the {@link Link} with a rel of {@link Link#REL_SELF}.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,15 +3,19 @@ package demo.order.domain;
|
|||||||
import demo.domain.Module;
|
import demo.domain.Module;
|
||||||
import demo.event.EventService;
|
import demo.event.EventService;
|
||||||
import demo.order.event.OrderEvent;
|
import demo.order.event.OrderEvent;
|
||||||
|
import demo.payment.domain.PaymentService;
|
||||||
|
|
||||||
@org.springframework.stereotype.Service
|
@org.springframework.stereotype.Service
|
||||||
public class OrderModule extends Module<Order> {
|
public class OrderModule extends Module<Order> {
|
||||||
|
|
||||||
private final OrderService orderService;
|
private final OrderService orderService;
|
||||||
|
private final PaymentService paymentService;
|
||||||
private final EventService<OrderEvent, Long> eventService;
|
private final EventService<OrderEvent, Long> eventService;
|
||||||
|
|
||||||
public OrderModule(OrderService orderService, EventService<OrderEvent, Long> eventService) {
|
public OrderModule(OrderService orderService, PaymentService paymentService, EventService<OrderEvent, Long>
|
||||||
|
eventService) {
|
||||||
this.orderService = orderService;
|
this.orderService = orderService;
|
||||||
|
this.paymentService = paymentService;
|
||||||
this.eventService = eventService;
|
this.eventService = eventService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,4 +36,8 @@ public class OrderModule extends Module<Order> {
|
|||||||
public EventService<OrderEvent, Long> getDefaultEventService() {
|
public EventService<OrderEvent, Long> getDefaultEventService() {
|
||||||
return eventService;
|
return eventService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PaymentService getPaymentService() {
|
||||||
|
return paymentService;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,19 @@
|
|||||||
package demo.payment.domain;
|
package demo.payment.domain;
|
||||||
|
|
||||||
public class Payment {
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import demo.domain.Aggregate;
|
||||||
|
import demo.domain.Module;
|
||||||
|
import org.springframework.hateoas.Link;
|
||||||
|
import org.springframework.hateoas.TemplateVariable;
|
||||||
|
import org.springframework.hateoas.UriTemplate;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Payment extends Aggregate<PaymentEvent, Long> {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private List<PaymentEvent> events = new ArrayList<>();
|
||||||
private Double amount;
|
private Double amount;
|
||||||
private PaymentMethod paymentMethod;
|
private PaymentMethod paymentMethod;
|
||||||
private PaymentStatus status;
|
private PaymentStatus status;
|
||||||
@@ -38,10 +50,47 @@ public class Payment {
|
|||||||
this.paymentMethod = paymentMethod;
|
this.paymentMethod = paymentMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonProperty("paymentId")
|
||||||
|
@Override
|
||||||
|
public Long getIdentity() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIdentity(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PaymentEvent> getEvents() {
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link Link} with a rel of {@link Link#REL_SELF}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Link getId() {
|
||||||
|
return new Link(new UriTemplate("http://payment-web/v1/payments/{id}")
|
||||||
|
.with("id", TemplateVariable.VariableType
|
||||||
|
.PATH_VARIABLE)
|
||||||
|
.expand(getIdentity())
|
||||||
|
.toString()).withSelfRel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T extends Module<A>, A extends Aggregate<PaymentEvent, Long>> T getModule() throws
|
||||||
|
IllegalArgumentException {
|
||||||
|
PaymentModule paymentModule = getModule(PaymentModule.class);
|
||||||
|
return (T) paymentModule;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Payment{" +
|
return "Payment{" +
|
||||||
"amount=" + amount +
|
"id=" + id +
|
||||||
|
", events=" + events +
|
||||||
|
", amount=" + amount +
|
||||||
", paymentMethod=" + paymentMethod +
|
", paymentMethod=" + paymentMethod +
|
||||||
", status=" + status +
|
", status=" + status +
|
||||||
"} " + super.toString();
|
"} " + super.toString();
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package demo.payment.domain;
|
||||||
|
|
||||||
|
import demo.event.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The domain event {@link PaymentEvent} tracks the type and state of events as applied to the {@link Payment} domain
|
||||||
|
* object. This event resource can be used to event source the aggregate state of {@link Payment}.
|
||||||
|
*
|
||||||
|
* @author kbastani
|
||||||
|
*/
|
||||||
|
public class PaymentEvent extends Event<Payment, PaymentEventType, Long> {
|
||||||
|
|
||||||
|
private Long eventId;
|
||||||
|
private PaymentEventType type;
|
||||||
|
private Payment payment;
|
||||||
|
private Long createdAt;
|
||||||
|
private Long lastModified;
|
||||||
|
|
||||||
|
public PaymentEvent() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public PaymentEvent(PaymentEventType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PaymentEvent(PaymentEventType type, Payment payment) {
|
||||||
|
this.type = type;
|
||||||
|
this.payment = payment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getEventId() {
|
||||||
|
return eventId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEventId(Long id) {
|
||||||
|
eventId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PaymentEventType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setType(PaymentEventType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Payment getEntity() {
|
||||||
|
return payment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEntity(Payment entity) {
|
||||||
|
this.payment = entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCreatedAt(Long createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getLastModified() {
|
||||||
|
return lastModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLastModified(Long lastModified) {
|
||||||
|
this.lastModified = lastModified;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package demo.payment.domain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link PaymentEventType} represents a collection of possible events that describe state transitions of
|
||||||
|
* {@link PaymentStatus} on the {@link Payment} aggregate.
|
||||||
|
*
|
||||||
|
* @author kbastani
|
||||||
|
*/
|
||||||
|
public enum PaymentEventType {
|
||||||
|
PAYMENT_CREATED,
|
||||||
|
ORDER_CONNECTED,
|
||||||
|
PAYMENT_PENDING,
|
||||||
|
PAYMENT_PROCESSED,
|
||||||
|
PAYMENT_FAILED,
|
||||||
|
PAYMENT_SUCCEEDED
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package demo.payment.domain;
|
||||||
|
|
||||||
|
import demo.domain.Module;
|
||||||
|
import demo.event.EventService;
|
||||||
|
import demo.order.event.OrderEvent;
|
||||||
|
|
||||||
|
@org.springframework.stereotype.Service
|
||||||
|
public class PaymentModule extends Module<Payment> {
|
||||||
|
|
||||||
|
private final PaymentService paymentService;
|
||||||
|
private final EventService<OrderEvent, Long> eventService;
|
||||||
|
|
||||||
|
public PaymentModule(PaymentService paymentService, EventService<OrderEvent, Long> eventService) {
|
||||||
|
this.paymentService = paymentService;
|
||||||
|
this.eventService = eventService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PaymentService getPaymentService() {
|
||||||
|
return paymentService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EventService<OrderEvent, Long> getEventService() {
|
||||||
|
return eventService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PaymentService getDefaultService() {
|
||||||
|
return paymentService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EventService<OrderEvent, Long> getDefaultEventService() {
|
||||||
|
return eventService;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package demo.payment.domain;
|
||||||
|
|
||||||
|
import demo.domain.Service;
|
||||||
|
import org.springframework.hateoas.TemplateVariable;
|
||||||
|
import org.springframework.hateoas.UriTemplate;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.RequestEntity;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
@org.springframework.stereotype.Service
|
||||||
|
public class PaymentService extends Service<Payment, Long> {
|
||||||
|
|
||||||
|
private RestTemplate restTemplate;
|
||||||
|
|
||||||
|
public PaymentService(RestTemplate restTemplate) {
|
||||||
|
this.restTemplate = restTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Payment get(Long paymentId) {
|
||||||
|
return restTemplate.getForObject(new UriTemplate("http://payment-web/v1/payments/{id}")
|
||||||
|
.with("id", TemplateVariable.VariableType.PATH_VARIABLE)
|
||||||
|
.expand(paymentId), Payment.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Payment create(Payment payment) {
|
||||||
|
return restTemplate.postForObject(new UriTemplate("http://payment-web/v1/payments").expand(),
|
||||||
|
payment, Payment.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Payment update(Payment payment) {
|
||||||
|
return restTemplate.exchange(new RequestEntity<>(payment, HttpMethod.PUT, new UriTemplate
|
||||||
|
("http://payment-web/v1/payments/{id}").with("id", TemplateVariable.VariableType.PATH_VARIABLE)
|
||||||
|
.expand(payment.getIdentity())), Payment.class)
|
||||||
|
.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean delete(Long paymentId) {
|
||||||
|
restTemplate.delete(new UriTemplate("http://payment-web/v1/payments/{id}").with("id", TemplateVariable
|
||||||
|
.VariableType.PATH_VARIABLE)
|
||||||
|
.expand(paymentId));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package demo.payment.domain;
|
|||||||
|
|
||||||
public enum PaymentStatus {
|
public enum PaymentStatus {
|
||||||
PAYMENT_CREATED,
|
PAYMENT_CREATED,
|
||||||
|
ORDER_CONNECTED,
|
||||||
PAYMENT_PENDING,
|
PAYMENT_PENDING,
|
||||||
PAYMENT_PROCESSED,
|
PAYMENT_PROCESSED,
|
||||||
PAYMENT_FAILED,
|
PAYMENT_FAILED,
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package demo.payment.domain;
|
||||||
|
|
||||||
|
import demo.order.domain.Order;
|
||||||
|
import org.springframework.hateoas.Link;
|
||||||
|
import org.springframework.hateoas.Resources;
|
||||||
|
|
||||||
|
public class Payments extends Resources<Order> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an empty {@link Resources} instance.
|
||||||
|
*/
|
||||||
|
public Payments() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link Resources} instance with the given content and {@link Link}s (optional).
|
||||||
|
*
|
||||||
|
* @param content must not be {@literal null}.
|
||||||
|
* @param links the links to be added to the {@link Resources}.
|
||||||
|
*/
|
||||||
|
public Payments(Iterable<Order> content, Link... links) {
|
||||||
|
super(content, links);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -135,17 +135,11 @@ public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderS
|
|||||||
.and()
|
.and()
|
||||||
.withExternal()
|
.withExternal()
|
||||||
.source(OrderStatus.PAYMENT_CREATED)
|
.source(OrderStatus.PAYMENT_CREATED)
|
||||||
.target(OrderStatus.PAYMENT_CONNECTED)
|
.target(OrderStatus.PAYMENT_PENDING)
|
||||||
.event(OrderEventType.PAYMENT_CONNECTED)
|
.event(OrderEventType.PAYMENT_CONNECTED)
|
||||||
.action(paymentConnected())
|
.action(paymentConnected())
|
||||||
.and()
|
.and()
|
||||||
.withExternal()
|
.withExternal()
|
||||||
.source(OrderStatus.PAYMENT_CONNECTED)
|
|
||||||
.target(OrderStatus.PAYMENT_PENDING)
|
|
||||||
.event(OrderEventType.PAYMENT_PENDING)
|
|
||||||
.action(paymentPending())
|
|
||||||
.and()
|
|
||||||
.withExternal()
|
|
||||||
.source(OrderStatus.PAYMENT_PENDING)
|
.source(OrderStatus.PAYMENT_PENDING)
|
||||||
.target(OrderStatus.PAYMENT_SUCCEEDED)
|
.target(OrderStatus.PAYMENT_SUCCEEDED)
|
||||||
.event(OrderEventType.PAYMENT_SUCCEEDED)
|
.event(OrderEventType.PAYMENT_SUCCEEDED)
|
||||||
@@ -166,7 +160,7 @@ public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderS
|
|||||||
return context -> applyEvent(context,
|
return context -> applyEvent(context,
|
||||||
new OrderCreated(context, event -> {
|
new OrderCreated(context, event -> {
|
||||||
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
||||||
// Get the account resource for the event
|
// Get the order resource for the event
|
||||||
Traverson traverson = new Traverson(
|
Traverson traverson = new Traverson(
|
||||||
URI.create(event.getLink("order").getHref()),
|
URI.create(event.getLink("order").getHref()),
|
||||||
MediaTypes.HAL_JSON
|
MediaTypes.HAL_JSON
|
||||||
@@ -183,7 +177,7 @@ public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderS
|
|||||||
return context -> applyEvent(context,
|
return context -> applyEvent(context,
|
||||||
new PaymentPending(context, event -> {
|
new PaymentPending(context, event -> {
|
||||||
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
||||||
// Get the account resource for the event
|
// Get the order resource for the event
|
||||||
Traverson traverson = new Traverson(
|
Traverson traverson = new Traverson(
|
||||||
URI.create(event.getLink("order").getHref()),
|
URI.create(event.getLink("order").getHref()),
|
||||||
MediaTypes.HAL_JSON
|
MediaTypes.HAL_JSON
|
||||||
@@ -200,7 +194,7 @@ public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderS
|
|||||||
return context -> applyEvent(context,
|
return context -> applyEvent(context,
|
||||||
new ReservationPending(context, event -> {
|
new ReservationPending(context, event -> {
|
||||||
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
||||||
// Get the account resource for the event
|
// Get the order resource for the event
|
||||||
Traverson traverson = new Traverson(
|
Traverson traverson = new Traverson(
|
||||||
URI.create(event.getLink("order").getHref()),
|
URI.create(event.getLink("order").getHref()),
|
||||||
MediaTypes.HAL_JSON
|
MediaTypes.HAL_JSON
|
||||||
@@ -217,7 +211,7 @@ public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderS
|
|||||||
return context -> applyEvent(context,
|
return context -> applyEvent(context,
|
||||||
new PaymentFailed(context, event -> {
|
new PaymentFailed(context, event -> {
|
||||||
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
||||||
// Get the account resource for the event
|
// Get the order resource for the event
|
||||||
Traverson traverson = new Traverson(
|
Traverson traverson = new Traverson(
|
||||||
URI.create(event.getLink("order").getHref()),
|
URI.create(event.getLink("order").getHref()),
|
||||||
MediaTypes.HAL_JSON
|
MediaTypes.HAL_JSON
|
||||||
@@ -231,19 +225,7 @@ public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderS
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Action<OrderStatus, OrderEventType> paymentSucceeded() {
|
public Action<OrderStatus, OrderEventType> paymentSucceeded() {
|
||||||
return context -> applyEvent(context,
|
return context -> applyEvent(context, new PaymentSucceeded(context));
|
||||||
new PaymentSucceeded(context, event -> {
|
|
||||||
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
|
||||||
// Get the account resource for the event
|
|
||||||
Traverson traverson = new Traverson(
|
|
||||||
URI.create(event.getLink("order").getHref()),
|
|
||||||
MediaTypes.HAL_JSON
|
|
||||||
);
|
|
||||||
|
|
||||||
return traverson.follow("self")
|
|
||||||
.toEntity(Order.class)
|
|
||||||
.getBody();
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@@ -251,15 +233,16 @@ public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderS
|
|||||||
return context -> applyEvent(context,
|
return context -> applyEvent(context,
|
||||||
new PaymentConnected(context, event -> {
|
new PaymentConnected(context, event -> {
|
||||||
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
||||||
// Get the account resource for the event
|
|
||||||
|
// Create a traverson for the root order
|
||||||
Traverson traverson = new Traverson(
|
Traverson traverson = new Traverson(
|
||||||
URI.create(event.getLink("order").getHref()),
|
URI.create(event.getLink("order").getHref()),
|
||||||
MediaTypes.HAL_JSON
|
MediaTypes.HAL_JSON
|
||||||
);
|
);
|
||||||
|
|
||||||
return traverson.follow("self")
|
// Traverse to the process payment link
|
||||||
.toEntity(Order.class)
|
return traverson.follow("self", "commands", "processPayment")
|
||||||
.getBody();
|
.toObject(Order.class);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,7 +251,7 @@ public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderS
|
|||||||
return context -> applyEvent(context,
|
return context -> applyEvent(context,
|
||||||
new PaymentCreated(context, event -> {
|
new PaymentCreated(context, event -> {
|
||||||
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
||||||
// Get the account resource for the event
|
// Get the order resource for the event
|
||||||
Traverson paymentResource = new Traverson(
|
Traverson paymentResource = new Traverson(
|
||||||
URI.create(event.getLink("payment").getHref()),
|
URI.create(event.getLink("payment").getHref()),
|
||||||
MediaTypes.HAL_JSON
|
MediaTypes.HAL_JSON
|
||||||
@@ -307,7 +290,7 @@ public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderS
|
|||||||
return context -> applyEvent(context,
|
return context -> applyEvent(context,
|
||||||
new ReservationSucceeded(context, event -> {
|
new ReservationSucceeded(context, event -> {
|
||||||
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
||||||
// Get the account resource for the event
|
// Get the order resource for the event
|
||||||
Traverson traverson = new Traverson(
|
Traverson traverson = new Traverson(
|
||||||
URI.create(event.getLink("order").getHref()),
|
URI.create(event.getLink("order").getHref()),
|
||||||
MediaTypes.HAL_JSON
|
MediaTypes.HAL_JSON
|
||||||
@@ -324,7 +307,7 @@ public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderS
|
|||||||
return context -> applyEvent(context,
|
return context -> applyEvent(context,
|
||||||
new ReservationSucceeded(context, event -> {
|
new ReservationSucceeded(context, event -> {
|
||||||
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
||||||
// Get the account resource for the event
|
// Get the order resource for the event
|
||||||
Traverson traverson = new Traverson(
|
Traverson traverson = new Traverson(
|
||||||
URI.create(event.getLink("order").getHref()),
|
URI.create(event.getLink("order").getHref()),
|
||||||
MediaTypes.HAL_JSON
|
MediaTypes.HAL_JSON
|
||||||
@@ -341,7 +324,7 @@ public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderS
|
|||||||
return context -> applyEvent(context,
|
return context -> applyEvent(context,
|
||||||
new ReservationFailed(context, event -> {
|
new ReservationFailed(context, event -> {
|
||||||
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
||||||
// Get the account resource for the event
|
// Get the order resource for the event
|
||||||
Traverson traverson = new Traverson(
|
Traverson traverson = new Traverson(
|
||||||
URI.create(event.getLink("order").getHref()),
|
URI.create(event.getLink("order").getHref()),
|
||||||
MediaTypes.HAL_JSON
|
MediaTypes.HAL_JSON
|
||||||
|
|||||||
@@ -5,14 +5,23 @@ import demo.order.event.OrderEventType;
|
|||||||
import demo.order.domain.Order;
|
import demo.order.domain.Order;
|
||||||
import demo.order.domain.OrderStatus;
|
import demo.order.domain.OrderStatus;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
import org.springframework.hateoas.MediaTypes;
|
||||||
|
import org.springframework.hateoas.client.Traverson;
|
||||||
|
import org.springframework.http.RequestEntity;
|
||||||
import org.springframework.statemachine.StateContext;
|
import org.springframework.statemachine.StateContext;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class PaymentSucceeded extends OrderFunction {
|
public class PaymentSucceeded extends OrderFunction {
|
||||||
|
|
||||||
final private Logger log = Logger.getLogger(PaymentSucceeded.class);
|
final private Logger log = Logger.getLogger(PaymentSucceeded.class);
|
||||||
|
|
||||||
|
public PaymentSucceeded(StateContext<OrderStatus, OrderEventType> context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
public PaymentSucceeded(StateContext<OrderStatus, OrderEventType> context, Function<OrderEvent, Order> lambda) {
|
public PaymentSucceeded(StateContext<OrderStatus, OrderEventType> context, Function<OrderEvent, Order> lambda) {
|
||||||
super(context, lambda);
|
super(context, lambda);
|
||||||
}
|
}
|
||||||
@@ -25,7 +34,50 @@ public class PaymentSucceeded extends OrderFunction {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Order apply(OrderEvent event) {
|
public Order apply(OrderEvent event) {
|
||||||
|
Order order;
|
||||||
|
|
||||||
log.info("Executing workflow for payment succeeded...");
|
log.info("Executing workflow for payment succeeded...");
|
||||||
return super.apply(event);
|
|
||||||
|
// Create a traverson for the root order
|
||||||
|
Traverson traverson = new Traverson(
|
||||||
|
URI.create(event.getLink("order").getHref()),
|
||||||
|
MediaTypes.HAL_JSON
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get the order resource attached to the event
|
||||||
|
order = traverson.follow("self")
|
||||||
|
.toEntity(Order.class)
|
||||||
|
.getBody();
|
||||||
|
|
||||||
|
// Set the order to a pending state
|
||||||
|
order = setOrderPaymentSucceededStatus(event, order);
|
||||||
|
|
||||||
|
context.getExtendedState().getVariables().put("order", order);
|
||||||
|
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link Order} resource to a payment succeeded state.
|
||||||
|
*
|
||||||
|
* @param event is the {@link OrderEvent} for this context
|
||||||
|
* @param order is the {@link Order} attached to the {@link OrderEvent} resource
|
||||||
|
* @return an {@link Order} with its updated state set to pending
|
||||||
|
*/
|
||||||
|
private Order setOrderPaymentSucceededStatus(OrderEvent event, Order order) {
|
||||||
|
// Set the account status to pending
|
||||||
|
order.setStatus(OrderStatus.PAYMENT_SUCCEEDED);
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
|
||||||
|
// Create a new request entity
|
||||||
|
RequestEntity<Order> requestEntity = RequestEntity.put(
|
||||||
|
URI.create(event.getLink("order").getHref()))
|
||||||
|
.contentType(MediaTypes.HAL_JSON)
|
||||||
|
.body(order);
|
||||||
|
|
||||||
|
// Update the account entity's status
|
||||||
|
order = restTemplate.exchange(requestEntity, Order.class).getBody();
|
||||||
|
|
||||||
|
return order;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ public class Order extends AbstractEntity {
|
|||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
private Long accountId;
|
||||||
|
|
||||||
|
private Long paymentId;
|
||||||
|
|
||||||
private OrderStatus status;
|
private OrderStatus status;
|
||||||
|
|
||||||
private Set<OrderEvent> events = new HashSet<>();
|
private Set<OrderEvent> events = new HashSet<>();
|
||||||
@@ -68,6 +72,22 @@ public class Order extends AbstractEntity {
|
|||||||
lineItems.add(lineItem);
|
lineItems.add(lineItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getAccountId() {
|
||||||
|
return accountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccountId(Long accountId) {
|
||||||
|
this.accountId = accountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getPaymentId() {
|
||||||
|
return paymentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPaymentId(Long paymentId) {
|
||||||
|
this.paymentId = paymentId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link Link} with a rel of {@link Link#REL_SELF}.
|
* Returns the {@link Link} with a rel of {@link Link#REL_SELF}.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -8,13 +8,19 @@ import demo.payment.domain.PaymentStatus;
|
|||||||
import demo.payment.event.PaymentEvent;
|
import demo.payment.event.PaymentEvent;
|
||||||
import demo.payment.event.PaymentEventType;
|
import demo.payment.event.PaymentEventType;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class ConnectOrder extends Action<Payment> {
|
public class ConnectOrder extends Action<Payment> {
|
||||||
public BiConsumer<Payment, Long> getConsumer() {
|
public BiFunction<Payment, Long, Payment> getFunction() {
|
||||||
return (payment, orderId) -> {
|
return (payment, orderId) -> {
|
||||||
|
Assert.isTrue(payment
|
||||||
|
.getStatus() == PaymentStatus.PAYMENT_CREATED, "Payment has already been connected to an order");
|
||||||
|
|
||||||
|
Payment result;
|
||||||
|
|
||||||
PaymentService paymentService = payment.getModule(PaymentModule.class)
|
PaymentService paymentService = payment.getModule(PaymentModule.class)
|
||||||
.getDefaultService();
|
.getDefaultService();
|
||||||
|
|
||||||
@@ -23,8 +29,17 @@ public class ConnectOrder extends Action<Payment> {
|
|||||||
payment.setStatus(PaymentStatus.ORDER_CONNECTED);
|
payment.setStatus(PaymentStatus.ORDER_CONNECTED);
|
||||||
payment = paymentService.update(payment);
|
payment = paymentService.update(payment);
|
||||||
|
|
||||||
// Trigger the payment connected
|
try {
|
||||||
payment.sendAsyncEvent(new PaymentEvent(PaymentEventType.ORDER_CONNECTED, payment));
|
// Trigger the payment connected
|
||||||
|
result = payment.sendEvent(new PaymentEvent(PaymentEventType.ORDER_CONNECTED, payment)).getEntity();
|
||||||
|
} catch (IllegalStateException ex) {
|
||||||
|
payment.setStatus(PaymentStatus.PAYMENT_CREATED);
|
||||||
|
payment.setOrderId(null);
|
||||||
|
paymentService.update(payment);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,31 @@ package demo.payment.action;
|
|||||||
|
|
||||||
import demo.domain.Action;
|
import demo.domain.Action;
|
||||||
import demo.payment.domain.Payment;
|
import demo.payment.domain.Payment;
|
||||||
|
import demo.payment.domain.PaymentModule;
|
||||||
|
import demo.payment.domain.PaymentService;
|
||||||
import demo.payment.domain.PaymentStatus;
|
import demo.payment.domain.PaymentStatus;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class ProcessPayment extends Action<Payment> {
|
public class ProcessPayment extends Action<Payment> {
|
||||||
public Consumer<Payment> getConsumer() {
|
public Consumer<Payment> getConsumer() {
|
||||||
return payment -> payment.setStatus(PaymentStatus.PAYMENT_PROCESSED);
|
return payment -> {
|
||||||
|
// Validations
|
||||||
|
Assert.isTrue(!Arrays.asList(PaymentStatus.PAYMENT_SUCCEEDED,
|
||||||
|
PaymentStatus.PAYMENT_PENDING,
|
||||||
|
PaymentStatus.PAYMENT_FAILED).contains(payment.getStatus()), "Payment has already been processed");
|
||||||
|
Assert.isTrue(payment.getStatus() == PaymentStatus.ORDER_CONNECTED,
|
||||||
|
"Payment must be connected to an order");
|
||||||
|
|
||||||
|
PaymentService paymentService = payment.getModule(PaymentModule.class)
|
||||||
|
.getDefaultService();
|
||||||
|
|
||||||
|
payment.setStatus(PaymentStatus.PAYMENT_PROCESSED);
|
||||||
|
paymentService.update(payment);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,8 +214,8 @@ public class PaymentController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add remote payment link
|
// Add remote payment link
|
||||||
if (payment.getOrderId() != null) {
|
if (payment.getOrderId() != null && !payment.hasLink("order")) {
|
||||||
Link result = getRemoteLink("order-web", "/v1/orders/{id}", payment.getOrderId(), "order ");
|
Link result = getRemoteLink("order-web", "/v1/orders/{id}", payment.getOrderId(), "order");
|
||||||
if (result != null)
|
if (result != null)
|
||||||
payment.add(result);
|
payment.add(result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,11 +90,9 @@ public class Payment extends AbstractEntity<PaymentEvent, Long> {
|
|||||||
|
|
||||||
@Command(method = "connectOrder", controller = PaymentController.class)
|
@Command(method = "connectOrder", controller = PaymentController.class)
|
||||||
public Payment connectOrder(Long orderId) {
|
public Payment connectOrder(Long orderId) {
|
||||||
getAction(ConnectOrder.class)
|
return getAction(ConnectOrder.class)
|
||||||
.getConsumer()
|
.getFunction()
|
||||||
.accept(this, orderId);
|
.apply(this, orderId);
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(method = "processPayment", controller = PaymentController.class)
|
@Command(method = "processPayment", controller = PaymentController.class)
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
package demo.domain;
|
package demo.domain;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link Action} is a reference of a method. A function contains an address to the location of a method. A function
|
* An {@link Action} is a reference of a method. A function contains an address to the location of a method. A function
|
||||||
* may contain meta-data that describes the inputs and outputs of a method. An action invokes a method annotated with
|
* may contain meta-data that describes the inputs and outputs of a method. An action invokes a method annotated with
|
||||||
@@ -14,10 +18,19 @@ import org.springframework.stereotype.Component;
|
|||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public abstract class Action<A extends Aggregate> implements ApplicationContextAware {
|
public abstract class Action<A extends Aggregate> implements ApplicationContextAware {
|
||||||
|
private final Logger log = Logger.getLogger(Action.class);
|
||||||
private ApplicationContext applicationContext;
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||||
this.applicationContext = applicationContext;
|
this.applicationContext = applicationContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Consumer<A> onSuccess(Map<String, Object> context) {
|
||||||
|
return a -> {};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Consumer<A> onError(Map<String, Object> context) {
|
||||||
|
return a -> {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user