JSR
286 Features:
One of the major feature added to JSR 286 is communication between Portlets through Eventing and Public Render Parameter.
One of the major feature added to JSR 286 is communication between Portlets through Eventing and Public Render Parameter.
Following features added to JSR286 are.
1. Events
2. Public
Render Parameter
3. Serving
Resources
4. Portlet
filters
5. Cookies,
document head section elements, and HTTP headers
6. Leveraging
the servlet life-cycle listeners
7. Portlet
URL listeners
8. Portlet-managed modes
9. Container runtime options
10. Java
5 features
a) Using
Generics
b) Introducing
a new enum class for all user profile attributes
c) GenericPortlet
also lets you use the following annotations to make dispatching life-cycle
calls to specific handler code easier:
ProcessAction.
This annotation allows you to annotate a method that should process a specific
action. To allow dispatching, the Action URL needs to include the parameter
javax.portlet.action.
ProcessEvent.
This annotation allows you to annotate methods that should process specific
events.
RenderMode.
This annotation allows you to annotate methods that should render a specific
portlet mode.
11. New
caching features
12. Taglib
additions
a) The
define objects tag is now enhanced and gives you the following additional
variables beyond the request, response, portletConfig from the V1.0:
b) portletSession. For
access to the portlet-scoped session.
c) portletSessionScope.
For access to the portlet-scoped session attribute key/values map.
d) portletPreferences.
For access to the portlet preferences.
e) portletPreferencesValues.
For access to the portlet preferences key/values map.
f) Each
of the URL generation tags has the following additional attributes:
copyCurrentRenderParameters.
For copying the current private render parameters to the URL.
escapeXml.
For turning the default XML escaping of the URL. As mentioned previously, in
JSR 168 it was not defined if a URL is XML-escaped or not. JSR 286 now has
defined the same behavior as the Java Standard Tag Library: by default all URLs
are escaped, but you can turn it off using the escapeXml attribute.
For
action URLs, there is also the additional name attribute that allows you to set
the javax.portlet.action parameter that is evaluated by the GenericPortlet for
dispatching to the ProcessAction annotated methods.
Other
additions made in the JSR 286 specification include these:
Adding a
new resourceURL tag for generating resource URLs
Adding
the new propertyTag that can be used inside portlet URL tags for attaching
properties to URLs
Events: portlet events that a portlet can receive and send
Public Render Parameters: render state that can be shared between portlets
Events in brief
In JSR 168(Portlet 1.0), the only way to achieve eventing between portlets was via portlet session. This was possible between portlets that are in the same webapplication. JSR 286(Portlet 2.0) defines a lifecycle for events and eventing is possible between portlets that are in different web applications.
An event is a life cycle operation that occurs before the rendering phase. Events can be described as a loosely coupled, brokered means of communication between portlets. Events allow portlets to respond on actions or state changes not directly related to an interaction of the user with the portlet.
A portlet can declare events in its deployment descriptor by using the event-definition element in the portlet application section. In the portlet section, each portlet specifies the events it would like to publish through the supported-publishing-event element and the events it would like to process through the supported-processing-event element.
The supported-publishing-event and supported-processing-event elements must reference the event name defined in the portlet application section in a event-definition element.
The portlet creates events using the setEvent() method during action processing. This will be processed by the portlet container after the action processing has finished. Portlets can also create events during event phase by calling setEvent() method on EventResponse.
To receive events, the portlet must implement the javax.Portlet.EventPortlet interface. The portlet container calls the processEvent() method for each event targeted to the portlet with an EventRequest and EventResponse object. The portlet can access the event that triggered the current process event call by using the EventRequest.getEvent() method. This method returns an object of type Event encapsulating the current event name and value.
Event names are represented as QNames to identify them uniquely. The event name can be retrieved by using the getQName() method that returns the complete QName of the event, or by using the getName() method that only returns the local part of the event name. The value of the event must be based on the type defined in the deployment descriptor.
Public Render Parameters: render state that can be shared between portlets
Events in brief
In JSR 168(Portlet 1.0), the only way to achieve eventing between portlets was via portlet session. This was possible between portlets that are in the same webapplication. JSR 286(Portlet 2.0) defines a lifecycle for events and eventing is possible between portlets that are in different web applications.
An event is a life cycle operation that occurs before the rendering phase. Events can be described as a loosely coupled, brokered means of communication between portlets. Events allow portlets to respond on actions or state changes not directly related to an interaction of the user with the portlet.
A portlet can declare events in its deployment descriptor by using the event-definition element in the portlet application section. In the portlet section, each portlet specifies the events it would like to publish through the supported-publishing-event element and the events it would like to process through the supported-processing-event element.
The supported-publishing-event and supported-processing-event elements must reference the event name defined in the portlet application section in a event-definition element.
The portlet creates events using the setEvent() method during action processing. This will be processed by the portlet container after the action processing has finished. Portlets can also create events during event phase by calling setEvent() method on EventResponse.
To receive events, the portlet must implement the javax.Portlet.EventPortlet interface. The portlet container calls the processEvent() method for each event targeted to the portlet with an EventRequest and EventResponse object. The portlet can access the event that triggered the current process event call by using the EventRequest.getEvent() method. This method returns an object of type Event encapsulating the current event name and value.
Event names are represented as QNames to identify them uniquely. The event name can be retrieved by using the getQName() method that returns the complete QName of the event, or by using the getName() method that only returns the local part of the event name. The value of the event must be based on the type defined in the deployment descriptor.
Example of Eventing between two portlets in different war files
Sender Portlet :
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd
http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" id="com.ibm.sender.SendEventPortlet.05f3b8ead2">
<portlet>
<portlet-name>SendEvent</portlet-name>
<display-name xml:lang="en">SendEvent</display-name>
<display-name>SendEvent</display-name>
<portlet-class>com.ibm.sender.SendEventPortlet</portlet-class>
<init-param>
<name>wps.markup</name>
<value>html</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<resource-bundle>com.ibm.sender.nl.SendEventPortletResource</resource-bundle>
<portlet-info>
<title>SendEvent</title>
<short-title>SendEvent</short-title>
<keywords>SendEvent</keywords>
</portlet-info>
<supported-publishing-event>
<qname xmlns:customns="http://dtoNS">
customns:publishEvent</qname>
</supported-publishing-event>
</portlet>
<default-namespace>http://Sender/</default-namespace>
<event-definition>
<qname xmlns:customns="http://dtoNS">
customns:publishEvent</qname>
<value-type>com.ibm.sender.DataTransferObject</value-type>
</event-definition>
</portlet-app>
Data Transfer Object:
package com.ibm.sender;
import
java.io.Serializable;
/**
* @author saurabh
*
*/
public class DataTransferObject
implements Serializable {
private String dtoStr;
/**
* @return the dtoStr
*/
public String
getDtoStr() {
return dtoStr;
}
/**
* @param dtoStr the dtoStr to set
*/
public void
setDtoStr(String dtoStr) {
this.dtoStr = dtoStr;
}
}
public void processAction(ActionRequest
request, ActionResponse response) throws
PortletException, java.io.IOException {
if(
request.getParameter(FORM_SUBMIT) != null ) {
// Set form
text in the session bean
SendEventPortletSessionBean
sessionBean = getSessionBean(request);
if( sessionBean !=
null )
sessionBean.setFormText(request.getParameter(FORM_TEXT));
}
System.out.println("Process
Action");
System.out.println("!!!!!!!!!!!Event
Triggered by portlet!!!!!!!!!");
//Initialize the fields in the class
as per your requirement
com.ibm.sender.DataTransferObject sampleObject = new
com.ibm.sender.DataTransferObject();
QName
sampleName = new QName("http://dtoNS", "publishEvent");
sampleObject.setDtoStr(request.getParameter(FORM_TEXT));
response.setEvent(sampleName,
sampleObject );
}
Receiver Portlet
<?xml
version="1.0" encoding="UTF-8"?>
<portlet-app
xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
version="2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd
http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
id="com.ibm.receiverproject.ReceiverEventPortlet.ef3a1aead2">
<portlet>
<portlet-name>ReceiverEvent</portlet-name>
<display-name
xml:lang="en">ReceiverEvent</display-name>
<display-name>ReceiverEvent</display-name>
<portlet-class>com.ibm.receiverproject.ReceiverEventPortlet</portlet-class>
<init-param>
<name>wps.markup</name>
<value>html</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<resource-bundle>com.ibm.receiverproject.nl.ReceiverEventPortletResource</resource-bundle>
<portlet-info>
<title>ReceiverEvent</title>
<short-title>ReceiverEvent</short-title>
<keywords>ReceiverEvent</keywords>
</portlet-info>
<supported-processing-event>
<qname xmlns:customns="http://dtoNS">
customns:publishEvent</qname>
</supported-processing-event>
</portlet>
<default-namespace>http://ReceiverProject/</default-namespace>
<event-definition>
<qname xmlns:customns="http://dtoNS">
customns:publishEvent</qname>
<value-type>com.ibm.receiverproject.DataTransferObject</value-type>
</event-definition>
</portlet-app>
/**
* Process an action request.
* @see
javax.portlet.Portlet#processEvent(javax.portlet.EventRequest,
javax.portlet.EventResponse)
*/
public void processEvent(EventRequest request,
EventResponse response) throws
PortletException, java.io.IOException {
Event sampleEvent = request.getEvent();
if(sampleEvent.getName().toString().equals("publishEvent"))
{
Object sampleProcessObject = sampleEvent.getValue();
DataTransferObject transferObject =(DataTransferObject)
sampleProcessObject;
PortletSession session = request.getPortletSession();
System.out.println("Process Event");
ReceiverEventPortletSessionBean sessionBean = (ReceiverEventPortletSessionBean)session.getAttribute(SESSION_BEAN);
sessionBean.setStr(transferObject.getDtoStr());
}
}
Public Render Parameter
Public render parameters allow JSR 286 portlets to share navigational state information. They are specially useful for coordinating the multiple navigation or viewer portlets that display different information items that are all related to the same parameter name. The portal stores all portlet render parameters, including public render parameters, as an encoded part of the current portal URL. Therefore public render parameters are correctly preserved by typical browser navigation actions such as Back button and bookmarking.
In order to allow coordination of render parameters with other portlets, within the same portlet application or across portlet applications, the portlet can declare public render parameters in its deployment descriptor using the public-render-parameter element in the portlet application section. Public render parameters are available in all lifecycle methods of the portlet: processAction, processEvent, render, and serveResource. Public render parameters can be viewed and changed by other portlets or components. In the portlet section each portlet can specify the public render parameters it would like to share via the
supported-public-render-parameter element. The supportedpublic-render-parameter element must reference the identifier of a public render parameter defined in the portlet application section in a public-render-parameter element.
The portlet should use the defined public render parameter identifier in its code in order to access the public render parameter.
The portlet container
must only send those public render parameters to a portlet which the
portlet has defined
support for using supported-public-render-parameter element in the
portlet.xml.
The portlet container must only share those render
parameters of a portlet which the portlet has
declared as supported public render parameters using supported-public-render-parameter
element in the portlet.xml.
Portlet
1
<portlet-app>
<Portlet>
<supported-public-render-parameter> publicparam
</supported-public-render-parameter>
...
</Portlet>
<public-render-parameter>
<identifier>publicparam</identifier>
<qname
xmlns:customns="http://dtoNS ">customns:publicparam
</qname>
</public-render-parameter>
</portlet-app>
Portlet
2
<portlet-app>
<Portlet>
<supported-public-render-parameter> publicparam
</supported-public-render-parameter>
...
</Portlet>
<public-render-parameter>
<identifier>publicparam</identifier>
<qname
xmlns:customns="http://dtoNS ">customns:publicparam
</qname>
</public-render-parameter>
</portlet-app>
Set the parameter In processAction,
processEvent or serveResource
response.setRenderParameter
("publicparam
", “test”); // StateAwareResponse
Resource Serving
The resource serving feature provides the ability for a portlet to serve a resource.
Portlets can create two different kinds of resource links in order to serve resources:
1. Direct links to the resource in the same portlet web application. These links are constructed by the portlet and encoded with the PortletResponse.encodeURL() method.
Note that this method might not return a valid URL.
Direct links are not guaranteed to pass through the portal server and will not have
the portlet context available.
Direct links should be used for use cases where the access to the portlet context
and access through the portal is not needed, as they are more efficient than
resource serving requests via resource URLs through the portal.
2. Resource URL links pointing back to the portlet. Via these links the
serveResource method of the ResourceServingPortlet interface is called and
the portlet can serve the resource. Thus resources served via resource URLs may
be protected by the portal security and can leverage the portlet context.
Static resources should still be served with direct links in order to allow portal
applications to configure and optimize static resource serving in a consistent
manner.
Example:
Home.jsp
<script type='text/javascript'>
function <portlet:namespace/>setCurrentDateTime() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
var messageText = document.getElementById("<portlet:namespace/>messageText");
messageText.innerHTML = xhr.responseText;
}
};
var url = '<portlet:resourceURL id="dateTime"/>' + "?fakeId=" + Math.random();
xhr.open("GET", url, true);
xhr.send();
}
</script>
<table>
<tr>
<td><b><a href="#" onclick="<portlet:namespace/>setCurrentDateTime();" style="color: black;">Refresh</a></b></td>
</tr>
</table>
<br/>
<div id="<portlet:namespace/>messageText">
</div>
DateTimeController
@Controller(value="dateTimeController")
@RequestMapping(value = "VIEW")
public class DateTimeController {
@ResourceMapping("dateTime")
public ModelAndView getDateTime(ResourceRequest request, ResourceResponse response) throws IOException {
SimpleDateFormat sdf = new SimpleDateFormat(
"dd-MMM-yyyy hh:mm:ss a");
Map<String, Object> model = new HashMap<String, Object>();
request.setAttribute("test", "test123");
request.getPortletSession().setAttribute("test1", "test1");
model.put("dateTime", sdf.format(new Date()));
return new ModelAndView("dateTimeAjax", model);
}
}
dateTimeAjax.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html" isELIgnored="false" %>
This is from dateTimeAjax.jsp page ::::::
<c:out value="${dateTime}"/>
<br/><br/><br/>
${test}
<br/><br/><br/>
${test1}
Portlet Filter in brief
Portlet filter are one of the major feature added on JSR 286.
A portlet
filter is a Java component that can be used to modify portlet request and
response before/after any lifecycle method of the portlet is being executed.
The concept of
Portlet filter is same as that of servlet filter. The only difference is that a
servlet has only one request handling method i.e. service() method and
therefore there is only one type of the servlet filter.
A portlet has
four types of request handling methods and therefore there are 4 different
types of portlet filters.
The portlet
API defines following interfaces for creating Portlet filter:
javax.portlet.filter.ResourceFilter
(for serveResource method)
javax.portlet.filter.RenderFilter
(for render method)
javax.portlet.filter.ActionFilter
(for processAction method)
javax.portlet.filter.EventFilter
(for processEvent method)
The portlet filter
programming model is modeled on the servlet filter model:
1. Define
the filters in the deployment descriptor. This definition is done using the
<filter> element, where you also need to state the life-cycle call to
which the filter should be applied.
2. Implement
the corresponding Filter interface in your filter. You can also list multiple
life-cycle entries and implement multiple Filter interfaces with your class.
3. Provide
a filter-mapping element where you describe to which portlets your filter
should be applied (you can also use an asterisk as a wildcard if it should be
applied to all portlets in the application).
A single filter class can provide filter
functionality for more than one lifecycle methods and also a single filter can
provide filter functionality for more than one portlet. There can be multiple filter associated with one lifecycle
method of a portlet. The javax.portlet.filter.FilterChain class (created by
Portlet container) is used to invoke the sequence of filters applicable for a
particular lifecycle method of a portlet. The doFilter() method of a portlet
filter may create customized request and response objects by using \*RequestWrapper
and \*ResponseWrapper classes and passing these wrappers to the doFilter()
method of FilterChain.
In order to
write a portlet filter, the developer is required to do the folowing 2 things :
1) Write a
filter class - A filter class should implement one or more of the above
mentioned four interfaces and should provide a no argument public constructor.
The filter class is also required to override init() and destroy() method of
javax.portlet.filter.PortletFilter interface.
2) Add entry
of filter in portlet.xml - After writing a portlet filter class, it can be
configured by adding following 2 xml fragements in portlet.xml.
<filter>
<filter-name>RenderFilterOne</filter-name>
<filter-class>com.test.filter.RenderFilterOne</filter-class>
<lifecycle>RENDER_PHASE</lifecycle>
<lifecycle>ACTION_PHASE</lifecycle>
<init-param>
<name>message</name>
<value>Filter
1 - portlet-container 2.0 Filter demo :)</value>
</init-param>
</filter>
<filter-mapping>
<filter-name>RenderFilterOne</filter-name>
<portlet-name>HelloWorld</portlet-name>
</filter-mapping>
* @author Saurabh.srivastava
*
*/
public class RenderFilterOne
implements RenderFilter,
ActionFilter {
/* (non-Javadoc)
*
@see javax.portlet.filter.RenderFilter#doFilter(javax.portlet.RenderRequest,
javax.portlet.RenderResponse, javax.portlet.filter.FilterChain)
*/
public void
doFilter(RenderRequest req, RenderResponse res,
FilterChain chain) throws IOException,
PortletException {
chain.doFilter(req, res);
}
/* (non-Javadoc)
*
@see javax.portlet.filter.PortletFilter#destroy()
*/
public void destroy() {
// TODO
Auto-generated method stub
}
/* (non-Javadoc)
*
@see javax.portlet.filter.PortletFilter#init(javax.portlet.filter.FilterConfig)
*/
public void
init(FilterConfig arg0) throws PortletException {
// TODO
Auto-generated method stub
}
/* (non-Javadoc)
*
@see javax.portlet.filter.ActionFilter#doFilter(javax.portlet.ActionRequest,
javax.portlet.ActionResponse, javax.portlet.filter.FilterChain)
*/
public void
doFilter(ActionRequest req, ActionResponse res,
FilterChain chain) throws IOException,
PortletException {
chain.doFilter(req, res);
}
The first xml
fragment defines a filter by providing a logical name to it. It tell portlet
container about the filter class and the lifecycle phases supported by it. You
can specify initialization parameters also.
The Second xml
fragment specifies the portlet(s) for which this filter will be applicable. You
can specify a single portlet name or mapping to a group of portlets using the
‘\*’ as a wildcard.
Portlet URL listeners
Starting from JSR 286 (Portlet Specification 2.0), portlets support two phase rendering and it defines doHeaders() method that you can implement if you want to do one of the following things
Portlet URL listeners
In some cases,
you may want to centrally manage setting specific properties on portlet URLs or
to enhance the portlet URL creation of existing portlets. One example involves
implementing a mapping of resources to shared IDs. You implement this mapping
only once in the listener, and the listener checks if the resource URL is
targeting a resource for which a shared QName exists and then sets the SHARED
property with the corresponding QName. For these use cases, the JSR 286
specification gives you the portlet URL listeners.
Container runtime options
Container
runtime options allow the portlet to supply specific options to the portlet
container that either change default behavior defined in the Java Portlet
Specification or add additional behaviors. JSR 286 defines a list of container
runtime options that are all optional except for actionScopedRequestAttributes.
javax.portlet.escapeXml. Allows you to turn off the XML escaping of
portlet URLs for each default, in case you have written a JSR 168 portlet that
assumes that URLs are not XML escaped and have migrated this to a JSR 286 portlet.
·
javax.portlet.renderHeaders. Enables the two-part rendering mechanism that lets you
set headers in streaming-based portal implementations.
·
javax.portlet.servletDefaultSessionScope. Allows you to change the default scope of the session
object provided to servlets or JSPs that are called from the portlet through
forward or include from application scope to portlet scope. That way, these
resources access the same session data using portlet and servlet APIs, which is
particularly convenient if your JSPs are written for a servlet-based Web
framework.
·
javax.portlet.actionScopedRequestAttributes. Allows Web frameworks to pass complex objects from the
action or event phase to the render phase through the request. You are able to
access these attributes until the next request with an action semantic (which
may be an action triggered through an Action URL or an event) occurs. This
feature likely is implemented by the portlet container by storing these
attributes in the session. Therefore, use this feature only if you cannot avoid
it, as it will probably cause some performance degradation. This option is the
only one that JSR 286 requires to be supported by all containers.
Enable two phase rendering in portlet
To overcome the problem that version 1.0 faced with contributing content outside the current portlet window, version 2.0 added a two-part render call:
- RENDER_HEADER part that allows the portlet to return content outside the current portlet window such as portlet title, preferred next possible portlet modes, cookies, document head section elements, and HTTP headers.
- RENDER_MARKUP part that allows the portlet to return its normal markup.
Starting from JSR 286 (Portlet Specification 2.0), portlets support two phase rendering and it defines doHeaders() method that you can implement if you want to do one of the following things
·
Change title of the portal page
·
Add header
·
Add cookie
The two phase request processing is disabled by
default, you can enable it by setting value of javax.portlet.renderHeaders
container run time option to true like this
<portlet>
…
<container-runtime-option>
<name>javax.portlet.renderHeaders</name>
<value>true</value>
</container-runtime-option>
…
</portlet>
protected void
doHeaders(RenderRequest renderRequest,
RenderResponse renderResponse){
//Setting cookie
Cookie cssKeyCookie = new Cookie(“Key”,
“Value”);
cssKeyCookie.setPath(“/”);
cssKeyCookie.setMaxAge(3600000);
renderResponse.addProperty(cssKeyCookie);
}
Resource:
JSR
286 Specification :