The
first version of the portlet specification, JSR-168/Portlet 1.0, did not include
any support for Inter Portlet Communication. The second version, JSR-286/Portlet
2.0, has supported
for IPC Mechanism.
JSR-286
makes it easy to share the data between two portlets. Using IPC mechanisms, we
can share the data from ACTION to VIEW phase and VIEW-VIEW Phase.
Definition :
“Intert Portlet
Communication means that to share data between the portlets”.
There
are 3 ways to share the data between 2 portlets.
1. Portlet session
2. IPC Mechanisms
1.
Public Render Parameters
2.
Events
3.
Client-Side IPC
3. Cookies
By
default, Each WAR has its own session and will not be shared with other WARs.
Liferay provides a mechanism by which Portlets can share session attributes
across WARs.
A
PortletSession is created for each user per portlet application. This makes the
PortletSession useful for communicating all user related information among
different portlets in the same portal application.
liferay-portlet.xml
:
Note: Place below tag after <instanceble/> tag
<portlet>
<private-session-attributes>false</private-session-attributes>
</portlet>
PortletSession session = renderRequest.getPortletSession();
session.setAttribute("sessionValue", some-value
,PortletSession.APPLICATION_SCOPE);
PortletSession ps = renderRequest.getPortletSession();
String tabNames = (String)ps.getAttribute("sessionValue
",PortletSession.APPLICATION_SCOPE);
In
JSR 168, the render parameters set in processAction is only available in the
render of the same portlet. With the Public Render Parameters feature, the
render parameters set in the processAction of one portlet will be available in
render of other portlets also.
By
adding the following property in portlet-ext, we can enable portlets to share
render states with other portlets that are on different pages:
portlet.public.render.parameter.distribution=ALL_PORTLETS
<portlet-app>
<portlet>
Note :Place below tag after
<security-role-ref>user</security-role-ref>
<supported-public-render-parameter>id1</supported-public-render-parameter>
</portlet>
Note : place below tag after end tag of </portlet>
<public-render-parameter>
<identifier>id1</identifier>
<qname
xmlns:x="http://abc.com/userId">x:param1</qname>
</public-render-parameter>
</portlet-app>
Note:We can declare a list of public
paramters for a portlet application.
Step 2 Set Parameter value inside processAction()
We
can set render parameter in the processAction() method by using the
defined public render parameter identifier as the key.
response.setRenderParameter("id1", "someIdValue");
E.g.
public void processAction(ActionRequest
request, ActionResponse response) throws IOException,
PortletException {
........
response.setRenderParameter("id1", “someIdValue”); ........
}
Specify
the render parameter the portlet would like to share in the portlet section.
<portlet-app>
<portlet>
<portlet-name >PortletB<
/portlet-name>
Note :Place below tag
after the <security-role-ref>user</security-role-ref>
<supported-public-render-parameter>id1</supported-public-render-parameter>
</portlet >
Note :Place the below
tag after the end tag of </portlet>
<public-render-parameter>
<identifier>id1</identifier>
<qname
xmlns:x="http://abc.com/userId">x:param1</qname>
</public-render-parameter>
</portlet-app>
Step 4 :Get the Parameter
A
portlet can read public render parameter using following method
request.getPublicParameterMap()
Note:Public render parameters are merged
with regular parameters so can also be read using
request.getParameter(“id1”);
Step 5: Remove the Render Parameter
A
portlet can remove a public render parameter by invoking following methods.
response.removePublicRenderParameter("id1")
2.2
Event Inter-portlet Communication
Portlet
events that a portlet can receive and send.
In JSR-168 The only
way to achieve eventing was through portlet session. The limitation of this
approach was that the Portlets has to be in the same web application.
In JSR-286 JSR 286
(Portlet 2.0) defines a lifecycle for events, so that eventing is possible
between portlets that are in different web applications.
By
adding the following property in portal-ext.properties, we can enable portlets
to send and receive events from other portlets that are on different pages
portlet.event.distribution=ALL_PORTLETS
portlet.xml
The
portlet standard defines a way of telling the portlet container which portlet
is responsible for sending an event.
Add
this inside <portlet>
tag:
<portlet-app>
<portlet>
Note :place below tag after the end
tag of <security-role-ref>user</security-role-ref>
<supported-publishing-event
xmlns:x='http://liferay.com'>
<qname>x:empinfo</qname>
</supported-publishing-event>>
</portlet>
Note :place the below tag after end tag
of </portlet>
<event-definition xmlns:x='http://liferay.com'>
<qname>x:empinfo</qname>
<value-type>java.lang.String</value-type>
</event-definition>
</portlet-app>
javax.xml.namespace.QName qName = new QName("http://liferay.com",
"empinfo", "x");
response.setEvent(qName, "Hi! You have
received Event Data sent from Sender Portlet");
portlet.xml
<portlet-app>
<portlet>
Note :Place below one after end tag of
<security-role-ref>user</security-role-ref>
<supported-processing-event
xmlns:x='http://liferay.com'>
<qname>x:empinfo</qname>
</supported-processing-event>
</portlet>
Note:Place the below one after end
tag of </portlet>
<event-definition
xmlns:x='http://liferay.com'>
<qname>x:empinfo</qname>
<value-type>java.lang.String</value-type>
</event-definition>
</portlet-app>
This
Event will be called after processAction
as shown in the picture:
Lifecycle for IPC Event
@javax.portlet.ProcessEvent(qname = "{http://liferay.com}empinfo")
public void handleProcessempinfoEvent(javax.portlet.EventRequest
request, javax.portlet.EventResponse response)
throws
javax.portlet.PortletException, java.io.IOException {
javax.portlet.Event event =
request.getEvent();
String value = (String)
event.getValue();
System.out.print("value in process
event>>>>>>>>>" + value);
response.setRenderParameter("empInfo", value);
}
There
are 2 APIs for client side IPC.
Event
generation (call from Portlet-A):
Liferay.fire(
'<eventName>', {
name: value
}
);
E.g.
Liferay.fire(
'planTravel', {
origin: 'pune',
destination : 'mumbai'
}
);
Event
Listener (call from Portlet-B):
Liferay.on(
'<eventName>',
function(event) {
// your code
}
);
E.g.
Liferay.on(
'<eventName>',
function(event) {
showNews('', event.origin);
showNews('',
event.destination);
}
);
In Portlet A –------view.jsp
ex:
<%@ page language="java"
contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/portlet"
prefix="portlet" %>
<portlet:defineObjects />
<script type="text/javascript">
function
doSearch() {
Liferay.fire('searchKeywords',
document.getElementById("<portlet:namespace/>search").value);
}
</script>
<form>
<input type="text" name="search"
id="<portlet:namespace/>search" />
<button name="Search" value="Search"
onclick="doSearch()" type="button">Search</button>
</form>
In Portlet-B
view.jsp
<%@ page language="java"
contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/portlet"
prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/aui"
prefix="aui" %>
<portlet:defineObjects />
<portlet:resourceURL var="rurl" />
<script type="text/javascript">
Liferay.on('searchKeywords', function(event,
p_data){
var A = AUI();
A.use('aui-io-request', function(aui)
{
A.io.request("<%= rurl %>", {
method : 'POST',
data: {search: p_data},
dataType : 'html',
on :
{
success : function()
{
AUI().one("#<portlet:namespace/>placeholder").html(this.get('responseData'));
}
}
});
});
});
</script>
Search Results:<br />
<div id="<portlet:namespace/>placeholder">
</div>
In Portlet B
html.jsp
<font color="red"><%= request.getAttribute("result") %></font>
In Portlet B ------>MVCPortlet
public void serveResource(ResourceRequest resourceRequest,
ResourceResponse resourceResponse) throws PortletException, IOException {
//do your search here and put results in 'result'
resourceRequest.setAttribute("result", "results for: " + resourceResponse.getParameter("search"));
getPortletContext().getRequestDispatcher("/html/ipcdemo8portlet/html.jsp").include(resourceRequest, resourceResponse);
}
3.Cookies
Other than the IPC mechanism, there is an easiest way to
get the data between portlets on different pages through Cookies.
But
there are some limitations for cookies:
1.
It will not accept more than 4KB size of data
2.
The biggest limitation is, the 20 cookies per server
limit
and
so it is not a good idea to use a different cookie for each variable that has
to be saved.
To Set the Cookies through jQuery:
<script src="/html/js/jquery/cookie.js"
type="text/javascript" > </script>
function setCookie(docURL) {
jQuery.cookie("cookieParam",docURL);
}
To Set the Cookies through java/jsp:
HttpServletResponse response =
PortalUtil.getHttpServletResponse(actionResponse);
Cookie cookieParam = new Cookie("cookieParam ", password);
response.addCookie(cookieParam);
To
get the Cookies through jQuery:
jQuery.cookie("cookieParam ");
To
get the Cookie through java/jsp:
String sessionid = "";
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (int i = 0; i < cookies.length;
i++) {
if (cookies[i].getName().equals("cookieParam
")) {
sessionid =
cookies[i].getValue();
break;
}
}
}