4 Replies Latest reply on Dec 7, 2012 1:15 PM by drwho

    Inter-portlet Communication in GateIn/JBossEPP and session sharing between portlet application context

    nicolavirgilio

      Hi,

       

      I am opening this new topic in the hope someone here can help me with a problem I am facing with GateIn/JBoss EPP 5.1.

       

      I am trying to implement IPC (inter-portlets communication) between 2 portlets and based on what I need to accomplish I feel quite limited by spec (2.0) itself. I will explain briefly the case.

       

      I am developing a portal based application comprised of several portlet applications (deployed as distinct wars). Some of the portlets which lives in different pages needs to share/communicate some data (i.e. parameters). This communication not necessarily needs to happen in both directions, so let's say 1 portlet write/send some data where another portlet from a different page/war will need to read the same data with the twist of a page redirection from one portlet to the other. This is to put it simple, now let me give me some more details about regarding the interactions between these two portlets.   

       

      In my specific case, there is one portletA sitting on a pageA and which renders an action URL in its render phase. When this actionURL is clicked and the action phase of portletA is invoked it has to redirect to portletB onto a different pageB. What I want to do is to pass during the redirection a number of parameters to portletB. One additional detail is that portletA and portletB lives in 2 different webapps thus excluding the use of a shared session object to pass attributes for our purpose. More over portletB is a thirty-party portlet which we don't have source code but it does support a number of publicRenderParameters out of the box with the optional extension API to allow more publicRenderParameters in case needed .

       

      IPC from spec 2.0 allows the use of public render parameters between portlets in different pages and from different webapps. Unfortunately sendRedirect (called in the action phase of portletA) would fail if render params are set during this same phase. I am able to share the params across the two portlets from two different apps and living in different pages but redirection from A to B is not possible under this condition.

       

      The question that want to ask is, has JBoss in version 5.1 or eventually the recent build 5.2 some sort of IPC implementation in its container that allows the sharing of attributes between portlets regardless of which apps they belong to or where it is instanced from (page)? Something like a session object living in the portal container context rather than the portlet context or webapp context. I know that there are some portal products that have something similar, like portal page parameter in websphere for example or a portal session sharing in liferay. Is there anything like this in JBoss?

       

      Any help would be very appreciated

       

      Many thanks

       

      Massimo

        • 1. Re: Inter-portlet Communication in GateIn/JBossEPP and session sharing between portlet application context
          julien_viet

          At some point the synchronization of session between web apps was considered by the JSR 286 expert group (specially that it exist in WSRP) but it was dropped for some reason I don't remember.

           

          You can implementation your own stuff by using a static map that would setup a shared context between users using some kind of reference counting based on the HttpSessionListener to update the shared map. The map would use the session ID as key as it is the same regardless of the wep app.

           

          public class Context {

            final HashMap<String, Object> entries = new ...;

             int referenceCount = 0;

          }

           

          public class SharedContext {

             private static final ConcurrentHashMap<String, Context> contexts = new ...;

             public static void bind(HttpSession session) {

                Context ctx = contexts.get(session.getId());

                if (ctx == null) {

                   contexts.put(session.getId(), ctx = new Context());

                }

                ctx.referenceCount++;

            }

             public static void unbind(HttpSession session) {

                Context ctx = contexts.get(session.getId());

                if (ctx != null) {

                   if (--ctx.referenceCount == 0) {

                      contexts.remove(session.getId());

                   }

                } else {

                   // If we are here it means there is a bug somewhere

                }

             }

             public static Object get(PortletRequest req, String name) {

                PortletSession session = req.getPortletSession(false);

                if (session != null) {

           

                  Context ctx = contexts.get(session.getId());

                   if (ctx != null) {

                      return ctx.entries.get(name);

                   }

               }

                return null;

            }

             public static void set(PortletRequest req, String name, Object value) {

                PortletSession session = req.getPortletSession();

                 Context context = contexts.get(session.getId());

                 if (context == null) {

                    throw new IllegalStateException("Probably that the web application does not have the session listener in its web.xml");

                 }

                 if (value != null) {

           

                   context.entries.put(name, value);

                } else {

                    context.entries.remove(name);

                 }

            }

          }

           

          public class SharedContextLifeCycle implements HttpSessionListener {

              // On session created invoke SharedContext.bind

              // On session destroyed invoke SharedContext.unbind

          }

           

          that should do the work and manage state in a correct manner.

          • 2. Re: Inter-portlet Communication in GateIn/JBossEPP and session sharing between portlet application context
            nicolavirgilio

            Hi, thanks for the reply.It has been long time since I posted as I had been kept busy on other things but anyway I wanted to post back just to share some findings.

             

            I have been trying several things to get the IPC working in the unlikely scenario of portlet distribution across different webapps and pages (and eventually servers and with wsrp setup). Let me just resume some options:

             

            1) Passing url parameters in the sendRedirect
             
             

             

            •     setting the value from PortletA(warA)

                    
                      response.sendRedirect("/portal/private/classic/testA?sky=grey");
                 

             

            •     reading the value from PortletB(warB)


                      import org.exoplatform.portal.application.PortalRequestContext;
                      import org.exoplatform.portal.webui.util.Util;
                      PortalRequestContext prContext = Util.getPortalRequestContext();
                      String skycolor = prContext.getRequest().getParameter("sky");
             
                  pros: simple
                  cons:use of portal api, at risk of passing sensible data into the browser url

                  note: not tested with wsrp
             
              2) Using cookies to share data between two wars
             
             

            •     setting the value from PortletA(warA)

                       import org.exoplatform.portal.application.PortalRequestContext;
                        PortalRequestContext prContext = Util.getPortalRequestContext();
                        Cookie cookie = new Cookie("sky", "grey" + counter++);
                        cookie.setPath("/");
                        cookie.setMaxAge(-1);
                        prContext.getResponse().addCookie(cookie);
                        response.sendRedirect("/portal/private/classic/testA");
                 

             

            •     reading the value from PortletB(warB)

                      import org.exoplatform.portal.application.PortalRequestContext;
                      PortalRequestContext prContext = Util.getPortalRequestContext();
                      Cookie[] cookies = request.getCookies();
                      String skycolor = getCookieValue(cookies, "sky", "null");
             
                  pros: none in particular
                  cons:use of portal api, adds to this application layer the cookies management overhead and risks, the data persists on the client machine (i.e. browser cookies)

             

                  note: not tested with wsrp


             
              3) Implementing a custom SharedContext manager to share data between two wars (Julien suggestion)
             
             

            •     setting the value from PortletA(warA)

                         SharedContext.set(request, "sky", "grey");
                          response.sendRedirect("/portal/private/classic/testA");
                 

             

            •     reading the value from PortletB(warB)

             

                        Object skycolor = (Object) SharedContext.get(request, "sky");
             
                  pros: clean coding, portal independent
                  cons: Portlets must reference a new compile-time dependency SharedContext.jar. At runtime the SharedContext.jar must be part of the server shared libraries so to allow always one ClassLoader to instantiate the same SharedContext static object from the two portlets, doen't work when webapps are on different server instances (jvm).

             

                  note: under wsrp it works.

             

             

            I hope someone could find this useful

             

             

            regards,

             

            Massimo

            • 3. Re: Inter-portlet Communication in GateIn/JBossEPP and session sharing between portlet application context
              julien_viet

              Hi Massimo,

               

              for the option 2, did you try to make it portal agnostic. Portlet 2.0 API allows to send/receive cookies like explained here : http://wpcertification.blogspot.com/2010/09/setting-headers-and-cookies-through.html

              • 4. Re: Inter-portlet Communication in GateIn/JBossEPP and session sharing between portlet application context
                drwho

                Julien,

                I am thinking about implementing your static map solution. Can SharedContextLifeCycle  class be implemented as a service with Portal Container scope? What I want to do is to provide Java POJO objects to a session initiate when the user logs into a user created site and those objects are destoryed when user logs out of the session.

                Gordon