Release inventory
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
*.class
|
||||
dump.rdb
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
@@ -8,6 +8,9 @@ import demo.order.event.OrderEventProcessor;
|
||||
import demo.order.event.OrderEventType;
|
||||
import demo.order.event.OrderEvents;
|
||||
import demo.payment.domain.Payment;
|
||||
import demo.reservation.domain.Reservation;
|
||||
import demo.reservation.domain.ReservationStatus;
|
||||
import demo.reservation.domain.Reservations;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -329,7 +332,7 @@ public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderS
|
||||
@Bean
|
||||
public Action<OrderStatus, OrderEventType> reservationFailed() {
|
||||
return context -> applyEvent(context,
|
||||
new ReservationSucceeded(context, event -> {
|
||||
new ReservationFailed(context, event -> {
|
||||
log.info(event.getType() + ": " + event.getLink("order").getHref());
|
||||
// Get the order resource for the event
|
||||
Traverson traverson = new Traverson(
|
||||
@@ -337,6 +340,22 @@ public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderS
|
||||
MediaTypes.HAL_JSON
|
||||
);
|
||||
|
||||
// Release the reservations
|
||||
Reservations reservations = traverson.follow("self", "reservations")
|
||||
.toObject(Reservations.class);
|
||||
|
||||
reservations.getContent().stream()
|
||||
.filter(r -> r.getStatus() == ReservationStatus.RESERVATION_SUCCEEDED)
|
||||
.forEach(r -> {
|
||||
Traverson res = new Traverson(
|
||||
URI.create(r.getLink("self").getHref()),
|
||||
MediaTypes.HAL_JSON
|
||||
);
|
||||
|
||||
res.follow("self", "commands", "releaseInventory")
|
||||
.toObject(Reservation.class);
|
||||
});
|
||||
|
||||
return traverson.follow("self")
|
||||
.toEntity(Order.class)
|
||||
.getBody();
|
||||
@@ -360,6 +379,5 @@ public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderS
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package demo.reservation.action;
|
||||
|
||||
import demo.domain.Action;
|
||||
import demo.inventory.domain.Inventory;
|
||||
import demo.inventory.domain.InventoryService;
|
||||
import demo.inventory.domain.InventoryStatus;
|
||||
import demo.inventory.event.InventoryEvent;
|
||||
import demo.reservation.domain.Reservation;
|
||||
import demo.reservation.domain.ReservationModule;
|
||||
import demo.reservation.domain.ReservationService;
|
||||
import demo.reservation.domain.ReservationStatus;
|
||||
import demo.reservation.event.ReservationEvent;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import static demo.inventory.event.InventoryEventType.INVENTORY_RELEASED;
|
||||
import static demo.reservation.event.ReservationEventType.RESERVATION_FAILED;
|
||||
|
||||
/**
|
||||
* Release inventory for a {@link Reservation}.
|
||||
*
|
||||
* @author Kenny Bastani
|
||||
*/
|
||||
@Service
|
||||
public class ReleaseInventory extends Action<Reservation> {
|
||||
private final Logger log = Logger.getLogger(this.getClass());
|
||||
private final InventoryService inventoryService;
|
||||
|
||||
public ReleaseInventory(InventoryService inventoryService) {
|
||||
this.inventoryService = inventoryService;
|
||||
}
|
||||
|
||||
public Function<Reservation, Reservation> getFunction() {
|
||||
return (reservation) -> {
|
||||
Assert.isTrue(reservation.getStatus() == ReservationStatus.RESERVATION_SUCCEEDED,
|
||||
"Reservation must be in a succeeded state");
|
||||
Assert.notNull(reservation.getInventory(), "The reservation has no connected inventory");
|
||||
|
||||
ReservationService reservationService = reservation.getModule(ReservationModule.class).getDefaultService();
|
||||
|
||||
Inventory inventory = reservation.getInventory();
|
||||
|
||||
try {
|
||||
// Remove the inventory and set the reservation to failed
|
||||
reservation.setInventory(null);
|
||||
reservation.setStatus(ReservationStatus.RESERVATION_FAILED);
|
||||
reservation = reservationService.update(reservation);
|
||||
|
||||
// Trigger the reservation failed event
|
||||
reservation.sendAsyncEvent(new ReservationEvent(RESERVATION_FAILED, reservation));
|
||||
} catch (Exception ex) {
|
||||
log.error("Could not release the reservation's inventory", ex);
|
||||
if (reservation.getStatus() == ReservationStatus.RESERVATION_FAILED) {
|
||||
// Rollback the attempt
|
||||
reservation.setInventory(inventory);
|
||||
reservation.setStatus(ReservationStatus.RESERVATION_SUCCEEDED);
|
||||
reservation = reservationService.update(reservation);
|
||||
}
|
||||
throw ex;
|
||||
} finally {
|
||||
// Release the inventory
|
||||
inventory.setReservation(null);
|
||||
inventory.setStatus(InventoryStatus.RESERVATION_PENDING);
|
||||
inventory = inventoryService.update(inventory);
|
||||
|
||||
// Trigger the inventory released event
|
||||
inventory.sendAsyncEvent(new InventoryEvent(INVENTORY_RELEASED, inventory));
|
||||
}
|
||||
|
||||
return reservation;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -101,6 +101,13 @@ public class ReservationController {
|
||||
.orElseThrow(() -> new RuntimeException("The command could not be applied"));
|
||||
}
|
||||
|
||||
@RequestMapping(path = "/reservations/{id}/commands/releaseInventory")
|
||||
public ResponseEntity releaseInventory(@PathVariable Long id) {
|
||||
return Optional.ofNullable(reservationService.get(id))
|
||||
.map(e -> new ResponseEntity<>(getReservationResource(e.releaseInventory()), HttpStatus.OK))
|
||||
.orElseThrow(() -> new RuntimeException("The command could not be applied"));
|
||||
}
|
||||
|
||||
@RequestMapping(path = "/reservations/{id}/commands/connectOrder")
|
||||
public ResponseEntity connectOrder(@PathVariable Long id, @RequestParam(value = "orderId") Long orderId) {
|
||||
return Optional.ofNullable(reservationService.get(id)
|
||||
|
||||
@@ -9,6 +9,7 @@ import demo.domain.Module;
|
||||
import demo.inventory.domain.Inventory;
|
||||
import demo.reservation.action.ConnectOrder;
|
||||
import demo.reservation.action.ConnectInventory;
|
||||
import demo.reservation.action.ReleaseInventory;
|
||||
import demo.reservation.controller.ReservationController;
|
||||
import demo.reservation.event.ReservationEvent;
|
||||
import demo.warehouse.domain.Warehouse;
|
||||
@@ -114,6 +115,13 @@ public class Reservation extends AbstractEntity<ReservationEvent, Long> {
|
||||
.apply(this);
|
||||
}
|
||||
|
||||
@Command(method = "releaseInventory", controller = ReservationController.class)
|
||||
public Reservation releaseInventory() {
|
||||
return getAction(ReleaseInventory.class)
|
||||
.getFunction()
|
||||
.apply(this);
|
||||
}
|
||||
|
||||
@Command(method = "connectOrder", controller = ReservationController.class)
|
||||
public Reservation connectOrder(Long orderId) {
|
||||
return getAction(ConnectOrder.class)
|
||||
|
||||
@@ -114,7 +114,13 @@ public class InventoryStateMachineConfig extends EnumStateMachineConfigurerAdapt
|
||||
.source(InventoryStatus.RESERVATION_CONNECTED)
|
||||
.target(InventoryStatus.INVENTORY_RESERVED)
|
||||
.event(InventoryEventType.INVENTORY_RESERVED)
|
||||
.action(inventoryReserved());
|
||||
.action(inventoryReserved())
|
||||
.and()
|
||||
.withExternal()
|
||||
.source(InventoryStatus.INVENTORY_RESERVED)
|
||||
.target(InventoryStatus.RESERVATION_PENDING)
|
||||
.event(InventoryEventType.INVENTORY_RELEASED)
|
||||
.action(inventoryReleased());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not configure state machine transitions", e);
|
||||
}
|
||||
@@ -173,5 +179,22 @@ public class InventoryStateMachineConfig extends EnumStateMachineConfigurerAdapt
|
||||
.getBody();
|
||||
}));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Action<InventoryStatus, InventoryEventType> inventoryReleased() {
|
||||
return context -> applyEvent(context,
|
||||
new InventoryReleased(context, event -> {
|
||||
log.info(event.getType() + ": " + event.getLink("inventory").getHref());
|
||||
// Get the inventory resource for the event
|
||||
Traverson traverson = new Traverson(
|
||||
URI.create(event.getLink("inventory").getHref()),
|
||||
MediaTypes.HAL_JSON
|
||||
);
|
||||
|
||||
return traverson.follow("self")
|
||||
.toEntity(Inventory.class)
|
||||
.getBody();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package demo.inventory.function;
|
||||
|
||||
import demo.inventory.domain.Inventory;
|
||||
import demo.inventory.domain.InventoryStatus;
|
||||
import demo.inventory.event.InventoryEvent;
|
||||
import demo.inventory.event.InventoryEventType;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class InventoryReleased extends InventoryFunction {
|
||||
|
||||
final private Logger log = Logger.getLogger(InventoryReleased.class);
|
||||
|
||||
public InventoryReleased(StateContext<InventoryStatus, InventoryEventType> context, Function<InventoryEvent,
|
||||
Inventory> lambda) {
|
||||
super(context, lambda);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply an {@link InventoryEvent} to the lambda function that was provided through the
|
||||
* constructor of this {@link InventoryFunction}.
|
||||
*
|
||||
* @param event is the {@link InventoryEvent} to apply to the lambda function
|
||||
*/
|
||||
@Override
|
||||
public Inventory apply(InventoryEvent event) {
|
||||
log.info("Executing workflow for inventory released...");
|
||||
return super.apply(event);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user