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 APPLICATION_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: ""(thread: "")");
String portletWindowId = (String)session.getAttribute(PORTLET_WINDOW_ID);
if ( portletWindowId == null )
System.out.println(" no portletWindowId yet - going to derive it. Current thread ("") call stack:");
for (StackTraceElement st : Thread.currentThread().getStackTrace()) System.out.println(st);
Double value = new Double(Math.random());
Enumeration names = session.getAttributeNames(PortletSession.APPLICATION_SCOPE);
System.out.println(" looking for attribute "" in current APPLICATION_SCOPE attributes:");
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);
if (portletWindowId == null) System.out.println(" --> error: failed to derive the 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:
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.