Liferay Service Patterns
Core Service Patterns
Section titled “Core Service Patterns”1. Gateway Pattern
Section titled “1. Gateway Pattern”Use Case: Centralize access to external systems or legacy code
Implementation:
public interface ExternalSystemGateway { public Response submitData(DataPayload payload);}
@Componentpublic class ExternalSystemGatewayImpl implements ExternalSystemGateway { // Implementation with retry logic, error handling, etc.}Benefits:
- Isolate external system dependencies
- Centralize cross-cutting concerns (logging, retries)
- Easier to mock for testing
2. Decorator Pattern
Section titled “2. Decorator Pattern”Use Case: Add functionality to existing services without modifying core implementation
Implementation:
classDiagram
class BookService {
+getBook(id)
}
class BookServiceImpl {
+getBook(id)
}
class BookServiceCacheDecorator {
-BookService bookService
-Cache cache
+getBook(id)
}
BookService <|-- BookServiceImpl
BookService <|-- BookServiceCacheDecorator
BookServiceCacheDecorator o-- BookServiceImpl
@Component( property = { "service.ranking:Integer=100" }, service = BookService.class)public class BookServiceCacheDecorator implements BookService {
@Reference(target = "(!(component.name=BookServiceCacheDecorator))") private BookService _bookService;
@Override public Book getBook(long id) { // Cache implementation }}3. Strategy Pattern
Section titled “3. Strategy Pattern”Use Case: Alternate implementations for business rules
Implementation:
public interface DiscountStrategy { public BigDecimal calculateDiscount(Order order);}
@Componentpublic class HolidayDiscountStrategy implements DiscountStrategy { // Implementation}
@Componentpublic class PricingService {
@Reference(policyOption = ReferencePolicyOption.GREEDY) private volatile List<DiscountStrategy> _discountStrategies;
public BigDecimal calculatePrice(Order order) { // Apply appropriate strategy }}Transactional Patterns
Section titled “Transactional Patterns”1. Retry Pattern
Section titled “1. Retry Pattern”Use Case: Handle transient failures in database operations
Implementation:
public class RetryTemplate {
public <T> T executeWithRetry(Callable<T> callable, int maxAttempts) { // Implementation with exponential backoff }}
@Componentpublic class OrderServiceImpl extends OrderServiceBaseImpl {
public void processOrder(Order order) { new RetryTemplate().executeWithRetry(() -> { // Transactional operation return null; }, 3); }}2. Compensation Pattern
Section titled “2. Compensation Pattern”Use Case: Handle rollbacks in distributed scenarios
Implementation:
public interface CompensatingAction { void execute(); void compensate();}
@Componentpublic class OrderProcessor {
public void process(Order order) { List<CompensatingAction> actions = new ArrayList<>();
try { actions.add(inventoryService.reserveItems(order)); actions.add(paymentService.authorizePayment(order)); // Commit all actions } catch (Exception e) { // Execute compensations in reverse order Collections.reverse(actions); actions.forEach(CompensatingAction::compensate); } }}Integration Patterns
Section titled “Integration Patterns”1. Bridge Pattern
Section titled “1. Bridge Pattern”Use Case: Connect Liferay services with external systems
Implementation:
classDiagram
class DocumentService {
+uploadDocument(file)
}
class LiferayDocumentServiceImpl {
+uploadDocument(file)
}
class CloudDocumentServiceImpl {
+uploadDocument(file)
}
class DocumentServiceFactory {
+getDocumentService()
}
DocumentService <|-- LiferayDocumentServiceImpl
DocumentService <|-- CloudDocumentServiceImpl
DocumentServiceFactory --> DocumentService
2. Event Bus Pattern
Section titled “2. Event Bus Pattern”Use Case: Decoupled service communication
Implementation:
@Componentpublic class OrderEventListener implements MessageListener {
@Override public void receive(Message message) { // Process order event }}
@Componentpublic class OrderServiceImpl extends OrderServiceBaseImpl {
public void completeOrder(Order order) { // Business logic
MessageBus messageBus = MessageBusUtil.getMessageBus(); messageBus.sendMessage( "liferay/order_events", new MessageCreator() { // Create message } ); }}Advanced Patterns
Section titled “Advanced Patterns”1. CQRS Pattern
Section titled “1. CQRS Pattern”Use Case: Separate read and write operations for complex domains
Implementation:
// Command side@Componentpublic class OrderCommandServiceImpl extends OrderCommandServiceBaseImpl { public void placeOrder(Order order) { // Validation and business logic orderPersistence.update(order);
// Send to query side through event }}
// Query side@Componentpublic class OrderQueryServiceImpl implements OrderQueryService {
private final Map<Long, OrderDTO> orderCache = new ConcurrentHashMap<>();
@Reference private OrderLocalService _orderLocalService;
public OrderDTO getOrder(long orderId) { return orderCache.computeIfAbsent(orderId, id -> { Order order = _orderLocalService.getOrder(id); return convertToDTO(order); }); }}2. Saga Pattern
Section titled “2. Saga Pattern”Use Case: Manage long-running business transactions
Implementation:
sequenceDiagram
participant O as OrderService
participant I as InventoryService
participant P as PaymentService
O->>I: Reserve items
I-->>O: Items reserved
O->>P: Authorize payment
P-->>O: Payment authorized
O->>I: Confirm reservation
O->>P: Capture payment
@Componentpublic class OrderSaga {
@Reference private InventoryService _inventoryService;
@Reference private PaymentService _paymentService;
public void execute(Order order) { SagaExecution saga = new SagaExecution();
saga.addStep( () -> _inventoryService.reserveItems(order), () -> _inventoryService.cancelReservation(order) );
saga.addStep( () -> _paymentService.authorizePayment(order), () -> _paymentService.cancelAuthorization(order) );
try { saga.execute(); } catch (SagaException e) { saga.compensate(); } }}Best Practices for Service Patterns
Section titled “Best Practices for Service Patterns”-
Pattern Selection Criteria:
- Match pattern complexity to problem complexity
- Consider Liferay’s built-in capabilities before custom implementations
- Evaluate performance implications
-
OSGi Integration:
- Use declarative services for dependency management
- Leverage service ranking for decorators
- Consider service availability in distributed patterns
-
Performance Considerations:
- Cache judiciously in decorators
- Batch operations in complex patterns
- Monitor saga timeouts
-
Testing Strategies:
- Mock external dependencies in unit tests
- Test compensation logic thoroughly
- Verify transactional boundaries
These patterns provide robust solutions to common challenges in Liferay service development while maintaining alignment with the platform’s architecture and capabilities.