Skip to content

Commit 8e95b94

Browse files
committed
Consolidate OrderService into domain module and centralize persistence configuration
- Merge OrderService interface and OrderServiceImpl into single OrderService class - Move OrderService from order-service-main to order-service-domain module - Move repository interfaces (OrderRepository, RestaurantRepository) to order-service-domain - Create OrderServiceInstrumentation interface to decouple metrics from domain - Add MicrometerOrderServiceInstrumentation in order-service-main for production - Add NoOpOrderServiceInstrumentation in order-service-domain for tests - Create OrderPersistenceConfiguration to centralize JPA repository and entity scanning - Move persistence tests to persistence package and simplify test configurations - Remove redundant test configuration classes Co-authored by Claude Code
1 parent 27c97b6 commit 8e95b94

16 files changed

Lines changed: 185 additions & 198 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package net.chrisrichardson.ftgo.orderservice.domain;
2+
3+
public class NoOpOrderServiceInstrumentation implements OrderServiceInstrumentation {
4+
@Override
5+
public void noteOrderPlaced() {
6+
}
7+
8+
@Override
9+
public void noteOrderApproved() {
10+
}
11+
12+
@Override
13+
public void noteOrderRejected() {
14+
}
15+
}

ftgo-order-service/order-service-persistence/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderRepository.java renamed to ftgo-order-service/order-service-domain/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderRepository.java

File renamed without changes.
Lines changed: 106 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,124 @@
11
package net.chrisrichardson.ftgo.orderservice.domain;
22

3+
import io.eventuate.tram.events.aggregates.ResultWithDomainEvents;
4+
import net.chrisrichardson.ftgo.orderservice.api.events.OrderDomainEvent;
5+
import net.chrisrichardson.ftgo.orderservice.api.events.OrderLineItem;
6+
import org.springframework.transaction.annotation.Transactional;
7+
38
import java.util.List;
49
import java.util.Optional;
10+
import java.util.function.Function;
11+
12+
import static java.util.stream.Collectors.toList;
13+
14+
public class OrderService {
15+
16+
private final OrderRepository orderRepository;
17+
private final RestaurantRepository restaurantRepository;
18+
private final OrderDomainEventPublisher orderAggregateEventPublisher;
19+
private final OrderServiceInstrumentation instrumentation;
20+
21+
public OrderService(OrderRepository orderRepository,
22+
RestaurantRepository restaurantRepository,
23+
OrderDomainEventPublisher orderAggregateEventPublisher,
24+
OrderServiceInstrumentation instrumentation) {
25+
this.orderRepository = orderRepository;
26+
this.restaurantRepository = restaurantRepository;
27+
this.orderAggregateEventPublisher = orderAggregateEventPublisher;
28+
this.instrumentation = instrumentation;
29+
}
30+
31+
@Transactional
32+
public Order createOrder(long consumerId, long restaurantId, DeliveryInformation deliveryInformation,
33+
List<MenuItemIdAndQuantity> lineItems) {
34+
Restaurant restaurant = restaurantRepository.findById(restaurantId)
35+
.orElseThrow(() -> new RestaurantNotFoundException(restaurantId));
36+
37+
List<OrderLineItem> orderLineItems = makeOrderLineItems(lineItems, restaurant);
38+
39+
ResultWithDomainEvents<Order, OrderDomainEvent> orderAndEvents =
40+
Order.createOrder(consumerId, restaurant, deliveryInformation, orderLineItems);
41+
42+
Order order = orderAndEvents.result;
43+
orderRepository.save(order);
44+
45+
orderAggregateEventPublisher.publish(order, orderAndEvents.events);
46+
47+
instrumentation.noteOrderPlaced();
48+
49+
return order;
50+
}
551

6-
/**
7-
* Domain service interface for order operations.
8-
* Implementation is provided by OrderServiceImpl in the main module.
9-
*/
10-
public interface OrderService {
52+
@Transactional(readOnly = true)
53+
public Optional<Order> findById(long orderId) {
54+
return orderRepository.findById(orderId).map(order -> {
55+
// Access lazy-loaded collections within transaction to avoid LazyInitializationException
56+
order.getOrderTotal();
57+
return order;
58+
});
59+
}
1160

12-
// REST API methods
13-
Order createOrder(long consumerId, long restaurantId, DeliveryInformation deliveryInformation,
14-
List<MenuItemIdAndQuantity> lineItems);
61+
private List<OrderLineItem> makeOrderLineItems(List<MenuItemIdAndQuantity> lineItems, Restaurant restaurant) {
62+
return lineItems.stream().map(li -> {
63+
MenuItem om = restaurant.findMenuItem(li.getMenuItemId()).orElseThrow(() -> new InvalidMenuItemIdException(li.getMenuItemId()));
64+
return new OrderLineItem(li.getMenuItemId(), om.getName(), om.getPrice(), li.getQuantity());
65+
}).collect(toList());
66+
}
1567

16-
Optional<Order> findById(long orderId);
68+
public void approveOrder(long orderId) {
69+
updateOrder(orderId, Order::noteApproved);
70+
instrumentation.noteOrderApproved();
71+
}
1772

18-
// Saga command handler methods
19-
void approveOrder(long orderId);
73+
public void rejectOrder(long orderId) {
74+
updateOrder(orderId, Order::noteRejected);
75+
instrumentation.noteOrderRejected();
76+
}
2077

21-
void rejectOrder(long orderId);
78+
public void beginCancel(long orderId) {
79+
updateOrder(orderId, Order::cancel);
80+
}
2281

23-
void beginCancel(long orderId);
82+
public void undoCancel(long orderId) {
83+
updateOrder(orderId, Order::undoPendingCancel);
84+
}
2485

25-
void undoCancel(long orderId);
86+
public void confirmCancelled(long orderId) {
87+
updateOrder(orderId, Order::noteCancelled);
88+
}
2689

27-
void confirmCancelled(long orderId);
90+
public Optional<RevisedOrder> beginReviseOrder(long orderId, OrderRevision revision) {
91+
return orderRepository.findById(orderId).map(order -> {
92+
ResultWithDomainEvents<LineItemQuantityChange, OrderDomainEvent> result = order.revise(revision);
93+
orderAggregateEventPublisher.publish(order, result.events);
94+
return new RevisedOrder(order, result.result);
95+
});
96+
}
2897

29-
Optional<RevisedOrder> beginReviseOrder(long orderId, OrderRevision revision);
98+
public void undoPendingRevision(long orderId) {
99+
updateOrder(orderId, Order::rejectRevision);
100+
}
30101

31-
void undoPendingRevision(long orderId);
102+
public void confirmRevision(long orderId, OrderRevision revision) {
103+
updateOrder(orderId, order -> order.confirmRevision(revision));
104+
}
32105

33-
void confirmRevision(long orderId, OrderRevision revision);
106+
public void createMenu(long id, String name, List<MenuItem> menuItems) {
107+
Restaurant restaurant = new Restaurant(id, name, menuItems);
108+
restaurantRepository.save(restaurant);
109+
}
34110

35-
// Event handler methods
36-
void createMenu(long id, String name, List<MenuItem> menuItems);
111+
public void reviseMenu(long id, List<MenuItem> menuItems) {
112+
restaurantRepository.findById(id).map(restaurant -> {
113+
restaurant.reviseMenu(menuItems);
114+
return restaurant;
115+
}).orElseThrow(RuntimeException::new);
116+
}
37117

38-
void reviseMenu(long id, List<MenuItem> menuItems);
118+
private Order updateOrder(long orderId, Function<Order, List<OrderDomainEvent>> updater) {
119+
return orderRepository.findById(orderId).map(order -> {
120+
orderAggregateEventPublisher.publish(order, updater.apply(order));
121+
return order;
122+
}).orElseThrow(() -> new OrderNotFoundException(orderId));
123+
}
39124
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package net.chrisrichardson.ftgo.orderservice.domain;
2+
3+
public interface OrderServiceInstrumentation {
4+
void noteOrderPlaced();
5+
void noteOrderApproved();
6+
void noteOrderRejected();
7+
}

ftgo-order-service/order-service-persistence/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/RestaurantRepository.java renamed to ftgo-order-service/order-service-domain/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/RestaurantRepository.java

File renamed without changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package net.chrisrichardson.ftgo.orderservice.domain;
2+
3+
import io.micrometer.core.instrument.MeterRegistry;
4+
5+
public class MicrometerOrderServiceInstrumentation implements OrderServiceInstrumentation {
6+
7+
private final MeterRegistry meterRegistry;
8+
9+
public MicrometerOrderServiceInstrumentation(MeterRegistry meterRegistry) {
10+
this.meterRegistry = meterRegistry;
11+
}
12+
13+
@Override
14+
public void noteOrderPlaced() {
15+
meterRegistry.counter("placed_orders").increment();
16+
}
17+
18+
@Override
19+
public void noteOrderApproved() {
20+
meterRegistry.counter("approved_orders").increment();
21+
}
22+
23+
@Override
24+
public void noteOrderRejected() {
25+
meterRegistry.counter("rejected_orders").increment();
26+
}
27+
}

ftgo-order-service/order-service-main/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderServiceConfiguration.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
import net.chrisrichardson.ftgo.orderservice.sagas.reviseorder.ReviseOrderSaga;
1717
import org.springframework.beans.factory.annotation.Value;
1818
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
19+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
20+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
1921
import org.springframework.context.annotation.Bean;
2022
import org.springframework.context.annotation.Configuration;
2123
import org.springframework.context.annotation.Import;
2224

23-
import java.util.Optional;
24-
2525
@Configuration
2626
@Import({TramEventsPublisherConfiguration.class, SagaOrchestratorConfiguration.class, CommonConfiguration.class, EventuateTramFlywayMigrationConfiguration.class})
2727
public class OrderServiceConfiguration {
@@ -30,10 +30,21 @@ public class OrderServiceConfiguration {
3030
public OrderService orderService(RestaurantRepository restaurantRepository,
3131
OrderRepository orderRepository,
3232
OrderDomainEventPublisher orderAggregateEventPublisher,
33-
Optional<MeterRegistry> meterRegistry) {
33+
OrderServiceInstrumentation instrumentation) {
34+
return new OrderService(orderRepository, restaurantRepository,
35+
orderAggregateEventPublisher, instrumentation);
36+
}
37+
38+
@Bean
39+
@ConditionalOnBean(MeterRegistry.class)
40+
public OrderServiceInstrumentation micrometerOrderServiceInstrumentation(MeterRegistry meterRegistry) {
41+
return new MicrometerOrderServiceInstrumentation(meterRegistry);
42+
}
3443

35-
return new OrderServiceImpl(orderRepository, restaurantRepository,
36-
orderAggregateEventPublisher, meterRegistry);
44+
@Bean
45+
@ConditionalOnMissingBean(OrderServiceInstrumentation.class)
46+
public OrderServiceInstrumentation noOpOrderServiceInstrumentation() {
47+
return new NoOpOrderServiceInstrumentation();
3748
}
3849

3950
@Bean

ftgo-order-service/order-service-main/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderServiceImpl.java

Lines changed: 0 additions & 148 deletions
This file was deleted.

0 commit comments

Comments
 (0)