tags:

views:

220

answers:

1

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?

+2  A: 
erickson
@erickson: File permissions all seem fine, cacls reports the file permissions to be the same both times too.I'm also not sure I can reuse my `ServiceLoader`, I'm creating a new one each time I reload a script since I have a new ClassLoader object. I did try calling `reload()` before and after (and both) and it didn't fix the problem.
stork
Relevant: http://www.docjar.com/html/api/sun/net/www/protocol/jar/JarURLConnection.java.htmlAm thinking this might be a problem with caching, does anybody know how to disable caching?
stork
So I fixed the problem. Turns out URLConnection was caching the jar and somehow messing it all up.There's a curious workaround for disabling caching with URLConnection, you need to call the non-static method `setDefaultUseCaches` method (which isn't easy):`new URL("http://localhost/").openConnection().setDefaultUseCaches(false);`Ugly fix, but it works. That method should be static.A better workaround would be to write a custom classloader but gosh that's a lot of effort.
stork