Search in sources :

Example 1 with MainClassLoader

use of co.cask.cdap.common.app.MainClassLoader in project cdap by caskdata.

the class MapReduceContainerLauncher method launch.

/**
 * Launches the given main class. The main class will be loaded through the {@link MapReduceClassLoader}.
 *
 * @param mainClassName the main class to launch
 * @param args          arguments for the main class
 */
@SuppressWarnings("unused")
public static void launch(String mainClassName, String[] args) throws Exception {
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler());
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    List<URL> urls = ClassLoaders.getClassLoaderURLs(systemClassLoader, new ArrayList<URL>());
    // Remove the URL that contains the given main classname to avoid infinite recursion.
    // This is needed because we generate a class with the same main classname in order to intercept the main()
    // method call from the container launch script.
    URL resource = systemClassLoader.getResource(mainClassName.replace('.', '/') + ".class");
    if (resource == null) {
        throw new IllegalStateException("Failed to find resource for main class " + mainClassName);
    }
    if (!urls.remove(ClassLoaders.getClassPathURL(mainClassName, resource))) {
        throw new IllegalStateException("Failed to remove main class resource " + resource);
    }
    // Create a MainClassLoader for dataset rewrite
    URL[] classLoaderUrls = urls.toArray(new URL[urls.size()]);
    ClassLoader mainClassLoader = new MainClassLoader(classLoaderUrls, systemClassLoader.getParent());
    // Install the JUL to SLF4J Bridge
    try {
        mainClassLoader.loadClass(SLF4JBridgeHandler.class.getName()).getDeclaredMethod("install").invoke(null);
    } catch (Exception e) {
        // Log the error and continue
        LOG.warn("Failed to invoke SLF4JBridgeHandler.install() required for jul-to-slf4j bridge", e);
    }
    ClassLoaders.setContextClassLoader(mainClassLoader);
    // Creates the MapReduceClassLoader. It has to be loaded from the MainClassLoader.
    try {
        final ClassLoader classLoader = (ClassLoader) mainClassLoader.loadClass(MapReduceClassLoader.class.getName()).newInstance();
        Runtime.getRuntime().addShutdownHook(new Thread() {

            @Override
            public void run() {
                if (classLoader instanceof AutoCloseable) {
                    try {
                        ((AutoCloseable) classLoader).close();
                    } catch (Exception e) {
                        System.err.println("Failed to close ClassLoader " + classLoader);
                        e.printStackTrace();
                    }
                }
            }
        });
        Thread.currentThread().setContextClassLoader(classLoader);
        // Setup logging and stdout/stderr redirect
        // Invoke MapReduceClassLoader.getTaskContextProvider()
        classLoader.getClass().getDeclaredMethod("getTaskContextProvider").invoke(classLoader);
        // Invoke StandardOutErrorRedirector.redirectToLogger()
        classLoader.loadClass("co.cask.cdap.common.logging.StandardOutErrorRedirector").getDeclaredMethod("redirectToLogger", String.class).invoke(null, mainClassName);
        Class<?> mainClass = classLoader.loadClass(mainClassName);
        Method mainMethod = mainClass.getMethod("main", String[].class);
        mainMethod.setAccessible(true);
        LOG.info("Launch main class {}.main({})", mainClassName, Arrays.toString(args));
        mainMethod.invoke(null, new Object[] { args });
        LOG.info("Main method returned {}", mainClassName);
    } catch (Throwable t) {
        // LOG the exception since this exception will be propagated back to JVM
        // and kill the main thread (hence the JVM process).
        // If we don't log it here as ERROR, it will be logged by UncaughtExceptionHandler as DEBUG level
        LOG.error("Exception raised when calling {}.main(String[]) method", mainClassName, t);
        throw t;
    }
}
Also used : MapReduceClassLoader(co.cask.cdap.internal.app.runtime.batch.MapReduceClassLoader) Method(java.lang.reflect.Method) URL(java.net.URL) SLF4JBridgeHandler(org.slf4j.bridge.SLF4JBridgeHandler) MapReduceClassLoader(co.cask.cdap.internal.app.runtime.batch.MapReduceClassLoader) MainClassLoader(co.cask.cdap.common.app.MainClassLoader) UncaughtExceptionHandler(co.cask.cdap.common.logging.common.UncaughtExceptionHandler) MainClassLoader(co.cask.cdap.common.app.MainClassLoader)

Aggregations

MainClassLoader (co.cask.cdap.common.app.MainClassLoader)1 UncaughtExceptionHandler (co.cask.cdap.common.logging.common.UncaughtExceptionHandler)1 MapReduceClassLoader (co.cask.cdap.internal.app.runtime.batch.MapReduceClassLoader)1 Method (java.lang.reflect.Method)1 URL (java.net.URL)1 SLF4JBridgeHandler (org.slf4j.bridge.SLF4JBridgeHandler)1