[ 
https://issues.apache.org/jira/browse/FELIX-2128?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12838389#action_12838389
 ] 

Jesse Glick commented on FELIX-2128:
------------------------------------

Note: possible to work around in the particular case I encountered by eagerly 
resolving the class referenced during finalization: 
http://hg.netbeans.org/core-main/rev/69ce73db7ccc

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

Reply via email to