Menu

deny access to parent class loader

2011-05-23
2013-05-02
  • Todd Detwiler

    Todd Detwiler - 2011-05-23

    I seem to be having conflicts using JPF when I have libraries that are both in the plugin and in the parent application. I tries setting probeParentLoaderLast to true. This got me around one problem, but I still have another. SLF4J if there are multiple implementations on the classpath. In general, I think of my plugins as fully self-contained. I would prefer if they had no access to classes on the parent applications classpath. Is it possible to configure JPF in this way?
    Thanks,
    Todd

     
  • Todd Detwiler

    Todd Detwiler - 2011-05-23

    Sorry for the terrible grammar. The above was supposed to say, "… I tried setting probeParentLoaderLast to true…. SLF4J fails if there are multiple implementations on the classpath."

     
  • Cobus Stroebel

    Cobus Stroebel - 2011-05-23

    Hi Todd

    I might be wrong but wouldn't it solve your problem if you only load the SLF4J library in the parent application?
    Then when the plugin fails to load the library from it's own classpath it would look for it in the parent application classpath and then load it?

    Regards

     
  • Todd Detwiler

    Todd Detwiler - 2011-05-23

    I tried that, it resulted in this error:

    xception in thread "main" java.lang.LinkageError: loader constraint violation: when resolving method "org.slf4j.impl.StaticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory;" the class loader (instance of org/java/plugin/standard/StandardPluginClassLoader) of the current class, org/slf4j/LoggerFactory, and the class loader (instance of sun/misc/Launcher$AppClassLoader) for resolved class, org/slf4j/impl/StaticLoggerBinder, have different Class objects for the type org/slf4j/ILoggerFactory used in the signature

    I would like my plugins to be developed by other developers who wish to extend the system. I'd prefer it if they didn't have to worry about which libraries and which versions were on the classpath of the parent application.

     
  • Todd Detwiler

    Todd Detwiler - 2011-05-23

    Actually str123js, you are correct. I had to remove two library jars and two other classes from my plugin code, which were on both the plugin and the parent classpaths. That worked, but I would prefer not to have to do that sort of trial and error every time I add a plugin. If I could make my plugins self-contained and without access to the parent classloader, that would be ideal. Does anyone know if that is possible?

     
  • Cobus Stroebel

    Cobus Stroebel - 2011-05-24

    Todd

    There was a bug with the probeParentLoaderLast attribute and a patch was released here. Checkout the source, apply the patch and re-compile. That should help you.

    Regards
    Cobus

     
  • Todd Detwiler

    Todd Detwiler - 2011-05-24

    Thanks Cobus, I'll give it a try. Do you recommend that I download the source bundle or checkout from CVS (e.g. how updated is the source bundle)?

     
  • Cobus Stroebel

    Cobus Stroebel - 2011-05-24

    I'm not sure if the source bundle includes the CVS files, so you might not be able to patch it, therefor I recommend you checkout from CVS and apply the patch through an IDE (I used NetBeans) or a CVS frontend utility.

     
  • Todd Detwiler

    Todd Detwiler - 2011-05-25

    OK, the patch helped, but hasn't entirely eliminated my classloader problem. I am still getting this error:

    log4j:ERROR A "org.apache.log4j.ConsoleAppender" object is not assignable to a "org.apache.log4j.Appender" variable.
    log4j:ERROR The class "org.apache.log4j.Appender" was loaded by
    log4j:ERROR  whereas object of type
    log4j:ERROR "org.apache.log4j.ConsoleAppender" was loaded by .
    log4j:ERROR Could not instantiate appender named "stdout".

    To me this still looks like I am having a conflict between the classloaders. The conflict isn't between my plugin code and a library, it is between one of the libraries my plugin loads and another that it depends on. I can probably make this work. But I am still curious as to the answer to my original question, can a plugin classloader be completely independent of the parent classloader (i.e. can we deny access from plugin to parent classloader)?

    Thanks,
    Todd

     
  • Pavel Sharov

    Pavel Sharov - 2011-05-25

    Todd,

    I guess you cannot deny access from plugin classloaders to the parent classloader just because it is via the parent that plugin classloaders have access to core JPF libraries. How would you for example extend org.java.plugin.boot.ApplicationPlugin to initialize your application, or use any other JPF core API? It seems that your problem is not constrained by JPF's 'inability' to block access to parent, but rather reduces to the concrete project configuration you are currently having. I can imagine a similar situation when you would have your own plugin having no parent classloader but instead depending on another plugin containing 'bad' dependencies for your library, just like the parent currently does, and you would have the same problem… The same can be modeled in any classloader hierarchy.
    Maybe it would be better for us to look deeper into your configuration. Can you describe the reason of the error in more detail? Are you having two sources for org.apache.log4j.Appender class one of which is extended by org.apache.log4j.ConsoleAppender and then attempted to assign to the other one? Why both of them are found?

    Regards,
    Pavel

     
  • Todd Detwiler

    Todd Detwiler - 2011-05-25

    Thanks for the reply Pavel. Regarding access to JPF libraries, first I should say that I have no core or application plugin. I could set that up if you think it would help. But presently I have a plain old java program loading plugins (no extension points yet). I would be fine with including JPF libraries both in by plugin classpath and in the parent app path if necessary.

    I would like others developers to be able to write plugins for my system, without having to worry about library conflicts. For example, suppose I remove some logging libraries from my plugin to circumvent the error that I posted previously. Then my plugin would be dependent on the parent app having those libraries. If I remove them from the parent, I would have to add them to some or all of my plugins. I am thinking of my plugins as stand-alone apps, except that input parameters are coming from the parent app and the parent app is consuming the results (these are query processing plugins).

    Regarding the specifics of my error, I have to admit that I don't know all of the details yet. The conflict appears to stem from the fact that both the parent and the plugin are trying to log using log4j and/or slf4j (I don't know how these two libraries interact). The reason that I am so fuzzy on the problem is that none of my code calls either of these libraries directly. Rather, 3rd party libraries that I am using from my code in-turn consume other 3rd party libraries, specifically these logging libraries. With the patch suggested by Cobus, I have been able get my plugin to run to completion, albeit with the errors above. But I fear that I may miss important log output.

    Do you have any additional thoughts or suggestions? Is there any reason why the omission of a core plugin might lead to additional classloader issues?

    Thanks for your time,
    Todd

     
  • Pavel Sharov

    Pavel Sharov - 2011-05-26

    Todd,

    I think I see your goal. So your application is supposed to support fully both the parent application's and the plugin environments, and you are right, a total isolation of these environments is required here. No, of course having the core plugin isn't going to fix the classloader issues.
    I suppose to play with the snippet in your parent code which has something to do with initializing the JPF environment, you have one don't you? The matter is that your JPF initializing code's classloader (from the parent application) is the one which will become all the plugins' parent classloader after JPF initialization is done. Currently it is something like sun.misc.Launcher$AppClassLoader. Create a special class in parent app, say JpfStart, and create a special classloader JpfStartLoader (a child of sun.misc.Launcher$AppClassLoader), capable of loading this only class, rejecting requests for any other class. You will have to use reflection to load JpfStart using JpfStartLoader and then to execute it. The result is that your plugins will have parent classloader (JpfStartLoader) that will be incapable of loading any class requested from the plugins environment, thus you get the desired isolation. Yes it's not too elegant, but I can't see anything else for now, as delegation to parent is fundamental to JPF and Java core classloaders and you cannot easily switch it off.

    Pavel

     

Log in to post a comment.