org.apache.hadoop.yarn.util.ApplicationClassLoader.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.yarn.util.ApplicationClassLoader.java

Source

/**
 * 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.util;

import java.io.File;
import java.io.FilenameFilter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience.Public;
import org.apache.hadoop.classification.InterfaceStability.Unstable;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Splitter;

/**
 * A {@link URLClassLoader} for YARN application isolation. Classes from
 * the application JARs are loaded in preference to the parent loader.
 */
@Public
@Unstable
public class ApplicationClassLoader extends URLClassLoader {

    private static final Log LOG = LogFactory.getLog(ApplicationClassLoader.class.getName());

    private static final FilenameFilter JAR_FILENAME_FILTER = new FilenameFilter() {
        @Override
        public boolean accept(File dir, String name) {
            return name.endsWith(".jar") || name.endsWith(".JAR");
        }
    };

    private ClassLoader parent;
    private List<String> systemClasses;

    public ApplicationClassLoader(URL[] urls, ClassLoader parent, List<String> systemClasses) {
        super(urls, parent);
        this.parent = parent;
        if (parent == null) {
            throw new IllegalArgumentException("No parent classloader!");
        }
        this.systemClasses = systemClasses;
    }

    public ApplicationClassLoader(String classpath, ClassLoader parent, List<String> systemClasses)
            throws MalformedURLException {
        this(constructUrlsFromClasspath(classpath), parent, systemClasses);
    }

    @VisibleForTesting
    static URL[] constructUrlsFromClasspath(String classpath) throws MalformedURLException {
        List<URL> urls = new ArrayList<URL>();
        for (String element : Splitter.on(File.pathSeparator).split(classpath)) {
            if (element.endsWith("/*")) {
                String dir = element.substring(0, element.length() - 1);
                File[] files = new File(dir).listFiles(JAR_FILENAME_FILTER);
                if (files != null) {
                    for (File file : files) {
                        urls.add(file.toURI().toURL());
                    }
                }
            } else {
                File file = new File(element);
                if (file.exists()) {
                    urls.add(new File(element).toURI().toURL());
                }
            }
        }
        return urls.toArray(new URL[urls.size()]);
    }

    @Override
    public URL getResource(String name) {
        URL url = null;

        if (!isSystemClass(name, systemClasses)) {
            url = findResource(name);
            if (url == null && name.startsWith("/")) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Remove leading / off " + name);
                }
                url = findResource(name.substring(1));
            }
        }

        if (url == null) {
            url = parent.getResource(name);
        }

        if (url != null) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("getResource(" + name + ")=" + url);
            }
        }

        return url;
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return this.loadClass(name, false);
    }

    @Override
    protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {

        if (LOG.isDebugEnabled()) {
            LOG.debug("Loading class: " + name);
        }

        Class<?> c = findLoadedClass(name);
        ClassNotFoundException ex = null;

        if (c == null && !isSystemClass(name, systemClasses)) {
            // Try to load class from this classloader's URLs. Note that this is like
            // the servlet spec, not the usual Java 2 behaviour where we ask the
            // parent to attempt to load first.
            try {
                c = findClass(name);
                if (LOG.isDebugEnabled() && c != null) {
                    LOG.debug("Loaded class: " + name + " ");
                }
            } catch (ClassNotFoundException e) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug(e);
                }
                ex = e;
            }
        }

        if (c == null) { // try parent
            c = parent.loadClass(name);
            if (LOG.isDebugEnabled() && c != null) {
                LOG.debug("Loaded class from parent: " + name + " ");
            }
        }

        if (c == null) {
            throw ex != null ? ex : new ClassNotFoundException(name);
        }

        if (resolve) {
            resolveClass(c);
        }

        return c;
    }

    @VisibleForTesting
    static boolean isSystemClass(String name, List<String> systemClasses) {
        if (systemClasses != null) {
            String canonicalName = name.replace('/', '.');
            while (canonicalName.startsWith(".")) {
                canonicalName = canonicalName.substring(1);
            }
            for (String c : systemClasses) {
                boolean result = true;
                if (c.startsWith("-")) {
                    c = c.substring(1);
                    result = false;
                }
                if (c.endsWith(".") && canonicalName.startsWith(c)) {
                    return result;
                } else if (canonicalName.equals(c)) {
                    return result;
                }
            }
        }
        return false;
    }
}