Portlet Advance
1. Portlet Core Architecture
Section titled “1. Portlet Core Architecture”Portlet Container & OSGi Integration
Section titled “Portlet Container & OSGi Integration”graph TB
subgraph OSGi Runtime
A[Portlet Container] --> B[Portlet 1]
A --> C[Portlet 2]
A --> D[...]
end
E[HTTP Requests] --> A
A --> F[Portal Page]
Key Components:
- Portlet Container: Manages lifecycle (init, render, destroy)
- OSGi Service Registry: Enables dependency injection
- Portlet Bridge: Connects portlets to Liferay’s rendering engine
Portlet Class Hierarchy
Section titled “Portlet Class Hierarchy”classDiagram
GenericPortlet <|-- MVCPortlet
GenericPortlet <|-- BaseJSPServlet
GenericPortlet : +doView()
GenericPortlet : +doEdit()
GenericPortlet : +doConfig()
MVCPortlet : +render()
MVCPortlet : +processAction()
2. Advanced Portlet Modes
Section titled “2. Advanced Portlet Modes”Custom Portlet Modes
Section titled “Custom Portlet Modes”@PortletConfiguration( portletName = "myPortlet", modes = { @PortletMode(name = "print", markup = "text/html"), @PortletMode(name = "dashboard") })public class MyPortlet extends GenericPortlet { @Override protected void doPrint(RenderRequest request, RenderResponse response) { // Print-specific rendering }}Mode Transition Flow
Section titled “Mode Transition Flow”stateDiagram-v2
[*] --> VIEW
VIEW --> EDIT: User clicks edit
EDIT --> CONFIG: Admin clicks config
CONFIG --> VIEW: Settings saved
VIEW --> PRINT: Print button
PRINT --> VIEW: Print complete
3. Inter-Portlet Communication (IPC)
Section titled “3. Inter-Portlet Communication (IPC)”Event-Based IPC
Section titled “Event-Based IPC”// Sender Portlet@ProcessAction(name = "sendData")public void sendData(ActionRequest request, ActionResponse response) { response.setEvent("user/data", userData);}
// Receiver Portlet@ProcessEvent(qname = "{http://example.com}user/data")public void receiveData(EventRequest request, EventResponse response) { UserData data = (UserData)request.getEvent();}Public Render Parameters
Section titled “Public Render Parameters”<portlet> <supported-public-render-parameter>user_id</supported-public-render-parameter></portlet>
<!-- liferay-portlet.xml --><portlet> <public-render-parameter> <identifier>user_id</identifier> <qname>[http://example.com]user_id</qname> </public-render-parameter></portlet>4. Advanced Configuration
Section titled “4. Advanced Configuration”Portlet Preferences (Database-Persisted)
Section titled “Portlet Preferences (Database-Persisted)”@PortletConfiguration( portletName = "configurablePortlet", preferences = { @PortletPreference( name = "colorScheme", value = "{\"default\":\"blue\",\"options\":[\"red\",\"green\"]}" ) })public class ConfigurablePortlet extends GenericPortlet { // ...}Dynamic Preference Management
Section titled “Dynamic Preference Management”PortletPreferences prefs = request.getPreferences();prefs.setValue("itemsPerPage", "10");prefs.store(); // Persists to database5. Performance Optimization
Section titled “5. Performance Optimization”Caching Strategies
Section titled “Caching Strategies”graph LR
A[Request] --> B{Cache Valid?}
B -->|Yes| C[Return Cached]
B -->|No| D[Process Request]
D --> E[Store in Cache]
Implementation:
@Header( name = "Cache-Control", value = "public, max-age=3600" // 1 hour cache)public class CachedPortlet extends GenericPortlet { // ...}Resource Serving Best Practices
Section titled “Resource Serving Best Practices”@ServeResource( resourceID = "chartData", contentType = "application/json")public void serveChartData(ResourceRequest request, ResourceResponse response) { // Generate and stream JSON}6. Security Considerations
Section titled “6. Security Considerations”Permission Checking
Section titled “Permission Checking”if (PortletPermissionUtil.contains( permissionChecker, plid, portletId, ActionKeys.VIEW)) { // Render content}CSRF Protection
Section titled “CSRF Protection”<portlet:actionURL var="formAction"> <portlet:param name="<%=Constants.CSRF_TOKEN%>" value="<%=request.getAttribute(Constants.CSRF_TOKEN)%>" /></portlet:actionURL>7. Migration Considerations (6.2 → 7.4)
Section titled “7. Migration Considerations (6.2 → 7.4)”Key Changes
Section titled “Key Changes”| Liferay 6.2 | Liferay 7.4 |
|---|---|
| PortletSpec 2.0 | PortletSpec 3.0 |
| Plugin SDK | Blade CLI/Gradle |
| Spring Portlet MVC | OSGi DS Components |
liferay-portlet.xml | OSGi Metadata |
Migration Path
Section titled “Migration Path”gantt
title Portlet Migration Timeline
dateFormat YYYY-MM-DD
section Analysis
Code Audit :done, a1, 2023-01-01, 14d
Dependency Mapping :active, a2, after a1, 10d
section Implementation
OSGi Conversion :a3, after a2, 21d
Testing :a4, after a3, 14d
8. Debugging & Troubleshooting
Section titled “8. Debugging & Troubleshooting”Common Issues
Section titled “Common Issues”- ClassCastException - Check OSGi service versions
- Portlet Not Appearing - Verify
bnd.bndheaders - Preferences Not Saving - Check permission constraints
Diagnostic Tools
Section titled “Diagnostic Tools”# Gogo Shell Commands:lb | grep my.portlet # Find bundleservices | grep Portlet # Check registrationslog:display # View logs9. Real-World Implementation Example
Section titled “9. Real-World Implementation Example”Complete Dashboard Portlet
Section titled “Complete Dashboard Portlet”@Component( property = { "com.liferay.portlet.display-category=category.sample", "com.liferay.portlet.instanceable=true", "javax.portlet.name=com_example_DashboardPortlet" }, service = Portlet.class)public class DashboardPortlet extends MVCPortlet {
@Reference private UserLocalService _userService;
@Override public void render(RenderRequest request, RenderResponse response) { request.setAttribute("userCount", _userService.getUsersCount()); super.render(request, response); }
@ServeResource public void serveCharts(ResourceRequest request, ResourceResponse response) { // Return JSON data for AJAX charts }}10. Future-Proofing
Section titled “10. Future-Proofing”Headless Portlet Patterns
Section titled “Headless Portlet Patterns”@ProviderTypepublic interface MyPortletService { String getDataAsJson();}
@Component(service = MyPortletService.class)public class MyPortletServiceImpl implements MyPortletService { // ...}Web Components Integration
Section titled “Web Components Integration”class MyPortletElement extends HTMLElement { connectedCallback() { this.innerHTML = `<h1>Portlet as Web Component</h1>`; }}customElements.define("my-portlet", MyPortletElement);Next Steps for Mastery
Section titled “Next Steps for Mastery”-
Deep Dive into OSGi Services:
Terminal window blade create -t service my-service-apiblade create -t service-wrapper my-service-override -
Explore Liferay’s Frontend Toolkit:
Terminal window npm init @liferay/js-portlet@latest -
Performance Tuning:
- Implement Fragment Caching
- Study Portlet Filter Chains