Author: janb

  • Using Java Server Faces, JSTL and Jetty

    Until now, Jetty has not provided Java Server Pages Standard Tag Library nor Java Server Faces support with the container. Webapps wishing to use either of these facilities have had to explicitly include the necessary jars in their webapps.

    With the rc1 version of Jetty 6, the JSTL1.0 and JSTL1.1 libraries will be automatically on the classpath for webapps using JSP2.1. This means webapp developers will be able to simply use these tags in their jsps. These JSTL goodies will also be available for Jetty maven plugin users too.

    Apart from simplified development, webapps will now be more transportable between web containers supporting servlet2.5 (although why would you ever want to move away from Jetty 🙂 ). Also, it will facilitate moving the webapp to a full-blown JavaEE container should it become necessary.

    Also from rc1, we have put the wiring in place to support container-wide availability of Java Server Faces implementations such as MyFaces or the JSF RI. We will not be distributing a JSF impl with Jetty, but you will be able to install your favourite into Jetty’s lib/ext directory (which is the location for jars to be shared between all deployed webapps) and follow the simple instructions I’ve put on the wiki:

    My Faces instructions or JSF RI instructions

    Keep checking the download page, as rc1 is on it’s way.

  • Jetty and Glassfish's JSP2.1 implementation

    I’ve been looking at Glassfish quite a bit lately, and liking what I see.
    In particular, I’ve been looking closely at the JSP 2.1 implementation. It appears to be robust and well-tested.

    My interest was prompted by the number of bug reports we were getting on the Jetty mailing lists about the JSP 2.1 implementation we were using, which was Jasper from Apache. For whatever reason, there seems to be little activity on this particular project.

    Glassfish, however, has an active community of developers who were welcoming of my initial enquiries about using it in Jetty and who have been very open to collaboration.

    It’s worth noting that Glassfish’s jsp implementation is based on that from Apache, and that some of the key developers of previous Apache Jasper versions are now working mainly on Glassfish.

    I was able to relatively quickly get a build of Jetty going using Glassfish’s Jasper. Initial testing has been very positive, so much so that we now use it exclusively as Jetty’s JSP 2.1 implementation.

    So far, this is available only in SVN head (checkout revision 782), however, we plan to do an rc1 release in the next few days, so stay tuned.

    Thanks to Jan Luehe from Glassfish for all the help with the integration, who I believe has blogged
    about the integration too.

  • Extending the Maven Plugin Classpath at Runtime

    This may not be too revolutionary, but I’ve spent enough time googling and asking questions on the Maven lists to believe that there isn’t a lot of information out there about topic so I thought I’d document it in a blog. Apologies to the Maven guys if this isn’t the best way of going about this (I believe Jason mentioned something about improvements to the Maven Embedder), but I needed a solution right now.
    The situation was that I wanted to be able to decide at runtime which jars to put onto the execution classpath for the Jetty6 Maven Plugin. The decision is based on the runtime environment: if the user is running with < 1.5 JVM, then I need to be able to download and use the JSP 2.0 jars. If, however, the user is running with a 1.5 JVM, then the JSP 2.1 jars should be used (as these mandate JDK 1.5).
    Rather than having to hard-code into my plugin a list of jars and their transitive dependencies for each version of JSP, I created one submodule for each JSP variant and listed all dependencies in the module’s pom.xml.
    This reduced the problem to downloading and transitively resolving a pom on-the-fly, then getting all of the resolved artifacts on the plugin’s execution classpath.

    Runtime Downloading and Transitive Resolution of a pom

    I used the Maven tools for manipulating artifacts. You need to put some configuration parameter declarations into your plugin to gather the necessary factories etc from the runtime environment to drive the tools. The ones I used were:

    /**
    * @component
    */
    private ArtifactResolver artifactResolver;
    /**
    *
    * @component
    */
    private ArtifactFactory artifactFactory;
    /**
    *
    * @component
    */
    private ArtifactMetadataSource metadataSource;
    /**
    *
    * @parameter expression="${localRepository}"
    */
    private ArtifactRepository localRepository;
    /**
    *
    * @parameter expression="${project.remoteArtifactRepositories}"
    */
    private List remoteRepositories;

    Then, it is a matter of downloading the pom, getting its dependencies and transitively resolving them. Here’s a snippet of the code I used to do the job generically:

    public Set transitivelyResolvePomDependencies (MavenProjectBuilder projectBuilder,
    String groupId, String artifactId,
    String versionId, boolean resolveProjectArtifact)
    throws MalformedURLException, ProjectBuildingException,
    InvalidDependencyVersionException, ArtifactResolutionException, ArtifactNotFoundException
    {
    //get the pom as an Artifact
    Artifact pomArtifact = getPomArtifact(groupId, artifactId, versionId);
    //load the pom as a MavenProject
    MavenProject project = loadPomAsProject(projectBuilder, pomArtifact);
    //get all of the dependencies for the project
    List dependencies = project.getDependencies();
    //make Artifacts of all the dependencies
    Set dependencyArtifacts = MavenMetadataSource.createArtifacts( artifactFactory, dependencies, null, null, null );
    //not forgetting the Artifact of the project itself
    dependencyArtifacts.add(project.getArtifact());
    List listeners = Collections.EMPTY_LIST;
    if (PluginLog.getLog().isDebugEnabled())
    {
    listeners = new ArrayList();
    listeners.add(new RuntimeResolutionListener());
    }
    //resolve all dependencies transitively to obtain a comprehensive list of jars
    ArtifactResolutionResult result =
    artifactResolver.resolveTransitively(dependencyArtifacts, pomArtifact,
    Collections.EMPTY_MAP,
    localRepository, remoteRepositories,
    metadataSource, null, listeners);
    return result.getArtifacts();
    }

    Now we can make some environment-based decisions on which pom use to extract the artifacts we want:

    //if we're running in a < 1.5 jvm
    Artifacts artifacts =
    resolver.transitivelyResolvePomDependencies(projectBuilder,
    "org.mortbay.jetty", "jsp-2.0", "6.0-SNAPSHOT", true);
    //else
    Artifacts artifacts =
    resolver.transitivelyResolvePomDependencies(projectBuilder,
    "org.mortbay.jetty", "jsp-2.1", "6.0-SNAPSHOT", true);

    Having got the artifacts, now we need to place them on the execution classpath.

    Runtime Maven Classpath Manipulation

    This is the bit I found really hair-raising. I’m not convinced it’s a bullet-proof solution, but all testing to date seems to indicate its working fine.
    Taking the Artifacts we got from the on-the-fly downloaded pom above, we need to put these into a Classloader and also arrange for the existing ContextClassLoader to be it’s parent (so we can resolve classes that are already on the plugin’s classpath).
    The first solution that springs to mind is to put the urls of the download jars into a URLClassLoader and make the current ContextClassLoader it’s parent like this:

    URL[] urls = new URL[artifacts.size()];
    Iterator itor = runtimeArtifacts.iterator();
    int i = 0;
    while (itor.hasNext())
    urls[i++] = ((Artifact)itor.next()).getFile().toURL();
    URLClassLoader cl = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());
    Thread.currentThread().setContextClassLoader(cl);

    However, after a lot of experimentation, it seems that this just simply does not work: the parent class loader does not seem able to correctly resolve classes and resource when delegated to from the URLClassLoader. The parent class loader is an instance of a ClassWorlds ClassLoader set up by the plugin execution environment.
    Experimenting further, I discovered it is possible to create a new ClassWorlds classloading hierarchy, injecting the jars that we downloaded earlier, and linking the existing (ClassWorlds) classloader as the parent of the new hierarchy. It looks like this:

    //create a new classloading space
    ClassWorld world = new ClassWorld();
    //use the existing ContextClassLoader in a realm of the classloading space
    ClassRealm realm = world.newRealm("plugin.jetty.container", Thread.currentThread().getContextClassLoader());
    //create another realm for just the jars we have downloaded on-the-fly and make
    //sure it is in a child-parent relationship with the current ContextClassLoader
    ClassRealm jspRealm = realm.createChildRealm("jsp");
    //add all the jars we just downloaded to the new child realm
    Iterator itor = artifacts.iterator();
    while (itor.hasNext())
    jspRealm.addConstituent(((Artifact)itor.next()).getFile().toURL();
    //make the child realm the ContextClassLoader
    Thread.currentThread().setContextClassLoader(jspRealm.getClassLoader());

    When used this way, the parent ClassWorlds classloader is able to correctly resolve classes and resources. The Jetty6 Maven Plugin is therefore able to automatically provide the correct JSP version at runtime without necessitating any user configuration.