2009-09-03 16 views
3

私のアプリケーションでは、SPI(サービスプロバイダインターフェイス)を使って書いたプラグインシステムがあるので、私はどこかに保管するscripts.jarというjarファイルを持っています。ではない)クラスパス上で、私はこの方法を使用して、それからスクリプトを読み込む:私は私のプログラムを起動したときSPIを使用してロードすると消えるjarエントリ

/** 
* 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; 
} 

は今、これが素晴らしく動作します。 jarファイルに任意のスクリプトを簡単にロードできます。

問題は、スクリプトをリロードする、つまりファイルを変更してscripts.jarを上書きした後にスクリプトをロードしようとすると発生します。私はこのエラーを取得する:

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 

は、だから、jarファイルエントリが見つからないが、私はそれはかなり簡単にありますチェックすることができます言う:

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 
    ... 

そしてそれはあまりにも、ちょうどいい大きさです。この問題は、変更されたスクリプトだけでなく、スクリプトを読み込もうとしたときに発生します。

これはバグ、入力と思われるでしょうか?

+0

1点ですが、プログラムの実行中にjarファイルを削除できるかどうかを確認しようとしましたが、できません。彼らはJavaで使用されていると言いますが、どうすればこのことができますか? 私が掲示したコードは、ファイルをロックするべきではありませんか? – stork

答えて

4

ファイルのアクセス許可を確認してください。オリジナルのJARが残りのアプリケーションと一緒に配置されると、プログラムによってそれを読み取ることができます。他のユーザーに読み取り権限を与えずに、別のユーザー—によって更新されている可能性があります。—とプログラムは、ファイルを開くことができません。

実行しているWindowsのバージョンを知ることはできませんが、セキュリティのプロパティダイアログまたはXP Homeの場合は、caclsコマンドで前後のアクセス許可を詳細に指定する必要があります。


更新:ServiceLoaderドキュメントを再読み込み、私はインスタンスメソッド、reloadに気づきました。コードでは、毎回新しいServiceLoaderが作成されますが、ServiceLoaderクラスはすべてのインスタンスで使用されるキャッシュを保持している可能性があります。新しいローダーを作成する代わりに、新しいローダーを作成しておき、reloadメソッドを使用して新しいスクリプトをチェックしてください。

+0

@erickson:ファイルアクセス権はすべてうまく見えますが、caclsはファイルアクセス権も同じようにレポートします。 私は 'ServiceLoader'を再利用できるとは思えません。私は新しいClassLoaderオブジェクトを持っているので、スクリプトをリロードするたびに新しいクラスを作成しています。私は 'reload()'を前と後(そして両方)呼び出すよう試みましたが、問題を解決しませんでした。 – stork

+0

関連:http://www.docjar.com/html/api/sun/net/www/protocol/jar/JarURLConnection.java.html これはキャッシュに問題があると考えていますが、誰でもキャッシュを無効にする方法を知っていますか? – stork

+7

私は問題を解決しました。 URLConnectionがjarファイルをキャッシュしていて、何とかそれをすべて乱していたことがわかります。 URLConnectionでキャッシングを無効にするには、静的でないメソッドのsetDefaultUseCachesメソッドを呼び出す必要があります(これは簡単ではありません)。 'new URL(" http:// localhost/").openConnection ).setDefaultUseCaches(false); ' 不自然な修正ですが、動作します。その方法は静的でなければなりません。 より良い回避策は、カスタムクラスローダーを書くことですが、大したことです。 – stork

関連する問題