You are viewing a plain text version of this content. The canonical link for it is here.
Posted to bridges-dev@portals.apache.org by "Ate Douma (JIRA)" <br...@portals.apache.org> on 2008/08/17 23:10:46 UTC

[jira] Updated: (PB-84) CCE in PortletWindowUtils.getPortletWindowId

     [ https://issues.apache.org/jira/browse/PB-84?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Ate Douma updated PB-84:
------------------------

    Attachment: portals-bridges-common-1.0.4.jar

The above is an incorrect assessment of how the code works.
And, although this "issue" has been brought up before, in my view the CCE thrown by OpenPortal (as well as JBoss Portal AFAIK) is a bug in the portlet container, *not* this method.

If you look at the rest of following code within this method, you'll notice the *random* generated Double object put in the session is put in there only for a for a very short time
and *replaced* within the same method almost immediately with a String object.

The whole point of this method is determining what the container provided PORTLET_WINDOW_ID is using a JSR-168 compliant "trick", in that PORTLET_SCOPE session attributes
are stored within the session using a predefined format which includes the PORTLET_WINDOW_ID (see: JSR-168 spec PLT.15.3).

For that purpose, a reasonably unique (double) value is generated using Math.random() and stored as a Double value within the session under PORTLET_SCOPE for an internal defined attribute name, "org.apache.portals.bridges.util.portlet_window_id".
Thereafter, all the APPLICATION_SCOPE  attributes are evaluated, looking again for this internal attribute name ("org.apache.portals.bridges.util.portlet_window_id") and (as an extra save guard)
its value is checked against the previously generated Double value to be sure the correct attribute value (name) is found.

Then, the temporary Double value is *replaced* with the real (String type) PORTLET_WINDOW_ID.

If the portlet container is implemented and behaving compliant to JSR-168, the above routine should work as expected and the temporary Double value should always be replaced again with a String value *within* the same method.
Also note: this part of the method is executed within a sychronized block so interference of other requests should not be possible either.

The fact this method fails (sometimes?) on OpenPortal and JBoss Portal in my view is very suspicious.
Somehow, the "org.apache.portals.bridges.util.portlet_window_id" attribute stored under PORTLET_SCOPE seems not be found correctly under SESSION_SCOPE, in which case this method will return null (this first time).
Subsequently, the following call to this method will indeed cause a CCE, sure.

Although I'd like to "fix" this problem, or even use a proper work around if possible, simply using the (obviously a Double) value as an Object won't help here.
Note: this method is supposed to return a String value and specifically a PORTLET_WINDOW_ID.

Until it is more clear what goes wrong here and why these portlet containers are not behaving as expected, I have no real solution available.

Tim, as you're encountering this problem with OpenPortal, it would be great if you could try to determine in more detail what goes on here.
I've created a modified version of the getPortletWindowId method which will produce some stack trace logging to the console which might tell us more  (note: requires Java 1.5):

    public static String getPortletWindowId(PortletSession session)
    {
        System.out.println("getPortletWindowId for session: "+session.getId()+"(thread: "+Thread.currentThread().getId()+")");
        
        String portletWindowId = (String)session.getAttribute(PORTLET_WINDOW_ID);
        if ( portletWindowId == null )
        {
            synchronized (session)
            {
                System.out.println("  no portletWindowId yet - going to derive it. Current thread ("+Thread.currentThread().getId()+") call stack:");
                for (StackTraceElement st : Thread.currentThread().getStackTrace()) System.out.println(st);                
                Double value = new Double(Math.random());
                session.setAttribute(PORTLET_WINDOW_ID, value);
                Enumeration names = session.getAttributeNames(PortletSession.APPLICATION_SCOPE);
                System.out.println(" looking for attribute "+PORTLET_WINDOW_ID+" in current APPLICATION_SCOPE attributes:");
                while (names.hasMoreElements())
                {
                    String name = (String)names.nextElement();
                    System.out.println(" found attribute: "+name);
                    if (PortletSessionUtil.decodeAttributeName(name).equals(PORTLET_WINDOW_ID) && value.equals(session.getAttribute(name,PortletSession.APPLICATION_SCOPE)) )
                    {
                        portletWindowId = name.substring("javax.portlet.p.".length(),name.indexOf('?'));
                        System.out.println("  --> found - PORTLET_WINDOW_ID = "+portletWindowId);
                        session.setAttribute(PORTLET_WINDOW_ID, portletWindowId);
                        break;
                    }
                }
                if (portletWindowId == null) System.out.println("  --> error: failed to derive the portletWindowId");                
            }
        }
        return portletWindowId;
    }

For your convenience I've attached a modified version of the portlet-bridges-common-1.0.4.jar with the above changed method compiled in it (again: using it requires Java 5).

I've run it myself (on Pluto/Jetspeed-2) which produces the following output (stack trace dump truncated for brevity):

  getPortletWindowId for session: FC9065541BED56975E35C1AD97BAB419(thread: 55)
    no portletWindowId yet - going to derive it. Current thread (55) call stack:
  java.lang.Thread.dumpThreads(Native Method)
  java.lang.Thread.getStackTrace(Thread.java:1383)
  org.apache.portals.bridges.util.PortletWindowUtils.getPortletWindowId(PortletWindowUtils.java:53)
  org.apache.portals.bridges.util.ServletPortletSessionProxy.createProxy(ServletPortletSessionProxy.java:59)
  org.apache.portals.bridges.struts.StrutsPortlet.processRequest(StrutsPortlet.java:420)
  org.apache.portals.bridges.struts.StrutsPortlet.doView(StrutsPortlet.java:301)
  javax.portlet.GenericPortlet.doDispatch(GenericPortlet.java:247)
  javax.portlet.GenericPortlet.render(GenericPortlet.java:175)
  org.apache.jetspeed.factory.JetspeedPortletInstance.render(JetspeedPortletInstance.java:103)
  org.apache.jetspeed.container.JetspeedContainerServlet.doGet(JetspeedContainerServlet.java:277)
  javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
  <snip/>
    looking for attribute org.apache.portals.bridges.util.portlet_window_id in current APPLICATION_SCOPE attributes:
    found attribute: javax.portlet.p.jp-2?org.apache.portals.bridges.util.portlet_window_id
    --> found - PORTLET_WINDOW_ID = jp-2

If you could try the same and provide me with the debug output you get, maybe we can get somewhat further with this problem.

Ate



> CCE in PortletWindowUtils.getPortletWindowId
> --------------------------------------------
>
>                 Key: PB-84
>                 URL: https://issues.apache.org/jira/browse/PB-84
>             Project: Portals Bridges
>          Issue Type: Bug
>          Components: common
>    Affects Versions: 1.0
>         Environment: Mac OS, Wicket Portlets, OpenPortal Portlet Container
>            Reporter: Tim Boudreau
>         Attachments: portals-bridges-common-1.0.4.jar
>
>
> I'm trying to get wicket portlet support working over OpenPortal.  I've hacked together implementations of ServletContextProvider and PortletResourceURLFactory - just required exposing WicketFilter from the Application to get the necessary data.  I can deploy a portlet, but...
> I'm getting this exception. 
> java.lang.ClassCastException: java.lang.Double
>         at org.apache.portals.bridges.util.PortletWindowUtils.getPortletWindowId(PortletWindowUtils.java:45)
> Looking at the code, this seems like a clear bug:  The method casts to String here:
> (String)session.getAttribute(PORTLET_WINDOW_ID);
> and if null fills in the value with an instance of Double.  If it's going to put a Double there, it should probably not expect a String - this exception will occur any time this method is called twice for a PortletSession, it will throw the CCE the second time it is called.
> Since the value is not used, probably simply changing it to 
>         Object portletWindowId = session.getAttribute(PORTLET_WINDOW_ID);
> would fix it.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


---------------------------------------------------------------------
To unsubscribe, e-mail: bridges-dev-unsubscribe@portals.apache.org
For additional commands, e-mail: bridges-dev-help@portals.apache.org