Friday, April 11, 2014

Liferay CometD Ajax Push / Liferay Reverse Ajax

Introduction:

Ajax Push is a mechanism to push data from server. Generally in the web application when the client request for the server then we will get the dynamic data or updated data from server to web client/browser.

But sometimes we need a mechanism it automatically push data from server to client this is called server push mechanism. Server push is technique to push data from server to client. In this scenarios client will not send request to server but server will automatically push the data to client when it get updated.

To make it work server push technique we will use one protocol called Bayeux protocol.

Bayeux:

Bayeux is a protocol for transporting asynchronous messages (primarily over HTTP), with low latency between a web server and a web client. The messages are routed via named channels and can be delivered

We can use protocol for server to client, client to server, client to client (via the server)
The primary purpose of Bayeux is to support responsive bidirectional interactions between web clients, for example using AJAX, and the web server.

Here we will produce data on some channels and client will subscribe channels. When client subscribe channeled as soon as data published on channels will aquatically reached the client who are subscribed channels.


CometD

CometD is a scalable HTTP-based event routing bus that uses a Ajax Push technology pattern known as Comet

CometD is a Dojo Foundation project to provide implementations of the Bayeux protocol in JavaScript, java, Perl, python and other languages. Other organizations (eg. Sun, IBM and BEA) also have implementations of Bayeux that are not strictly part of the CometD project, but where possible they are linked to from this site.


Environment:

Liferay 6.2 +Tomcat 7.x+MySQL 5.1

Note:

The code will work for portal 6.2 version you can try for 6.1 too.

Download Liferay CometD Ajax Push Portlet from following location
You can find source and war file


Portlet Screen-1:


Procedure for deploy portlet and Use:

You can use war file and directly place in your portal deploy folder and test or you can also use source to deploy portlet.

Once portlet is deployed successfully you can see the portlet in sample category name as Liferay Commet D Reverse Ajax.

As soon as you place the portlet in page you can see updated stock prices for every few seconds and it will be updated automatically.

You can also open portlet in another browser there also you can see price changes automatically.

Note:

Before use this portlet please Read entire Article and Use it

Implementation:

We will use Bayeux java implementation for produce data on channels.

Once data produced on channels we will use CometD java script implementation to get the data to client automatically. We have Dojo and JQuery java script implementation for CometD.


Using ComedD Ajax Push in Liferay Portlet
  1. Configure CometD servlet in portlet web.xml
  2. Implement Data Producer to produce data
  3. Implement Service to publish data on Channels Using Bayeux
  4. Use CometD java script in client side to subscribe channel and show data.

Concept:

We will take an example of stock prices updates so that we will send stock price changes to client when changes in price changes in stocks.

We will use Java Scheduler to produce data for every few second from server side and as soon as data produced we will use CometD service to publish data on channels.

In the client side we will use CometD JQuery to subscribe the channels and show the stock price changes.

Configure CometD servlet in portlet web.xml

We need configure CometD servlet to initiate all the process. We have different servlets one of the servlet AnnotationCometdServlet and need to pass CometD service as init parameter.

The following is code snippet

<servlet>
        <servlet-name>cometd</servlet-name>
        <servlet-class>org.cometd.annotation.AnnotationCometdServlet</servlet-class>
        <init-param>
            <param-name>transports</param-name>
            <param-value>org.cometd.websocket.server.WebSocketTransport</param-value>
        </init-param>
        <init-param>
            <param-name>services</param-name>
            <param-value>com.meera.commetd.StockPriceService</param-value>
        </init-param>
        <init-param>
            <param-name>maxLazyTimeout</param-name>
            <param-value>2000</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>cometd</servlet-name>
        <url-pattern>/cometd/*</url-pattern>
    </servlet-mapping>


Implement Data Producer to produce data

We already we need some source need to generate data so we will use some java class to produce data.

We will randomly generate some price for stock quotes and we have used Scheduler Executer to run this task for every few seconds. We have used StockPriceEmitter java class


Implement Service to publish data on Channels Using Bayeux

We need service that responsible for publish data on channels with the help of Bayeux protocol. We need create channel and then need to publish

The following example syntax to create channel and publish

Create channel


bayeuxServer.createChannelIfAbsent(channelName, new ConfigurableServerChannel.Initializer()
            {
                public void configureChannel(ConfigurableServerChannel channel)
                {
                    channel.setPersistent(true);
                    channel.setLazy(true);
                }
            });



Publish data on channel


ServerChannel channel = bayeuxServer.getChannel(channelName);
            channel.publish(sender, data);


Use CometD java script in client side to subscribe channel and show data

In the client side will use CometD java script implementation to subscribe channel and show the data.

We need configure CometD servlet URL and need to add two leisters to make hand shake with server.

The following is syntax


var cometURL = location.protocol + "//" + location.host + config.contextPath + "/cometd";
        cometd.configure({
            url: cometURL,
            logLevel: 'debug'
        });

        cometd.addListener('/meta/handshake', _metaHandshake);
        cometd.addListener('/meta/connect', _metaConnect);
        cometd.handshake();


Subscribe Channel Syntax


cometd.subscribe('/stock/*', function(message)
                    {
var data = message.data;

});


Note:

We need add CometD java script implementation source in page and we will use cometd is java script object available to call methods.

We have implement application related java script in application.js

The following are all required java script source files


<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/cometd-namespace.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/cometd-json.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/AckExtension.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/TransportRegistry.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/Transport.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/RequestTransport.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/WebSocketTransport.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/CallbackPollingTransport.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/LongPollingTransport.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/Utils.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/Cometd.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/jquery.cometd.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/application.js"></script>


Complete Source code for Implementation

The following is web.xml file


<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
 http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
       <display-name>LiferayCommetDRevserseAjax-portlet</display-name>
        <servlet>
        <servlet-name>cometd</servlet-name>
        <servlet-class>org.cometd.annotation.AnnotationCometdServlet</servlet-class>
        <init-param>
            <param-name>transports</param-name>
            <param-value>org.cometd.websocket.server.WebSocketTransport</param-value>
        </init-param>
        <init-param>
            <param-name>services</param-name>
            <param-value>com.meera.commetd.StockPriceService</param-value>
        </init-param>
        <init-param>
            <param-name>maxLazyTimeout</param-name>
            <param-value>2000</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>cometd</servlet-name>
        <url-pattern>/cometd/*</url-pattern>
    </servlet-mapping>
    <filter>
        <filter-name>cross-origin</filter-name>
        <filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>cross-origin</filter-name>
        <url-pattern>/cometd/*</url-pattern>
    </filter-mapping>
       <jsp-config>
              <taglib>
                     <taglib-uri>http://java.sun.com/portlet_2_0</taglib-uri>
                     <taglib-location>
                           /WEB-INF/tld/liferay-portlet.tld
                     </taglib-location>
              </taglib>
              <taglib>
                     <taglib-uri>http://liferay.com/tld/aui</taglib-uri>
                     <taglib-location>/WEB-INF/tld/aui.tld</taglib-location>
              </taglib>
       </jsp-config>
</web-app>


The following is StockPriceServiceJava Class


import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.inject.Inject;
import org.cometd.annotation.Service;
import org.cometd.annotation.Session;
import org.cometd.bayeux.server.BayeuxServer;
import org.cometd.bayeux.server.ConfigurableServerChannel;
import org.cometd.bayeux.server.LocalSession;
import org.cometd.bayeux.server.ServerChannel;
@Service
public class StockPriceService implements StockPriceEmitter.Listener
{
    @Inject
    private BayeuxServer bayeuxServer;
    @Session
    private LocalSession sender;

    public void onUpdates(List<StockPriceEmitter.Update> updates)
    {
        for (StockPriceEmitter.Update update : updates)
        {
            // Create the channel name using the stock symbol
            String channelName = "/stock/" + update.getSymbol().toLowerCase(Locale.ENGLISH);

            // Initialize the channel, making it persistent and lazy
            bayeuxServer.createChannelIfAbsent(channelName, new ConfigurableServerChannel.Initializer()
            {
                public void configureChannel(ConfigurableServerChannel channel)
                {
                    channel.setPersistent(true);
                    channel.setLazy(true);
                }
            });

            // Convert the Update business object to a CometD-friendly format
            Map<String, Object> data = new HashMap<String, Object>(4);
            data.put("symbol", update.getSymbol());
            data.put("oldValue", update.getOldValue());
            data.put("newValue", update.getNewValue());
              System.out.println("===========================");
            // Publish to all subscribers
            ServerChannel channel = bayeuxServer.getChannel(channelName);
            channel.publish(sender, data);
        }
    }
}



The following is StockPriceEmitter java class


import java.util.ArrayList;
import java.util.Arrays;
import java.util.EventListener;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; 
public class StockPriceEmitter implements Runnable {
       private final ScheduledExecutorService scheduler = Executors
                     .newSingleThreadScheduledExecutor();
       private final List<String> symbols = new ArrayList<String>();
       private final Map<String, Float> values = new HashMap<String, Float>();
       private final List<Listener> listeners = new CopyOnWriteArrayList<Listener>();

       public StockPriceEmitter() {
              symbols.addAll(Arrays.asList("ORCL", "MSFT", "GOOG", "YHOO", "FB"));
              values.put("ORCL", 29.94f);
              values.put("MSFT", 27.10f);
              values.put("GOOG", 655.37f);
              values.put("YHOO", 17.82f);
              values.put("FB", 21.33f);
       }
       public List<Listener> getListeners() {
              return listeners;
       }
       public void start() {
              run();
       }
       public void stop() {
              scheduler.shutdownNow();
       }
       public void run() {
              Random random = new Random();

              List<Update> updates = new ArrayList<Update>();

              // Randomly choose how many stocks to update
              int howMany = random.nextInt(symbols.size()) + 1;
              for (int i = 0; i < howMany; ++i) {
                     // Randomly choose which one to update
                     int which = random.nextInt(symbols.size());
                     String symbol = symbols.get(which);
                     float oldValue = values.get(symbol);

                     // Randomly choose how much to update
                     boolean sign = random.nextBoolean();
                     float howMuch = random.nextFloat();
                     float newValue = oldValue + (sign ? howMuch : -howMuch);

                     // Store the new value
                     values.put(symbol, newValue);

                     updates.add(new Update(symbol, oldValue, newValue));
              }

              // Notify the listeners
              for (Listener listener : listeners) {
                     listener.onUpdates(updates);
              }

              // Randomly choose how long for the next update
              // We use a max delay of 1 second to simulate a high rate of updates
              long howLong = random.nextInt(1000);
              scheduler.schedule(this, howLong, TimeUnit.MILLISECONDS);
       }

       public static class Update {
              private final String symbol;
              private final float oldValue;
              private final float newValue;

              public Update(String symbol, float oldValue, float newValue) {
                     this.symbol = symbol;
                     this.oldValue = oldValue;
                     this.newValue = newValue;
              }

              public String getSymbol() {
                     return symbol;
              }

              public float getOldValue() {
                     return oldValue;
              }

              public float getNewValue() {
                     return newValue;
              }
       }

       public interface Listener extends EventListener {
              void onUpdates(List<Update> updates);
       }
}


The following is Liferay Portlet Class

import java.io.IOException;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import com.liferay.util.bridges.mvc.MVCPortlet;
public class LiferayCommetDReverseAjax extends MVCPortlet {
     private StockPriceEmitter emitter;
    public void startStockUpdates(
    ActionRequest actionRequest, ActionResponse actionResponse)
                     throws IOException, PortletException {
    emitter = new StockPriceEmitter();
 StockPriceService service(StockPriceService)getPortletContext().
getAttribute(StockPriceService.class.getName());
  // Register the service as a listener of the emitter
  emitter.getListeners().add(service);
                      // Start the emitter
    emitter.start();
              }
public void stopStockUpdates(
ActionRequest actionRequest, ActionResponse actionResponse)
throws IOException, PortletException {
//emitter = new StockPriceEmitter();
emitter.stop();
              }
}


The following is application.js code


(function($)
{
    var cometd = $.cometd;
//alert(cometd);
    $(document).ready(function()
    {
        function _connectionEstablished()
        {
            $('#body').append('<div>CometD Connection Established</div>');
        }

        function _connectionBroken()
        {
            $('#body').append('<div>CometD Connection Broken</div>');
        }

        function _connectionClosed()
        {
            $('#body').append('<div>CometD Connection Closed</div>');
        }

        // Function that manages the connection status with the Bayeux server
        var _connected = false;
        function _metaConnect(message)
        {
            if (cometd.isDisconnected())
            {
                _connected = false;
                _connectionClosed();
                return;
            }

            var wasConnected = _connected;
            _connected = message.successful === true;
            if (!wasConnected && _connected)
            {
                _connectionEstablished();
            }
            else if (wasConnected && !_connected)
            {
                _connectionBroken();
            }
        }

        // Function invoked when first contacting the server and
        // when the server has lost the state of this client
        function _metaHandshake(handshake)
        {
            if (handshake.successful === true)
            {
                cometd.batch(function()
                {
                    cometd.subscribe('/stock/*', function(message)
                    {
                   
                    var data = message.data;
                        var symbol = data.symbol;
                        var value = data.newValue;
                       // alert(symbol);
                        var id = 'stock_'+ symbol;
                        var symbolDiv=document.getElementById(id);
                        if (!symbolDiv)
                        {
                        symbolDiv = document.createElement('div');
                        symbolDiv.id =id;
                        document.getElementById('stocks').appendChild(symbolDiv);
                        }
                        symbolDiv.innerHTML = '<span class="symbol">' + symbol + ': <b>' + value + '</b></span>';
                    });
                    // Publish on a service channel since the message is for the server only
                    //cometd.publish('/stock/*', { name: 'World' });
                });
            }
        }

        // Disconnect when the page unloads
        $(window).unload(function()
        {
            cometd.disconnect(true);
        });

        var cometURL = location.protocol + "//" + location.host + config.contextPath + "/cometd";
        cometd.configure({
            url: cometURL,
            logLevel: 'debug'
        });

        cometd.addListener('/meta/handshake', _metaHandshake);
        cometd.addListener('/meta/connect', _metaConnect);
        cometd.handshake();
    });
})(jQuery);


The following is portlet JSP page.


<%@ include file="init.jsp"%>
 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/cometd-namespace.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/cometd-json.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/AckExtension.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/TransportRegistry.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/Transport.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/RequestTransport.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/WebSocketTransport.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/CallbackPollingTransport.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/LongPollingTransport.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/Utils.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/Cometd.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/jquery.cometd.js"></script>
           <script type="text/javascript" src="<%=renderRequest.getContextPath() %>/js/comet/application.js"></script>
<%--
    The reason to use a JSP is that it is very easy to obtain server-side configuration
    information (such as the contextPath) and pass it to the JavaScript environment on the client.
    --%>
<style>
#stocks .symbol b{
color:red;
}
#controler-table td{
padding-left:30px;
}
</style>
<script type="text/javascript">
        var config = {
            contextPath: '<%=renderRequest.getContextPath()%>'
        };
 </script>
<portlet:actionURL  var="startStockUpdates" name="startStockUpdates">
</portlet:actionURL>
<portlet:actionURL  var="stopStockUpdates" name="stopStockUpdates">
</portlet:actionURL>
<h2>Liferay CometD Ajax Push Portlet</h2>
<br/>
<table id="controler-table">
       <tr>
              <td><a href="<%=startStockUpdates.toString()%>">Start</a></td>
              <td><a href="<%=stopStockUpdates.toString()%>">Stop</a></td>
       </tr>
</table>
<br/>
<div id="stocks"></div>


Author

Tuesday, April 8, 2014

Introduction to JSR 286/ Portlet Specification 2.0

Introduction:

JSR 286 is advanced portlet specification and it was added new features to JSR 168.
We can also call Portlet Specification 2.0. Java Community People was founf some of the limitations in JSR 168 and they are added new specifications to JSR 168 then they released as JSR 286 standards.

We already know JSR 168 standard and Portlet Specification 1.0


In JSR 168 covers the basic portlet technology need and its specification later Java Community People was added more features and specification in JSR 286.

The following are important Specification and Features
  • Inter Portlet Communication
  • Another State in Lifecycle
  • Ajax Support
  • Serving Resources
  • Portlet Filter and Listeners
  • Support Many Web Application Frame works in Portal Container
  • Improve Cache Mechanism
  • Support for WSRP 2.0

Inter Portlet Communication

The important feature in JSR 286 is Inter portlet communication. Inter portlet communication is mechanism to send or receive data between two portlets.

We can achieve IPC with different ways in portlets and we can make communication between portlet which are in same page or other pages too. We will use different ways based on our requirement.

In JSR 168 IPC works between portlets which are in same page using Portlet Session Mechanism.

In JSR 286 they made communication between portlet which are in different pages using other mechanism

The following are new IPC mechanism added in JSR 286
  1. Events
  2. Public Render Parameters

Events:

Event based mechanism way to communicate between portlet which are in same or in other page too.

Here one portlet will send the event and other portlet will listen the event. Here another method added in lifecycle so that it send or publish the events and when page render respective listener portlets receive the dada or events. Here before portlet execute render phase it can send events to other portlets


Public Render Parameters

Public render parameters are another way in IPC. We will use some public render parameters to each portlet so that it will carry the data between portlet and it will available to other portlets.
We will define some public render parameter such a way it will available to other portlet to get the data from that.

Another State in Portlet Lifecycle

New lifecycle phase added in portlet lifecycle. In JSR 168 the state of transition change from Action Phase to Direct Render Phase no more states in between that.

In JSR 286 to implement IPC they will add another Lifecycle state that is called Events Phase.
Before transition from Action Phase to Render Phase portlet can send events to other portlet in Events phase. So that another  lifecycle phase was added for portlet so that it will send some events to other portlet.



 Ajax Support

JSR 286 support Ajax mechanism to communicate with server. This is one of the good features. Generally if any portlet is have in action page other portlet need to render the portlet within the page.

With the help of Ajax we can avoid render all portlets in page. We simply send Ajax call from portlet so that we can communicate with server then get the response.

Serving Resources

In JSR 168 portlet specification will render only HTML content in render phase it can’t render some resources like pdf, images and other content type.

In JSR 286 was added another feature called serving resources with help of this we can serve the images, pdf and other content types to client.

In the portlet interface they added new method called serveResource(----)  method so that It will serve the other content types to client. This method also used specially for Ajax call in portlet, to call this method we will use different URL i.e. serve recourse URL.

Generally in the portlet transition state will always change from Action Phase to Render Phase when we perform actions.

But when we call serve Resource phase it will directly serve the content and it won’t go to render phase.

Portlet Filter and Listeners

We can portlet related filters and Listeners in portlet portlet.xml file. This will add advantage to perform some events or some actions before portlet is rendered.

Support Many Web Application Frame works in Portal Container

Generally Portal specification is different and we will use portlet container to manage portlets and its lifecycle. But we have many elegant web application frameworks.

In JSR 286 support other web frame works to run in portlet container so that developer can develop portlet in any web application frame work and run in the portlet container with help of small changes. It will support JSF, Struts, Spring, Vaadin and other MVC bases frameworks.

Support for WSRP 2.0

The Web Services for Remote Portlets specification defines a web service interface for accessing and interacting with interactive presentation-oriented web services.

This will help us access portlet from remote location other portals. We need to deploy portlet in portal we simply use this protocol we can access other portlet which are in other portlet container.


Author

Monday, April 7, 2014

Introduction to JSR 168/Portlet Specification 1.0

Introduction:

Sun micro system introduced Java Portlet technology to the world. In the Technology world each and every technology has some specifications based on this different people will implemented the software. The requirement specification is called Application Programming Interface.

Coming to portlet technology all requirement specifications comes under JSR 168 standards.
JSR 168 is portlet specification defined by java community people based on this many people implemented portlet technologies.JSR 168 is called portlet 1.0 specification.

Many vendors have implemented the Portlet Technology specification namely Liferay, uPortal, Web logic Portals, Webspear Portals and Apache Jetspeed.

JSR 168 is starting version of portlet technology and then people was added more specification in JSR 286.

This portlet technology specification was defined the portlet lifecycle and its management in the portlet container. Portlet lifecycle is similar to servlet lifecycle.

We already know to run or manage servlet lifecycle we need servlet containers similarly we have portlet container which is responsible for manage lifecycle of portlet.

All these specification and portlet lifecycle and management was specified in JSR 168 and JSR 286 standers all vendors who implemented the portlet technology should follow the portlet specification.

JSR 168 Portlet Important Specifications
  • Provide Run time environment to run portlet i.e. define portlet container
  • Implement API between Portlet Containers and Portlets
  • Implement Mechanism to store transient and persistence data for portlet.
  • Define Portlet Lifecycle
  • Provide methods for easy deployments of portlets
  • Allow portlets run in other vendor portals which follows JSR 168 standards.
  • Run JSR 168 portlets as remote portlets using the Web Services for Remote Portlets (WSRP) protocol
Important Artifacts in JSR 168 specification
  1. Portal
  2. Portlet
  3. Portlet Container
  4. Portal Page
Portal

Portal is web application which provides content aggregation, personalization and single sign of from different sources. Portal consists of web pages and each page has dynamic and static content.

Portal Page:

Portlet page is part of portal and its simple a web page. In general web application page consist of one dynamic application but coming to portal page it consist of multiple dynamic application and static content all together is called portal page.

A portal page is an aggregation of dynamic content and static content we can say portal page is fragments of dynamic and static content served by portlet container. Each portal page has specific layout there all portlet applications are reside.

Example Diagram For portal Page


Portlet Container

Portlet container is responsible for manage the portlet lifecycle. Portlet container is similar to server container.

Portlet container is integrated with web server/application so that it will use http protocol to communicate with client and serve the content. Generally some application server has provision to inbuilt with portlet container to support run time environment to portlet.

Portlet

Portlet is fragment of dynamic content which reside in portal page. Similar to servlet, portlets are web components that are deployed inside of a container and generate dynamic content. On the technical side, a portlet is a class that implements the javax.portlet.Portlet interface and is packaged and deployed as a .war file inside of a portlet container

Portlet properties

  • Portlets are managed by specialized containers called portlet containers.
  • Portlets are server side component which generate the dynamic content.
  • Portlet have its own lifecycle which will be manage by portlet container
  • Portlet will be used request/response mechanism to interact with web client using http protocol.

How portlets are differed from Servlet
  • Generally in servlet web application each servlet will be referred by URL to invoke or access and each web page content will be served by one servlet but in portlets each page will be served by different  portlet and each portlet will have its own lifecycle and own URL pattern to execute.
  • Servlet will generate dynamic content which send to browser and it’s in single web page but portlet will server fragment of dynamic content and portal page is responsible to aggregate content from different portlet to generate whole page.

Portlet life cycle

As we already know each portlet has it own lifecycle and which will be managed by portlet container. According to the JSR 168 standard portlet have three lifecycle stages.

init:

 Initialize the portlet and put the portlet into service

Handle requests:

Process different kinds of action- and render-requests

Destroy:

Put portlet out of service

Theoretically we have 3 lifecycle stages in portlets and these will be implemented via portlet interface. Portlet interface is implemented in jax.portlet package by Sun Microsystems.

Every portlet that should implement the portlet interface or it should extend the class that already implemented the portlet interface.

As we know portlet have three lifecycle staged and the following are interface methods which handle portlet lifecycle cycle in portlet implementation.

init(PortletConfig config):

This method is initialize the portlet and this will be called only once when portlet is instantiated, we can say when we drag and drop portlet in page.

If any necessary functionality required at initial time of portlet we will use this method and write code here. It is similar to servlet init method. This method can be used to create expensive objects/resources used by the portlet.

processAction(ActionRequest request, ActionResponse response):

When user is requested to server then portlet will execute process action method.
This method will notify the portlet that used has triggered an action this portlet. , a portlet can issue a redirect, change its portlet mode or window state, modify its persistent state, or set render parameters.

render(RenderRequest request, RenderResponse response):

Render method will generate content and that will be send to web client.
In the portal page we have many portlet we have triggered action in one portlet then all portlet will be executed render method to aggregate dynamic content. The portlet can produce markup that may depend on the portlet mode or window state, render parameters, request attributes, persistent state, session data, or backend data.

destroy ():

Indicate to the portlet the life cycle's end. This method allows the portlet to free up resources and update any persistent data that belongs to this portlet.

Note:

In the portlet lifecycle for each action or request the final method is render method. Render method will be called for every time to aggregate content or produce content.

Generally portlet have different URL to call these methods like Action URL and Render URL.
Action URL will execute portlet porcessAction(----) method and then it will be execute the render(----) method.

Render URL will execute the portlet render (---) method only.



Portlet Characteristics

Portlet have addition Characteristics when we compare with servlet.

Portlet Widow States:

Portlet has different window states. Window state specifies how portlet will look in the page .Window state decides how much space will be accommodated in portlet page.

The following are important window states as for JSR 168 Standards.

Maximized:

When portlet state is decided as Maximized then entire page only one portlet is visible.
Generally we will use this state after perform some action then we will make widow state is Maximized.

Normal:

Specified that is portlet may share the page with other portlets. This is the default window state.

Minimized:

Portlet should only render minimal output or no output at all.

Portlet Modes:

Portlet mode specifies that the function will be performed by portlet.
Generally following are the portlet modes that each portlet should support as for JSR 168 standards.

View:

 This view mode is when portlet is access or render then portlet is in view mode and this is default mode for portlet.

Edit:

Edit mode will be used to edit some portlet functionality and generally we wil use this mode for administrator to modify or edit something.

Help:

This will used to provide content to end user about portlet i.e how to use and access portlet like help information.

Persistent storage for preferences:

Portlets provide a PortletPreferences object for storing user preferences. These preferences are stored in a persistent data store, so they will be available across server restarts. As a developer, you don't have to worry about the actual implementation of how it is stored.

Author

Recent Posts

Recent Posts Widget

Popular Posts