Archive for June, 2006

What’s in your classpath?

Tuesday, June 20th, 2006

On the mojo developper list, someone was searching for a way to find information about the jars available to a particular classloader. In particular, as all jars produced by maven contain a pom.properties file, it would be useful for debugging purposes to be able to fetch all these properties files.

This little blog entry presents JarInfo, a little class to help you retrieve this information. For the impatient, here’s a screenshot of the resulting information displayed in a JSP.

problem and solution

We first need to identify all jars available to the classloader. We cannot rely on the JVM classpath, available through the java.class.path System properties. While in very simple cases this classpath may contain what you are looking for, a more complex application, especially one involving some sort of container, will hide the real set of jars used by your application behind a classloader hierarchy.

Some particular ClassLoader implementations let you retrieve the information directly. An example is the getURLs() method in the URLClassLoader class. But of course, there’s no similar method in the ClassLoader abstract class: ClassLoaders have been designed with a more generic idea in mind! So we are going to need a little trick to find a generic solution.

The initial idea of the mojo developer was to use the ClassLoader#getResources() call to try to locate all pom.properties files. There are 2 major issues with that:

  • the location of a pom.properties in a jar file is project dependent. Maven currently stores them under META-INF/maven/groupId/artifactId/pom.properties
  • not all Jar files have a pom.properties file, so we will have limited classpath information

So we need to find another way. Fortunately there’s another file that fulfills these two criteria: the META-INF/MANIFEST.MF.

So if we ask the ClassLoader to list the Manifest files it knows, we will obtain an Enumeration of URLs. For all the manifest files located under a jar file, the URLs when turned into a String will have the following format:
jar:${jarurl}!/META-INF/MANIFEST.MF. Easy enough to parse to obtain the URL of the jar file itself.

So here we go:

public static Collection findJarUrls( ClassLoader classLoader )
    throws java.io.IOException
{
    java.util.Enumeration e = classLoader.getResources( MANIFEST_PATH );
    List jarUrls = new ArrayList();
    for ( ; e.hasMoreElements(); )
    {
        String path = e.nextElement().toString();
        if ( path.startsWith( "jar:" ) )
        {
            String jarPath = path.substring( 4, path.indexOf( "!" ) );
            jarUrls.add( new URL( jarPath ) );
        }
    }
    return jarUrls;
}

public static Collection findJarUrls()
    throws java.io.IOException
{
    return findJarUrls( Thread.currentThread().getContextClassLoader() );
}

Now that we have a Jar url, we need to process the Jar. The SDK already contains some utility classes JarInputStream and JarFile that can help us in this task. But it lacks some features for our needs, in particular the ability to search the contents of the jar file. So let’s create a class to wrap all this information.

class JarInfo
{
    private URL url;

    public JarInfo( URL url )
        throws URISyntaxException
    {
        this.url = url;
        this.uri = url.toURI();
    }

    ...

    private JarFile getJarFile()
        throws IOException, SecurityException
    {
        return new JarFile( new File( uri ) );
    }

    public Collection findResources( String resourceNamePattern )
        throws ...
    {
        ...
    }

}

Now, we have to retrieve information from these jars, including the manifest contents and why not, the pom.properties file. A possible way to achieve this:

public Collection findResources( String resourceNamePattern )
    throws IOException, SecurityException, URISyntaxException
{
    URI str = url.toURI();
    JarFile file = new JarFile( new File( str ) );

    List result = new ArrayList();
    Enumeration e = file.entries();
    while ( e.hasMoreElements() )
    {
        JarEntry jarEntry = (JarEntry) e.nextElement();
        if ( jarEntry.getName().matches( resourceNamePattern ) )
        {
            result.add( jarEntry.getName() );
        }
    }
    return result;
}

Now given a JarEntry, all you need to do is getName() to get the path inside the jar.

Finally if ever you need to load a custom resource from a particular jar file, you may want to:

public InputStream getResourceAsStream( String resourcePath )
    throws IOException
{
    JarFile jarFile = getJarFile();
    ZipEntry ze = jarFile.getEntry( resourcePath );
    return jarFile.getInputStream( ze );
}

The jar is currently available at in my maven snapshot repository, but I will put the code online as soon as I get some time. In the mean time, browse the XRef code.

See also:

JWich

Google spreadsheets limitations

Friday, June 9th, 2006

I’ve tried Google spreadsheets and unfortunately, right now, the import functionality doesn’t let me test the tool.

I’ve got 2-3 spreadsheets that I would love to put online. One is my freelance accounting spreadsheet. That way I could share it with my accountant. No need to go and see her :) Second a couple of administrative spreadsheets for various projects. But when I tried to import them, one failed “spreadsheet couldn’t be imported” and another “file is too large”. Go figure. (thos issues and other reported)
On the other side, the quick tests I’ve made on small spreadsheets I created myself hold their promises. I guess I just have to try again in some weeks !
Now if only we could have templates, better desktop and gmail integration and why not some online disk space, I would be sold.

update: after some tweaking, I’ve managed to upload properly. I forced the deletion of everything that was around the used cells of the spreadsheets, and now the server happily imports them.

Rich web client and market penetration. Flash 8

Monday, June 5th, 2006

Macromedia announces flash v9 for Linux (expected sometimes in 2007).

At the same time, support for Flash v8 appears to be at around 70% market penetration while flash 7 reaches 95%.

Yet more and more sites are v8 only. I am not a flash addict and usually avoid flash sites (because they tend to overuse flash advertising that pop up under my nose), but I wasn’t able to play Sony/Google Da Vinci’s quest nor to follow the official Roland Garros/IBM web site.

Can someone tell me what flash v8 gives to the developper that warrants to lose a quarter of your users (including all Linux ones)? Is it too costly to support both v7 and v8 from a single code base?
BTW, didn’t IBM decide to switch their desktop to Linux? I guess that once they do that they will put the pressure on Adobe to properly support Linux. Or they will help gnash.