Spring Portlet IPC – Inter-portlet communications

Spring Portlet IPC – Inter-portlet communications

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]

catche

 

[googlefont font=”Enriqueta” fontsize=”30″]pitcher-portlet.xml[/googlefont]

pitcher

 

[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]

applicationcontext

 

[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>

Done !

17 comments

  1. Thanks, this was really helpful.

    Reply
  2. Thanks, looked ages for a working example…

    Reply
  3. 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

    Reply
    1. 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.

      Reply
  4. 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.

    Reply
  5. This is exactly what I am looking for. Thank you very much!!!

    Reply
  6. 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?

    Reply
    1. 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.

      Reply
  7. 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.

    Reply
    1. 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.

      Reply
  8. 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

    Reply
  9. 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

    Reply
  10. 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”);
    }

    }

    Reply
  11. Also pay attention on these 2 configuration, 1 is publishing-event another 1 is processing-event


    x:ipc.pitch


    x:ipc.pitch

    Reply
  12. 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

    Reply
  13. This Example looks impressive to me but I have two doubts

    1.why is defined two times
    2.where the applicationContext.xml is configured?

    Reply
    1. To answer your question there is no web.xml defined 2 times. ApplicationContext is in the article. Please read properly, example is provided. Thanks 🙂

      Reply

Leave a Reply to zielgruppe Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.