Skip to content

Commit c8e00dc

Browse files
committed
Refactor saga proxies to use annotation-based pattern
- Convert ConsumerServiceProxy, KitchenServiceProxy, and AccountingServiceProxy from CommandEndpoint fields to methods returning CommandWithDestination - Add @SagaParticipantProxy and @SagaParticipantOperation annotations - Update CreateOrderSaga to use invokeParticipant(this::method) pattern - Move command creation logic from CreateOrderSagaState to CreateOrderSaga - Add final modifier to AccountingServiceChannels.accountingServiceChannel This aligns with the pattern used in eventuate-tram-sagas-examples-customers-and-orders. Co-authored by Claude Code
1 parent b8a23b6 commit c8e00dc

7 files changed

Lines changed: 103 additions & 85 deletions

File tree

ftgo-order-service/order-service-proxies-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountservice/api/AccountingServiceChannels.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33

44
public class AccountingServiceChannels {
55

6-
public static String accountingServiceChannel = "accountingService";
6+
public static final String accountingServiceChannel = "accountingService";
77

88
}
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
package net.chrisrichardson.ftgo.orderservice.sagaparticipants;
22

33
import io.eventuate.tram.commands.common.Success;
4-
import io.eventuate.tram.sagas.simpledsl.CommandEndpoint;
5-
import io.eventuate.tram.sagas.simpledsl.CommandEndpointBuilder;
4+
import io.eventuate.tram.commands.consumer.CommandWithDestination;
5+
import io.eventuate.tram.commands.consumer.CommandWithDestinationBuilder;
6+
import io.eventuate.tram.sagas.simpledsl.annotations.SagaParticipantOperation;
7+
import io.eventuate.tram.sagas.simpledsl.annotations.SagaParticipantProxy;
68
import net.chrisrichardson.ftgo.accountservice.api.AccountingServiceChannels;
79
import net.chrisrichardson.ftgo.accountservice.api.AuthorizeCommand;
10+
import net.chrisrichardson.ftgo.common.Money;
811

12+
@SagaParticipantProxy(channel = AccountingServiceChannels.accountingServiceChannel)
913
public class AccountingServiceProxy {
1014

11-
public final CommandEndpoint<AuthorizeCommand> authorize= CommandEndpointBuilder
12-
.forCommand(AuthorizeCommand.class)
13-
.withChannel(AccountingServiceChannels.accountingServiceChannel)
14-
.withReply(Success.class)
15-
.build();
16-
15+
@SagaParticipantOperation(commandClass = AuthorizeCommand.class, replyClasses = Success.class)
16+
public CommandWithDestination authorize(long consumerId, Long orderId, Money orderTotal) {
17+
return CommandWithDestinationBuilder
18+
.send(new AuthorizeCommand(consumerId, orderId, orderTotal))
19+
.to(AccountingServiceChannels.accountingServiceChannel)
20+
.build();
21+
}
1722
}
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
package net.chrisrichardson.ftgo.orderservice.sagaparticipants;
22

33
import io.eventuate.tram.commands.common.Success;
4-
import io.eventuate.tram.sagas.simpledsl.CommandEndpoint;
5-
import io.eventuate.tram.sagas.simpledsl.CommandEndpointBuilder;
4+
import io.eventuate.tram.commands.consumer.CommandWithDestination;
5+
import io.eventuate.tram.commands.consumer.CommandWithDestinationBuilder;
6+
import io.eventuate.tram.sagas.simpledsl.annotations.SagaParticipantOperation;
7+
import io.eventuate.tram.sagas.simpledsl.annotations.SagaParticipantProxy;
8+
import net.chrisrichardson.ftgo.common.Money;
69
import net.chrisrichardson.ftgo.consumerservice.api.ConsumerServiceChannels;
710
import net.chrisrichardson.ftgo.consumerservice.api.ValidateOrderByConsumer;
811

12+
@SagaParticipantProxy(channel = ConsumerServiceChannels.consumerServiceChannel)
913
public class ConsumerServiceProxy {
1014

11-
12-
public final CommandEndpoint<ValidateOrderByConsumer> validateOrder= CommandEndpointBuilder
13-
.forCommand(ValidateOrderByConsumer.class)
14-
.withChannel(ConsumerServiceChannels.consumerServiceChannel)
15-
.withReply(Success.class)
16-
.build();
17-
15+
@SagaParticipantOperation(commandClass = ValidateOrderByConsumer.class, replyClasses = Success.class)
16+
public CommandWithDestination validateOrder(long consumerId, long orderId, Money orderTotal) {
17+
return CommandWithDestinationBuilder
18+
.send(new ValidateOrderByConsumer(consumerId, orderId, orderTotal))
19+
.to(ConsumerServiceChannels.consumerServiceChannel)
20+
.build();
21+
}
1822
}
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,36 @@
11
package net.chrisrichardson.ftgo.orderservice.sagaparticipants;
22

33
import io.eventuate.tram.commands.common.Success;
4-
import io.eventuate.tram.sagas.simpledsl.CommandEndpoint;
5-
import io.eventuate.tram.sagas.simpledsl.CommandEndpointBuilder;
4+
import io.eventuate.tram.commands.consumer.CommandWithDestination;
5+
import io.eventuate.tram.commands.consumer.CommandWithDestinationBuilder;
6+
import io.eventuate.tram.sagas.simpledsl.annotations.SagaParticipantOperation;
7+
import io.eventuate.tram.sagas.simpledsl.annotations.SagaParticipantProxy;
68
import net.chrisrichardson.ftgo.kitchenservice.api.*;
79

10+
@SagaParticipantProxy(channel = KitchenServiceChannels.COMMAND_CHANNEL)
811
public class KitchenServiceProxy {
912

10-
public final CommandEndpoint<CreateTicket> create = CommandEndpointBuilder
11-
.forCommand(CreateTicket.class)
12-
.withChannel(KitchenServiceChannels.COMMAND_CHANNEL)
13-
.withReply(CreateTicketReply.class)
14-
.build();
13+
@SagaParticipantOperation(commandClass = CreateTicket.class, replyClasses = CreateTicketReply.class)
14+
public CommandWithDestination createTicket(long restaurantId, Long orderId, TicketDetails ticketDetails) {
15+
return CommandWithDestinationBuilder
16+
.send(new CreateTicket(restaurantId, orderId, ticketDetails))
17+
.to(KitchenServiceChannels.COMMAND_CHANNEL)
18+
.build();
19+
}
1520

16-
public final CommandEndpoint<ConfirmCreateTicket> confirmCreate = CommandEndpointBuilder
17-
.forCommand(ConfirmCreateTicket.class)
18-
.withChannel(KitchenServiceChannels.COMMAND_CHANNEL)
19-
.withReply(Success.class)
20-
.build();
21-
public final CommandEndpoint<CancelCreateTicket> cancel = CommandEndpointBuilder
22-
.forCommand(CancelCreateTicket.class)
23-
.withChannel(KitchenServiceChannels.COMMAND_CHANNEL)
24-
.withReply(Success.class)
25-
.build();
21+
@SagaParticipantOperation(commandClass = ConfirmCreateTicket.class, replyClasses = Success.class)
22+
public CommandWithDestination confirmCreateTicket(Long ticketId) {
23+
return CommandWithDestinationBuilder
24+
.send(new ConfirmCreateTicket(ticketId))
25+
.to(KitchenServiceChannels.COMMAND_CHANNEL)
26+
.build();
27+
}
2628

29+
@SagaParticipantOperation(commandClass = CancelCreateTicket.class, replyClasses = Success.class)
30+
public CommandWithDestination cancelCreateTicket(long ticketId) {
31+
return CommandWithDestinationBuilder
32+
.send(new CancelCreateTicket(ticketId))
33+
.to(KitchenServiceChannels.COMMAND_CHANNEL)
34+
.build();
35+
}
2736
}

ftgo-order-service/order-service-sagas/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/createorder/CreateOrderSaga.java

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package net.chrisrichardson.ftgo.orderservice.sagas.createorder;
22

3+
import io.eventuate.tram.commands.consumer.CommandWithDestination;
34
import io.eventuate.tram.sagas.orchestration.SagaDefinition;
45
import io.eventuate.tram.sagas.simpledsl.SimpleSaga;
56
import net.chrisrichardson.ftgo.orderservice.api.events.OrderDetails;
@@ -8,6 +9,8 @@
89
import net.chrisrichardson.ftgo.orderservice.domain.OrderService;
910
import net.chrisrichardson.ftgo.orderservice.sagaparticipants.*;
1011
import net.chrisrichardson.ftgo.kitchenservice.api.CreateTicketReply;
12+
import net.chrisrichardson.ftgo.kitchenservice.api.TicketDetails;
13+
import net.chrisrichardson.ftgo.kitchenservice.api.TicketLineItem;
1114
import org.slf4j.Logger;
1215
import org.slf4j.LoggerFactory;
1316

@@ -36,15 +39,15 @@ public CreateOrderSaga(OrderService orderService, ConsumerServiceProxy consumerS
3639
.invokeLocal(this::create)
3740
.withCompensation(this::reject)
3841
.step()
39-
.invokeParticipant(consumerService.validateOrder, CreateOrderSagaState::makeValidateOrderByConsumerCommand)
42+
.invokeParticipant(this::validateConsumer)
4043
.step()
41-
.invokeParticipant(kitchenService.create, CreateOrderSagaState::makeCreateTicketCommand)
44+
.invokeParticipant(this::createTicket)
4245
.onReply(CreateTicketReply.class, CreateOrderSagaState::handleCreateTicketReply)
43-
.withCompensation(kitchenService.cancel, CreateOrderSagaState::makeCancelCreateTicketCommand)
46+
.withCompensation(this::cancelTicket)
4447
.step()
45-
.invokeParticipant(accountingService.authorize, CreateOrderSagaState::makeAuthorizeCommand)
48+
.invokeParticipant(this::authorizePayment)
4649
.step()
47-
.invokeParticipant(kitchenService.confirmCreate, CreateOrderSagaState::makeConfirmCreateTicketCommand)
50+
.invokeParticipant(this::confirmTicket)
4851
.step()
4952
.invokeLocal(this::approve)
5053
.build();
@@ -88,4 +91,44 @@ private void approve(CreateOrderSagaState data) {
8891
private void reject(CreateOrderSagaState data) {
8992
orderService.rejectOrder(data.getOrderId());
9093
}
94+
95+
private CommandWithDestination validateConsumer(CreateOrderSagaState data) {
96+
OrderDetails orderDetails = data.getOrderDetails();
97+
return consumerService.validateOrder(
98+
orderDetails.getConsumerId(),
99+
data.getOrderId(),
100+
orderDetails.getOrderTotal());
101+
}
102+
103+
private CommandWithDestination createTicket(CreateOrderSagaState data) {
104+
OrderDetails orderDetails = data.getOrderDetails();
105+
TicketDetails ticketDetails = makeTicketDetails(orderDetails);
106+
return kitchenService.createTicket(
107+
orderDetails.getRestaurantId(),
108+
data.getOrderId(),
109+
ticketDetails);
110+
}
111+
112+
private TicketDetails makeTicketDetails(OrderDetails orderDetails) {
113+
List<TicketLineItem> ticketLineItems = orderDetails.getLineItems().stream()
114+
.map(li -> new TicketLineItem(li.getMenuItemId(), li.getName(), li.getQuantity()))
115+
.toList();
116+
return new TicketDetails(ticketLineItems);
117+
}
118+
119+
private CommandWithDestination cancelTicket(CreateOrderSagaState data) {
120+
return kitchenService.cancelCreateTicket(data.getOrderId());
121+
}
122+
123+
private CommandWithDestination authorizePayment(CreateOrderSagaState data) {
124+
OrderDetails orderDetails = data.getOrderDetails();
125+
return accountingService.authorize(
126+
orderDetails.getConsumerId(),
127+
data.getOrderId(),
128+
orderDetails.getOrderTotal());
129+
}
130+
131+
private CommandWithDestination confirmTicket(CreateOrderSagaState data) {
132+
return kitchenService.confirmCreateTicket(data.getTicketId());
133+
}
91134
}

ftgo-order-service/order-service-sagas/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/createorder/CreateOrderSagaState.java

Lines changed: 1 addition & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
package net.chrisrichardson.ftgo.orderservice.sagas.createorder;
22

3-
import net.chrisrichardson.ftgo.accountservice.api.AuthorizeCommand;
4-
import net.chrisrichardson.ftgo.consumerservice.api.ValidateOrderByConsumer;
53
import net.chrisrichardson.ftgo.orderservice.api.events.OrderDetails;
6-
import net.chrisrichardson.ftgo.orderservice.api.events.OrderLineItem;
74
import net.chrisrichardson.ftgo.orderservice.domain.DeliveryInformation;
85
import net.chrisrichardson.ftgo.orderservice.domain.MenuItemIdAndQuantity;
9-
import net.chrisrichardson.ftgo.kitchenservice.api.*;
6+
import net.chrisrichardson.ftgo.kitchenservice.api.CreateTicketReply;
107
import org.slf4j.Logger;
118
import org.slf4j.LoggerFactory;
129

1310
import java.util.List;
1411

15-
import static java.util.stream.Collectors.toList;
16-
1712
public class CreateOrderSagaState {
1813

1914
private Logger logger = LoggerFactory.getLogger(getClass());
@@ -80,46 +75,8 @@ public long getTicketId() {
8075
return ticketId;
8176
}
8277

83-
CreateTicket makeCreateTicketCommand() {
84-
return new CreateTicket(getOrderDetails().getRestaurantId(), getOrderId(), makeTicketDetails(getOrderDetails()));
85-
}
86-
87-
private TicketDetails makeTicketDetails(OrderDetails orderDetails) {
88-
return new TicketDetails(makeTicketLineItems(orderDetails.getLineItems()));
89-
}
90-
91-
private List<TicketLineItem> makeTicketLineItems(List<OrderLineItem> lineItems) {
92-
return lineItems.stream().map(this::makeTicketLineItem).collect(toList());
93-
}
94-
95-
private TicketLineItem makeTicketLineItem(OrderLineItem orderLineItem) {
96-
return new TicketLineItem(orderLineItem.getMenuItemId(), orderLineItem.getName(), orderLineItem.getQuantity());
97-
}
98-
9978
void handleCreateTicketReply(CreateTicketReply reply) {
10079
logger.debug("getTicketId {}", reply.getTicketId());
10180
setTicketId(reply.getTicketId());
10281
}
103-
104-
CancelCreateTicket makeCancelCreateTicketCommand() {
105-
return new CancelCreateTicket(getOrderId());
106-
}
107-
108-
ValidateOrderByConsumer makeValidateOrderByConsumerCommand() {
109-
return new ValidateOrderByConsumer(
110-
getOrderDetails().getConsumerId(),
111-
getOrderId(),
112-
getOrderDetails().getOrderTotal());
113-
}
114-
115-
AuthorizeCommand makeAuthorizeCommand() {
116-
return new AuthorizeCommand(
117-
getOrderDetails().getConsumerId(),
118-
getOrderId(),
119-
getOrderDetails().getOrderTotal());
120-
}
121-
122-
ConfirmCreateTicket makeConfirmCreateTicketCommand() {
123-
return new ConfirmCreateTicket(getTicketId());
124-
}
12582
}

ftgo-order-service/order-service-sagas/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/createorder/OrderSagaService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import java.util.List;
1111

12+
@Transactional
1213
public class OrderSagaService {
1314

1415
private final OrderRepository orderRepository;
@@ -23,7 +24,6 @@ public OrderSagaService(OrderRepository orderRepository,
2324
this.createOrderSaga = createOrderSaga;
2425
}
2526

26-
@Transactional
2727
public Order createOrder(long consumerId, long restaurantId,
2828
DeliveryInformation deliveryInformation,
2929
List<MenuItemIdAndQuantity> lineItems) {

0 commit comments

Comments
 (0)