The resource serving feature enables a portlet to serve a resource. Portlets can create two kinds of resource links to serve requests:
Direct links to the resources in the same portlet web application. Direct links are not guaranteed to pass through the portal server and will not have portlet context available. So, a direct link should be used in cases where access to the portlet context and access through portal server is not needed.
Resource URL links that point back to the portlet. These links call the serveResource() method of ResourceServingPortlet. This way, the portlet can serve a resource that is protected by the portal security and can leverage the portlet context. Portlet container does not render any output in addition to the content returned by the serveResource call. Thus, the serveResource() method provides more control to you by giving access to write directly on the response object where portal server just acts as a proxy.
The portlet can create resource URLs pointing back to itself in the following ways:
By invoking the createResourceURL() method of the RenderResponse object or ResourceResponse object .
By using resourceURL tag (for example, portlet:resourceURL).
When an end user invokes such a resource URL the portlet container calls the serveResource() method of the portlet and renders the content returned by the serveResource call.
The serveResource() method can also be used to implement AJAX use cases by invoking the resourceURL() method through the XMLHttpRequest in client-side JavaScript code. The client-side code of the portlet is then responsible for inserting either the markup or update the page DOM in a non-disruptive manner for the other components on the page.
The presentation logic for the resource serving portlet looks as below and shows how to serve portlet fragments by using the serveResource method:
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %> ......... <portlet:defineObjects/> ........ ........ <portlet:resourceURL var="jsURL" id="js" escapeXml="false" /> /* Load Dojo library, if it hasn't already */ if (typeof dojo == "undefined") { /* build script tag */ var script = document.createElement("script"); script.src = "<%=renderResponse.encodeURL(jsURL.toString())%>; ......... } ......... <portlet:resourceURL var="invoiceURL" id="invoice" escapeXml="false" /> <script type="text/javascript"> /* Use Dojo.io.bind to asynchronously get invoice content */ function <portlet:namespace/>_loadInvoice(invoice) { /* If an invoice was selected */ if (invoice != null && invoice != "null") { ......... var bindArgs = { url: "<%=renderResponse.encodeURL(invoiceURL.toString())%>", method: "POST", content: querystring, handle: function(type, data, evt) { if (type == "error") { /* Swap returned error message */ data = "<p style='color:red'>" + data.message + "</p>"; } /* Swap returned data into div tag */ var div = document.getElementById("<portlet:namespace/>_content"); div.innerHTML = ""; div.innerHTML = data; }, mimetype: "text/html" }; dojo.io.bind(bindArgs); } }; |
The portlet class that serves the resource looks as below:
public class InvoicePortlet extends GenericPortlet { ......... @Override public void serveResource(ResourceRequest request, ResourceResponse response) throws PortletException, IOException { response.setContentType("text/html"); String resourceID = request.getResourceID(); Locale locale = request.getLocale(); if (resourceID.equals("invoice")) { String invoice = request.getParameter("invoice"); if (invoice == null) { throw new PortletException("Required parameter, invoice, is missing."); } else { String path = "/html/" + invoice + ".html"; String content = getContents(path, locale, true); PrintWriter writer = response.getWriter(); writer.print(content); } } else if (resourceID.equals("js")) { String content = getContents(jsPage, locale, false); PrintWriter writer = response.getWriter(); writer.print(content); } } ......... } |
The following figure shows the Invoice Portlet. When the user selects a invoice number in the drop-down box, an asynchronous request (AJAX call) is made by the JavaScript client to the portlet. The serveResource() method of the portlet is invoked to serve the content.
Portlet Container 2.0 introduces a Portlet Policy that governs policies related to events, container events and public render parameters. The policy specifies how the events, container events, and public render parameters are distributed. It also specifies the maximum generation of events to prevent endless loops. If a portlet sends an event to other portlets, it is considered as one event generation. If the other portlets send events, that is considered as two event generations and so on. It also provides the ability to enable/disable the container events.
The portlet-policy.xml file is located in PortalServer-Data-Directory/portals/portal-id/config. The schema is located at https://portlet-container.dev.java.net/xml/portlet-policy.xsd.
The portlet-policy.xml file looks like this:
<portlet-policy xmlns="https://portlet-container.dev.java.net/xml/portlet-policy.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://portlet-container.dev.java.net/xml/portlet-policy.xsd" version="1.0"> <event-policy> <event-distribution>VISIBLE_PORTLETS_ON_PAGE</event-distribution> <max-event-generation>3</max-event-generation> </event-policy> <container-event-policy> <event-distribution>ALL_PORTLETS</event-distribution> <max-event-generation>2</max-event-generation> <event> <name>login</name> <status>enabled</status> </event> <event> <name>logout</name> <status>enabled</status> </event> </container-event-policy> <public-render-parameter-policy> <public-render-parameter-distribution>VISIBLE_PORTLETS_ON_PAGE</public-render-parameter-distribution> </public-render-parameter-policy> </portlet-policy> |
The above example shows that only visible portlets on the page will receive events and public render parameters. This also specifies that the maximum number of events permitted to be generated is two. This also specifies that the container events, login and logout are enabled. Currently, only login and logout container events are supported.
Any portlet interested in login event should specify the following in its portlet.xml. The processEvent() method of the portlet will be called when the user logs in.
<supported-processing-event> <qname xmlns:x="urn:oasis:names:tc:wsrp:v2:types"> x:login </qname> </supported-processing-event> |
Any portlet interested in logout event should specify the following in its portlet.xml. The processEvent() method of the portlet will be called when the user logs out.
<supported-processing-event> <qname xmlns:x="urn:oasis:names:tc:wsrp:v2:types"> x:logout </qname> </supported-processing-event> |