[ 
https://issues.apache.org/jira/browse/OOZIE-2714?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16345314#comment-16345314
 ] 

Peter Bacsko commented on OOZIE-2714:
-------------------------------------

After experimenting with this classloader POC, I've decided not to follow this 
approach. I've run into all kinds of tricky problems, eventually the whole 
solution became hacky and unreliable.

A list of problems I've seen:
1) Classes under {{java.*}} cannot be loaded by a custom CL, it must be 
delegated - not a big deal, can be handled
2) {{sun.misc.Unsafe}} cannot be loaded by a custom CL either, because we get 
an {{UnsatisfiedLinkError}}, so it must be delegated too. This means a special 
case that we have to consider.
3) If {{rt.jar}} is not on the classpath (and I think most of the time it's 
not), then we have to construct an {{URL}} array which has it before we pass it 
to the constructor of {{ConflictCheckingClassLoader}}. The reason is that some 
stuff under {{javax.*}} are extended by 3rd party libraries. A concrete 
example: {{com.ctc.wstx.stax.WstxInputFactory}} extends 
{{javax.xml.stream.XMLInputFactory}}. The first is loaded by our custom loader, 
however, it does not find {{XMLInputFactory}} which ends up being picked up by 
the bootstrap loader. This leads to the following error:

{noformat}
Caused by: java.lang.LinkageError: loader constraint violation: when resolving 
overridden method 
"com.ctc.wstx.stax.WstxInputFactory.createXMLEventReader(Ljavax/xml/transform/Source;)Ljavax/xml/stream/XMLEventReader;"
 the class loader (instance of 
org/apache/oozie/action/hadoop/ConflictDetectingClassLoader) of the current 
class, com/ctc/wstx/stax/WstxInputFactory, and its superclass loader (instance 
of <bootloader>), have different Class objects for the type 
javax/xml/transform/Source used in the signature
{noformat}

Solving this is already very hacky.  

4) There's another problem in {{UserGroupInformation}}. It loads the class 
{{com.sun.security.auth.UnixPrincipal}} with reflection. However, instead of 
using the current classloader, it explicitly uses the system classloader (which 
is, by default, an instance of {{sun.misc.Launcher$AppClassLoader}}. Later on, 
we load {{UnixPrincipal}} with our custom classloader. But this causes the JVM 
to treat these classes differently - if the CL is different, they're considered 
different, even if their byte representation is the same. There is an 
{{isAssignableFrom()}} check in {{javax.security.auth.Subject}} which returns 
false and eventually {{UserGroupInformation.getCurrentUser()}} fails.

It's just too many problems to handle. And who knows what other edge cases we 
have to consider. 

Therefore I suggest using a 3rd party library JHades: http://jhades.github.io/. 
It was released under MIT license. If that's good for us, we should go ahead 
and create a POC with JHades.

> Detect conflicting resources during class loading
> -------------------------------------------------
>
>                 Key: OOZIE-2714
>                 URL: https://issues.apache.org/jira/browse/OOZIE-2714
>             Project: Oozie
>          Issue Type: New Feature
>          Components: core
>            Reporter: Peter Bacsko
>            Assignee: Peter Bacsko
>            Priority: Major
>         Attachments: ClassLoaderTest.java, OOZIE-2714-POC01.patch, 
> OOZIE-2714-POC02.patch
>
>
> There are a bunch of issues in Oozie which are related to class loading. 
> The main problem is that the classpath is constructed in a way which is very 
> specific to Oozie:
> - Hadoop lib jars
> - Sharelib jars
> - User-defined jars
> Sometimes there is a conflict between sharelib and hadoop lib version. Also, 
> users can add their own jars which sometimes contain a different version of 
> popular libraries such as Guava, Apache commons, etc.
> We should be able to detect these conflicts and print exact error message so 
> that Oozie users can take appropriate actions to resolve the problem.
> A possible approach is the following:
> * start the execution of an action on a different thread
> * replace the thread's context classloader with a classloader which can 
> detect conflicts
> * when the JVM invokes the {{loadClass()}} method of the classloader, it  
> scans through the jars (which are available as {{URLClassPath}} objects). If 
> it finds the given resource in at least two jars, it can do different things 
> depending on the setup:
> ** throws an error immediately, mentioning the conflicting jars (this is 
> probably too strict - but still an option)
> ** loads the two resource into a byte array and compares them - it only 
> throws an error if there is difference
> ** compares the jars but only emits an error message if there is a conflict
> ** something else (user defined action?)
> Implementing such a classloader is not difficult and would greatly enhance 
> the supportability of Oozie. It could work in multiple modes depending on the 
> setup - perhaps being able to control it from a workflow config is desirable. 
> If there's any problem, we should be able to turn it off completely, too.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to