Wednesday, November 30, 2005

JSR 168 Portlet Notes

* These are written to be used with uPortal 2.3.3 or so, but they should be general.

* I'm taking this as the directory structure
src---build.xml [ant file for building, deploying, and warring the portlet
|
--external_libs [pluto/portlet jar files not to be included in the war]
|
--java [portlet source code]
|
--webapp [the deploy directory that gets warred up at the end]

The webapp directory has this structure:
webapp---images
|
--jsp [jsp pages loaded by the portlet]
|
--WEB-INF [classes, lib, web.xml, portlet.xml]

* If using ant, make sure you read the task documents carefully. The directory
structure it creates may not match your source directory--you have to specify lib and classes
explicily.

* I wasted a lot of time trying to deploy a simple portlet into uPortal and finally
found that my web.xml file had a problem. I originally copied this over from the
testsuite's web.xml file:


Junk Testsuite

tomcat



The uPortal tool "ant deployPortletApp" constantly gave "Exception in thread "main" java.lang.StackOverflowError".
This is in the Deployer.java file from uPortal, in the prepareWebArchive() method. The lines

WebApplicationUnmarshaller wau = new WebApplicationUnmarshaller();
wau.init(new FileInputStream(webXml), webModule);

were the source of the error--probably this wraps some castor-like thing that processes the xml. I don't know why it
failed for my test portlet but worked for the testsuite. Anyway, I changed this to


Junk Testsuite


and it worked like a charm.

* I'm doing everything below as uPortal's "admin" user. I don't know or want to learn the uPortal channel control
permissions yet.

* After deploying the portlet, I can add it using the channel manager. Had problems because I did not read the
(uPortal portlet) instructions carefully as usual. You must make sure that you give the channel the correct Portlet
Definition ID. If you don't you will get errors (not repeated here) telling you that uPortal couldn't find
that ID. Just make sure your ID is [webapp_name].[portlet_name] where [webapp_name] is the name of the webapp
that contains the portlet (same name as the .war) and [portlet_name] is defined in the portlet's portlet.xml file.

* And my portlet content did not show up, although I got no errors. After futzing around for a while, I realized I had made
the dumb mistake of omitting the call to the request dispatcher's include() method. Along the way, I managed to learn that
the portlet context is indeed for the webapp that runs it (not uPortal, but "testsuite" or whatever webapp), so the
requestdispatcher should be initialized with paths relative to the specific webapp. In other words, if you want to
load webapps/junk/junk.jsp, you use context.getRequestDispatcher("junk.jsp").

* After a couple of times recreating the war and redeploying it with uPortal's build target, I realized this procedure could
be shortened by just recompiling the portlet directly into the deployment location (ie the
tomcat webapp) and restarting the webserver to reload the classes rather than redeploying the portlet through uPortal
(which introduces uncertainties). This worked fine.

* System.out.println's indicate that the portlet runs doDispatch() after running init() and before doView()--more precisely, doView
is not called if doDispatch is there. If I remove doDispatch(), then doView() is called. Tra-la.

* My portlet definition xml file never shows up in uPortal's WEB-INF/classes/properties/chanpub directory. May have to
do this by hand, but I don't yet see that this is a problem.

* Another flakiness: if you delete a channel, it will still appear in the list of available channels until you log out.
This may be an update issue--if I wait long enough, the system configuration will update itself. But I did not follow up
on this--it is quicker to just logout and login.

* A useful debugging note: load your jsp pages from their deployment directories first to make sure they are debugged before
loading them through portlets. This only gets you so far, but at least it can catch simple compiler errors. Your portlet variables
(from the pluto definedObjects tag) will have null values, so the page won't work in standalone mode outside the container (ie by
loading directly in the browser).

* If you have mistakes in your JSP content (things that prevent it from compiling, noted above) you get
Channel ID: 94
Message: IChannelRenderer.completeRendering() threw
Error type: Channel failed to render (code 1)
Problem type:
Error message null [based on exception: null]

* One issue that will be important (and I think is undefined) is portlet caching rules. That is, how differently do different
containers handle caching? This is important for linked content that makes heavy use of forms. You don't want, for example,
to repost form parameters everytime you reload a tab. Likewise you don't want to lose state just by clicking on different tabs
before returning to your original portlet.

* Interestingly, JSP session variables and cookies loaded by portlets from different webapps have the same ID and the same
session cookie. But session attributes are different! Session attributes put into the session in one jsp page can be retrieved
by other JSP pages loaded/managed by the same portlet, but they can't be retrieved by JSP pages running in other webapps that
are managed by other portlets. Not unexpected, but it was unexpected that the session variables would think that they are the same.

No comments: