[
https://issues.apache.org/jira/browse/RANGER-4201?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
caijialiang updated RANGER-4201:
--------------------------------
Description:
Issue description: HBase fails to start after enabling Ranger 2.4 plugin.
Problem analysis is required.
environment:
linux centos7.4
hbase 2.4.13
ranger 2.4
jdk1.8
hadoop 3.3.4
zookeeper 3.5.9
Symptom: After integrating Ranger with HBase, HBase Master cannot start, and
Region Server also crashes after running for a period of time. The same error
message occurs during both processes.
{code:java}
[master/gs-server-13481:16000:becomeActiveMaster] coprocessor.CoprocessorHost:
The coprocessor
org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor threw
java.lang.ExceptionInInitializerError
java.lang.ExceptionInInitializerError
at
com.sun.jersey.core.spi.factory.MessageBodyFactory.initReaders(MessageBodyFactory.java:182)
at
com.sun.jersey.core.spi.factory.MessageBodyFactory.initReaders(MessageBodyFactory.java:175)
at
com.sun.jersey.core.spi.factory.MessageBodyFactory.init(MessageBodyFactory.java:162)
at com.sun.jersey.api.client.Client.init(Client.java:343)
at com.sun.jersey.api.client.Client.access$000(Client.java:119)
at com.sun.jersey.api.client.Client$1.f(Client.java:192)
at com.sun.jersey.api.client.Client$1.f(Client.java:188)
at com.sun.jersey.spi.inject.Errors.processWithErrors(Errors.java:193)
at com.sun.jersey.api.client.Client.<init>(Client.java:188)
at com.sun.jersey.api.client.Client.<init>(Client.java:171)
at com.sun.jersey.api.client.Client.create(Client.java:683)
at
org.apache.ranger.plugin.util.RangerRESTClient.buildClient(RangerRESTClient.java:228)
at
org.apache.ranger.plugin.util.RangerRESTClient.getClient(RangerRESTClient.java:193)
at
org.apache.ranger.plugin.util.RangerRESTClient.get(RangerRESTClient.java:473)
at
org.apache.ranger.admin.client.RangerAdminRESTClient.getRangerRolesDownloadResponse(RangerAdminRESTClient.java:1340)
at
org.apache.ranger.admin.client.RangerAdminRESTClient.getRolesIfUpdatedWithCred(RangerAdminRESTClient.java:1202)
at
org.apache.ranger.admin.client.RangerAdminRESTClient.getRolesIfUpdated(RangerAdminRESTClient.java:167)
at
org.apache.ranger.plugin.util.RangerRolesProvider.loadUserGroupRolesFromAdmin(RangerRolesProvider.java:183)
at
org.apache.ranger.plugin.util.RangerRolesProvider.loadUserGroupRoles(RangerRolesProvider.java:123)
at
org.apache.ranger.plugin.util.PolicyRefresher.loadRoles(PolicyRefresher.java:495)
at
org.apache.ranger.plugin.util.PolicyRefresher.startRefresher(PolicyRefresher.java:144)
at
org.apache.ranger.plugin.service.RangerBasePlugin.init(RangerBasePlugin.java:245)
at
org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor.start(RangerAuthorizationCoprocessor.java:1120)
at
org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor.start(RangerAuthorizationCoprocessor.java:160)
at
org.apache.hadoop.hbase.coprocessor.BaseEnvironment.startup(BaseEnvironment.java:69)
at
org.apache.hadoop.hbase.coprocessor.CoprocessorHost.checkAndLoadInstance(CoprocessorHost.java:285)
at
org.apache.hadoop.hbase.coprocessor.CoprocessorHost.loadSystemCoprocessors(CoprocessorHost.java:171)
at
org.apache.hadoop.hbase.master.MasterCoprocessorHost.<init>(MasterCoprocessorHost.java:155)
at
org.apache.hadoop.hbase.master.HMaster.initializeCoprocessorHost(HMaster.java:3870)
at
org.apache.hadoop.hbase.master.HMaster.finishActiveMasterInitialization(HMaster.java:902)
at
org.apache.hadoop.hbase.master.HMaster.startActiveMasterManager(HMaster.java:2175)
at org.apache.hadoop.hbase.master.HMaster.lambda$run$0(HMaster.java:520)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException:
org.glassfish.jersey.internal.RuntimeDelegateImpl
at
javax.ws.rs.ext.RuntimeDelegate.findDelegate(RuntimeDelegate.java:130)
at javax.ws.rs.ext.RuntimeDelegate.getInstance(RuntimeDelegate.java:97)
at javax.ws.rs.core.MediaType.valueOf(MediaType.java:172)
at com.sun.jersey.core.header.MediaTypes.<clinit>(MediaTypes.java:65)
... 33 more
Caused by: java.lang.ClassNotFoundException:
org.glassfish.jersey.internal.RuntimeDelegateImpl
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at javax.ws.rs.ext.FactoryFinder.newInstance(FactoryFinder.java:87)
at javax.ws.rs.ext.FactoryFinder.find(FactoryFinder.java:185)
at
javax.ws.rs.ext.RuntimeDelegate.findDelegate(RuntimeDelegate.java:112)
... 36 more {code}
Steps to reproduce:
* 1.After installing HBase 2.x and Ranger 2.4, configure HBase by modifying
the hbase-site.xml file:
* Set hbase.coprocessor.master.classes to
org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor
* Set hbase.coprocessor.region.classes to
org.apache.hadoop.hbase.security.access.SecureBulkLoadEndpoint,org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor
* Set hbase.coprocessor.regionserver.classes to
org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor
* Restart HBase and check the HBase Master logs to observe the exception and
see the Master crash soon after
solution:delete
/usr/bigtop/3.2.0/usr/lib/hbase/lib/ranger-hbase-plugin-impl/jersey-core-1.19.3.jar
related issues
https://issues.apache.org/jira/browse/HBASE-22029
https://issues.apache.org/jira/browse/HBASE-22052
!image-2023-04-27-16-11-05-561.png!
Problem Analysis:
Conclusion: Exception caused by class loading order
Analysis process: The call chain is roughly as follows: master start ->
org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor.start ...
->com.sun.jersey.api.client.Client.create
...->com.sun.jersey.core.spi.factory.MessageBodyFactory.init
->com.sun.jersey.core.header.MediaTypes ->javax.ws.rs.core.MediaType.valueOf ->
javax.ws.rs.ext.RuntimeDelegate.getInstance ->
javax.ws.rs.ext.RuntimeDelegate.findDelegate
I have fully investigated this call chain and found that the root cause of the
problem is that javax.ws.rs.ext.RuntimeDelegate in the
javax.ws.rs-api-2.1.1.jar package in HBase did not find
org.glassfish.jersey.internal.RuntimeDelegateImpl when calling findDelegate,
which caused the error. Specifically, javax.ws.rs.ext.RuntimeDelegate first
looks for the default JAXRS_RUNTIME_DELEGATE, which is
"javax.ws.rs.ext.RuntimeDelegate". If it cannot be found, it will fallback and
load JAXRS_DEFAULT_RUNTIME_DELEGATE, which is
org.glassfish.jersey.internal.RuntimeDelegateImpl.
The method "findDelegate" in "javax.ws.rs.ext.RuntimeDelegate" is as follows:
{code:java}
public abstract class RuntimeDelegate {
public static final String JAXRS_RUNTIME_DELEGATE_PROPERTY =
"javax.ws.rs.ext.RuntimeDelegate";
private static final String JAXRS_DEFAULT_RUNTIME_DELEGATE =
"org.glassfish.jersey.internal.RuntimeDelegateImpl";
private static final Object RD_LOCK = new Object();
private static ReflectPermission suppressAccessChecksPermission = new
ReflectPermission("suppressAccessChecks");
private static volatile RuntimeDelegate cachedDelegate; protected
RuntimeDelegate() {
}
public static RuntimeDelegate getInstance() {
// Double-check idiom for lazy initialization of fields.
// Local variable is used to limit the number of more expensive
accesses to a volatile field.
RuntimeDelegate result = cachedDelegate;
if (result == null) { // First check (no locking)
synchronized (RD_LOCK) {
result = cachedDelegate;
if (result == null) { // Second check (with locking)
cachedDelegate = result = findDelegate();
}
}
}
return result;
} private static RuntimeDelegate findDelegate() {
try {
Object delegate = FactoryFinder.find(
JAXRS_RUNTIME_DELEGATE_PROPERTY,
JAXRS_DEFAULT_RUNTIME_DELEGATE,
RuntimeDelegate.class);
if (!(delegate instanceof RuntimeDelegate)) {
Class pClass = RuntimeDelegate.class;
String classnameAsResource = pClass.getName().replace('.', '/')
+ ".class";
ClassLoader loader = pClass.getClassLoader();
if (loader == null) {
loader = ClassLoader.getSystemClassLoader();
}
URL targetTypeURL = loader.getResource(classnameAsResource);
throw new LinkageError("ClassCastException: attempting to cast"
+
delegate.getClass().getClassLoader().getResource(classnameAsResource)
+ " to " + targetTypeURL);
}
return (RuntimeDelegate) delegate;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
{code}
When the "jersey-core-1.19.3.jar" file is removed from
"/usr/bigtop/3.2.0/usr/lib/hbase/lib/ranger-hbase-plugin-impl/", HBase can
start normally.
It is not clear which class, either "javax.ws.rs.ext.RuntimeDelegate" or
"org.glassfish.jersey.internal.RuntimeDelegateImpl", is loaded by HBase at this
point.
To determine which class is loaded and from which JAR file it is loaded, we can
first remove "/usr/lib/hbase/lib/javax.ws.rs-api-2.1.1.jar" and start HBase
normally. Then, we can use the Arthas tool (https://github.com/alibaba/arthas)
to sniff and determine which class is loaded and from which JAR file it is
loaded by the HBase JVM.
After starting HBase normally, run the Arthas startup script "sudo -u hbase -EH
./as.sh " attach to the HBase process. Then, execute "sc -d
javax.ws.rs.ext.RuntimeDelegat" to check whether
"javax.ws.rs.ext.RuntimeDelegate" is loaded.
result:
{code:java}
[arthas@1719]$ sc -d javax.ws.rs.ext.RuntimeDelegate
class-info com.sun.jersey.core.spi.factory.AbstractRuntimeDelegate
code-source
/usr/bigtop/3.2.0/usr/lib/hadoop-hdfs/lib/jersey-core-1.19.jar
name com.sun.jersey.core.spi.factory.AbstractRuntimeDelegate
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name AbstractRuntimeDelegate
modifier abstract,public
annotation
interfaces
super-class +-javax.ws.rs.ext.RuntimeDelegate
+-java.lang.Object
class-loader +-sun.misc.Launcher$AppClassLoader@4fca772d
+-sun.misc.Launcher$ExtClassLoader@436a4e4b
classLoaderHash 4fca772d class-info
com.sun.jersey.server.impl.provider.RuntimeDelegateImpl
code-source /usr/bigtop/3.2.0/usr/lib/hadoop/lib/jersey-server-1.19.jar
name com.sun.jersey.server.impl.provider.RuntimeDelegateImpl
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name RuntimeDelegateImpl
modifier public
annotation
interfaces
super-class +-com.sun.jersey.core.spi.factory.AbstractRuntimeDelegate
+-javax.ws.rs.ext.RuntimeDelegate
+-java.lang.Object
class-loader +-sun.misc.Launcher$AppClassLoader@4fca772d
+-sun.misc.Launcher$ExtClassLoader@436a4e4b
classLoaderHash 4fca772d class-info javax.ws.rs.ext.RuntimeDelegate
code-source /usr/bigtop/3.2.0/usr/lib/hbase/lib/javax.ws.rs-api-2.1.1.jar
name javax.ws.rs.ext.RuntimeDelegate
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name RuntimeDelegate
modifier abstract,public
annotation
interfaces
super-class +-java.lang.Object
class-loader +-sun.misc.Launcher$AppClassLoader@4fca772d
+-sun.misc.Launcher$ExtClassLoader@436a4e4b
classLoaderHash 4fca772dAffect(row-cnt:3) cost in 112 ms. {code}
By removing the jersey-core-1.19.3.jar file from
/usr/bigtop/3.2.0/usr/lib/hbase/lib/ranger-hbase-plugin-impl/, we can see that
the abstract class javax.ws.rs.ext.RuntimeDelegate is loaded by the
AppClassLoader from the javax.ws.rs-api-2.1.1.jar file located in
/usr/bigtop/3.2.0/usr/lib/hbase/lib/.
At the same time, the implementation of javax.ws.rs.ext.RuntimeDelegate, which
is com.sun.jersey.server.impl.provider.RuntimeDelegateImpl, is loaded from the
jersey-server-1.19.jar file located in /usr/bigtop/3.2.0/usr/lib/hadoop/lib/.
Note that the hadoop lib directory is appended to HBase's classpath when HBase
is started, which is why it can be loaded.
Additionally, the abstract class
com.sun.jersey.core.spi.factory.AbstractRuntimeDelegate, which inherits from
RuntimeDelegate, is loaded from the jersey-core-1.19.jar file located in
/usr/bigtop/3.2.0/usr/lib/hadoop-hdfs/lib/.
However, even after removing the jersey-core-1.19.3.jar file, we can still see
that HBase loads the same version of jersey-core-1.19.jar from the hadoop lib
directory. Therefore, the root cause of the error is not a class not found due
to a version conflict, but rather due to the order in which the class loader
loads the classes.
To verify this conclusion, the simplest way is to:
# Before deleting the jersey-core-1.19.3.jar file from
/ranger-hbase-plugin-impl/, print out the loading information of all the
classes involved in the stack trace of the heap dump exception in the log.
# After deleting the jersey-core-1.19.3.jar file, print out the loading
information of all the classes involved in the stack trace of the heap dump
exception in the log.
# Use regular expressions to batch delete the timestamps from the log, and
then compare the two log files to see any differences in the class loading
information.
In the Ranger 2.4 source code, Ranger implements its own class loader,
RangerPluginClassLoader, which inherits from URLClassLoader. During
initialization, it is passed the path to the
ranger-\{componentname}-plugin-impl directory, and all the classes in this
directory will be loaded by RangerPluginClassLoader. The parent is set to null,
which in my understanding, is to block delegation loading. This is because all
the classes in the ranger-\{componentname}-plugin-impl directory are
dependencies of the Ranger plugin. For example, if the version of a jar that it
depends on is lower, if the delegation loading mechanism is used, it is easy to
load the higher version of the class under the component/lib directory, leading
to class conflict issues. Therefore, parent is set to null.
Internally, RangerPluginClassLoader first tries to load the jar files under the
ranger-\{componentname}-plugin-impl directory using the parent URLClassLoader.
If it can't be loaded, it uses the componentClassLoader, which is the current
thread context's class loader, to load it.
!image-2023-04-27-16-13-44-504.png!
Next, you can take a look at the source code of the
"RangerAuthorizationCoprocessor" class in Ranger. This class initializes an
instance of "rangerPluginClassLoader" and activates it. Within this class,
there are pre and post hooks for various HBase operations, primarily for
performing range permission-related operations. This triggers the loading of
Ranger-related classes by the rangerPluginClassLoader.
!image-2023-04-27-16-14-10-803.png!
Why does the hook activate the Ranger class loader at the beginning and
de-activate it after the hook method ends? Doesn't this approach impact
performance?
!image-2023-04-27-16-14-37-202.png!
The reason for de-activating the Ranger class loader after the hook method ends
is because the rangerPluginClassLoader code sets itself as the current thread's
context class loader. If it's not deactivated, it can cause conflicts with the
lower version packages loaded in the .../ranger-hbase-plugin-impl/ directory,
which can cause issues during subsequent operations. Therefore, the conclusion
is that this involves the rangerPluginClassLoader and the AppClassLoader of the
thread's context class loader.
We also need to understand how to load an instance of "RuntimeDelegate" and how
it searches for the implementation of "javax.ws.rs.ext.RuntimeDelegate". We
should also investigate why it cannot find the implementation class and instead
looks for "org.glassfish.jersey.internal.RuntimeDelegateImpl", causing an error.
First, the "RuntimeDelegate" class is loaded via the
"javax.ws.rs.ext.RuntimeDelegate.findDelegate" method, which calls
"FactoryFinder.find" to load the class. Once loaded, the instance must be of
type "RuntimeDelegate".
{code:java}
private static RuntimeDelegate findDelegate() {
try {
Object delegate = FactoryFinder.find("javax.ws.rs.ext.RuntimeDelegate",
"org.glassfish.jersey.internal.RuntimeDelegateImpl", RuntimeDelegate.class);
if (!(delegate instanceof RuntimeDelegate)) {
Class<RuntimeDelegate> pClass = RuntimeDelegate.class;
String classnameAsResource = pClass.getName().replace('.', '/') +
".class";
ClassLoader loader = pClass.getClassLoader();
if (loader == null)
loader = ClassLoader.getSystemClassLoader();
URL targetTypeURL = loader.getResource(classnameAsResource);
throw new LinkageError("ClassCastException: attempting to cast" +
delegate
.getClass().getClassLoader().getResource(classnameAsResource) + "
to " + targetTypeURL);
}
return (RuntimeDelegate)delegate;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
} {code}
The process of loading the class via "FactoryFinder.find" is contained in the
"javax.ws.rs.ext.FactoryFinder.find" method, as shown in the following code:
{code:java}
/**
* Finds the implementation {@code Class} for the given factory name,
* or if that fails, finds the {@code Class} for the given fallback
* class name and create its instance. The arguments supplied MUST be
* used in order. If using the first argument is successful, the second
* one will not be used.
* <p>
* This method is package private so that this code can be shared.
*
* @param factoryId the name of the factory to find, which is
* a system property.
* @param fallbackClassName the implementation class name, which is
* to be used only if nothing else.
* is found; {@code null} to indicate that
* there is no fallback class name.
* @param service service to be found.
* @param <T> type of the service to be found.
* @return the instance of the specified service; may not be {@code null}.
* @throws ClassNotFoundException if the given class could not be found
* or could not be instantiated.
*/
static <T> Object find(final String factoryId, final String
fallbackClassName, Class<T> service) throws ClassNotFoundException {
ClassLoader classLoader = getContextClassLoader(); try {
Iterator<T> iterator = ServiceLoader.load(service,
FactoryFinder.getContextClassLoader()).iterator();
if(iterator.hasNext()) {
return iterator.next();
}
} catch (Exception | ServiceConfigurationError ex) {
LOGGER.log(Level.FINER, "Failed to load service " + factoryId +
".", ex);
} try {
Iterator<T> iterator = ServiceLoader.load(service,
FactoryFinder.class.getClassLoader()).iterator();
if(iterator.hasNext()) {
return iterator.next();
}
} catch (Exception | ServiceConfigurationError ex) {
LOGGER.log(Level.FINER, "Failed to load service " + factoryId +
".", ex);
} // try to read from $java.home/lib/jaxrs.properties
FileInputStream inputStream = null;
String configFile = null;
try {
String javah = System.getProperty("java.home");
configFile = javah + File.separator + "lib" + File.separator +
"jaxrs.properties";
File f = new File(configFile);
if (f.exists()) {
Properties props = new Properties();
inputStream = new FileInputStream(f);
props.load(inputStream);
String factoryClassName = props.getProperty(factoryId);
return newInstance(factoryClassName, classLoader);
}
} catch (Exception ex) {
LOGGER.log(Level.FINER, "Failed to load service " + factoryId
+ " from $java.home/lib/jaxrs.properties", ex);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException ex) {
LOGGER.log(Level.FINER, String.format("Error closing %s
file.", configFile), ex);
}
}
} // Use the system property
try {
String systemProp = System.getProperty(factoryId);
if (systemProp != null) {
return newInstance(systemProp, classLoader);
}
} catch (SecurityException se) {
LOGGER.log(Level.FINER, "Failed to load service " + factoryId
+ " from a system property", se);
} if (fallbackClassName == null) {
throw new ClassNotFoundException(
"Provider for " + factoryId + " cannot be found", null);
} return newInstance(fallbackClassName, classLoader);
}
} {code}
To summarize the "FactoryFinder.find" method, it uses the thread context class
loader to load "javax.ws.rs.ext.RuntimeDelegate". If that fails, it attempts to
load it from system properties or alternative class names. If it still cannot
be found, it tries to load "org.glassfish.jersey.internal.RuntimeDelegateImpl".
If it cannot be loaded, it throws an exception.
When the
/usr/bigtop/3.2.0/usr/lib/hbase/lib/ranger-hbase-plugin-impl/jersey-core-1.19.3.jar
file was not deleted, the class loading order was as follows:
javax.ws.rs.ext.RuntimeDelegate(appClassLoader) ->
javax.ws.rs.ext.RuntimeDelegate.HeaderDelegate(RangerPluginClassLoader) ->
javax.ws.rs.ext.RuntimeDelegate.HeaderDelegateProvider(RangerPluginClassLoader
jersey-core-1.19.3.jar ranger-hbase-plugin-impl/jersey-core-1.19.3.jar).
The RangerPluginClassLoader searched for the
com.sun.jersey.spi.HeaderDelegateProvider implementation class in the
META-INF/services/com.sun.jersey.spi.HeaderDelegateProvider file of the
jersey-core-1.19.3.jar file, found the
com.sun.jersey.core.impl.provider.header.LocaleProvider class in
ranger-hbase-plugin-impl/jersey-core-1.19.3.jar, and returned it.
However, javax.ws.rs.ext.RuntimeDelegate.findDelegate would fail because
delegate instanceof RuntimeDelegate returned false.
As a fallback, it searched for
org.glassfish.jersey.internal.RuntimeDelegateImpl, which was not found in the
hbase classpath and caused an exception to be thrown.
After removing ranger-hbase-plugin-impl/jersey-core-1.19.3.jar, HBase can be
started normally. The class loading order is as follows:
javax.ws.rs.ext.RuntimeDelegate is loaded from
/usr/lib/hadoop/lib/javax.ws.rs-api-2.1.1.jar. Then, the implementation class
of javax.ws.rs.ext.RuntimeDelegate is searched for, which is found in
/usr/lib/hadoop/lib/jersey-server-1.19.jar->META-INF/services/javax.ws.rs.ext.RuntimeDelegate->com.sun.jersey.server.impl.provider.RuntimeDelegateImpl,
and successfully loaded.
The above class loading order was determined by modifying the code in the
RangerPluginClassLoader to print out the process of loading all classes.
!image-2023-04-27-16-15-44-539.png!
The following is a log that includes the class loading order. By analyzing this
log in conjunction with the Ranger class loader code, the above results can be
determined.
was:
hbase version 2.4.13
ranger version 2.4
hbase master can't start after installed ranger-hbase-plugin
{code:java}
ERROR [master/gs-server-13481:16000:becomeActiveMaster] master.HMaster: *****
ABORTING master gs-server-13481,16000,1681377561702: The coprocessor
org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor threw
java.lang.ExceptionInIniti
alizerError *****
java.lang.ExceptionInInitializerError
at
com.sun.jersey.core.spi.factory.MessageBodyFactory.initReaders(MessageBodyFactory.java:182)
at
com.sun.jersey.core.spi.factory.MessageBodyFactory.initReaders(MessageBodyFactory.java:175)
at
com.sun.jersey.core.spi.factory.MessageBodyFactory.init(MessageBodyFactory.java:162)
at com.sun.jersey.api.client.Client.init(Client.java:343)
at com.sun.jersey.api.client.Client.access$000(Client.java:119)
at com.sun.jersey.api.client.Client$1.f(Client.java:192)
at com.sun.jersey.api.client.Client$1.f(Client.java:188)
at com.sun.jersey.spi.inject.Errors.processWithErrors(Errors.java:193)
at com.sun.jersey.api.client.Client.<init>(Client.java:188)
at com.sun.jersey.api.client.Client.<init>(Client.java:171)
at com.sun.jersey.api.client.Client.create(Client.java:683)
at
org.apache.ranger.plugin.util.RangerRESTClient.buildClient(RangerRESTClient.java:228)
at
org.apache.ranger.plugin.util.RangerRESTClient.getClient(RangerRESTClient.java:193)
at
org.apache.ranger.plugin.util.RangerRESTClient.get(RangerRESTClient.java:473)
at
org.apache.ranger.admin.client.RangerAdminRESTClient.getRangerRolesDownloadResponse(RangerAdminRESTClient.java:1340)
at
org.apache.ranger.admin.client.RangerAdminRESTClient.getRolesIfUpdatedWithCred(RangerAdminRESTClient.java:1202)
at
org.apache.ranger.admin.client.RangerAdminRESTClient.getRolesIfUpdated(RangerAdminRESTClient.java:167)
at
org.apache.ranger.plugin.util.RangerRolesProvider.loadUserGroupRolesFromAdmin(RangerRolesProvider.java:183)
at
org.apache.ranger.plugin.util.RangerRolesProvider.loadUserGroupRoles(RangerRolesProvider.java:123)
at
org.apache.ranger.plugin.util.PolicyRefresher.loadRoles(PolicyRefresher.java:495)
at
org.apache.ranger.plugin.util.PolicyRefresher.startRefresher(PolicyRefresher.java:144)
at
org.apache.ranger.plugin.service.RangerBasePlugin.init(RangerBasePlugin.java:245)
at
org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor.start(RangerAuthorizationCoprocessor.java:1120)
at
org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor.start(RangerAuthorizationCoprocessor.java:160)
at
org.apache.hadoop.hbase.coprocessor.BaseEnvironment.startup(BaseEnvironment.java:69)
at
org.apache.hadoop.hbase.coprocessor.CoprocessorHost.checkAndLoadInstance(CoprocessorHost.java:285)
at
org.apache.hadoop.hbase.coprocessor.CoprocessorHost.loadSystemCoprocessors(CoprocessorHost.java:171)
at
org.apache.hadoop.hbase.master.MasterCoprocessorHost.<init>(MasterCoprocessorHost.java:155)
at
org.apache.hadoop.hbase.master.HMaster.initializeCoprocessorHost(HMaster.java:3870)
at
org.apache.hadoop.hbase.master.HMaster.finishActiveMasterInitialization(HMaster.java:902)
at
org.apache.hadoop.hbase.master.HMaster.startActiveMasterManager(HMaster.java:2175)
at org.apache.hadoop.hbase.master.HMaster.lambda$run$0(HMaster.java:520)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException:
org.glassfish.jersey.internal.RuntimeDelegateImpl
at
javax.ws.rs.ext.RuntimeDelegate.findDelegate(RuntimeDelegate.java:130)
at javax.ws.rs.ext.RuntimeDelegate.getInstance(RuntimeDelegate.java:97)
at javax.ws.rs.core.MediaType.valueOf(MediaType.java:172)
at com.sun.jersey.core.header.MediaTypes.<clinit>(MediaTypes.java:65)
... 33 more
Caused by: java.lang.ClassNotFoundException:
org.glassfish.jersey.internal.RuntimeDelegateImpl
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at javax.ws.rs.ext.FactoryFinder.newInstance(FactoryFinder.java:87)
at javax.ws.rs.ext.FactoryFinder.find(FactoryFinder.java:185)
at
javax.ws.rs.ext.RuntimeDelegate.findDelegate(RuntimeDelegate.java:112)
... 36 more
{code}
The HBase library depends on the javax.ws.rs-api-2.1.1.jar which loads the
org.glassfish.jersey.internal.RuntimeDelegateImpl class. However, this class is
only available in the Jersey 2 library. Therefore, when the HBase Ranger plugin
includes the jersey-client and jersey-core 1.x libraries, it pollutes the HBase
RuntimeDelegate loading.
This issue is described in the HBase issue tracker:
https://issues.apache.org/jira/browse/HBASE-22052
To reproduce this issue, install the HBase Ranger plugins for Ranger 2.4 on
HBase 2.x and enable the Ranger plugin by adding the following configuration
properties: hbase.coprocessor.master.classes
org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor
hbase.coprocessor.region.classes
org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor
hbase.coprocessor.regionserver.classes
org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor Then,
restart the HBase cluster.
Solution: When packaging hbase-agent in the distro module, modify the assembly
descriptor file src/main/assembly/hbase-agent.xml of hbase-agent. Remove jersey
core and jersey client from the includes section so that hbase 2 can load its
own jersey2-related packages.
> Hbase master can't start due to ranger-hbase-plugin jersey jar conflict
> ------------------------------------------------------------------------
>
> Key: RANGER-4201
> URL: https://issues.apache.org/jira/browse/RANGER-4201
> Project: Ranger
> Issue Type: Bug
> Components: Ranger
> Affects Versions: 2.3.0, 2.4.0
> Reporter: caijialiang
> Assignee: caijialiang
> Priority: Major
> Attachments: image-2023-04-27-16-11-05-561.png,
> image-2023-04-27-16-13-44-504.png, image-2023-04-27-16-14-10-803.png,
> image-2023-04-27-16-14-37-202.png, image-2023-04-27-16-15-44-539.png
>
>
>
> Issue description: HBase fails to start after enabling Ranger 2.4 plugin.
> Problem analysis is required.
> environment:
> linux centos7.4
> hbase 2.4.13
> ranger 2.4
> jdk1.8
> hadoop 3.3.4
> zookeeper 3.5.9
> Symptom: After integrating Ranger with HBase, HBase Master cannot start, and
> Region Server also crashes after running for a period of time. The same error
> message occurs during both processes.
>
> {code:java}
> [master/gs-server-13481:16000:becomeActiveMaster]
> coprocessor.CoprocessorHost: The coprocessor
> org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor threw
> java.lang.ExceptionInInitializerError
> java.lang.ExceptionInInitializerError
> at
> com.sun.jersey.core.spi.factory.MessageBodyFactory.initReaders(MessageBodyFactory.java:182)
> at
> com.sun.jersey.core.spi.factory.MessageBodyFactory.initReaders(MessageBodyFactory.java:175)
> at
> com.sun.jersey.core.spi.factory.MessageBodyFactory.init(MessageBodyFactory.java:162)
> at com.sun.jersey.api.client.Client.init(Client.java:343)
> at com.sun.jersey.api.client.Client.access$000(Client.java:119)
> at com.sun.jersey.api.client.Client$1.f(Client.java:192)
> at com.sun.jersey.api.client.Client$1.f(Client.java:188)
> at com.sun.jersey.spi.inject.Errors.processWithErrors(Errors.java:193)
> at com.sun.jersey.api.client.Client.<init>(Client.java:188)
> at com.sun.jersey.api.client.Client.<init>(Client.java:171)
> at com.sun.jersey.api.client.Client.create(Client.java:683)
> at
> org.apache.ranger.plugin.util.RangerRESTClient.buildClient(RangerRESTClient.java:228)
> at
> org.apache.ranger.plugin.util.RangerRESTClient.getClient(RangerRESTClient.java:193)
> at
> org.apache.ranger.plugin.util.RangerRESTClient.get(RangerRESTClient.java:473)
> at
> org.apache.ranger.admin.client.RangerAdminRESTClient.getRangerRolesDownloadResponse(RangerAdminRESTClient.java:1340)
> at
> org.apache.ranger.admin.client.RangerAdminRESTClient.getRolesIfUpdatedWithCred(RangerAdminRESTClient.java:1202)
> at
> org.apache.ranger.admin.client.RangerAdminRESTClient.getRolesIfUpdated(RangerAdminRESTClient.java:167)
> at
> org.apache.ranger.plugin.util.RangerRolesProvider.loadUserGroupRolesFromAdmin(RangerRolesProvider.java:183)
> at
> org.apache.ranger.plugin.util.RangerRolesProvider.loadUserGroupRoles(RangerRolesProvider.java:123)
> at
> org.apache.ranger.plugin.util.PolicyRefresher.loadRoles(PolicyRefresher.java:495)
> at
> org.apache.ranger.plugin.util.PolicyRefresher.startRefresher(PolicyRefresher.java:144)
> at
> org.apache.ranger.plugin.service.RangerBasePlugin.init(RangerBasePlugin.java:245)
> at
> org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor.start(RangerAuthorizationCoprocessor.java:1120)
> at
> org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor.start(RangerAuthorizationCoprocessor.java:160)
> at
> org.apache.hadoop.hbase.coprocessor.BaseEnvironment.startup(BaseEnvironment.java:69)
> at
> org.apache.hadoop.hbase.coprocessor.CoprocessorHost.checkAndLoadInstance(CoprocessorHost.java:285)
> at
> org.apache.hadoop.hbase.coprocessor.CoprocessorHost.loadSystemCoprocessors(CoprocessorHost.java:171)
> at
> org.apache.hadoop.hbase.master.MasterCoprocessorHost.<init>(MasterCoprocessorHost.java:155)
> at
> org.apache.hadoop.hbase.master.HMaster.initializeCoprocessorHost(HMaster.java:3870)
> at
> org.apache.hadoop.hbase.master.HMaster.finishActiveMasterInitialization(HMaster.java:902)
> at
> org.apache.hadoop.hbase.master.HMaster.startActiveMasterManager(HMaster.java:2175)
> at
> org.apache.hadoop.hbase.master.HMaster.lambda$run$0(HMaster.java:520)
> at java.lang.Thread.run(Thread.java:748)
> Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException:
> org.glassfish.jersey.internal.RuntimeDelegateImpl
> at
> javax.ws.rs.ext.RuntimeDelegate.findDelegate(RuntimeDelegate.java:130)
> at
> javax.ws.rs.ext.RuntimeDelegate.getInstance(RuntimeDelegate.java:97)
> at javax.ws.rs.core.MediaType.valueOf(MediaType.java:172)
> at com.sun.jersey.core.header.MediaTypes.<clinit>(MediaTypes.java:65)
> ... 33 more
> Caused by: java.lang.ClassNotFoundException:
> org.glassfish.jersey.internal.RuntimeDelegateImpl
> at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
> at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
> at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
> at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
> at java.lang.Class.forName0(Native Method)
> at java.lang.Class.forName(Class.java:264)
> at javax.ws.rs.ext.FactoryFinder.newInstance(FactoryFinder.java:87)
> at javax.ws.rs.ext.FactoryFinder.find(FactoryFinder.java:185)
> at
> javax.ws.rs.ext.RuntimeDelegate.findDelegate(RuntimeDelegate.java:112)
> ... 36 more {code}
> Steps to reproduce:
>
> * 1.After installing HBase 2.x and Ranger 2.4, configure HBase by modifying
> the hbase-site.xml file:
> * Set hbase.coprocessor.master.classes to
> org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor
> * Set hbase.coprocessor.region.classes to
> org.apache.hadoop.hbase.security.access.SecureBulkLoadEndpoint,org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor
> * Set hbase.coprocessor.regionserver.classes to
> org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor
> * Restart HBase and check the HBase Master logs to observe the exception and
> see the Master crash soon after
> solution:delete
> /usr/bigtop/3.2.0/usr/lib/hbase/lib/ranger-hbase-plugin-impl/jersey-core-1.19.3.jar
>
>
> related issues
> https://issues.apache.org/jira/browse/HBASE-22029
> https://issues.apache.org/jira/browse/HBASE-22052
> !image-2023-04-27-16-11-05-561.png!
> Problem Analysis:
> Conclusion: Exception caused by class loading order
>
> Analysis process: The call chain is roughly as follows: master start ->
> org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor.start
> ... ->com.sun.jersey.api.client.Client.create
> ...->com.sun.jersey.core.spi.factory.MessageBodyFactory.init
> ->com.sun.jersey.core.header.MediaTypes ->javax.ws.rs.core.MediaType.valueOf
> -> javax.ws.rs.ext.RuntimeDelegate.getInstance ->
> javax.ws.rs.ext.RuntimeDelegate.findDelegate
> I have fully investigated this call chain and found that the root cause of
> the problem is that javax.ws.rs.ext.RuntimeDelegate in the
> javax.ws.rs-api-2.1.1.jar package in HBase did not find
> org.glassfish.jersey.internal.RuntimeDelegateImpl when calling findDelegate,
> which caused the error. Specifically, javax.ws.rs.ext.RuntimeDelegate first
> looks for the default JAXRS_RUNTIME_DELEGATE, which is
> "javax.ws.rs.ext.RuntimeDelegate". If it cannot be found, it will fallback
> and load JAXRS_DEFAULT_RUNTIME_DELEGATE, which is
> org.glassfish.jersey.internal.RuntimeDelegateImpl.
> The method "findDelegate" in "javax.ws.rs.ext.RuntimeDelegate" is as follows:
> {code:java}
> public abstract class RuntimeDelegate {
> public static final String JAXRS_RUNTIME_DELEGATE_PROPERTY =
> "javax.ws.rs.ext.RuntimeDelegate";
> private static final String JAXRS_DEFAULT_RUNTIME_DELEGATE =
> "org.glassfish.jersey.internal.RuntimeDelegateImpl";
> private static final Object RD_LOCK = new Object();
> private static ReflectPermission suppressAccessChecksPermission = new
> ReflectPermission("suppressAccessChecks");
> private static volatile RuntimeDelegate cachedDelegate; protected
> RuntimeDelegate() {
> }
> public static RuntimeDelegate getInstance() {
> // Double-check idiom for lazy initialization of fields.
> // Local variable is used to limit the number of more expensive
> accesses to a volatile field.
> RuntimeDelegate result = cachedDelegate;
> if (result == null) { // First check (no locking)
> synchronized (RD_LOCK) {
> result = cachedDelegate;
> if (result == null) { // Second check (with locking)
> cachedDelegate = result = findDelegate();
> }
> }
> }
> return result;
> } private static RuntimeDelegate findDelegate() {
> try {
> Object delegate = FactoryFinder.find(
> JAXRS_RUNTIME_DELEGATE_PROPERTY,
> JAXRS_DEFAULT_RUNTIME_DELEGATE,
> RuntimeDelegate.class);
> if (!(delegate instanceof RuntimeDelegate)) {
> Class pClass = RuntimeDelegate.class;
> String classnameAsResource = pClass.getName().replace('.',
> '/') + ".class";
> ClassLoader loader = pClass.getClassLoader();
> if (loader == null) {
> loader = ClassLoader.getSystemClassLoader();
> }
> URL targetTypeURL = loader.getResource(classnameAsResource);
> throw new LinkageError("ClassCastException: attempting to
> cast"
> +
> delegate.getClass().getClassLoader().getResource(classnameAsResource)
> + " to " + targetTypeURL);
> }
> return (RuntimeDelegate) delegate;
> } catch (Exception ex) {
> throw new RuntimeException(ex);
> }
> }
> {code}
> When the "jersey-core-1.19.3.jar" file is removed from
> "/usr/bigtop/3.2.0/usr/lib/hbase/lib/ranger-hbase-plugin-impl/", HBase can
> start normally.
>
> It is not clear which class, either "javax.ws.rs.ext.RuntimeDelegate" or
> "org.glassfish.jersey.internal.RuntimeDelegateImpl", is loaded by HBase at
> this point.
>
> To determine which class is loaded and from which JAR file it is loaded, we
> can first remove "/usr/lib/hbase/lib/javax.ws.rs-api-2.1.1.jar" and start
> HBase normally. Then, we can use the Arthas tool
> (https://github.com/alibaba/arthas) to sniff and determine which class is
> loaded and from which JAR file it is loaded by the HBase JVM.
> After starting HBase normally, run the Arthas startup script "sudo -u hbase
> -EH ./as.sh " attach to the HBase process. Then, execute "sc -d
> javax.ws.rs.ext.RuntimeDelegat" to check whether
> "javax.ws.rs.ext.RuntimeDelegate" is loaded.
>
> result:
> {code:java}
> [arthas@1719]$ sc -d javax.ws.rs.ext.RuntimeDelegate
> class-info com.sun.jersey.core.spi.factory.AbstractRuntimeDelegate
> code-source
> /usr/bigtop/3.2.0/usr/lib/hadoop-hdfs/lib/jersey-core-1.19.jar
> name com.sun.jersey.core.spi.factory.AbstractRuntimeDelegate
> isInterface false
> isAnnotation false
> isEnum false
> isAnonymousClass false
> isArray false
> isLocalClass false
> isMemberClass false
> isPrimitive false
> isSynthetic false
> simple-name AbstractRuntimeDelegate
> modifier abstract,public
> annotation
> interfaces
> super-class +-javax.ws.rs.ext.RuntimeDelegate
> +-java.lang.Object
> class-loader +-sun.misc.Launcher$AppClassLoader@4fca772d
> +-sun.misc.Launcher$ExtClassLoader@436a4e4b
> classLoaderHash 4fca772d class-info
> com.sun.jersey.server.impl.provider.RuntimeDelegateImpl
> code-source /usr/bigtop/3.2.0/usr/lib/hadoop/lib/jersey-server-1.19.jar
> name com.sun.jersey.server.impl.provider.RuntimeDelegateImpl
> isInterface false
> isAnnotation false
> isEnum false
> isAnonymousClass false
> isArray false
> isLocalClass false
> isMemberClass false
> isPrimitive false
> isSynthetic false
> simple-name RuntimeDelegateImpl
> modifier public
> annotation
> interfaces
> super-class +-com.sun.jersey.core.spi.factory.AbstractRuntimeDelegate
> +-javax.ws.rs.ext.RuntimeDelegate
> +-java.lang.Object
> class-loader +-sun.misc.Launcher$AppClassLoader@4fca772d
> +-sun.misc.Launcher$ExtClassLoader@436a4e4b
> classLoaderHash 4fca772d class-info javax.ws.rs.ext.RuntimeDelegate
> code-source
> /usr/bigtop/3.2.0/usr/lib/hbase/lib/javax.ws.rs-api-2.1.1.jar
> name javax.ws.rs.ext.RuntimeDelegate
> isInterface false
> isAnnotation false
> isEnum false
> isAnonymousClass false
> isArray false
> isLocalClass false
> isMemberClass false
> isPrimitive false
> isSynthetic false
> simple-name RuntimeDelegate
> modifier abstract,public
> annotation
> interfaces
> super-class +-java.lang.Object
> class-loader +-sun.misc.Launcher$AppClassLoader@4fca772d
> +-sun.misc.Launcher$ExtClassLoader@436a4e4b
> classLoaderHash 4fca772dAffect(row-cnt:3) cost in 112 ms. {code}
> By removing the jersey-core-1.19.3.jar file from
> /usr/bigtop/3.2.0/usr/lib/hbase/lib/ranger-hbase-plugin-impl/, we can see
> that the abstract class javax.ws.rs.ext.RuntimeDelegate is loaded by the
> AppClassLoader from the javax.ws.rs-api-2.1.1.jar file located in
> /usr/bigtop/3.2.0/usr/lib/hbase/lib/.
> At the same time, the implementation of javax.ws.rs.ext.RuntimeDelegate,
> which is com.sun.jersey.server.impl.provider.RuntimeDelegateImpl, is loaded
> from the jersey-server-1.19.jar file located in
> /usr/bigtop/3.2.0/usr/lib/hadoop/lib/. Note that the hadoop lib directory is
> appended to HBase's classpath when HBase is started, which is why it can be
> loaded.
> Additionally, the abstract class
> com.sun.jersey.core.spi.factory.AbstractRuntimeDelegate, which inherits from
> RuntimeDelegate, is loaded from the jersey-core-1.19.jar file located in
> /usr/bigtop/3.2.0/usr/lib/hadoop-hdfs/lib/.
> However, even after removing the jersey-core-1.19.3.jar file, we can still
> see that HBase loads the same version of jersey-core-1.19.jar from the hadoop
> lib directory. Therefore, the root cause of the error is not a class not
> found due to a version conflict, but rather due to the order in which the
> class loader loads the classes.
>
> To verify this conclusion, the simplest way is to:
> # Before deleting the jersey-core-1.19.3.jar file from
> /ranger-hbase-plugin-impl/, print out the loading information of all the
> classes involved in the stack trace of the heap dump exception in the log.
> # After deleting the jersey-core-1.19.3.jar file, print out the loading
> information of all the classes involved in the stack trace of the heap dump
> exception in the log.
> # Use regular expressions to batch delete the timestamps from the log, and
> then compare the two log files to see any differences in the class loading
> information.
> In the Ranger 2.4 source code, Ranger implements its own class loader,
> RangerPluginClassLoader, which inherits from URLClassLoader. During
> initialization, it is passed the path to the
> ranger-\{componentname}-plugin-impl directory, and all the classes in this
> directory will be loaded by RangerPluginClassLoader. The parent is set to
> null, which in my understanding, is to block delegation loading. This is
> because all the classes in the ranger-\{componentname}-plugin-impl directory
> are dependencies of the Ranger plugin. For example, if the version of a jar
> that it depends on is lower, if the delegation loading mechanism is used, it
> is easy to load the higher version of the class under the component/lib
> directory, leading to class conflict issues. Therefore, parent is set to null.
> Internally, RangerPluginClassLoader first tries to load the jar files under
> the ranger-\{componentname}-plugin-impl directory using the parent
> URLClassLoader. If it can't be loaded, it uses the componentClassLoader,
> which is the current thread context's class loader, to load it.
> !image-2023-04-27-16-13-44-504.png!
> Next, you can take a look at the source code of the
> "RangerAuthorizationCoprocessor" class in Ranger. This class initializes an
> instance of "rangerPluginClassLoader" and activates it. Within this class,
> there are pre and post hooks for various HBase operations, primarily for
> performing range permission-related operations. This triggers the loading of
> Ranger-related classes by the rangerPluginClassLoader.
> !image-2023-04-27-16-14-10-803.png!
> Why does the hook activate the Ranger class loader at the beginning and
> de-activate it after the hook method ends? Doesn't this approach impact
> performance?
> !image-2023-04-27-16-14-37-202.png!
> The reason for de-activating the Ranger class loader after the hook method
> ends is because the rangerPluginClassLoader code sets itself as the current
> thread's context class loader. If it's not deactivated, it can cause
> conflicts with the lower version packages loaded in the
> .../ranger-hbase-plugin-impl/ directory, which can cause issues during
> subsequent operations. Therefore, the conclusion is that this involves the
> rangerPluginClassLoader and the AppClassLoader of the thread's context class
> loader.
> We also need to understand how to load an instance of "RuntimeDelegate" and
> how it searches for the implementation of "javax.ws.rs.ext.RuntimeDelegate".
> We should also investigate why it cannot find the implementation class and
> instead looks for "org.glassfish.jersey.internal.RuntimeDelegateImpl",
> causing an error.
> First, the "RuntimeDelegate" class is loaded via the
> "javax.ws.rs.ext.RuntimeDelegate.findDelegate" method, which calls
> "FactoryFinder.find" to load the class. Once loaded, the instance must be of
> type "RuntimeDelegate".
> {code:java}
> private static RuntimeDelegate findDelegate() {
> try {
> Object delegate = FactoryFinder.find("javax.ws.rs.ext.RuntimeDelegate",
> "org.glassfish.jersey.internal.RuntimeDelegateImpl", RuntimeDelegate.class);
> if (!(delegate instanceof RuntimeDelegate)) {
> Class<RuntimeDelegate> pClass = RuntimeDelegate.class;
> String classnameAsResource = pClass.getName().replace('.', '/') +
> ".class";
> ClassLoader loader = pClass.getClassLoader();
> if (loader == null)
> loader = ClassLoader.getSystemClassLoader();
> URL targetTypeURL = loader.getResource(classnameAsResource);
> throw new LinkageError("ClassCastException: attempting to cast" +
> delegate
> .getClass().getClassLoader().getResource(classnameAsResource) + "
> to " + targetTypeURL);
> }
> return (RuntimeDelegate)delegate;
> } catch (Exception ex) {
> throw new RuntimeException(ex);
> }
> } {code}
> The process of loading the class via "FactoryFinder.find" is contained in the
> "javax.ws.rs.ext.FactoryFinder.find" method, as shown in the following code:
> {code:java}
> /**
> * Finds the implementation {@code Class} for the given factory name,
> * or if that fails, finds the {@code Class} for the given fallback
> * class name and create its instance. The arguments supplied MUST be
> * used in order. If using the first argument is successful, the second
> * one will not be used.
> * <p>
> * This method is package private so that this code can be shared.
> *
> * @param factoryId the name of the factory to find, which is
> * a system property.
> * @param fallbackClassName the implementation class name, which is
> * to be used only if nothing else.
> * is found; {@code null} to indicate that
> * there is no fallback class name.
> * @param service service to be found.
> * @param <T> type of the service to be found.
> * @return the instance of the specified service; may not be {@code null}.
> * @throws ClassNotFoundException if the given class could not be found
> * or could not be instantiated.
> */
> static <T> Object find(final String factoryId, final String
> fallbackClassName, Class<T> service) throws ClassNotFoundException {
> ClassLoader classLoader = getContextClassLoader(); try {
> Iterator<T> iterator = ServiceLoader.load(service,
> FactoryFinder.getContextClassLoader()).iterator();
> if(iterator.hasNext()) {
> return iterator.next();
> }
> } catch (Exception | ServiceConfigurationError ex) {
> LOGGER.log(Level.FINER, "Failed to load service " + factoryId +
> ".", ex);
> } try {
> Iterator<T> iterator = ServiceLoader.load(service,
> FactoryFinder.class.getClassLoader()).iterator();
> if(iterator.hasNext()) {
> return iterator.next();
> }
> } catch (Exception | ServiceConfigurationError ex) {
> LOGGER.log(Level.FINER, "Failed to load service " + factoryId +
> ".", ex);
> } // try to read from $java.home/lib/jaxrs.properties
> FileInputStream inputStream = null;
> String configFile = null;
> try {
> String javah = System.getProperty("java.home");
> configFile = javah + File.separator + "lib" + File.separator +
> "jaxrs.properties";
> File f = new File(configFile);
> if (f.exists()) {
> Properties props = new Properties();
> inputStream = new FileInputStream(f);
> props.load(inputStream);
> String factoryClassName = props.getProperty(factoryId);
> return newInstance(factoryClassName, classLoader);
> }
> } catch (Exception ex) {
> LOGGER.log(Level.FINER, "Failed to load service " + factoryId
> + " from $java.home/lib/jaxrs.properties", ex);
> } finally {
> if (inputStream != null) {
> try {
> inputStream.close();
> } catch (IOException ex) {
> LOGGER.log(Level.FINER, String.format("Error closing %s
> file.", configFile), ex);
> }
> }
> } // Use the system property
> try {
> String systemProp = System.getProperty(factoryId);
> if (systemProp != null) {
> return newInstance(systemProp, classLoader);
> }
> } catch (SecurityException se) {
> LOGGER.log(Level.FINER, "Failed to load service " + factoryId
> + " from a system property", se);
> } if (fallbackClassName == null) {
> throw new ClassNotFoundException(
> "Provider for " + factoryId + " cannot be found", null);
> } return newInstance(fallbackClassName, classLoader);
> }
> } {code}
> To summarize the "FactoryFinder.find" method, it uses the thread context
> class loader to load "javax.ws.rs.ext.RuntimeDelegate". If that fails, it
> attempts to load it from system properties or alternative class names. If it
> still cannot be found, it tries to load
> "org.glassfish.jersey.internal.RuntimeDelegateImpl". If it cannot be loaded,
> it throws an exception.
> When the
> /usr/bigtop/3.2.0/usr/lib/hbase/lib/ranger-hbase-plugin-impl/jersey-core-1.19.3.jar
> file was not deleted, the class loading order was as follows:
> javax.ws.rs.ext.RuntimeDelegate(appClassLoader) ->
> javax.ws.rs.ext.RuntimeDelegate.HeaderDelegate(RangerPluginClassLoader) ->
> javax.ws.rs.ext.RuntimeDelegate.HeaderDelegateProvider(RangerPluginClassLoader
> jersey-core-1.19.3.jar ranger-hbase-plugin-impl/jersey-core-1.19.3.jar).
> The RangerPluginClassLoader searched for the
> com.sun.jersey.spi.HeaderDelegateProvider implementation class in the
> META-INF/services/com.sun.jersey.spi.HeaderDelegateProvider file of the
> jersey-core-1.19.3.jar file, found the
> com.sun.jersey.core.impl.provider.header.LocaleProvider class in
> ranger-hbase-plugin-impl/jersey-core-1.19.3.jar, and returned it.
> However, javax.ws.rs.ext.RuntimeDelegate.findDelegate would fail because
> delegate instanceof RuntimeDelegate returned false.
> As a fallback, it searched for
> org.glassfish.jersey.internal.RuntimeDelegateImpl, which was not found in the
> hbase classpath and caused an exception to be thrown.
> After removing ranger-hbase-plugin-impl/jersey-core-1.19.3.jar, HBase can be
> started normally. The class loading order is as follows:
> javax.ws.rs.ext.RuntimeDelegate is loaded from
> /usr/lib/hadoop/lib/javax.ws.rs-api-2.1.1.jar. Then, the implementation class
> of javax.ws.rs.ext.RuntimeDelegate is searched for, which is found in
> /usr/lib/hadoop/lib/jersey-server-1.19.jar->META-INF/services/javax.ws.rs.ext.RuntimeDelegate->com.sun.jersey.server.impl.provider.RuntimeDelegateImpl,
> and successfully loaded.
> The above class loading order was determined by modifying the code in the
> RangerPluginClassLoader to print out the process of loading all classes.
> !image-2023-04-27-16-15-44-539.png!
> The following is a log that includes the class loading order. By analyzing
> this log in conjunction with the Ranger class loader code, the above results
> can be determined.
>
--
This message was sent by Atlassian Jira
(v8.20.10#820010)