Friday, April 25, 2014

JSR 286- A brief study

JSR 286 Features:

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.

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;
      }

}

 Process Action of Sender
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

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:
  1. 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.
  2. 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 :

No comments:

Post a Comment