introduction to portlets using liferay portal (part 2)

Post on 23-Aug-2014

16.339 Views

Category:

Investor Relations

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

Presentation about Portlets and Liferay Portal held at Costa Rica Java Users Group

TRANSCRIPT

ARTISANS OF OPEN SOURCE

Rivet Logic Corporation 11410 Isaac Newton Square N. Suite 210 Reston, VA 20190, USA Ph: 703.955.3480 Fax: 703.234.7711

Rivet Logic Costa Rica SRL Costa Rica Developer's Forge Edificio María Luisa, 3A office Paseo Colón, San José, Costa Rica Ph: (506) 2256-1024 Fax: (506) 2256-1024

Introduction to Portlets using Liferay Portal (Part 2)

By: Aníbal Gómez-Estrada http://rivetlogic.com/web/agomez

October 19th, 2011

ARTISANS OF OPEN SOURCE Rivet Logic Overview

•  Award-winning consulting and systems integration firm focused on enabling open source –based software solutions for content management, collaboration and community:

–  Innovator of the Year: JBoss (2008) –  Solution of the Year: Alfresco (2010) –  Platinum Partner: Liferay (2011)

•  We use top-notch open source technology:

•  Company Facts: –  Founded in 2005. Consistently Profitable and Employee-owned. 40+ Consultants –  Headquarters in Virginia, USA. Near-shore office in San José, Costa Rica for two years –  Certified Liferay Partner since 2006:

•  Conduct all public training on East Coast, USA •  Contributor (software, documentation, forums, training material) •  20+ Liferay projects underway or completed!

ARTISANS OF OPEN SOURCE Agenda

•  Introduction –  Portals and Portlets –  Liferay SDK Plugin Types –  Liferay Service Builder –  Portlets 1.0 (JSR 168)

•  Portlets 2.0 (JSR 286) –  Resource Serving –  Inter-Portlet Communication –  Lifecycle Revisited –  Portlet Filters and PortletURL Listeners –  Enhancements:

•  Servlet Programming Features •  Annotations •  Tag Libraries

•  Conclusion –  Questions and Answers –  References

•  Announcements –  JSF 2.0 Portlets using Liferay Portal is Available Now! –  Rivet Logic Is Hiring!

ARTISANS OF OPEN SOURCE

Introduction

ARTISANS OF OPEN SOURCE Portals and Portlets

In a Nutshell

A Portal is designed to be a single web-based environment where all users applications

run integrated together in a

systematic way”

Liferay Portal is a Portlet Container and Portal Server

Platform and environment to run/administer web sites

and to integrate portlets

Portal Architecture:

ARTISANS OF OPEN SOURCE Liferay SDK Plugin Types

Themes

•  Themes customize the overall structure and look and feel of the Portal pages and are based on HTML, CSS and Velocity/FreeMarker

•  Theme Plugins are based on a pre-made theme which gives the site minimal structure (either unstyled or styled) •  Customizations are overlaid against the “base theme” with a overwriting mechanism

and differentiation scheme •  Provide control over everything: HTML, CSS and images inside portlets (box) and

outside (page) and positioning/behavior of the top navigation elements

•  Deployed Themes can be used at level different levels: the overall site, a community/organization or a single page

More Info: http://www.liferay.com/community/wiki/-/wiki/Main/Themes

ARTISANS OF OPEN SOURCE Liferay SDK Plugin Types (2)

Layout Templates •  Layout Templates control how portlets are arranged

on a Portal page and are created with a combination of HTML, CSS and Velocity

•  They make up the body of the page, the large area where portlets can be dragged and dropped into

•  Allow portlets to be embedded into templates •  Deployed Layout Templates are used at page level

•  For Instance:

More Info: http://www.liferay.com/web/guest/community/wiki/-/wiki/Main/Layout+Template

ARTISANS OF OPEN SOURCE Liferay SDK Plugin Types (3)

Hooks •  Hooks allow to hook custom code at different extension

points in order to either change, override or extend: •  Display: JSPs and Language Properties •  Behavior: Portal Server Lifecycle Events, Services, Model Listeners

and Portal Properties

•  Hook Plugins are Java code –based and they are hot-deployable, as well as, Themes, Layout Templates and Portlet Plugins do!

More Info: http://www.liferay.com/community/wiki/-/wiki/Main/Portal+Hook+Plugins

ARTISANS OF OPEN SOURCE Liferay SDK Plugin Types (4)

Portlets •  Portlets are componentized

user-facing applications that generate a fragment of the Portal page

In this presentation, you will learn more about what Portlet Plugins are!

•  For now, let’s take a look at some of the portlets available for Liferay Portal..

More Info: http://www.liferay.com/community/wiki/-/wiki/Main/Out+of+The+Box+Portlets

ARTISANS OF OPEN SOURCE Liferay SDK Plugin Types (5)

Ext •  Ext allow to extend/override built-in code in special

scenarios that can not be met by another plugin types: •  Easily extensible: Liferay Portal is implemented on top of Spring,

Hibernate and Struts/Tiles, so custom code can be plugged in very easily •  Complete control: It allows access to internal APIs or even overwriting

files/classes provided in the Liferay core •  To be carefully used: it is a powerful tool that comes with a cost in terms of

complexity and maintenance!

•  Ext Plugins are NOT hot-deployable! –  Require server restart –  Can not be un-deployed

More Info: https://www.liferay.com/community/wiki/-/wiki/Main/Ext+Plugin

ARTISANS OF OPEN SOURCE Liferay Service Builder

•  Service Builder is a tool built by Liferay to automate the creation of Services, Models and Persistence –related interfaces and classes relying on Liferay API, Spring and Hibernate: •  Input: an XML file specifying the structure of Model classes and data-storage –related

operations

•  Ouput: a service JAR that can be exposed either at a global or local (ie. Portlet plugin) levels and a set of implementation classes with beans and basic logic generated for the Model and Service/Persistence classes

•  When specified, Service Builder also generates Javascript stubs for remote access (ie. client side / browser)!

More Info: http://www.liferay.com/community/wiki/-/wiki/Main/Service+Builder

ARTISANS OF OPEN SOURCE Portlet 1.0 (JSR 168)

•  JSR 168 in a Nutshell: –  Portlet Container Contract and Portlet Lifecycle –  Packaging and Deployment –  Portlet Modes and Window States –  Portlet Preferences Management –  JSP Support –  User Information and Security –  Localization and Caching

•  JSR 168 defined the overall UI component model and provided a few support for building integrated/coordinated composite applications. However, “portlets are islands” in JSR 168: –  Can not generate non-markup content –  Can not communicate with other portlets –  Can not influence the portal page

ARTISANS OF OPEN SOURCE

Portlet 2.0 (JSR 286)

ARTISANS OF OPEN SOURCE Portlet 2.0 (JSR 286)

•  JSR 286 addresses limitations identified by many portal vendors that caused custom solutions and not portable to be placed in their products –  Released in June, 2008 –  Expert Group: IBM, ASF, Oracle, BEA, Liferay, among others

•  Features introduced in JSR 286’s Portlet API also fill some gaps with related technologies, such as J2EE 1.4, WSRP, Servlets, JSF, among others

•  JSR 286 mainly addresses following topics: –  Resource Serving * –  Inter-Portlet Communication: Event-Notification and Public Render

Parameters * –  Portlet Filters and PortletURL Listeners * –  Servlet Programming Model Features * –  Enhancement on Annotations, JSP support, Portlet Modes, Caching *

ARTISANS OF OPEN SOURCE Resource Serving

•  In JSR 168, dynamically generated resources could not be directly served from a portlet instance. An additional servlet was needed to serve the resources: –  Disadvantages: Out of Portal’s Scope (No Access to render parameters, portlet mode,

window state, portlet preferences, portlet session, etc). Not under Portal access control (Servlet to be secured separately)

–  Advantages: less overhead because the request does not have to pass through the additional portal framework. Adequate when serving large media streams…

•  JSR 286 introduces Resource Serving as a lifecycle operation that is dispatched directly from corresponding portlet instance: –  Normally occurs after a render call and can be used to implement AJAX use cases –  Does not generate a full new portal page. Returned content not aggregated with another

markup. The resource response allows full control over output stream –  Cannot set new render parameters, portlet mode, or window state since the portal

does not have a chance to update other parts of the page

•  During a Resource Request, a portlet implementing ResourceServingPortlet interface can create dynamic resources through serveResource() method

•  Portlet API provide Resource URLs for Resource Serving requests. They are created with RenderResponse.createResourceURL() and trigger lifecycle serveResource() method. ResourceURLs can be set with params as other URLs

ARTISANS OF OPEN SOURCE Resource Serving (2)

•  Let’s create a new JSP-based Portlet which returns a greeting on Ajax call: File: /WEB-INF/src/com/sample/jsp/portlets/JSPPortlet.java package com.sample.jsp.portlets;

import java.io.IOException;import java.io.OutputStream;import javax.portlet.*;

public class JSPPortlet extends javax.portlet.GenericPortlet {

@Override protected void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException { PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher("/html/view.jsp"); rd.include(request,response); }

@Override public void serveResource(ResourceRequest request, ResourceResponse response) throws PortletException, IOException { OutputStream stream = response.getPortletOutputStream(); response.setContentType("text/html");

stream.write( String.format( "%1$s (Ajax - %2$s)!!”, request.getParameter("ajax-parameter-greeting"), Math.random() ).getBytes() ); }}

ARTISANS OF OPEN SOURCE Resource Serving (3)

•  Now, let’s create the JSP page invoking the portlet via Ajax: File: /html/view.jsp

<%@ page session="false" contentType="text/html; charset=ISO-8859-1" %><%@ page import="javax.portlet.*"%><%@ taglib uri='/WEB-INF/tld/liferay-portlet.tld' prefix='portlet'%>

<portlet:defineObjects/>

<portlet:resourceURL var="resourceUrl"> <portlet:param name="ajax-parameter-greeting" value="Hello World from Resource Serving Param" /></portlet:resourceURL><p> <input type="button" value='Ajax!' title='<%=resourceUrl%>’ onclick="javascript:ajaxHelloWorld('<%=resourceUrl%>');” /></p><div id="msg_display">The data from the server will go here</div>

<script type="text/javascript"> /* PLEASE LOOK AT NEXT SLIDE */</script>

ARTISANS OF OPEN SOURCE Resource Serving (4)

•  Now, let’s create the JSP page invoking the portlet via Ajax (2): File: /html/view.jsp ...<script type="text/javascript">function ajaxHelloWorld(url){ var request = createXMLHttpRequest(); var callback = function() { var msg_display = document.getElementById("msg_display"); if (request.readyState == 4) { if (request.status == 200) { msg_display.innerHTML = request.responseText; } else { msg_display.innerHTML = "ERROR: "+ request.statusText; } } }; request.onreadystatechange = callback; request.open("GET", url, true); request.send();}

function createXMLHttpRequest() { var request; if (window.XMLHttpRequest) { request = new XMLHttpRequest(); } else if (window.ActiveXObject) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {} } } return request;}</script>

ARTISANS OF OPEN SOURCE Resource Serving (5)

•  Finally, let’s add the portlet in corresponding deployment descriptors File: /WEB-INF/portlet.xml <portlet-app ...> ... <portlet> <portlet-name>jsp-hello-world-portlet</portlet-name> <display-name>JSP 2.0 Hello World Portlet</display-name> <portlet-class>com.sample.jsp.portlets.JSPPortlet</portlet-class>

<supports> <mime-type>text/html</mime-type> </supports>

<portlet-info> <title>JSP 2.0 Hello World Portlet</title> <short-title>JSP 2.0 Hello World Portlet</short-title> <keywords>JSP 2.0 Hello World Portlet</keywords> </portlet-info> </portlet> ...</portlet-app>

File: /WEB-INF/liferay-portlet.xml <liferay-portlet-app> <portlet> <portlet-name>jsp-hello-world-portlet</portlet-name> <icon>/icon.png</icon> <instanceable>true</instanceable> </portlet></liferay-portlet-app>

File: /WEB-INF/liferay-display.xml <display> <category name="category.sample"> <portlet id=”jsp-hello-world-portlet" /> </category></display>

ARTISANS OF OPEN SOURCE Resource Serving (6)

•  After re-deploying our Portlet plugin and clicking portlet’s button:

ARTISANS OF OPEN SOURCE Resource Serving (7)

•  An additional resource ID can be set on the resource URL that clearly identifies the resource through ResourceURL.setResourceID() method, such as: –  resourceUrl.setResourceID("WEB-INF/jsp/xmlcontent.jspx"); –  When extending GenericPortlet, a serveResource call is automatically dispatched to the JSP,

which can then make use of the portlet state information by including the portlet tag library

•  Serving static resources using the portlet's serveResource() method causes unnecessary performance overhead: –  Static resources like image files packaged in the portlet WAR should normally be

referenced with static resource URLs, such as: String url = response.encodeURL(request.getContextPath()+"/icons/myimage.gif");

•  In contrast to RenderURLs, all HTTP methods (GET, POST or DELETE) can be leveraged with ResourceURLs (not only GET) which means: –  Methods to change state can be used in the serveResource() call. But, changes should

be limited to private state of portlet: Portlet-scoped session and Portlet Preferences –  State that affects other portlets should not be modified because the portal

framework has no chance to update another portions of the page on serveResource()

ARTISANS OF OPEN SOURCE IPC: Event Notifications

•  In JSR 168, the only way to achieve communication between portlets was through portlet session. Only possible with portlets in same web-app…

•  JSR 286 provides a loosely coupled publish/subscribe model that allows portlets in different web applications to send and receive events

•  An event is a lifecycle operation that occurs before the rendering phase and allow portlets to respond on actions or state changes

•  Descriptor portlet.xml must declare events and define what portlets are allowed to produce and consume them: –  Event name is represented as QName (Namespace + Localpart) to identify it uniquely –  Event payload (argument) is represented by a java.io.Serializable class

•  During action and event lifecycle operations, a portlet can publish events through inherited StateAwareResponse’s setEvent() method

•  During event lifecycle operation, a portlet implementing EventPortlet interface can handle events through processEvent() method

ARTISANS OF OPEN SOURCE IPC: Event Notifications (2)

•  Let's create a new "Hello World" portlet which issues an event once its action button is clicked: File: /WEB-INF/src/com/sample/generic/portlets/HelloWorldPortlet.java package com.sample.generic.portlets;

import java.io.IOException;import java.io.PrintWriter;import javax.portlet.*;import javax.xml.namespace.QName;

public class HelloWorldPortlet extends javax.portlet.GenericPortlet { @Override protected void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException { PrintWriter writer = response.getWriter(); writer.write( String.format( "<form action='%1$s' method='POST'>" + "<input type='submit' value='Change!' />"+ "</form>", response.createActionURL().toString() ) ); }

@Override public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException { response.setEvent( new QName("http://sample.com/events", "ipc.speak.world"), "The Event PayLoad!!" ); }}

ARTISANS OF OPEN SOURCE IPC: Event Notifications (3)

•  Let's create a new "Hello World" portlet which issues an event once its action button is clicked: File: /WEB-INF/src/com/sample/generic/portlets/GoodbyeWorldPortlet.java package com.sample.generic.portlets;

import java.io.IOException;import java.io.PrintWriter;import javax.portlet.*;

public class GoodbyeWorldPortlet implements javax.portlet.Portlet, javax.portlet.EventPortlet { public void init(PortletConfig config) throws PortletException {} public void destroy() {}

public void render(RenderRequest request, RenderResponse response)throws PortletException, IOException {

PrintWriter writer = response.getWriter();

String renderParameter = request.getParameter("render-param-greeting"); writer.write( String.format(

"<p>%1$s</p>”, (renderParameter != null) ? renderParameter : "Waiting for Greeting...” ) ); }

public void processAction(ActionRequest request, ActionResponse response)throws PortletException, IOException {}

public void processEvent(EventRequest request, EventResponse response) throws PortletException, IOException { Event event = request.getEvent(); if ("{http://sample.com/events}ipc.speak.world".equals(event.getQName().toString()) && "The Event PayLoad!!".equals(event.getValue())) { response.setRenderParameter("render-param-greeting", "Goodbye World!!"); } }}

ARTISANS OF OPEN SOURCE IPC: Event Notifications (4)

•  Let’s now declare the event and add the portlets in the standard deployment descriptor: File: /WEB-INF/portlet.xml <portlet-app ...> ... <portlet> <portlet-name>generic-hello-world-portlet</portlet-name> <display-name>Generic 2.0 Hello World Portlet</display-name> <portlet-class>com.sample.generic.portlets.HelloWorldPortlet</portlet-class>

<supports> <mime-type>text/html</mime-type> </supports>

<portlet-info> <title>Generic 2.0 Hello World Portlet</title> <short-title>Generic 2.0 Hello World Portlet</short-title> <keywords>Generic 2.0 Hello World Portlet</keywords> </portlet-info>

<supported-publishing-event> <qname xmlns:x="http://sample.com/events">x:ipc.speak.world</qname> </supported-publishing-event> </portlet> ... <event-definition> <qname xmlns:x="http://sample.com/events">x:ipc.speak.world</qname> <value-type>java.lang.String</value-type> </event-definition></portlet-app>

ARTISANS OF OPEN SOURCE IPC: Event Notifications (5)

•  Let’s now declare the event and add the portlets in the standard deployment descriptor (2): File: /WEB-INF/portlet.xml <portlet-app ...> ... <portlet> <portlet-name>generic-goodbye-world-portlet</portlet-name> <display-name>Generic 2.0 Goodbye World Portlet</display-name> <portlet-class>com.sample.generic.portlets.GoodbyeWorldPortlet</portlet-class>

<supports> <mime-type>text/html</mime-type> </supports>

<portlet-info> <title>Generic 2.0 Goodbye World Portlet</title> <short-title>Generic 2.0 Goodbye World Portlet</short-title> <keywords>Generic 2.0 Goodbye World Portlet</keywords> </portlet-info>

<supported-processing-event> <qname xmlns:x="http://sample.com/events">x:ipc.speak.world</qname> </supported-processing-event> </portlet> ...</portlet-app>

ARTISANS OF OPEN SOURCE IPC: Event Notifications (6)

•  Finally, let’s add liferay -specific configuration for our new Portlets: File: /WEB-INF/liferay-portlet.xml <liferay-portlet-app> ... <portlet> <portlet-name>generic-hello-world-portlet</portlet-name> <icon>/icon.png</icon> <instanceable>true</instanceable> </portlet> <portlet> <portlet-name>generic-goodbye-world-portlet</portlet-name> <icon>/icon.png</icon> <instanceable>true</instanceable> </portlet> ...</liferay-portlet-app>

File: /WEB-INF/liferay-display.xml <display> <category name="category.sample"> ... <portlet id="generic-hello-world-portlet" /> <portlet id="generic-goodbye-world-portlet" /> ... </category></display>

ARTISANS OF OPEN SOURCE IPC: Event Notifications (7)

•  After re-deploying our Portlet plugin, adding both portlets to the same page and click on “Hello World” portlet’s button…

ARTISANS OF OPEN SOURCE IPC: Event Notifications (8)

•  JSR 286 defines some additional features for event definition and declaration available from portlet.xml:

–  Default namespace: a namespace defined through <default-namespace> element can be applied to all events defined only with a local name (<name> element)

–  Aliases: an alternative name defined through <alias> element can be used to coordinate communication between portlets that need to use different names for same event

–  Wildcards: <supported-processing-event> and <supported-publishing-event> elements can use trailing-dot -based wildcards to match events names which local part is defined in hierarchical manner using the dot (.) as a separator. For example: •  “x:foo.event.” can match “x:foo.event.one” and “x:foo.event.two”, but not “x:foo.bar.event” •  “x:foo..” can match “x:foo.event.one” and “x:foo.event.two” and “x:foo.bar.event”

ARTISANS OF OPEN SOURCE IPC: Event Notifications (9)

File: /WEB-INF/portlet.xml <portlet-app ...> ... <portlet> <portlet-name>generic-hello-world-portlet</portlet-name> ... <supported-processing-event> <qname xmlns:x="http://sample.com/events">x:ipc..</qname> </supported-processing-event> </portlet> ... <portlet> <portlet-name>generic-goodbye-world-portlet</portlet-name> ... <supported-processing-event> <name>ipc.speak.world</name> </supported-processing-event> </portlet> ... <default-namespace>http://sample.com/events</default-namespace> ... <event-definition> <name>ipc.hello.world</name> <alias xmlns:x="http://sample.com/events">x:ipc.speak.world</alias> <value-type>java.lang.String</value-type> </event-definition> ...</portlet-app>

•  JSR 286 defines some additional features for event definition and declaration available from portlet.xml:

ARTISANS OF OPEN SOURCE IPC: Public Render Parameters

•  In JSR 168, render parameters set in processAction() method are only available in the render phase of the same portlet

•  JSR 286 allows render parameters to be shared across portlets of same web page. They enable coordination between portlets (parameter passing) and avoid the additional process event call

•  Public render parameters are available in all lifecycle methods and can be viewed or changed by other portlets or components

•  Descriptor portlet.xml must declare public render parameters and specify which ones are to be shared for each portlet: –  Name is represented as QName (Namespace + Localpart) to identify it uniquely –  Identifier defines how it can be referenced from different portlets configuration

•  Similarly to Events, features for public render parameters available from portlet.xml: –  Default namespace: a namespace defined through element <default-namespace>

can be applied to all public render parameters defined only with a local name (<name>) –  Aliases: an alternative name defined through element <alias> can be used to

coordinate portlets that need to use different names for same public render parameter

ARTISANS OF OPEN SOURCE IPC: Public Render Parameters (2)

•  Let’s replace mechanism for Inter-Portlet communication through Public Render Parameters: File: /WEB-INF/src/com/sample/generic/portlets/HelloWorldPortlet.java

package com.sample.generic.portlets;

import java.io.IOException;import java.io.PrintWriter;import javax.portlet.*;import javax.xml.namespace.QName;

public class HelloWorldPortlet extends javax.portlet.GenericPortlet { ... @Override public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException { response.setRenderParameter ( "render-param-greeting", "Goodbye World from Public Render Parameter!!" ); //response.setEvent //( // new QName("http://sample.com/events", "ipc.speak.world"), "The Event PayLoad!!" //); }}

ARTISANS OF OPEN SOURCE IPC: Public Render Parameters (3)

•  Let’s now declare the public render parameter in the standard deployment descriptor: File: /WEB-INF/portlet.xml

<portlet-app ...> ... <portlet> <portlet-name>generic-hello-world-portlet</portlet-name> ... <supported-public-render-parameter> render-param-greeting </supported-public-render-parameter> </portlet> ... <portlet> <portlet-name>generic-goodbye-world-portlet</portlet-name> ... <supported-public-render-parameter> render-param-greeting </supported-public-render-parameter> </portlet> ... <default-namespace>http://sample.com/events</default-namespace> ... <public-render-parameter> <identifier>render-param-greeting</identifier> <name>ipc.render.world</name> </public-render-parameter> ...</portlet-app>

ARTISANS OF OPEN SOURCE IPC: Public Render Parameters (4)

•  After re-deploying our Portlet plugin and clicking on “Hello World” portlet’s button…

ARTISANS OF OPEN SOURCE Contract and Lifecycle Revisited

•  Request handling sequence after lifecycle methods introduced by JSR 286:

ARTISANS OF OPEN SOURCE Let’s Take a Break!

Rivet Logic Corporation 11410 Isaac Newton Square N. Suite 210 Reston, VA 20190, USA Ph: 703.955.3480 Fax: 703.234.7711

Rivet Logic Costa Rica SRL Costa Rica Developer's Forge Edificio María Luisa, 3A office Paseo Colón, San José, Costa Rica Ph: (506) 2256-1024 Fax: (506) 2256-1024

Introduction to Portlets using Liferay Portal (Part 2)

By: Aníbal Gómez-Estrada http://rivetlogic.com/web/agomez

October 19th, 2011

ARTISANS OF OPEN SOURCE Portlet Filters

•  JSR-268 introduces Portlet Filters as a means to intercept any lifecycle call to a portlet and manage custom behavior in centralized way

•  Portlet Filters are reusable pieces of code that can transform content in both request and response of the portlet

•  Functionality implementable through Portlet Filters: –  Pass additional data into the portlet (as attributes or parameters) –  Output filtering for security enforcement or markup compliance –  Collecting diagnostic information –  Bridging between Web application frameworks

•  Portlet Filter model is based on the Servlet Filter model...

ARTISANS OF OPEN SOURCE Portlet Filters (2)

•  Depending on type of lifecycle call to be filtered, a Portlet Filters must implement one of the following interfaces: –  javax.portlet.filter.RenderFilter –  javax.portlet.filter.ActionFilter –  javax.portlet.filter.EventFilter –  javax.portlet.filter.ResourceFilter

•  Portlet Filters have the following lifecycle: –  Initialization: init() called when filter is instantiated. FilterConfig

holding init parameters and PortletContext is provided for resource initialization

–  Deinitialization: destroy() called when filter is being taken out of service. To contain logic that cleans it up (ie, memory, file handles, threads, etc)

–  Filtering: doFilter () called each time an action request/response pair is passed through the chain due to a client request

ARTISANS OF OPEN SOURCE Portlet Filters (3)

•  At runtime, a filter chain of all filters is applied: –  Each filter gets the current request/response and the filter chain –  After doing its pre/post processing, the filter can either:

•  Terminate the request processing, or •  Call the next element in the chain by passing in either the received request and

response, or wrapped versions

–  The last element in the filter chain is the portlet itself!

•  Descriptor portlet.xml must define: –  Filters with a name, intended lifecycle phase (ACTION_PHASE,

EVENT_PHASE, RENDER_PHASE or RESOURCE_PHASE), PortletFilter class and init parameters

–  Filter mappings by associating filters to portlets. Order of filter-mapping defines the order in which they are applied at runtime

ARTISANS OF OPEN SOURCE Portlet Filters (4)

•  Let’s create a PortletFilter to agregate content at beginning/end on render response: File: /WEB-INF/src/com/sample/generic/filters/RenderFilter.java package com.sample.generic.filters;

import java.io.IOException;import java.io.PrintWriter;import javax.portlet.*;import javax.portlet.filter.*;

public class RenderFilter implements javax.portlet.filter.RenderFilter {

private String prologueMessage, epilogueMessage;

public void init(FilterConfig config) throws PortletException { prologueMessage = config.getInitParameter("filter-init-parameter-prologue"); epilogueMessage = config.getInitParameter("filter-init-parameter-epilogue"); } public void destroy() { }

public void doFilter(RenderRequest request,RenderResponse response, FilterChain chain) throws IOException, PortletException {

PrintWriter writer = response.getWriter();

writer.write(String.format("<p>%1$s</p>", prologueMessage));

chain.doFilter(request, response);

writer.write(String.format("<p>%1$s</p>", epilogueMessage)); }}

ARTISANS OF OPEN SOURCE Portlet Filters (5)

•  Now, let’s define/enable our PorletFilter on each existing portlet:

File: /WEB-INF/portlet.xml <portlet-app ...> ... <portlet>...</portlet> ... <filter> <filter-name>render-filter</filter-name> <filter-class>com.sample.generic.filters.RenderFilter</filter-class> <lifecycle>RENDER_PHASE</lifecycle> <init-param> <name>filter-init-parameter-prologue</name> <value>Good Morning,</value> </init-param> <init-param> <name>filter-init-parameter-epilogue</name> <value>Have a Good Day!</value> </init-param> </filter> <filter-mapping> <filter-name>render-filter</filter-name> <portlet-name>generic-hello-world-portlet</portlet-name> <portlet-name>generic-goodbye-world-portlet</portlet-name> <portlet-name>jsp-hello-world-portlet</portlet-name> </filter-mapping> ... <default-namespace>...</default-namespace> ...</portlet-app>

ARTISANS OF OPEN SOURCE Portlet Filters (6)

•  After re-deploying our Portlet plugin:

ARTISANS OF OPEN SOURCE Portlet URL Listeners

•  JSR-268 introduces Portlet URL Listeners as a means to intercept URLs in centralized way, before they get generated (ie. when methods toString() or write() are called on URLs)

•  Functionality implementable through Portlet URL Listeners is around managing specific Portlet –related properties on URLs: –  Parameters, portlet mode, window state –  Security, Cache level of resources, etc

•  In order to receive a callback whenever a Portlet URL is generated, Portlet URL Listeners must implement interface javax.portlet.PortletURLGenerationListener with methods: –  filterRenderURL() for RenderURLs –  filterActionURL() for ActionURLs –  filterResourceURL() for ResourceURLs

ARTISANS OF OPEN SOURCE Portlet URL Listeners (2)

•  Descriptor portlet.xml must register Portlet URL Listeners with a <listener> element for each PortletURLGenerationListener class

•  Order of <listener> elements defines the order they are applied at runtime

•  Let’s create a Portlet URL Listener to override parameter value for Ajax call on previously created Portlet: File: /WEB-INF/src/com/sample/generic/listeners/ResourceURLListener.java package com.sample.generic.listeners;

import javax.portlet.*;

public class ResourceURLListener implements PortletURLGenerationListener {

public void filterActionURL(PortletURL actionURL) { }

public void filterRenderURL(PortletURL renderURL) { }

public void filterResourceURL(ResourceURL resourceURL) { resourceURL.setParameter ( "ajax-parameter-greeting", "Hello World from Resource URL Listener" ); }}

ARTISANS OF OPEN SOURCE Portlet URL Listeners (3)

•  Now, let’s define/enable our PorletFilter on each existing portlet: File: /WEB-INF/portlet.xml <portlet-app ...> ... <public-render-parameter>...</public-render-parameter> ... <listener> <display-name>Hello World Portlet URL Listener</display-name> <listener-class>com.sample.generic.listeners.ResourceURLListener</listener-class> </listener> ...</portlet-app>

After re-deploying our Portlet plugin and clicking on Portlet’s button:

ARTISANS OF OPEN SOURCE Servlet Programming Features

•  If compared to Servlets, JSR-168 restricted the portlet programming model in some areas because some Servlet model features -assuming only one component on the page- are not easily applied on Portlets

•  JSR-268 provides nearly the same capabilities as the Servlet programming model plus the portlet specific extensions…

•  Document head section elements, HTTP headers and Cookies: JSR-268 allows the portlet to contribute to sections of portal page outside its portlet window: –  Document head section elements: a two-part render call (RENDER_HEADER and

RENDER_MARKUP) is enabled in order portlets can return content outside the portlet window (ie. HTML ones such as meta, link, or style) through GenericPortlet.doHeaders()

–  HTTP Headers (ie. app-specific Pragma headers) via PortletResponse.setProperty() –  Cookies through PortletResponse.addProperty() at the response of each life-cycle method

(processAction, processEvent, render, and serveResource): •  Cookies are not guaranteed to be shared across different portlets and may be stored by the portal (not at the client) •  To set cookies in the render method, the renderHeaders option should be turned on and the cookies should be set in the

RENDER_HEADERS part by using overriding GenericPortlet.doHeaders()

•  Dispatching to Servlets and JSPs: A portlet can invoke servlets and JSPs in all lifecycle methods by using methods include() or forward() via a request dispatcher (PortletContext.getRequestDispatcher()): –  Action/event can be dispatched to logic written in a servlet, or do forward in serving resource –  Servlet request/response objs given to the servlet/JSP are based on portlet request/response:

•  Attributes set in the portlet request are available in the included servlet request •  The portlet and the included servlet or JSP share the same output stream •  Attributes set in the portlet session are accessible from the servlet session and vice versa

ARTISANS OF OPEN SOURCE Annotations

•  JSR-268 introduces Annotations for directly dispatching requests when using GenericPortlet to ease configuration pain

–  Annotation @ProcessEvent for event calls @ProcessEvent(qname="{http://sample.com/events}ipc.speak.world")

public void processSpeakWorldEvent(EventRequest req, EventResponse res){...}

–  Annotation @ProcessAction for action calls via a ActionURL with parameter "javax.portlet.action” set:

@ProcessAction(name="speakWorld”) public void speakWorld(ActionRequest request, ActionResponse response){...}

–  Annotation @RenderMode for render calls for a corresponding Portlet Mode

@RenderMode(name="VIEW") public void speakWorld(RenderRequest request, RenderResponse response){...}

ARTISANS OF OPEN SOURCE Tag Libraries

•  JSR-268 provides new tags to ease JSP development: –  <portlet:resourceURL>: build ResourceURL refering back to the portlet –  Attributes copyCurrentRenderParameters and escapeXML on

RenderURL, ActionURL and ResourceURL –  <portlet:namespace>: returns unique value for the current Portlet window

•  Since Portlet’s markup is aggregated in same page, name of items that should be unique should be “namespaced” through PortletRequest.getNamespace(): –  Returned value is same/preserved for the entire lifetime of the Portlet window –  To be used to prefix names that should be unique (ie. html ids/names,

javascript functions/variables, etc)

<script type="text/javascript”> … function <portlet:namespace/>ajaxHelloWorld(url){...} …

</script>… <input type="button" value='Ajax!' title='<%=resourceUrl%>’ onclick="javascript:<portlet:namespace/>ajaxHelloWorld('<%=resourceUrl%>');”/>

ARTISANS OF OPEN SOURCE

Conclusion

ARTISANS OF OPEN SOURCE Questions?

Rivet Logic Corporation 11410 Isaac Newton Square N. Suite 210 Reston, VA 20190, USA Ph: 703.955.3480 Fax: 703.234.7711

Rivet Logic Costa Rica SRL Costa Rica Developer's Forge Edificio María Luisa, 3A office Paseo Colón, San José, Costa Rica Ph: (506) 2256-1024 Fax: (506) 2256-1024

Introduction to Portlets using Liferay Portal (Part 2)

By: Aníbal Gómez-Estrada http://rivetlogic.com/web/agomez

October 19th, 2011

ARTISANS OF OPEN SOURCE References

JSR 286: Portlet Specification 2.0

http://www.bluesunrise.com/portlet-api/javax/portlet/package-summary.html

http://www.ibm.com/developerworks/websphere/library/techarticles/0803_hepper/0803_hepper.html

http://developers.sun.com/portalserver/reference/techart/jsr286/jsr286.html

http://download.oracle.com/docs/cd/E15919_01/wlp.1032/e14244/javaportlets.htm#BCGIBGBJ

http://www.liferay.com

ARTISANS OF OPEN SOURCE

Announcements

ARTISANS OF OPEN SOURCE Available At My Blog!

JSF 2.0 Portlets using Liferay Portal Available At My Blog!

http://rivetlogic.com/web/agomez/

Contents Introduction to Portlet Bridges Setup and Hello World Portlet

Internationalization Actions and Navigation

Portlet Preferences Inter-Portlet Communication

ARTISANS OF OPEN SOURCE Rivet Logic Is Hiring!

We are hiring! Java developers – mcalvo@rivetlogic.com

•  Award-winning consulting and systems integration firm focused on enabling open source –based software solutions for content management, collaboration and community:

–  Innovator of the Year: JBoss (2008) –  Solution of the Year: Alfresco (2010) –  Platinum Partner: Liferay (2011)

•  We use top-notch open source technology:

•  Company Facts: –  Founded in 2005. Consistently Profitable and Employee-owned. 40+ Consultants –  Headquarters in Virginia, USA. Near-shore office in San José, Costa Rica for two years –  Certified Liferay Partner since 2006

top related