You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@felix.apache.org by "Jesse Glick (JIRA)" <ji...@apache.org> on 2010/02/23 21:49:27 UTC

[jira] Created: (FELIX-2128) Permit class loading after framework shutdown

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


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.


[jira] Commented: (FELIX-2128) Permit class loading after framework shutdown

Posted by "Richard S. Hall (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/FELIX-2128?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12838691#action_12838691 ] 

Richard S. Hall commented on FELIX-2128:
----------------------------------------

A bundle leaving live objects around after its stop() method is called is misbehaving, yes. Admittedly, this is a corner case that causes issues with that definition, but it is still the case.

So, I talked with Thomas Watson (Equinox dude) about this and apparently they have run into this issue before too with a shutdown hook or something. He and I both agree this bundle is breaking the rules. However, in this case, they did modify Equinox to reopen the JAR file. I asked him how do they know when to close the JAR file and he says they don't. So, effectively it is a potential resource leak since we cannot assume that the JVM actually exits after a framework shutdown. (Alternatively, we could go into a mode where we open, read, and close the JAR file in one go to avoid the issue.)

Regarding your workaround, yeah, that works but it is pretty fragile. We'll think about this some more. Thanks for you input!

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


[jira] Commented: (FELIX-2128) Permit class loading after framework shutdown

Posted by "Jesse Glick (JIRA)" <ji...@apache.org>.
    [ 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.


[jira] Commented: (FELIX-2128) Permit class loading after framework shutdown

Posted by "Jesse Glick (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/FELIX-2128?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12838370#action_12838370 ] 

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

So a bundle containing a class with an overridden Object.finalize that refers to another type in the bundle is "misbehaving"? (Granted this is not the most likely reason for code to be accessed after a bundle has been stopped, but it is one possible reason.)

Related to the diagnostic patch - in my case, the code which manages the ReferenceQueue does catch LinkageError when dealing with foreign objects; currently it logs these at WARNING but it could easily be fixed to log at FINE instead. However Felix misbehaves in its management of the error. It first prints a stack trace for the "JAR closed" from JarContent, unconditionally, then returns null (rather than passing up the ISE); then later throws a CNFE with no cause. It would be better to use the original ISE from ZipFile as the cause of the CNFE (possibly including the stack trace of the call to close() as the "cause" of the ISE, as in the current patch), so that the code which finally catches the resulting NCDFE could decide what to do with it. If you agree I can create a reworked patch #2 for that.

To the security issue - the current patch #1 just uses two-arg File.createTempFile for simplicity, but it could easily be modified to use the cache location. It also currently does not attempt to request permissions for the file copy and reopen, but that could be fixed as well.

To the performance question - in principle making a copy of the JAR could be expensive on some filesystems, but this is better than throwing exceptions. Remember that patch #1 only does a copy if an error would otherwise have occurred. As mentioned parenthetically in my original comment, this means that a race condition is possible whereby a JAR is deleted or recreated after bundle shutdown but before first zombie load from it, but this seems the lesser of two evils compared to imposing an unnecessary performance penalty on the great majority of bundles which will never be accessed after shutdown.

I have no problem with conditionally enabling patch #1 based on a framework property and could supply a modified #1 if so requested. It would be nice if a future revision of the OSGi spec dealt with this issue more carefully, though; Java provides no foolproof, generic way to ensure that no instances of classes defined by a given ClassLoader are weakly reachable, other than by passively waiting for the loader itself to be collected and finalized.

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


[jira] Commented: (FELIX-2128) Permit class loading after framework shutdown

Posted by "Richard S. Hall (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/FELIX-2128?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12838234#action_12838234 ] 

Richard S. Hall commented on FELIX-2128:
----------------------------------------

Jesse, I understand this sort of sucks, but I cannot see changing this behavior to resurrect JAR files. From the point of view of the framework, this is a misbehaving module. Additionally, it is not clear that this patch fixes all cases, since an uninstalled followed by a refresh will actually result in the JAR files being deleted, so resurrecting them is not an option.

In all of these years, we've only had issues with this when users didn't properly stop bundle-created threads. So, while it may actually happen in the wild, I am not convinced of its value as a use case in general. We can probably apply your diagnostic patch at a minimum. Still, I will try to discuss this with a few other people and see if there are any other options.

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


[jira] Commented: (FELIX-2128) Permit class loading after framework shutdown

Posted by "Karl Pauls (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/FELIX-2128?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12838239#action_12838239 ] 

Karl Pauls commented on FELIX-2128:
-----------------------------------

There is a security issue with this as well. The bundle cache needs to be secure on the file system. Moving jars out of there into a potentially world readable/writtable location would be really bad. 

Furthermore, assuming you have big bundles and or a setup where copying is slow (flash, network shares, etc.) this might introduce other, performance releated issues. 

I guess, if at all, this would need to be configurable and switched off by default (plus maybe warnings when security is enabled and the feature is switched on). 

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


[jira] Updated: (FELIX-2128) Permit class loading after framework shutdown

Posted by "Jesse Glick (JIRA)" <ji...@apache.org>.
     [ 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.


[jira] Updated: (FELIX-2128) Permit class loading after framework shutdown

Posted by "Jesse Glick (JIRA)" <ji...@apache.org>.
     [ 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-lazarus.diff

Suggested patch. (Probably presupposes JDK 5+ but I could find no mention of Felix's base JRE and it does not seem to use animal-sniffer.dev.java.net to enforce anything.)

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