[ https://issues.apache.org/jira/browse/FELIX-2128?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Jesse Glick updated FELIX-2128: ------------------------------- Attachment: FELIX-2128-diagnosis.diff Alternate patch which simply supplies a cause for the ISE so that you can see when the JAR was closed. > Permit class loading after framework shutdown > --------------------------------------------- > > Key: FELIX-2128 > URL: https://issues.apache.org/jira/browse/FELIX-2128 > Project: Felix > Issue Type: Improvement > Components: Framework > Affects Versions: felix-2.0.3 > Environment: Linux, JDK 6. > Reporter: Jesse Glick > Priority: Minor > Attachments: FELIX-2128-diagnosis.diff, FELIX-2128-lazarus.diff > > > In > http://hg.netbeans.org/core-main/raw-file/default/core.netigso/test/unit/src/org/netbeans/core/osgi/ActivatorTest.java > I have some unit tests which repeatedly launch Felix, start some bundles, > shut down, and repeat. On occasion - more reproducibly if calls to > System.gc() and System.runFinalization() are inserted into > ActivatorTest.setUp - I get errors like these (though the test still passes): > {noformat} > ERROR: JarContent: Unable to read bytes. (java.lang.IllegalStateException: > zip file closed) > java.lang.IllegalStateException: zip file closed > at java.util.zip.ZipFile.ensureOpen(ZipFile.java:403) > at java.util.zip.ZipFile.getEntry(ZipFile.java:148) > at java.util.jar.JarFile.getEntry(JarFile.java:206) > at org.apache.felix.framework.util.JarFileX.getEntry(JarFileX.java:77) > at > org.apache.felix.framework.cache.JarContent.getEntryAsBytes(JarContent.java:120) > at > org.apache.felix.framework.ModuleImpl$ModuleClassLoader.findClass(ModuleImpl.java:1746) > at > org.apache.felix.framework.ModuleImpl.findClassOrResourceByDelegation(ModuleImpl.java:723) > at > org.apache.felix.framework.ModuleImpl.access$100(ModuleImpl.java:61) > at > org.apache.felix.framework.ModuleImpl$ModuleClassLoader.loadClass(ModuleImpl.java:1698) > at java.lang.ClassLoader.loadClass(ClassLoader.java:248) > at java.lang.Class.getDeclaredMethods0(Native Method) > at java.lang.Class.privateGetDeclaredMethods(Class.java:2427) > at java.lang.Class.getMethod0(Class.java:2670) > at java.lang.Class.getMethod(Class.java:1603) > at > org.openide.util.WeakListenerImpl$ListenerReference.getRemoveMethod(WeakListenerImpl.java:610) > at > org.openide.util.WeakListenerImpl$ListenerReference.run(WeakListenerImpl.java:563) > at > org.openide.util.lookup.implspi.ActiveQueue$Impl.run(ActiveQueue.java:73) > at java.lang.Thread.run(Thread.java:619) > Feb 23, 2010 3:22:53 PM org.openide.util.lookup.implspi.ActiveQueue$Impl run > WARNING: null > java.lang.NoClassDefFoundError: org/openide/loaders/FolderListListener > at java.lang.Class.getDeclaredMethods0(Native Method) > at java.lang.Class.privateGetDeclaredMethods(Class.java:2427) > at java.lang.Class.getMethod0(Class.java:2670) > at java.lang.Class.getMethod(Class.java:1603) > at > org.openide.util.WeakListenerImpl$ListenerReference.getRemoveMethod(WeakListenerImpl.java:610) > at > org.openide.util.WeakListenerImpl$ListenerReference.run(WeakListenerImpl.java:563) > at > org.openide.util.lookup.implspi.ActiveQueue$Impl.run(ActiveQueue.java:73) > at java.lang.Thread.run(Thread.java:619) > Caused by: java.lang.ClassNotFoundException: > org.openide.loaders.FolderListListener > at > org.apache.felix.framework.ModuleImpl.findClassOrResourceByDelegation(ModuleImpl.java:779) > at > org.apache.felix.framework.ModuleImpl.access$100(ModuleImpl.java:61) > at > org.apache.felix.framework.ModuleImpl$ModuleClassLoader.loadClass(ModuleImpl.java:1698) > at java.lang.ClassLoader.loadClass(ClassLoader.java:248) > ... 8 more > {noformat} > Here some code in a bundle has registered a special ReferenceQueue and is > doing some minor cleanup of recently finalized objects. Unfortunately running > this code block can trigger fresh class loading and JarContent throws an ISE > when trying to load from the now-closed JAR file. The situation is less > likely to come up in a real app than in a unit test but still possible - in > case a bundle is dynamically unloaded, or some cleanup tasks happen to run > during JVM shutdown. > The timing of class loading is not easily predictable: it will occur any time > a section of code is run for the first time. Even in the absence of apparent > threads, it is very hard to guarantee that no class loading will take place > after code ceases to be called externally, since overridden finalize() > methods and JVM shutdown hooks can be called passively at any time. The code > in this example could disable its RQ upon BundleActivator.stop if it were > originally written for use inside OSGi, but it is not. > I have come up with a patch to JarFileX which lets it load classes from > nominally closed JARs on an emergency basis. (This was implemented years ago > in the NetBeans module system.) To make it safer for the original JAR to be > recreated or deleted, especially on Windows with its mandatory file locks, a > temporary copy is made. > (Safest would be to copy the original JAR eagerly in close(), but this would > impose a huge performance penalty. Instead, the JAR is copied on demand only > in cases where an ISE would otherwise be thrown. It is possible for the JAR > to be modified/deleted after close() but before the next class load, in which > case the ISE will still occur; similarly if a SecurityManager prevents the > copying, etc.) > It is not clear to me from the OSGi spec whether it is permissible for the > bundle class loader to continue to function after framework shutdown (or > generally after a bundle moves into an unresolved state). The spec seems to > say that Bundle.loadClass should throw ISE, but this is different from > performing implicit class loading at the VM's request as part of running > already-loaded code. For what it's worth, 4.4.10 does say "all old exports > must remain available for existing bundles and future resolves until the > refreshPackages method is called or the Framework is restarted". While more > permissive behavior is very useful for situations like these, if it > contradicts the spec, I might suggest one or both of the following: > 1. Enable emergency loading only with an optional Felix framework property. > Then, for example, unit tests which knew they would be starting and stopping > code which potentially left behind live threads or finalizer queues etc. > could set the property to avoid printing such exceptions. > 2. At least report when close() was called to assist the user in debugging > the problem. -- This message is automatically generated by JIRA. - You can reply to this email to add a comment to the issue online.