Portlet 2.0 support inter-portlet communication, the following simple example show the step by step together using spring and portlet.
You may download the source from here
In the following tutorial, I’ll create 2 portlet to interact from pitch-portlet to catcher-portlet. In this example pitch-portlet will generate a random number and display on catcher portlet.
[googlefont font=”Enriqueta” fontsize=”30″]PitcherController[/googlefont]
package com.loongest.sample.ipc.pitcher; import java.util.Random; import javax.portlet.ActionResponse; import javax.portlet.RenderRequest; import javax.xml.namespace.QName; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.support.SessionStatus; import org.springframework.web.portlet.bind.annotation.ActionMapping; @Controller @RequestMapping("VIEW") public class PitcherController { @ActionMapping("pitchBall") public void pitchBallAction(SessionStatus status, ActionResponse response) { String pitchType = null; Random random = new Random(System.currentTimeMillis()); int pitch = random.nextInt(3)+1; switch(pitch) { case 1 : pitchType = "Fast Ball"; break; case 2 : pitchType = "Curve Ball"; break; case 3 : pitchType = "Slider"; break; default : pitchType = "Screw Ball"; } QName qname = new QName("http://liferay.com/events","ipc.pitch"); response.setEvent(qname, pitchType); status.setComplete(); } @RequestMapping public String render(Model model, SessionStatus status, RenderRequest req) { return "pitcher"; } }
[googlefont font=”Enriqueta” fontsize=”30″]CatcherController[/googlefont]
package com.loongest.sample.ipc.catcher; import javax.portlet.Event; import javax.portlet.EventRequest; import javax.portlet.EventResponse; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.portlet.bind.annotation.EventMapping; @Controller @RequestMapping("VIEW") public class CatcherController { @RequestMapping public String doView(RenderRequest request, RenderResponse response){ return "catcher"; } @EventMapping(value ="{http://liferay.com/events}ipc.pitch") public void receiveEvent(EventRequest request, EventResponse response, ModelMap map) { Event event = request.getEvent(); String pitch = (String)event.getValue(); map.put("pitch", pitch); response.setRenderParameter("pitch", pitch); } }
[googlefont font=”Enriqueta” fontsize=”30″]catcher-portlet.xml[/googlefont]
[googlefont font=”Enriqueta” fontsize=”30″]pitcher-portlet.xml[/googlefont]
[googlefont font=”Enriqueta” fontsize=”30″]catcher.jsp[/googlefont]
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="portlet" uri="http://java.sun.com/portlet" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <portlet:defineObjects/> <p> And the pitch is ... </p> <p> <c:if test="${param.pitch ne ''}"> <c:out value="${param.pitch}"/> </c:if> <c:if test="${param.pitch eq ''}"> ...waiting for pitch </c:if> </p>
[googlefont font=”Enriqueta” fontsize=”30″]pitcher.jsp[/googlefont]
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="portlet" uri="http://java.sun.com/portlet" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <portlet:defineObjects/> <p> Click the link below to pitch the ball </p> <a href="<portlet:actionURL name="pitchBall"></portlet:actionURL>">Pitch!</a>
[googlefont font=”Enriqueta” fontsize=”30″]applicationContext.xml[/googlefont]
[googlefont font=”Enriqueta” fontsize=”30″]liferay-portlet.xml[/googlefont]
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE liferay-portlet-app PUBLIC "-//Liferay//DTD Portlet Application 5.2.0//EN" "http://www.liferay.com/dtd/liferay-portlet-app_5_2_0.dtd"> <liferay-portlet-app> <portlet> <portlet-name>pitcher</portlet-name> <icon>/icon.png</icon> <instanceable>true</instanceable> <header-portlet-css>/css/test.css</header-portlet-css> <footer-portlet-javascript>/js/test.js</footer-portlet-javascript> </portlet> <portlet> <portlet-name>catcher</portlet-name> <icon>/icon.png</icon> <instanceable>true</instanceable> <header-portlet-css>/css/test.css</header-portlet-css> <footer-portlet-javascript>/js/test.js</footer-portlet-javascript> </portlet> <role-mapper> <role-name>administrator</role-name> <role-link>Administrator</role-link> </role-mapper> <role-mapper> <role-name>guest</role-name> <role-link>Guest</role-link> </role-mapper> <role-mapper> <role-name>power-user</role-name> <role-link>Power User</role-link> </role-mapper> <role-mapper> <role-name>user</role-name> <role-link>User</role-link> </role-mapper> </liferay-portlet-app>
[googlefont font=”Enriqueta” fontsize=”30″]portlet.xml[/googlefont]
<?xml version="1.0" encoding="UTF-8"?> <portlet-app version="2.0" xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" 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"> <portlet> <portlet-name>pitcher</portlet-name> <portlet-class> org.springframework.web.portlet.DispatcherPortlet </portlet-class> <init-param> <name>contextConfigLocation</name> <value>/WEB-INF/context/pitcher-portlet.xml</value> </init-param> <supports> <mime-type>text/html</mime-type> <portlet-mode>view</portlet-mode> </supports> <portlet-info> <title>Pitcher</title> </portlet-info> <supported-publishing-event> <qname xmlns:x="http://liferay.com/events">x:ipc.pitch</qname> </supported-publishing-event> </portlet> <portlet> <portlet-name>catcher</portlet-name> <portlet-class> org.springframework.web.portlet.DispatcherPortlet </portlet-class> <init-param> <name>contextConfigLocation</name> <value>/WEB-INF/context/catcher-portlet.xml</value> </init-param> <supports> <mime-type>text/html</mime-type> <portlet-mode>view</portlet-mode> </supports> <portlet-info> <title>Catcher</title> </portlet-info> <supported-processing-event> <qname xmlns:x="http://liferay.com/events">x:ipc.pitch</qname> </supported-processing-event> </portlet> <event-definition> <qname xmlns:x="http://liferay.com/events">x:ipc.pitch</qname> <value-type>java.lang.String</value-type> </event-definition> </portlet-app>
[googlefont font=”Enriqueta” fontsize=”30″]liferay-display.xml[/googlefont]
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE display PUBLIC "-//Liferay//DTD Display 5.2.0//EN" "http://www.liferay.com/dtd/liferay-display_5_2_0.dtd"> <display> <category name="Spring MVC Portlet 3.0"> <portlet id="pitcher" /> <portlet id="catcher" /> </category> </display>
[googlefont font=”Enriqueta” fontsize=”30″]web.xml[/googlefont]
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>Sample Portal</display-name> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> <servlet-name>view</servlet-name> <servlet-class> org.springframework.web.servlet.ViewRendererServlet </servlet-class> </servlet> <servlet> <servlet-name>view</servlet-name> <servlet-class> org.springframework.web.servlet.ViewRendererServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>view</servlet-name> <url-pattern>/WEB-INF/servlet/view</url-pattern> </servlet-mapping> </web-app>
Thanks, this was really helpful.
Thanks, looked ages for a working example…
Hi,
I am trying to implement IPC between two different portlets in “two different war files” using spring 3.0 MVC framework.
I have created the 2 projects and have implemented the code but seems that event is not getting fired or it was not getting caught in the other controller..
do you have any sample code to demonstrate the IPC between portlets in different war files.
Thanks in Advance
Hi, as far as i known it cant work in two different war files. Because the event is define in portlet.xml and each war will only load on their own portlet.xml. But you can give a try, because the the qname should be unique.
Hi, perhaps this is not on content but in any case, I have been reading about your web site and it looks truly neat. impassioned about your authorship. I’m building a new web log and hard put to make it appear great, and provide really good content. I have observed a lot on your web site and I look forward to more updates and will be coming back.
This is exactly what I am looking for. Thank you very much!!!
hi,
can we achieve this using ResourceMapping…?
In my case i m submitting the form thr ajax request and for that I have controller which has resource mapping which does nt allows ActionRequest and ActionResponse…is their any other way to achieve this?
From the idea you mention seem like first portlet is ajax approach and second is IPC. I suggest you revise the design, maybe you can implement for portletA with (ActionMapping and EventMapping) and portletB with (EventMapping). The effect will be the same.
Hi
I am trying to develop ipc with Spring MVC. Here i am sending complicated data between two portlets(not string value bean object).
I am getting event fired but i am not getting data.
@EventMapping(value=”{http://www.namespace.com}Employee”)
public void receiveEvent(EventRequest request, EventResponse response)
{
Event event = request.getEvent();
if(event.getName().equals(“Employee”)){
Employee emp = (Employee)event.getValue();
System.out.println(“Employee====”+emp);
request.setAttribute(“employee”, emp);
response.setRenderParameter(“myaction”, “target”);
}
}
Here Employee is the Bean class. This two portlets are different wars. Please help me
Thanks,
Sathish.
No, you cannot pass object. Why not u just pass the string (Eg employee Id). From the other portlet, you can reuse this String employeeId and query from database. This should be more easy.
Thanks for quick reply, I am sending Bean object in JSR 286 applications using event based communication in two different wars.
That’s why i am trying to implement in Spring MVC. Here i am getting following error.
Event payload cannot be converted to xml stream for the value type: com.ipc.spring.Employee of event: {http://www.namespace.com}Employee
java.lang.ClassNotFoundException: com.ipc.spring.Employee
Here i am sending code
Source portlet code
@ActionMapping(params= “myaction=event” )
public void settingEvent(ActionRequest request , ActionResponse response) throws Exception {
System.out.println(“empname=”+request.getParameter(“empName”));
QName qName = new QName(“http://www.namespace.com”, “Employee”);
Employee emp = new Employee();
emp.setEmpId(Integer.parseInt(request.getParameter(“empid”)));
emp.setEmpName(request.getParameter(“empName”));
response.setEvent(qName, emp);
}
xml file
– – – – – –
x:Employee
x:Employee
com.ipc.spring.Employee
Target Portlet
@EventMapping(value=”{http://www.namespace.com}Employee”)
public void receiveEvent(EventRequest request, EventResponse response)
{
Event event = request.getEvent();
if(event.getName().equals(“Employee”)){
Employee emp = (Employee)event.getValue();
System.out.println(“QName: ” + event.getQName());
System.out.println(“Event Name: ” + event.getName());
System.out.println(“Employee====”+event.getValue());
request.setAttribute(“employee”, emp);
response.setRenderParameter(“myaction”, “target”);
}
}
target xml file
– – – – –
x:Employee
x:Employee
com.ipc.spring.Employee
Thanks for quick reply, I am sending Bean object in JSR 286 applications using event based communication in two different wars.
That’s why i am trying to implement in Spring MVC. Here i am getting following error.
Event payload cannot be converted to xml stream for the value type: com.ipc.spring.Employee of event: {http://www.namespace.com}Employee
java.lang.ClassNotFoundException: com.ipc.spring.Employee
Here i am sending code
Source portlet code
@ActionMapping(params= “myaction=event” )
public void settingEvent(ActionRequest request , ActionResponse response) throws Exception {
System.out.println(“empname=”+request.getParameter(“empName”));
QName qName = new QName(“http://www.namespace.com”, “Employee”);
Employee emp = new Employee();
emp.setEmpId(Integer.parseInt(request.getParameter(“empid”)));
emp.setEmpName(request.getParameter(“empName”));
response.setEvent(qName, emp);
}
xml file
x:Employee
x:Employee
com.ipc.spring.Employee
Target Portlet
@EventMapping(value=”{http://www.namespace.com}Employee”)
public void receiveEvent(EventRequest request, EventResponse response)
{
Event event = request.getEvent();
if(event.getName().equals(“Employee”)){
Employee emp = (Employee)event.getValue();
System.out.println(“QName: ” + event.getQName());
System.out.println(“Event Name: ” + event.getName());
System.out.println(“Employee====”+event.getValue());
request.setAttribute(“employee”, emp);
response.setRenderParameter(“myaction”, “target”);
}
}
target xml file
x:Employee
x:Employee
com.ipc.spring.Employee
Only String allow. I suppose you have EmployeeService
@Autowired EmployeeService service;
//
@EventMapping(value=”{http://www.namespace.com}Employee”)
public void receiveEvent(EventRequest request, EventResponse response)
{
Event event = request.getEvent();
String employeeId = (String)event.getValue();
Employee emp = service.getEmployeeById(employeeId);
request.setAttribute(“employee”, emp);
response.setRenderParameter(“myaction”, “target”);
}
}
Also pay attention on these 2 configuration, 1 is publishing-event another 1 is processing-event
yes, Here Source is publishing-event and Target is processing-event. I am getting following values in target.
System.out.println(“QName: ” + event.getQName()); // QName: {http://www.namespace.com}Employee
System.out.println(“Event Name: ” + event.getName()); // Event Name: Employee
But i am not getting System.out.println(“Employee====”+event.getValue()); // null
This Example looks impressive to me but I have two doubts
1.why is defined two times
2.where the applicationContext.xml is configured?
To answer your question there is no web.xml defined 2 times. ApplicationContext is in the article. Please read properly, example is provided. Thanks 🙂