Skip to content

Commit bd3e921

Browse files
authored
Adding code for MP Reactive Messaging 3.0.1
1 parent e83574a commit bd3e921

71 files changed

Lines changed: 6422 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

code/chapter13/README.adoc

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
= Design of MicroProfile E-commerce Application using Reactive Messaging
2+
:toc: left
3+
:icons: font
4+
:source-highlighter: highlightjs
5+
6+
This document provides a service-by-service design for using Reactive Messaging in the MicroProfile e-Commerce application. It outlines the recommended channels, event payloads, and responsibilities for each microservice, while also recommending a hybrid architecture that combines synchronous REST calls with asynchronous event-driven communication.
7+
8+
== Design goals
9+
10+
* Keep each service responsible for its own data and lifecycle transitions.
11+
* Use events for long-running business workflow progression instead of tightly coupled HTTP chains.
12+
* Keep REST for reads, administration, direct client queries, and immediate request/response interactions.
13+
* Combine REST and Reactive Messaging in a practical hybrid architecture.
14+
* Start simple with in-memory wiring, then switch to Kafka for multi-service deployment.
15+
16+
== Recommended architecture: Hybrid REST + Reactive Messaging
17+
18+
A pure event-driven design is not required for every interaction. In this application, the most practical approach is a hybrid model:
19+
20+
* Use *REST with MicroProfile Rest Client* for operations that need an immediate response, such as fetching data, validating requests, or initiating checkout.
21+
* Use *Reactive Messaging* for asynchronous workflow steps that span multiple services, such as payment authorization, inventory reservation, shipment updates, and status notifications.
22+
23+
=== Use REST for
24+
25+
* shopping cart and checkout initiation
26+
* synchronous reads and lookups
27+
* administrative CRUD operations
28+
* validations where the caller needs an immediate result
29+
30+
=== Use Reactive Messaging for
31+
32+
* order lifecycle events
33+
* payment success or failure notifications
34+
* inventory reservation outcomes
35+
* shipping progress updates
36+
* audit, monitoring, and user notifications
37+
38+
== Recommended channel names
39+
40+
[cols="2,2,3,3", options="header"]
41+
|===
42+
|Channel |Produced by |Consumed by |Purpose
43+
44+
|`order-created`
45+
|Order Service
46+
|Payment Service
47+
|Publish a newly persisted order that is ready for payment.
48+
49+
|`payment-authorized`
50+
|Payment Service
51+
|Inventory Service, Order Service
52+
|Notify that payment succeeded.
53+
54+
|`payment-failed`
55+
|Payment Service
56+
|Order Service
57+
|Notify that payment was rejected or failed.
58+
59+
|`inventory-reserved`
60+
|Inventory Service
61+
|Shipment Service, Order Service
62+
|Notify that stock has been reserved successfully.
63+
64+
|`inventory-rejected`
65+
|Inventory Service
66+
|Order Service
67+
|Notify that stock could not be reserved.
68+
69+
|`shipment-created`
70+
|Shipment Service
71+
|Order Service
72+
|Notify that shipment processing has started.
73+
74+
|`shipment-dispatched`
75+
|Shipment Service
76+
|Order Service, User Service
77+
|Notify that the package has left the warehouse.
78+
79+
|`shipment-delivered`
80+
|Shipment Service
81+
|Order Service, User Service
82+
|Notify that the order has been delivered.
83+
84+
|`order-status-events`
85+
|Order Service
86+
|Shopping Cart Service, User Service, observability components
87+
|Publish normalized order state changes for downstream consumers.
88+
|===
89+
90+
== Suggested event payload classes
91+
92+
Use small, explicit payload types rather than reusing full JPA-style entities everywhere.
93+
94+
* `OrderCreatedEvent`
95+
* `PaymentResultEvent`
96+
* `InventoryReservationEvent`
97+
* `ShipmentEvent`
98+
* `OrderStatusChangedEvent`
99+
100+
Each event should include identifiers such as `orderId`, `userId`, `timestamp`, and only the fields needed by downstream services.
101+
102+
== Service-by-service design
103+
104+
=== Shopping Cart Service
105+
106+
The Shopping Cart service remains the user-facing checkout initiator.
107+
Checkout begins synchronously through REST, and then transitions into an event-driven workflow once the order has been accepted.
108+
109+
*Suggested bean classes:*
110+
111+
* `CheckoutClient`
112+
** Uses `RestClient` to call the Order Service synchronously at checkout time
113+
* `OrderStatusListener`
114+
** Consumes `order-status-events` to show current order progress in the UI
115+
116+
*Recommended responsibility:*
117+
118+
* Keep cart calculation and cart management synchronous.
119+
* Use REST to submit the order when the user confirms checkout.
120+
* Rely on downstream events only after the order has been accepted and persisted.
121+
122+
=== Order Service
123+
124+
The Order service should remain the system of record for order lifecycle state.
125+
126+
*Suggested bean classes:*
127+
128+
* `OrderCreationHandler`
129+
** Called by the existing REST-based checkout flow
130+
** Calls the existing `OrderService.createOrder(...)`
131+
** Emits `OrderCreatedEvent` to `order-created`
132+
* `OrderStatusEventHandler`
133+
** Consumes `payment-authorized`, `payment-failed`, `inventory-reserved`, `inventory-rejected`, `shipment-created`, `shipment-dispatched`, and `shipment-delivered`
134+
** Calls the existing `OrderService.updateOrderStatus(...)`
135+
* `OrderStatusPublisher`
136+
** Emits normalized updates to `order-status-events`
137+
138+
*Recommended responsibility:*
139+
140+
* Persist the initial order.
141+
* Listen for downstream business outcomes.
142+
* Update status transitions such as `CREATED`, `PAID`, `PROCESSING`, `SHIPPED`, and `DELIVERED`.
143+
144+
=== Payment Service
145+
146+
The Payment service should react to newly created orders and publish payment outcomes.
147+
148+
*Suggested bean classes:*
149+
150+
* `PaymentRequestHandler`
151+
** `@Incoming("order-created")`
152+
** Uses payment gateway logic from the current `PaymentService`
153+
** Emits to either `payment-authorized` or `payment-failed`
154+
* `PaymentAuditLogger`
155+
** Consumes `payment-authorized` and `payment-failed` for audit and telemetry
156+
157+
*Recommended responsibility:*
158+
159+
* Own payment authorization and failure handling.
160+
* Avoid direct synchronous callbacks into Order where possible.
161+
162+
=== Inventory Service
163+
164+
The Inventory service should reserve or reject stock after payment authorization.
165+
166+
*Suggested bean classes:*
167+
168+
* `InventoryReservationHandler`
169+
** `@Incoming("payment-authorized")`
170+
** Uses the existing `InventoryService` to validate products and update quantities
171+
** Emits `inventory-reserved` or `inventory-rejected`
172+
* `LowStockPublisher`
173+
** Emits optional low-stock notifications when quantity drops below a threshold
174+
175+
*Recommended responsibility:*
176+
177+
* Keep inventory ownership local to the Inventory service.
178+
* Publish stock reservation outcomes instead of requiring the Order service to poll or chain REST calls.
179+
180+
=== Shipment Service
181+
182+
The Shipment service should start logistics only after inventory is successfully reserved.
183+
184+
*Suggested bean classes:*
185+
186+
* `ShipmentRequestHandler`
187+
** `@Incoming("inventory-reserved")`
188+
** Creates a shipment record and emits `shipment-created`
189+
* `ShipmentLifecyclePublisher`
190+
** Emits `shipment-dispatched` and `shipment-delivered`
191+
192+
*Recommended responsibility:*
193+
194+
* Replace parts of the current direct HTTP-based coordination with event-driven shipment updates.
195+
* Keep shipment lifecycle state local to the Shipment service.
196+
197+
=== User Service
198+
199+
The User service does not need to sit in the core order-processing path, but it can subscribe to status updates for communication and personalization.
200+
201+
*Suggested bean classes:*
202+
203+
* `UserNotificationHandler`
204+
** `@Incoming("order-status-events")`
205+
** Sends order progress notifications such as paid, shipped, or delivered
206+
207+
*Recommended responsibility:*
208+
209+
* Consume events for user-facing notifications rather than participating in transactional order workflow.
210+
211+
=== Catalog Service
212+
213+
The Catalog service can remain mostly REST-based for product browsing and product lookup.
214+
215+
*Suggested bean classes:*
216+
217+
* `ProductChangedPublisher` (optional)
218+
** Emits product update events when price or availability metadata changes
219+
* `InventoryProjectionHandler` (optional)
220+
** Consumes low-stock or inventory-summary events if a denormalized read model is needed
221+
222+
*Recommended responsibility:*
223+
224+
* Keep product reads synchronous and simple.
225+
* Add messaging only when product updates need to be broadcast to other services.
226+
227+
== End-to-end workflow
228+
229+
. Shopping Cart initiates checkout using a synchronous REST call to the Order Service
230+
. Order Service persists the order and emits `order-created`
231+
. Payment Service consumes `order-created` and emits `payment-authorized` or `payment-failed`
232+
. Inventory Service consumes `payment-authorized` and emits `inventory-reserved` or `inventory-rejected`
233+
. Shipment Service consumes `inventory-reserved` and emits `shipment-created`, then `shipment-dispatched`, then `shipment-delivered`
234+
. Order Service consumes all result events and emits normalized `order-status-events`
235+
. User-facing and observability components subscribe to `order-status-events`
236+
237+
This approach gives the caller an immediate response at checkout time while still allowing the fulfillment workflow to proceed asynchronously across services.
238+
239+
== Practical adoption plan
240+
241+
=== Step 1: Introduce payment messaging
242+
243+
* Order Service publishes `order-created`
244+
* Payment Service consumes it and publishes `payment-authorized`
245+
246+
=== Step 2: Add inventory reservation
247+
248+
* Inventory Service consumes `payment-authorized`
249+
* Publish `inventory-reserved` and `inventory-rejected`
250+
251+
=== Step 3: Add shipment lifecycle events
252+
253+
* Shipment Service consumes `inventory-reserved`
254+
* Emit shipment lifecycle messages
255+
256+
=== Step 4: Publish normalized order state
257+
258+
* Order Service becomes the single place that converts downstream outcomes into official order statuses

code/chapter13/order/README.adoc

Whitespace-only changes.

code/chapter13/order/pom.xml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>io.microprofile.tutorial</groupId>
8+
<artifactId>order</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
<packaging>war</packaging>
11+
12+
<name>order</name>
13+
14+
<properties>
15+
<maven.compiler.release>21</maven.compiler.release>
16+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
17+
<liberty.var.http.port>8050</liberty.var.http.port>
18+
<liberty.var.https.port>8051</liberty.var.https.port>
19+
<lombok.version>1.18.36</lombok.version>
20+
</properties>
21+
22+
<dependencies>
23+
<dependency>
24+
<groupId>org.eclipse.microprofile</groupId>
25+
<artifactId>microprofile</artifactId>
26+
<version>7.1</version>
27+
<type>pom</type>
28+
<scope>provided</scope>
29+
</dependency>
30+
31+
<dependency>
32+
<groupId>jakarta.platform</groupId>
33+
<artifactId>jakarta.jakartaee-api</artifactId>
34+
<version>10.0.0</version>
35+
<scope>provided</scope>
36+
</dependency>
37+
38+
<dependency>
39+
<groupId>org.eclipse.microprofile.reactive.messaging</groupId>
40+
<artifactId>microprofile-reactive-messaging-api</artifactId>
41+
<version>3.0.1</version>
42+
<scope>provided</scope>
43+
</dependency>
44+
45+
<dependency>
46+
<groupId>org.projectlombok</groupId>
47+
<artifactId>lombok</artifactId>
48+
<version>${lombok.version}</version>
49+
<scope>provided</scope>
50+
</dependency>
51+
52+
<dependency>
53+
<groupId>org.apache.kafka</groupId>
54+
<artifactId>kafka-clients</artifactId>
55+
<version>3.7.0</version>
56+
</dependency>
57+
58+
</dependencies>
59+
60+
<build>
61+
<finalName>${project.artifactId}</finalName>
62+
<plugins>
63+
<plugin>
64+
<groupId>org.apache.maven.plugins</groupId>
65+
<artifactId>maven-war-plugin</artifactId>
66+
<version>3.3.2</version>
67+
<configuration>
68+
<failOnMissingWebXml>false</failOnMissingWebXml>
69+
</configuration>
70+
</plugin>
71+
72+
<plugin>
73+
<groupId>io.openliberty.tools</groupId>
74+
<artifactId>liberty-maven-plugin</artifactId>
75+
<version>3.10</version>
76+
<configuration>
77+
<serverName>OrderServer</serverName>
78+
</configuration>
79+
</plugin>
80+
</plugins>
81+
</build>
82+
</project>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package io.microprofile.tutorial.store.order;
2+
3+
import jakarta.ws.rs.ApplicationPath;
4+
import jakarta.ws.rs.core.Application;
5+
6+
import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition;
7+
import org.eclipse.microprofile.openapi.annotations.info.Contact;
8+
import org.eclipse.microprofile.openapi.annotations.info.Info;
9+
import org.eclipse.microprofile.openapi.annotations.info.License;
10+
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
11+
12+
/**
13+
* JAX-RS application for order management.
14+
*/
15+
@ApplicationPath("/api")
16+
@OpenAPIDefinition(
17+
info = @Info(
18+
title = "Order API",
19+
version = "1.0.0",
20+
description = "API for managing orders and order items",
21+
license = @License(
22+
name = "Eclipse Public License 2.0",
23+
url = "https://www.eclipse.org/legal/epl-2.0/"),
24+
contact = @Contact(
25+
name = "Order API Support",
26+
email = "support@example.com")),
27+
tags = {
28+
@Tag(name = "Order", description = "Operations related to order management"),
29+
@Tag(name = "OrderItem", description = "Operations related to order item management")
30+
}
31+
)
32+
public class OrderApplication extends Application {
33+
// The resources will be discovered automatically
34+
}

0 commit comments

Comments
 (0)