Pluto portlet container notes

Pluto is the Apache Software Foundation's reference implementation of the Portlet container API JSR-168 http://jcp.org/aboutJava/communityprocess/final/jsr168/index.html.

This page contains some notes from my attempts to install Pluto, and to compile and run the Pluto tests using Eclipse.


1. Pluto 1.0.1-rc4 installation and test

The Pluto project uses Maven, and comes ready with a project.xml file. However, the Maven configuration dows not work with maven 1.1 or 2.0, so use Maven 1.02:

  1. Install Maven 1.0.2, and update MAVEN_HOME and PATH variables. (See MavenNotes)

  2. Optionally, create a personalized build.properties in your home directory. (This will override anything specified in a project.) Running on Windows, I prefer to not store everything in my "home" directory, so I have used this to use a common directory for my "personalized" maven options (e.g. C:\DEV\Maven). Remember to use '/' or '\\' for filename path separators in the property file. (Again, see MavenNotes)

  3. Download and unzip the Pluto source distribution (start [here http://portals.apache.org/pluto/mirrors.cgi]) into a working directory.

  4. Create a file build.properties in the Pluto base directory, specifying the Tomcat installation directory (or, this may be specified in the home directory build.properties mentioned above.

  5. Run "maven fullDeployment" from the Pluto working copy base directory. First time this is run, it causes many files upon which Pluto depends to be downloaded from a public maven repository. (NOTE: doing this without creating build.properties causes new top-level directories to be created (common, shared, webapps).)
  6. Now start Tomcat.
    • First time I did this, I got errors relating to log4j.jar. I'm not sure of the exact cause, though I suspect a hangover from a previous uPortal installation, which installed its own version of Pluto to be run by Tomcat. In the event, I completely removed Tomcat, deleted all files from the Tomcat installation directory, reinstalled Tomcat and the Tomcat admin package, and re-ran the "maven fullDeployment" from the Pluto source kit base directory. This time, Tomcat started cleanly without log4j problems.

  7. Browse to http://localhost:8080/pluto/portal. This a page is displayed with a number of test options. Select each of the tests in turn.

  8. Somewhere, it says that the "Application Scoped Session Attributes Test" requires the Tomcat conf/server.xml file to me modified with emptySessionPath="true". I edited conf/server.xml to contain:

    • <Connector port="8080"               
                 maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
                 enableLookups="false" redirectPort="8443" acceptCount="100"
                 connectionTimeout="20000" disableUploadTimeout="true" 
                 emptySessionPath="true" />
      But this didn't work either.
  9. Log in to Pluto (or Tomcat?) for the Security mapping test to pass.
  10. Click "Dispatcher Render Parameter Test" in portlet 2 - test passes; then "Simple Parameter Test" in portlet 1 - this test passes, but the portlet 2 display changes to failed. Is this a software bug or a test bug?

2. Compile and run Pluto 1.0.1-rc4 in Eclipse

These instructions presume that Eclipse is has been installed and set up. I am using Eclipse version 3.2, with JDK 1.5.0-04

I found that first running "Maven fullDeployment" (see above) to ensure that all the dependencies were downloaded made it easier to import the project into Eclipse. This may have been an artefact of previous errors, and unnecessary, so YMMV.

  1. In the Pluto source base directory, run "maven eclipse".
    • First time, an error is displayed indicating a plugin cactus-maven cannot be downloaded (or something like that)

      Google for cactus-maven yields: http://www.ibiblio.org/maven/cactus/plugins/. Locate the latest version of the jar file there and download to plugins subdirectory of Maven installation. (cf. appendix in Maven: A developer's notebook [O'Reilly].)

      Now, re-running "maven eclipse" works, downloading a number of additional files in the process.

  2. Start Eclipse, create MAVEN_REPO variable referencing the maven repository directory (Window -> Preferences -> Java -> Build path -> Classpath variables).

  3. Import the project into Eclipse (File -> Import/Export -> Existing projects into workspace).

  4. The project now exists in Eclipse, but the source directories and build path do not appear to be configured. Looking at http://maven.apache.org/reference/plugins/eclipse/properties.html there's reference to a configuration option for the Eclipse workspace; I'm using a non-standard location with my Eclipse, hence edit $USER_HOME/build.properties to include:

    • # Location for Eclipse workspace files
      And try re-building the eclipse project. Still no joy. Multiprojects are different. Googling for "maven eclipse multiproject" turns up some more info. The maven command is:
      maven -Dgoal=eclipse multiproject:goal
      Which creates Eclipse project descriptions for all the sub-projects. Make sure that any .project and .classpath files left in the Pluto project root directory are removed. Now start Eclipse and import the projects (note: there are 5-6 of them) from the Pluto directory tree; there should be 5 of them.
  5. Sub-project "pluto-descriptors", failed with this error: "The project was not built since its build path is incomplete. Cannot find the class file for org.apache.xml.serialize.OutputFormat. Fix the build path then try building this project". This problem was fixed by including "C:\Program Files\Java\jdk1.5.0_04\jre\lib\endorsed\XerxesImpl.jar" in the Java build path for this eclipse sub-project. (Project -> Properties -> Java build path -> L:ibraries -> Add external jars)

  6. Now I try to run unit tests under Eclipse. The only one that shows any sign of working is pluto-descriptors, which reports a number of failures (as well as some successes, so there's some progress). I think one problem may be a failure to read portlet.xml, possibly due to an incorrect working directory, but I couldn't be sure.

    • Adding src/conf to the pluto-descriptors source path in Eclipse allows that test to pass. It turns out the problem was the castor mapping files not being on the classpath. The mapping files are apparently used for mapping Java objects when marshalling/unmarshalling, and would appear to be:
  7. I also needed to add $MAVEN_REPO/junit/jars/junit-3.8.1.jar to Java build path for modules "testuite" and "pluto-deploy", and now get "No tests found" when attempting to run the JUnit tests. This is looking like a dead-end.

Subsequently, in email discussion with Pluto developers, I found that the only unit tests in the Pluto source kit are those in package pluto-descriptors, so the above results are exactly what should happen.

3. Pluto 1.1 installation and test

My goal is to use Pluto and its test code to create a test environment for WSRP4J. The Pluto developers recommended that I use Pluto 1.1 for this purpose, since it has been refactored to make the code easier to follow. (I certainly found the Pluto 1.0 code seemed rather hard to follow in places.)

But Pluto 1.1 is new code, and as I write I am still struggling to get it to install on my system. Pluto 1.1 also uses Maven 2 for build and installation, so this must also be installed. Note that alpha- or beta- releases of Maven 2.0 don't work: the final release is required.

2005-11003: I have succeeded in getting Pluto 1.1 to install and run (with a few acknowledged errors in the test suite). I have encountered problems using Tomcat 5.5.12, so for not I'm using Tomcat 5.5.9, which seems to work OK. Here is the procedure I used for a clean install from source:


Now to build and install Pluto:

Maven version: 2.0 }}}

$> mvn install $> mvn pluto:install -DinstallDir="C:/Dev/Apache Software Foundation/Tomcat 5.5.9" }}} The directory in the last command should be replaced with the actual Tomcat installation location. (Note: at the time of writing, there is an error in the cd command in the instructions at http://portals.apache.org/pluto/1.1/getting-started.html).

This completes the installation of Pluto 1.1.

4. Compile and run Pluto 1.1 in Eclipse

These notes made using Eclipse 3.2 (development stream stable release M2) on Windows XP with JDK 1.5.0_04.

There is a "Guide to using Eclipse with Maven 2.x" at http://maven.apache.org/guides/mini/guide-ide-eclipse.html.

$> mvn eclipse:eclipse }}}

D:\Work\OxfordCS\Pluto-1.1\maven-pluto-plugin overlaps the workspace location: D:\Work\OxfordCS }}}

4.1. Updating Pluto 1.1 Eclipse projects

Sometimes, the project structure or details may change between Pluto source releases. To obtain the latest version, and get it to build in eclipse, perform the following:

$> mvn install $> mvn pluto:install -DinstallDir="C:/Dev/Apache Software Foundation/Tomcat 5.5.9" }}}


Updating the Pluto software may mean that the configuration files change. My unit tests use a selective copy of the Pluto driver/container/portlet configuration data, and it may be necessary to update this before the tests can be successfully run.

[At the time of writing, the current Pluto source revision (svn:357031) doesn't deploy successfully on Tomcat. I am hoping for a fix or other clues about how to resolve this problem.]

5. Request flows in Pluto 1.1

The details here are based on the test portal driver and test suite provided with the Pluto 1.1 distribution, and installed by the instructions given above, but my hope is that the general elements of the request flow are more generally applicable.

<jsp:forward page="template.jsp"/> }}}


</TABLE> }}}

</render-config> }}} TO BE CONFIRMED -- which suggests that the content rendered by <pluto:render> is obtained from portlets (servlets?) named TestPortlet1 and TestPortlet2.

List dds = appDD.getPortlets();

PortletDD dd = null; for (int i = 0; i < dds.size(); i++) {

} }}}

</portlet> }}}


6. Creating Pluto 1.1 unit tests

My goal in what follows is to create a number of unit tests that drive test cases in the Pluto test portlet in the context of JUnit test rather than via HTTP from a browser. As well as avoiding the overhead of running via a web application server, this also makes it easier to trace the portal and portlet code using a debugger such as that which is part of the Eclipse IDE.

My strategy has been to use ServletUnit, a component of HttpUnit, to replace the Tomcat servlet engine, and to use simulated web requests scripted and tested as JUnit test cases that call the simulated container.

Unfortunately, HttpUnit ships with a version of servletapi.jar that is not compatible with Pluto and/or Tomcat 5.5. (As far as I can tell, HttpUnit is using the Servlet API version 2.2 or 2.3, but Tomcat 5.5 uses servlet API version 2.4 which, among other things, has the JSP 2.0 API separated from the servlet API). Running the Pluto portal driver with the Tomcat 5.5 JSP libraries causes a java "Method not found" error: class javax.servlet.jsp.tagext.TagAttributeInfo has an additional constructor in JSP 2.0 that is used by the Tomcat JSP compiler. For now, I have overcome the problem by dint of some surgery on the servlet.jar file that is part of the Httpunit distribution, removing all the JSP classes so that they can be picked up from a separate jar file that implements the JSP 2.0 API ($M2_REPO/jspapi/jsp-api/2.0/jsp-api-2.0.jar).

I made another change to the ServletUnit code, in file /httpunit/src/com/meterware/servletunit/ServletRunner.java, adding a new constructor for the ServletRunner class, thus:

     * Constructor which expects an input stream containing the web.xml for the application,
     * a File indicating a context directory, and a string indicating a context path.
     * [[[GK]]] Added to allow circumvention of file: URI creation bug in javax.xml.parser
     * @param webXml the web.xml input stream
     * @param contextDir a file object corresponding to the context directory
     * @param contextPath the context path
     * TODO: refactor other constructors to use this and eliminate duplicate code
    public ServletRunner( InputStream webXML, File contextDir, String contextPath ) 
    throws IOException, SAXException 
        _application = new WebApplication( HttpUnitUtils.newParser().parse( new InputSource( webXML ) ),
                        contextDir, contextPath );
        completeInitialization( contextPath );

This constructor allows me to specify the working directory for the servlet code (contextDir) separately from the context URI (contextPath). Within the test harness driver code Testcase class instance, the ServletRunner instance is created thus:

    protected void setUp() throws Exception {
        File webxmlfile = new File("src/test/resource/WEB-INF/web.xml");
        File contextfile = new File("src/test/resource");
        String contextpath = "/pluto";
        InputStream webxmlstr = new FileInputStream(webxmlfile);
        runner = new ServletRunner(webxmlstr, contextfile, contextpath);
        client = runner.newClient();

These changes allow the Pluto portal driver to initialize itself in the ServletUnit environment, but are not enough to allow invocation of a portlet. Portlet invocation initially appears to work, but when the response is analyzed, the rendered data from the portlet is replaced by a Java exception and stack trace. (Data rendered by the portal itself is fine: it is just the portlet-rendering that is not correct. The cause for this appears to be that Servletunit does not support multiple applications, and when the portal driver attempt to retrieve a context for the portlet servlet, it receives a null pointer instead (see ServletUnitServletContext.getServletContext). Also, there is some additional configuration data in webapps/testuite/WEB-INF/web.xml that maps portlet invoker context paths to the testsuite servlets; but it is not obvious how to configure Servletunit to handle multiple wab application paths and configurations.

I observe that the ServletUnit implementation of ServletContext uses a WebApplication value to determine the location of a resource for getResourceAsStream, suggeting that multiple WebApplications must be created, and a common directory of path->ServletContext values be maintained in order to serve different servlets from different context directories. I created a static Hashtable value in WebApplication could serve this purpose, and modified ServletUnitServletContext.getServletContext to access the corresponding WebApplication, and then use this map returning a context value.

With this change, the application ran a good deal further, but the portlet code running in a separate servlet is unable to access the tag library code portlet.tld. I am unable to see how the location of the TLD files should be passed to the portlet, so I coped them into the test suite web application area (testsuite/WEB-INF/tld/), and modified the test suite configuration file (testsuite/WEB-INF/web.xml) to reflect this location, thus:

<!-- Copied from pluto/WEB-INF/web.xml, together with tld directory -->

With these changes, I am able to render the portlet test cases in the unit test environment, and to test the results thus generated.

-- GrahamKlyne 2005-11-03 11:52:40