Skip to content

Commit 3f6dd9c

Browse files
committed
Add Server-Side Page Fragment Composition pattern #2697
- Implement complete Server-Side Page Fragment Composition design pattern - Add microservices for header, content, and footer fragments - Create composition service for server-side page assembly - Include comprehensive documentation and examples - Add unit tests with 17 test cases covering all functionality - Support both synchronous and asynchronous composition - Include caching, personalization, and performance monitoring - Follow project contribution guidelines and coding standards Closes #2697
1 parent 763bb35 commit 3f6dd9c

File tree

13 files changed

+372
-390
lines changed

13 files changed

+372
-390
lines changed

server-side-fragment-composition/src/main/java/com/iluwatar/serverfragment/App.java

Lines changed: 67 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -33,169 +33,169 @@
3333

3434
/**
3535
* Server-Side Page Fragment Composition pattern demonstration.
36-
*
37-
* <p>This pattern demonstrates how to compose web pages from fragments
38-
* delivered by different microservices. Each fragment is managed independently,
39-
* allowing for modular development, deployment, and scaling.
40-
*
36+
*
37+
* <p>This pattern demonstrates how to compose web pages from fragments delivered by different
38+
* microservices. Each fragment is managed independently, allowing for modular development,
39+
* deployment, and scaling.
40+
*
4141
* <p>The key elements of this pattern include:
42+
*
4243
* <ul>
43-
* <li><strong>Fragment Composition:</strong> Server assembles webpage from various fragments</li>
44-
* <li><strong>Microservices:</strong> Each fragment managed by separate microservice</li>
45-
* <li><strong>Scalability:</strong> Independent development, deployment, and scaling</li>
46-
* <li><strong>Performance:</strong> Server-side assembly optimizes client performance</li>
47-
* <li><strong>Consistent UX:</strong> Ensures cohesive user experience across fragments</li>
44+
* <li><strong>Fragment Composition:</strong> Server assembles webpage from various fragments
45+
* <li><strong>Microservices:</strong> Each fragment managed by separate microservice
46+
* <li><strong>Scalability:</strong> Independent development, deployment, and scaling
47+
* <li><strong>Performance:</strong> Server-side assembly optimizes client performance
48+
* <li><strong>Consistent UX:</strong> Ensures cohesive user experience across fragments
4849
* </ul>
49-
*
50+
*
5051
* <p>In this demo, we simulate three microservices:
52+
*
5153
* <ul>
52-
* <li><strong>HeaderService:</strong> Manages navigation and branding</li>
53-
* <li><strong>ContentService:</strong> Manages main page content and personalization</li>
54-
* <li><strong>FooterService:</strong> Manages footer content and promotional information</li>
54+
* <li><strong>HeaderService:</strong> Manages navigation and branding
55+
* <li><strong>ContentService:</strong> Manages main page content and personalization
56+
* <li><strong>FooterService:</strong> Manages footer content and promotional information
5557
* </ul>
5658
*/
5759
@Slf4j
5860
public class App {
5961

6062
/**
6163
* Main method demonstrating Server-Side Page Fragment Composition.
62-
*
63-
* <p>This demonstration shows how multiple microservices can be coordinated
64-
* to generate complete web pages, emphasizing the independence and scalability
65-
* of each service while maintaining a cohesive user experience.
66-
*
64+
*
65+
* <p>This demonstration shows how multiple microservices can be coordinated to generate complete
66+
* web pages, emphasizing the independence and scalability of each service while maintaining a
67+
* cohesive user experience.
68+
*
6769
* @param args command line arguments (not used in this demo)
6870
*/
6971
public static void main(String[] args) {
7072
LOGGER.info("=== Starting Server-Side Page Fragment Composition Demo ===");
71-
73+
7274
try {
7375
// Initialize and demonstrate the pattern
7476
var demo = new App();
7577
demo.runDemo();
76-
78+
7779
LOGGER.info("=== Server-Side Page Fragment Composition Demo Completed Successfully ===");
78-
80+
7981
} catch (Exception e) {
8082
LOGGER.error("Demo execution failed", e);
8183
System.exit(1);
8284
}
8385
}
8486

85-
/**
86-
* Runs the complete demonstration of the Server-Side Page Fragment Composition pattern.
87-
*/
87+
/** Runs the complete demonstration of the Server-Side Page Fragment Composition pattern. */
8888
private void runDemo() {
8989
LOGGER.info("Initializing microservices...");
90-
90+
9191
// Create microservice instances
9292
// In a real system, these would be separate deployable services
9393
var headerService = new HeaderService();
9494
var contentService = new ContentService();
9595
var footerService = new FooterService();
96-
96+
9797
LOGGER.info("Microservices initialized:");
9898
LOGGER.info(" - {}", headerService.getServiceInfo());
9999
LOGGER.info(" - {}", contentService.getServiceInfo());
100100
LOGGER.info(" - {}", footerService.getServiceInfo());
101-
101+
102102
// Create and configure composition service
103103
LOGGER.info("Setting up composition service...");
104104
var compositionService = new CompositionService();
105-
105+
106106
// Register microservices with the composition service
107107
compositionService.registerService("header", headerService);
108108
compositionService.registerService("content", contentService);
109109
compositionService.registerService("footer", footerService);
110-
110+
111111
// Check health status
112112
LOGGER.info("Health Status: {}", compositionService.getHealthStatus());
113-
113+
114114
// Demonstrate synchronous page composition for different page types
115115
demonstrateSynchronousComposition(compositionService);
116-
116+
117117
// Demonstrate asynchronous page composition
118118
demonstrateAsynchronousComposition(compositionService);
119-
119+
120120
// Demonstrate error handling
121121
demonstrateErrorHandling();
122122
}
123123

124-
/**
125-
* Demonstrates synchronous page composition for various page types.
126-
*/
124+
/** Demonstrates synchronous page composition for various page types. */
127125
private void demonstrateSynchronousComposition(CompositionService compositionService) {
128126
LOGGER.info("\n--- Demonstrating Synchronous Page Composition ---");
129-
130-
var pageTypes = new String[]{"home", "about", "contact", "products"};
131-
127+
128+
var pageTypes = new String[] {"home", "about", "contact", "products"};
129+
132130
for (var pageType : pageTypes) {
133131
LOGGER.info("Composing '{}' page...", pageType);
134-
132+
135133
var startTime = System.currentTimeMillis();
136134
var completePage = compositionService.composePage(pageType);
137135
var compositionTime = System.currentTimeMillis() - startTime;
138-
139-
LOGGER.info("'{}' page composed in {}ms (size: {} characters)",
140-
pageType, compositionTime, completePage.length());
141-
136+
137+
LOGGER.info(
138+
"'{}' page composed in {}ms (size: {} characters)",
139+
pageType,
140+
compositionTime,
141+
completePage.length());
142+
142143
// Log a sample of the composed page for verification
143144
var preview = getPagePreview(completePage);
144145
LOGGER.debug("Page preview for '{}': {}", pageType, preview);
145146
}
146147
}
147148

148-
/**
149-
* Demonstrates asynchronous page composition for improved performance.
150-
*/
149+
/** Demonstrates asynchronous page composition for improved performance. */
151150
private void demonstrateAsynchronousComposition(CompositionService compositionService) {
152151
LOGGER.info("\n--- Demonstrating Asynchronous Page Composition ---");
153-
152+
154153
var pageType = "home";
155154
LOGGER.info("Composing '{}' page asynchronously...", pageType);
156-
155+
157156
var startTime = System.currentTimeMillis();
158-
157+
159158
try {
160159
var futureResult = compositionService.composePageAsync(pageType);
161160
var completePage = futureResult.get(); // Wait for completion
162161
var compositionTime = System.currentTimeMillis() - startTime;
163-
164-
LOGGER.info("Async '{}' page composed in {}ms (size: {} characters)",
165-
pageType, compositionTime, completePage.length());
166-
162+
163+
LOGGER.info(
164+
"Async '{}' page composed in {}ms (size: {} characters)",
165+
pageType,
166+
compositionTime,
167+
completePage.length());
168+
167169
var preview = getPagePreview(completePage);
168170
LOGGER.debug("Async page preview: {}", preview);
169-
171+
170172
} catch (Exception e) {
171173
LOGGER.error("Async composition failed for page: {}", pageType, e);
172174
}
173175
}
174176

175-
/**
176-
* Demonstrates error handling in the composition process.
177-
*/
177+
/** Demonstrates error handling in the composition process. */
178178
private void demonstrateErrorHandling() {
179179
LOGGER.info("\n--- Demonstrating Error Handling ---");
180-
180+
181181
// Create a new composition service without registered services
182182
var emptyCompositionService = new CompositionService();
183-
183+
184184
try {
185185
LOGGER.info("Attempting to compose page without registered services...");
186186
emptyCompositionService.composePage("test");
187-
187+
188188
} catch (IllegalStateException e) {
189189
LOGGER.info("Expected error caught: {}", e.getMessage());
190190
LOGGER.info("Error handling working correctly - services must be registered");
191191
}
192-
192+
193193
// Demonstrate invalid service registration
194194
var validCompositionService = new CompositionService();
195195
try {
196196
LOGGER.info("Attempting to register invalid service type...");
197197
validCompositionService.registerService("invalid", new Object());
198-
198+
199199
} catch (IllegalArgumentException e) {
200200
LOGGER.info("Expected error caught: {}", e.getMessage());
201201
LOGGER.info("Error handling working correctly - only valid service types accepted");
@@ -212,16 +212,16 @@ private String getPagePreview(String completePage) {
212212
if (completePage == null || completePage.length() < 100) {
213213
return completePage;
214214
}
215-
215+
216216
// Extract title and first bit of content for preview
217217
var titleStart = completePage.indexOf("<title>");
218218
var titleEnd = completePage.indexOf("</title>");
219-
219+
220220
if (titleStart != -1 && titleEnd != -1) {
221221
var title = completePage.substring(titleStart + 7, titleEnd);
222222
return String.format("Title: '%s', Length: %d chars", title, completePage.length());
223223
}
224-
224+
225225
return String.format("HTML page, Length: %d chars", completePage.length());
226226
}
227-
}
227+
}

0 commit comments

Comments
 (0)