views:

92

answers:

2

I went through the JAR specification document and found that an in-memory hashtable is created using INDEX.LST file to speed up the class file look up process.

If any one can answer my following questions -

  1. When is the hashtable constructed? When the application loads or when the request comes for loading the applet?

  2. Since all the classes are already part of the archive, why should one get InvalidJarIndexException. How can indexes become invalid? e.g. In my case I get InvalidJarIndexException when I use index=true along with indexjars in my ant build but I do not see any exceptions when indexjars are not used.

  3. How should I go about resolving the InvalidJarIndexException if I want to stick with indexing?

  4. Role of java browser plugin in downloading jar files?

A: 

I've never came across this problem, so I'm unfraid I won't help you much, but I'll do my best to lighten things up.

  1. It's constructed when the class loader loads: the class loader itself looks for an index.list file and use it if it's available.

  2. You can get this exception if the index.list file is corrupted, because if the class loader has found an index file, it won't look in the classpath anymore to load a class: it will only use the index. Here, it seems it can't even load it, so it throws InvalidJarIndexException

  3. Try to manually generate the index.list with the jar tool, using the -i option. If it works, then it's an ant issue: compare the generated files to investigate. If it still doesn't work, inspect the index.list file manually (bad encoding ? truncated long paths ? missing classes ?).

  4. Irrelevant. The class loading process is done by the class loader. The way the jar file is actually run doesn't matter.

Edit to add Devil Jin's comment:

The indexing in ant had bugs earlier. You need to use versions 1.6 or after to get indexing working. To get a jar indexed you have to set index=true along with specifying jar files within indexjars tag. ant.apache.org/manual/Tasks/jar.html#indexjars

Samuel_xL
I did the `diff` between two jar files having `index.lst` where one of them was working and other was throwing exception and I did not observe any differences. The `index.lst` file appears to be simple text file where the jar names and the inner packages are listed.I have no clear observation when does actually this exception happens or what causes the index to be invalidatedThe index.lst file is generated successfully using `ant`. I do not see any `ant` issue here as
Devil Jin
I also tried my luck constructing a sample application which loads three jars as part of the applet. I fiddled around with the jars, modifying them updating them using ant but with no success in re-creating the exception
Devil Jin
I also index most of my Jar files but it didn't work correctly with Ant so my indexing of the Jar in Ant is:<exec executable="c:/java/jdk/jdk6/bin/jar.exe" dir="dist" failonerror="true"> <arg value="-i" /> <arg value="${app.name}.jar" /></exec>
Anthony
The indexing in ant had bugs earlier. You need to use versions 1.6 or after to get indexing working. To get a jar indexed you have to set `index=true` along with specifying jar files within `<indexjars>` tag.http://ant.apache.org/manual/Tasks/jar.html#indexjars
Devil Jin
A: 

JarIndex seems to be useful for applets and networking. It can prevent from loading unnecessary archives.

Here we have a so called root jar which includes an INDEX.LIST file and that file includes a mapping from class to library. The classloader will read the file, create an internal hashtable and use this table to determine, where a class can be found. If the library has not been loaded yet, then it will load it to load the class. Otherwise it would have to load all libraries at once just to resolve a single class (because a class name never gives any clue where a class can be found)

Once the classloader finds such an index, it trusts that information and will complain with an exception if the information is not true. Say the index tells the classloader that com.example.MyClass can be found inside http://example.com/a.jar, then it will download (if not already done) the jar and only look inside this library. If there's no such class it will not look in different jars (or even download additional jars) but will have a hump with you (and throw an exception).

If you encounter such an exception you might be pretty lost. The problem (corrupt INDEX.LIST file) can't be fixed on the consumers side. But because the classloader expects the INDEX.LIST file in the first jar on the classpath, changing the order of libraries in the classpath expression could solve such a problem by disabling the indexer feature.


Further Reading


Working Example with ant

I created two very simple classes to print Hello world:

package test;

public class Hello {
    public static void main(String[] args) {
        System.out.println(HelloTextFactory.createResponse());
    }
}

and

package test;

public class HelloTextFactory {
    public static String createResponse() {
        return "Hello world";
    }
}

and an ant file (build.xml) to create the archives:

<project name="test">
    <target name="jar" description="description">
        <delete file="main.jar" />
        <delete file="factory.jar" />

        <jar destfile="factory.jar" includes="test/HelloTextFactory.class" basedir="bin" />
        <jar destfile="main.jar" includes="test/Hello.class" basedir="bin" index="true">
            <indexjars>
                <fileset dir="." id="jars">
                    <include name="factory.jar" />
                </fileset>
            </indexjars>
            <manifest>
                <attribute name="Main-Class" value="test.Hello" />
                <attribute name="Class-Path" value="factory.jar" />
            </manifest>
        </jar>
    </target>
</project>

This build file assumes that the classes have been compiled into the bin folder before running the script.

Running the build script creates two jars, main.jar contains an index and java -jar main.jar runs successfully. Then I moved the second class into a different package and started the build again. And again, it created a working application.

During experimentation I realized that

  • it is necessary to force creation of all jars, especially the main jar. If ant rebuilds factory.jar the index will not be updated and may be invalid. That's why I added the delete tasks.
  • main.jar has to be created after all other jars are created.
Andreas_D
My question is about `INDEX.LST`. From the name it appears that the file stores indexes but if you open the file it stores the jar file name and the packages contained.If the hash table is constructed during loading, the indexes should be valid. When does the index become invalid then? and Why?
Devil Jin
The filename is `INDEX.LIST` (at least according to the provided doc). The index will become invalid if the content of a lib changes and the changes are not reflected in the INDEX file. Like you move classes from one lib to another. Then the classloader won't be able to find the classes and throw an exception.
Andreas_D
I thought the same. When I first encountered the exception I looked into jar file. The class file did exist there, then I looked in to the INDEX.LST file and did not find any thing missing thereI could not make out where did the indexes went wrong. Same jar file worked when I removed indexing from it.I also created sample application and tried to re-create the exception by updating the jar files with signatures. So far unsuccessful
Devil Jin
@Devil Jin - there is one known issue with JarIndex, I added a link to my answer. Please check, if you're in the same situation.
Andreas_D
I am using ant to create jar files. I am not sure if ant internally calls JarIndex.merge().I have still to verify if pack200 --repack --segment-limit=-1 updates the jar files so that the indexes are invalid.
Devil Jin
... much work, no upvote, no bounty. bad luck ;-(
Andreas_D