Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disappearing jar entry when loading using SPI

Tags:

java

So in my application I have a plugin system that I've written using SPI (service provider interface), so I have a jar file called scripts.jar that I keep somewhere (note: it's not on the classpath), then I load a script from it using this method:

/**
 * Loads a script from the given name, regardless of case.
 * @param name script name
 * @return the loaded Script
 */
public static Script loadScript(Client c, String name) {
    Script script = null;
    try {
        URLClassLoader loader = new URLClassLoader(new URL[]{new File(Config.CONF_DIR, "scripts.jar").toURI().toURL()});
        ServiceLoader serviceLoader = ServiceLoader.load(Script.class, loader);
        serviceLoader.reload();
        Iterator<Script> scripts = serviceLoader.iterator();
        while(scripts.hasNext()) {
            Script cur = scripts.next();
            if(cur.getClass().getSimpleName().equalsIgnoreCase(name)) {
                script = cur;
                break;
            }
        }
    } catch(Exception e) {
        log.warn("Error loading script "+name, e);
    }
    return script;
}

Now, this works fantastically when I start my program. I can load any script in the jar with ease.

The problem arises when I reload the script - i.e. change the file, and overwrite scripts.jar, then try to load any script. I get this error:

    Exception in thread "anjin_san:test" java.util.ServiceConfigurationError: org.stork.script.Script: Error reading configuration file
        at java.util.ServiceLoader.fail(ServiceLoader.java:207)
        at java.util.ServiceLoader.parse(ServiceLoader.java:284)
        at java.util.ServiceLoader.access$200(ServiceLoader.java:164)
        at java.util.ServiceLoader$LazyIterator.hasNext(ServiceLoader.java:332)
        at java.util.ServiceLoader$1.hasNext(ServiceLoader.java:415)
        at org.stork.script.Script.loadScript(Script.java:408)
        at org.stork.Client$2.run(Client.java:95)
        at java.lang.Thread.run(Thread.java:619)
Caused by: java.io.FileNotFoundException: JAR entry META-INF/services/org.stork.script.Script not found in C:\Users\stork\Documents\bot-sama\etc\scripts.jar
        at sun.net.www.protocol.jar.JarURLConnection.connect(JarURLConnection.java:122)
        at sun.net.www.protocol.jar.JarURLConnection.getInputStream(JarURLConnection.java:132)
        at java.net.URL.openStream(URL.java:1010)
        at java.util.ServiceLoader.parse(ServiceLoader.java:279)
        ... 6 more

So it says the jar entry can't be found, but I can check it's there fairly easily:

    C:\Users\stork\Documents\bot-sama\etc>jar tvf scripts.jar
     0 Thu Sep 03 16:58:00 BST 2009 META-INF/
   102 Thu Sep 03 16:57:58 BST 2009 META-INF/MANIFEST.MF
     0 Thu Sep 03 16:35:20 BST 2009 META-INF/services/
   482 Thu Sep 03 16:57:52 BST 2009 META-INF/services/org.stork.script.Script
   ...

And it's the right size, too. The problem happens when I try to load any script, not just the one that was modified.

I'm thinking this might be a bug, any input?

like image 264
stork Avatar asked Jun 10 '26 12:06

stork


1 Answers

Check the file permissions. When the original JAR is placed there with the rest of the application, it is readable by the program. Perhaps its being updated by a different user—without granting read permissions to other users—and the program can no longer open the file.

I can't tell which version of Windows you are running, but the security properties dialog or, on XP Home, the cacls command should detail the permissions before and after.


Update: Re-reading the ServiceLoader documentation, I noticed an instance method, reload. Although the code creates a new ServiceLoader each time it's needed, it may be that the ServiceLoader class is keeping a cache that is used by all instances. Rather than creating new loaders, try keeping one around, and using the reload method to check for new scripts.

like image 157
erickson Avatar answered Jun 12 '26 03:06

erickson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!