Skip to main content

Writing Portlets in Wicket using the OpenPortal Portlet Server

Posted by timboudreau on August 16, 2008 at 10:32 AM PDT

Addendum, two days later: The solution here almost works, but doesn't. You really need the actual servlet, not something being proxied by WicketFilter - action processing happens before the ThreadLocal for the HTTP request and response have been assigned. Basically, you can get a wicket portlet up in OpenPortal this way, but the first request after that will fail.

I have patched OpenPortal to implement the apache portal bridge properly (add a class that assigns the ThreadLocal inside com.sun.portal.portletcontainer.appengine.PortalAppEngineServlet.service() and unassign it on exit; then implement the bridge calling that (I'm sure this is not how the OpenPortal folks would prefer such a thing to be implemented - the Portlet API appears to have been written to take great pains not to assume servlets are part of the equation, and that's probably a Good Thing™, but here it's needed.

The result is almost working - still have to figure out why OpenPortal sometimes sends an ActionResponse where it looks like it should be a RenderResponse; that and completely grokking how org.apache.portals.bridges.common.PortletResourceURLFactory is really supposed to rewrite URLs (looking at how Apache Jetspeed does it didn't help as much as I'd hoped) should do it.

So, sorry for the false alarm, but given that my instructions involved patching a bunch of stuff (now it involves patching OpenPortal, Wicket and Apache Portal Bridges - it's been a long day of reading source code for multiple portal servers - I expect nobody went off and immediately tried to duplicate this.

For anybody concerned about it, the 80/20 rule still stands :-)


I'm helping my friend Jon on a project involving Portlets. There is a nice integration of OpenPortal (the Sun Java System We Made This Name So Long You Can't Say It Portal Server by any other name) with NetBeans, for one-click deployment. But OpenPortal is missing the Apache Portlet Bridges stuff necessary to use the wicket portlet. So I wrote an implementation last night. It's not beautiful, and is currently tied to Wicket, but it will get you going.

It's a fun project also because Jon and I grew up a mile from each other and learned programming together. Interesting that we're doing today (sitting in front of a computer coding together) exactly what we were doing 28 years ago (except that we were about 12 and it was Z-80 assembly language).

Anyway, he's trying to get some stuff going with Wicket and Portlets. I've got to say I'm not in love with the Portlet spec to say the least - for some light reading check out the WSRP spec (although if a portal server implements it, what it does could be cool). I do like the idea of writing Portlets as simple Wicket Applications - that is sweet.

Anyway, here's what you need to do to make it work. It goes through Wicket to get the filter, which is probably not really what you want, but it does make it usable (if someone knows a way to get this stuff from inside the bowels of OpenPortal and implement it right, let me know).

First you need to get the sources to the Apache Portals Bridges project. Don't get scared - we're just patching one file to fix a bug in the common subproject, and it's simple. Open org.apache.portals.bridges.util.PortletWindowUtils.getPortletWindowId. If you have NetBeans Maven Support, you can just open the project, look up the type and rebuild it.

getPortletWindowId() does something odd: It calls session.getAttribute(PORTLET_WINDOW_ID) and casts the result as a String. Then it puts a Double under that key. Needless to say, if this method is called twice in the same session, it will throw a ClassCastException, which is what we're fixing. Change two lines and add one so it looks like this:

        Object portletWindowId = session.getAttribute(PORTLET_WINDOW_ID);
        if ( portletWindowId == null )
        {
            synchronized (session)
            {
                Double value = new Double(Math.random());
                portletWindowId = value;
                session.setAttribute(PORTLET_WINDOW_ID, value);
                Enumeration names = session.getAttributeNames(PortletSession.APPLICATION_SCOPE);
                while (names.hasMoreElements())
                {
                    String name = (String)names.nextElement();
                    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('?'));
                        session.setAttribute(PORTLET_WINDOW_ID, portletWindowId);
                        break;
                    }                   
                }
            }
        }
        return portletWindowId.toString();

The thing we need now is implementations of org.apache.portals.bridges.common.ServletContextProvider andcom.sun.portal.bridge.PortletResourceURLFactoryImpl for OpenPortal. Not being a portlet expert, this is a bit of a hack, because I'm getting the servlet context from the Wicket Application. Hopefully someone will read this and know where in OpenPortal-source to do this.

Anyway, it's all in the attached project - get that and build it and put it on the classpath of your web application. It contains an interface your Wicket application needs to implement (provides public access to WicketFilter->ServletContext) and a subclass of WicketPortlet [or you can implement IPortletBridge from the attached project on your existing Application if you're already subclassing it - this is the ugly stuff]). Similarly, your WicketApplication subclass needs to implement IWicketApplicationPortletBridge (just makes getWicketFilter() public).

Finally, modify your portlet.xml to point to my subclass of WicketPortlet (I said this was ugly, didn't I?) or your portlet if it now implements my IPortletBridge interface)
<portlet-class>com.sun.portal.bridge.BridgePortlet</portlet-class>

Now you need to add two parameters to your portlet.xml to tell it where the implementations of the two Apache Portals Bridges implementation are:

<init-param>
    <name>ServletContextProvider</name>
    <value>com.sun.portal.bridge.ServletContextProviderImpl</value>
</init-param>
<init-param>
    <name>PortletResourceURLFactory</name>
    <value>com.sun.portal.bridge.PortletResourceURLFactoryImpl</value>
</init-param>

If you've already got your Portlet working on, say, JetSpeed, you won't need to modify the web.xml file for your web application. If you're just getting going, here's mine for completeness:

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
   
    <filter>
        <filter-name>WicketPortlet</filter-name>
        <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
        <init-param>
            <param-name>applicationClassName</param-name>
            <param-value>com.jons.project.JonsWicketApplication</param-value>
        </init-param>
        <init-param>
          <param-name>detectPortletContext</param-name>
          <param-value>true</param-value>
        </init-param>       
       
    </filter>
   
    <filter-mapping>
        <filter-name>WicketPortlet</filter-name>
        <url-pattern>/wicket/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
    </filter-mapping>   
</web-app>

Anyway, it would be nice if this stuff would just work with OpenPortal, but this should work in the until then. I've filed a bug with the fix for commons-bridges, so hopefully that will be fixed soon. Also, perhaps I can add a portal template to NetBeans Wicket Support so you can just do New Project > Web > Wicket Portal Project (although it would be nice to get rid of the hacks first).

The implementation of the bridges interfaces can be downloaded here - it's just an Ant-based NetBeans project. Add it to your web app's classpath and implement the two interfaces described above. A zip of the sources is also available (you need portals-bridges-common, Wicket 1.3.x and the servlet API on the classpath to build it).

Related Topics >>

Comments

Hi, I am implementing a JSR

Hi,

I am implementing a JSR 286 Portlet which uses some spring beans using OpenPortal Container Project.

I need a handle on ServletContext to get Spring ApplicationContext.

[prettifyclass="jive-code jive-java"]ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(&amp;lt;pass ServletContext&amp;gt;); [/prettify]

Even in the JSR 286 Portlet spec no where it mentioned a way to get ServletContext.

Any ideas?

Thanks