/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.yarn.server.nodemanager.containermanager; import java.io.IOException; import java.net.MalformedURLException; import java.nio.ByteBuffer; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Arrays; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.util.ApplicationClassLoader; import org.apache.hadoop.util.ReflectionUtils; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.server.api.ApplicationInitializationContext; import org.apache.hadoop.yarn.server.api.ApplicationTerminationContext; import org.apache.hadoop.yarn.server.api.AuxiliaryService; import org.apache.hadoop.yarn.server.api.ContainerInitializationContext; import org.apache.hadoop.yarn.server.api.ContainerTerminationContext; final class AuxiliaryServiceWithCustomClassLoader extends AuxiliaryService { private final AuxiliaryService wrapped; private final ClassLoader customClassLoader; private AuxiliaryServiceWithCustomClassLoader(String name, AuxiliaryService wrapped, ClassLoader customClassLoader) { super(name); this.wrapped = wrapped; this.customClassLoader = customClassLoader; } @Override protected void serviceInit(Configuration conf) throws Exception { // We pass a shared configuration as part of serviceInit call. // To avoid the scenario that we could get a ClassNotFoundException // when we use customClassLoader to load the class, we create a copy // of the configuration. Configuration config = new Configuration(conf); // reset the service configuration setConfig(config); config.setClassLoader(customClassLoader); ClassLoader original = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(customClassLoader); try { wrapped.init(config); } finally { Thread.currentThread().setContextClassLoader(original); } } @Override protected void serviceStart() throws Exception { ClassLoader original = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(customClassLoader); try { wrapped.start(); } finally { Thread.currentThread().setContextClassLoader(original); } } @Override protected void serviceStop() throws Exception { ClassLoader original = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(customClassLoader); try { wrapped.stop(); } finally { Thread.currentThread().setContextClassLoader(original); } } @Override public void initializeApplication( ApplicationInitializationContext initAppContext) { ClassLoader original = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(customClassLoader); try { wrapped.initializeApplication(initAppContext); } finally { Thread.currentThread().setContextClassLoader(original); } } @Override public void stopApplication(ApplicationTerminationContext stopAppContext) { ClassLoader original = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(customClassLoader); try { wrapped.stopApplication(stopAppContext); } finally { Thread.currentThread().setContextClassLoader(original); } } @Override public ByteBuffer getMetaData() { ClassLoader original = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(customClassLoader); try { return wrapped.getMetaData(); } finally { Thread.currentThread().setContextClassLoader(original); } } @Override public void initializeContainer(ContainerInitializationContext initContainerContext) { ClassLoader original = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(customClassLoader); try { wrapped.initializeContainer(initContainerContext); } finally { Thread.currentThread().setContextClassLoader(original); } } @Override public void stopContainer(ContainerTerminationContext stopContainerContext) { ClassLoader original = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(customClassLoader); try { wrapped.stopContainer(stopContainerContext); } finally { Thread.currentThread().setContextClassLoader(original); } } @Override public void setRecoveryPath(Path recoveryPath) { ClassLoader original = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(customClassLoader); try { wrapped.setRecoveryPath(recoveryPath); } finally { Thread.currentThread().setContextClassLoader(original); } } public static AuxiliaryServiceWithCustomClassLoader getInstance( Configuration conf, String className, String appClassPath) throws IOException, ClassNotFoundException { String[] systemClasses = conf.getTrimmedStrings(String.format( YarnConfiguration.NM_AUX_SERVICES_SYSTEM_CLASSES, className)); ClassLoader customClassLoader = createAuxServiceClassLoader( appClassPath, systemClasses); Class<?> clazz = Class.forName(className, true, customClassLoader); Class<? extends AuxiliaryService> sClass = clazz.asSubclass( AuxiliaryService.class); AuxiliaryService wrapped = ReflectionUtils.newInstance(sClass, conf); return new AuxiliaryServiceWithCustomClassLoader( className + " with custom class loader", wrapped, customClassLoader); } private static ClassLoader createAuxServiceClassLoader( final String appClasspath, final String[] systemClasses) throws IOException { try { return AccessController.doPrivileged( new PrivilegedExceptionAction<ClassLoader>() { @Override public ClassLoader run() throws MalformedURLException { return new ApplicationClassLoader(appClasspath, AuxServices.class.getClassLoader(), Arrays.asList(systemClasses)); } } ); } catch (PrivilegedActionException e) { Throwable t = e.getCause(); if (t instanceof MalformedURLException) { throw (MalformedURLException) t; } throw new IOException(e); } } }