Understanding Service-builder Modules
Liferay Service Builder is a powerful code generation tool that automates the creation of service and persistence layers for custom entities. It streamlines development by generating boilerplate code, enforcing best practices, and integrating seamlessly with Liferay’s permission and transaction systems. This approach ensures consistency, scalability, and maintainability for enterprise applications.
Service Builder Fundamentals
Section titled “Service Builder Fundamentals”Why Service Builder?
Section titled “Why Service Builder?”- Rapid Development: Generates 80% of boilerplate code
- Consistency: Standardized service structure
- Optimized: Built-in caching and transaction management
- Integrated: Works seamlessly with Liferay’s permission system
Basic Workflow
Section titled “Basic Workflow”graph TD
A[Define service.xml] --> B[Run buildService]
B --> C[Implement custom methods]
C --> D[Rebuild service]
Core Architectural Patterns
Section titled “Core Architectural Patterns”1. Layered Architecture Pattern
Section titled “1. Layered Architecture Pattern”classDiagram
class Entity {
+Model layer
}
class Persistence {
+DAO layer
}
class LocalServiceImpl {
+Business logic
}
class ServiceImpl {
+Remote facade
}
Entity <-- Persistence
Persistence <-- LocalServiceImpl
LocalServiceImpl <-- ServiceImpl
Best Practice:
- Keep business logic in
*LocalServiceImpl - Use
*ServiceImplonly as remote facade - Never modify generated classes
2. Bridge Pattern for Custom SQL
Section titled “2. Bridge Pattern for Custom SQL”<entity name="Employee" ...> <!-- ... --> <finder name="Department" return-type="Collection"> <finder-column name="departmentId" /> </finder></entity>public class EmployeeFinderImpl extends EmployeeFinderBaseImpl { public List<Employee> findByDepartment(long departmentId, int start, int end) { // Custom SQL implementation }}Data Modeling Patterns
Section titled “Data Modeling Patterns”1. Entity Design Patterns
Section titled “1. Entity Design Patterns”Basic Entity:
<entity name="Book" local-service="true" remote-service="true"> <column name="bookId" type="long" primary="true" /> <column name="title" type="String" /> <column name="author" type="String" /></entity>Advanced Patterns:
- TypeSettings Pattern: Store flexible attributes as JSON
<column name="typeSettings" type="String" />- Audit Trail Pattern:
<column name="createDate" type="Date" /><column name="modifiedDate" type="Date" /><column name="userId" type="long" />2. Relationship Patterns
Section titled “2. Relationship Patterns”One-to-Many:
<entity name="Department" ...> <!-- ... --></entity>
<entity name="Employee" ...> <column name="departmentId" type="long" /> <finder name="Department" return-type="Collection"> <finder-column name="departmentId" /> </finder></entity>Many-to-Many:
<entity name="Student" ...> <!-- ... --></entity>
<entity name="Course" ...> <!-- ... --></entity>
<entity name="StudentCourse" local-service="true"> <column name="studentCourseId" type="long" primary="true" /> <column name="studentId" type="long" /> <column name="courseId" type="long" /> <finder name="Student" return-type="Collection"> <finder-column name="studentId" /> </finder> <finder name="Course" return-type="Collection"> <finder-column name="courseId" /> </finder></entity>Service Layer Patterns
Section titled “Service Layer Patterns”1. Facade Pattern
Section titled “1. Facade Pattern”Local Service (BookLocalServiceImpl):
public Book addBook(long userId, String title, String author) { // Validation validate(title, author);
// Create entity long bookId = counterLocalService.increment(); Book book = bookPersistence.create(bookId); book.setTitle(title); book.setAuthor(author);
// Audit fields book.setUserId(userId); book.setCreateDate(new Date());
return bookPersistence.update(book);}Remote Service (BookServiceImpl):
public Book addBook(long userId, String title, String author) { return bookLocalService.addBook(userId, title, author);}2. Strategy Pattern for Business Logic
Section titled “2. Strategy Pattern for Business Logic”public interface DiscountCalculator { BigDecimal calculateDiscount(Order order);}
@Component(service = DiscountCalculator.class)public class HolidayDiscountCalculator implements DiscountCalculator { // Implementation}
public class OrderLocalServiceImpl extends OrderLocalServiceBaseImpl {
@Reference(policyOption = ReferencePolicyOption.GREEDY) private volatile List<DiscountCalculator> _discountCalculators;
public BigDecimal calculateTotal(Order order) { BigDecimal total = order.getBaseAmount();
for (DiscountCalculator calculator : _discountCalculators) { total = total.subtract(calculator.calculateDiscount(order)); }
return total; }}Performance Optimization
Section titled “Performance Optimization”1. Caching Patterns
Section titled “1. Caching Patterns”Entity Cache (enabled by default):
sequenceDiagram
Client->>Service: getBook(123)
Service->>Cache: Check cache
alt Cache Hit
Cache-->>Service: Return cached book
else Cache Miss
Service->>Database: SELECT * FROM Book WHERE bookId=123
Service->>Cache: Store book
end
Service-->>Client: Return book
Finder Cache:
<finder name="Author" return-type="Collection" db-index="false"> <finder-column name="author" /></finder>2. Batch Processing Pattern
Section titled “2. Batch Processing Pattern”public void updateAllBooks(LambdaFunction<Book, Book> updateFunction) { DynamicQuery query = DynamicQueryFactoryUtil.forClass(Book.class);
try (BatchSession batchSession = persistence.openBatchSession()) { List<Book> books = bookPersistence.findWithDynamicQuery(query);
for (Book book : books) { Book updatedBook = updateFunction.apply(book); bookPersistence.update(book, batchSession); }
batchSession.flush(); }}Integration Patterns
Section titled “Integration Patterns”1. Adapter Pattern for External Systems
Section titled “1. Adapter Pattern for External Systems”@Component(service = InventoryService.class)public class InventoryServiceAdapter implements InventoryService {
@Reference private BookLocalService _bookLocalService;
@Reference private ExternalInventorySystem _externalSystem;
public boolean checkStock(long bookId, int quantity) { Book book = _bookLocalService.getBook(bookId); return _externalSystem.checkAvailability(book.getISBN(), quantity); }}2. Event Bus Pattern
Section titled “2. Event Bus Pattern”public class OrderLocalServiceImpl extends OrderLocalServiceBaseImpl {
public Order completeOrder(long orderId) { Order order = orderPersistence.findByPrimaryKey(orderId); order.setStatus("COMPLETED"); orderPersistence.update(order);
// Send event MessageBus messageBus = MessageBusUtil.getMessageBus(); messageBus.sendMessage( "liferay/order_events", MessageCreator.createMessage(order));
return order; }}Testing Strategies
Section titled “Testing Strategies”1. Unit Testing Pattern
Section titled “1. Unit Testing Pattern”public class BookLocalServiceImplTest {
@Mock private BookPersistence _bookPersistence;
@InjectMocks private BookLocalServiceImpl _service;
@Test public void testAddBook() { when(_bookPersistence.create(anyLong())).thenReturn(new BookImpl());
Book book = _service.addBook(1, "Title", "Author");
assertNotNull(book); assertEquals("Title", book.getTitle()); }}2. Integration Testing Pattern
Section titled “2. Integration Testing Pattern”@RunWith(Arquillian.class)public class BookServiceIntegrationTest {
@Inject private BookLocalService _bookLocalService;
@Test public void testAddBook() { Book book = _bookLocalService.addBook( TestPropsValues.getUserId(), "Test Book", "Test Author");
assertNotNull(book.getBookId()); }}Migration Patterns
Section titled “Migration Patterns”1. Versioning Pattern
Section titled “1. Versioning Pattern”<entity name="Book" ...> <column name="version" type="double" /></entity>public Book updateBook(long bookId, String title) { Book book = bookPersistence.findByPrimaryKey(bookId); book.setTitle(title); book.setVersion(book.getVersion() + 1); return bookPersistence.update(book);}2. Blue-Green Deployment Pattern
Section titled “2. Blue-Green Deployment Pattern”- Create parallel tables (
Book_v2) - Implement dual-write in service layer
- Migrate data gradually
- Switch read operations to new table
- Remove old table
Key Benefits of Service Builder
Section titled “Key Benefits of Service Builder”-
Rapid Development:
- Generates 90% of persistence code
- Standardized service structure
- Built-in best practices
-
Optimized Performance:
- Automatic caching
- Batch processing support
- Optimized SQL generation
-
Liferay Integration:
- Built-in permission checking
- Audit fields support
- Seamless upgrade process
-
Maintainability:
- Clear separation of concerns
- Generated code is consistent
- Easy to refactor
Service Builder provides an excellent balance between productivity and flexibility, making it ideal for most Liferay development scenarios while still allowing custom patterns when needed.