All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tuscany.sca.node.launcher.NodeLauncherUtil Maven / Gradle / Ivy

The newest version!
/*
 * 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.tuscany.sca.node.launcher;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Common functions and constants used by the admin components.
 *
 * @version $Rev: 790349 $ $Date: 2009-07-01 13:02:09 -0700 (Wed, 01 Jul 2009) $
 */
final class NodeLauncherUtil {
    private static final String NODE_FACTORY = "org.apache.tuscany.sca.node.NodeFactory";

    private static final Logger logger = Logger.getLogger(NodeLauncherUtil.class.getName());

    private static final String TUSCANY_HOME = "TUSCANY_HOME";
    private static final String TUSCANY_PATH = "TUSCANY_PATH";


    /**
     * Returns a ClassLoader for the Tuscany runtime JARs for use in a standalone
     * J2SE environment.
     *
     * @param parentClassLoader
     *
     * @return
     */
    static ClassLoader standAloneRuntimeClassLoader(ClassLoader parentClassLoader) throws FileNotFoundException, URISyntaxException, MalformedURLException {
        return runtimeClassLoader(parentClassLoader, new StandAloneJARFileNameFilter());
    }

    /**
     * Returns a ClassLoader for the Tuscany runtime JARs for use in a Webapp
     * environment.
     *
     * @param parentClassLoader
     *
     * @return
     */
    static ClassLoader webAppRuntimeClassLoader(ClassLoader parentClassLoader) throws FileNotFoundException, URISyntaxException, MalformedURLException {
        return runtimeClassLoader(parentClassLoader, new WebAppJARFileNameFilter());
    }

    /**
     * Returns a ClassLoader for the Tuscany runtime JARs.
     *
     * @param parentClassLoader
     * @param filter
     *
     * @return
     */
    private static ClassLoader runtimeClassLoader(ClassLoader parentClassLoader, FilenameFilter filter) throws FileNotFoundException, URISyntaxException, MalformedURLException {
        // First try to see if the runtime classes are already on the classpath
        // If yes, skip the discovery to avoid duplicate jars
        try {
            Class.forName(NODE_FACTORY, false, parentClassLoader);
            return parentClassLoader;
        } catch (ClassNotFoundException e) {
            // Ignore;
        }
        // Build list of runtime JARs
        Set jarDirectoryURLs = new HashSet();
        Set jarURLs = new HashSet();

        // First determine the path to the launcher class
        String resource = NodeLauncherUtil.class.getName().replace('.', '/') + ".class";
        URL url = NodeLauncherUtil.class.getClassLoader().getResource(resource);
        if (url == null) {
            throw new FileNotFoundException(resource);
        }
        URI uri = url.toURI();

        // If the launcher class is in a JAR, add all runtime JARs from directory containing
        // that JAR (e.g. the Tuscany modules directory) as well as the ../modules and
        // ../lib directories
        String scheme = uri.getScheme();
        if (scheme.equals("jar")) {
            String path = uri.toString().substring(4);
            int i = path.indexOf("!/");
            if (i != -1) {
                path = path.substring(0, i);
                uri = URI.create(path);
            }

            File file = new File(uri);
            if (file.exists()) {
                File jarDirectory = file.getParentFile();
                if (jarDirectory != null && jarDirectory.exists()) {
                    File homeDirectory = jarDirectory.getParentFile();
                    if (homeDirectory != null && homeDirectory.exists()) {
                        collectJARFiles(homeDirectory.getPath(), jarDirectoryURLs, jarURLs, filter);
                    }
                }
            }
        }

        // Look for a TUSCANY_HOME system property or environment variable
        // Add all the JARs found under $TUSCANY_HOME, $TUSCANY_HOME/modules
        // and $TUSCANY_HOME/lib
        String home = System.getProperty(TUSCANY_HOME);
        if (home == null || home.length() == 0) {
            home = System.getenv(TUSCANY_HOME);
        }
        if (home != null && home.length() != 0) {
            logger.fine(TUSCANY_HOME + ": " + home);
            collectJARFiles(home, jarDirectoryURLs, jarURLs, filter);
        }

        // Look for a TUSCANY_PATH system property or environment variable
        // Add all the JARs found under $TUSCANY_PATH, $TUSCANY_PATH/modules
        // and $TUSCANY_PATH/lib
        String ext = System.getProperty(TUSCANY_PATH);
        if (ext == null || ext.length() == 0) {
            ext = System.getenv(TUSCANY_PATH);
        }
        if (ext != null && ext.length() != 0) {
            logger.fine(TUSCANY_PATH + ": " + ext);
            String separator = System.getProperty("path.separator");
            for (StringTokenizer tokens = new StringTokenizer(ext, separator); tokens.hasMoreTokens(); ) {
                collectJARFiles(tokens.nextToken(), jarDirectoryURLs, jarURLs, filter);
            }
        }

        // Return the runtime class loader
        if (!jarURLs.isEmpty()) {
            // Remove the URLs which are already in the parent classloader
            if (parentClassLoader instanceof URLClassLoader) {
                URLClassLoader cl = (URLClassLoader)parentClassLoader;
                jarURLs.removeAll(Arrays.asList(cl.getURLs()));
            }

            // Return a ClassLoader configured with the runtime JARs
            ClassLoader classLoader = new RuntimeClassLoader(jarURLs.toArray(new URL[jarURLs.size()]), parentClassLoader);
            return classLoader;

        } else {
            return null;
        }
    }

    /**
     * Collect JAR files under the given directory.
     *
     * @param directory
     * @param jarDirectoryURLs
     * @param jarURLs
     * @param filter
     * @throws MalformedURLException
     */
    private static void collectJARFiles(String directory, Set jarDirectoryURLs, Collection jarURLs, FilenameFilter filter)
        throws MalformedURLException {
        File directoryFile = new File(directory);
        URL directoryURL = directoryFile.toURI().toURL();
        if (!jarDirectoryURLs.contains(directoryURL) && directoryFile.exists()) {

            // Collect files under $TUSCANY_HOME
            jarDirectoryURLs.add(directoryURL);
            collectJARFiles(directoryFile, jarURLs, filter, false);

            // Collect files under $TUSCANY_HOME/modules
            File modulesDirectory = new File(directoryFile, "modules");
            URL modulesDirectoryURL = modulesDirectory.toURI().toURL();
            if (!jarDirectoryURLs.contains(modulesDirectoryURL) && modulesDirectory.exists()) {
                jarDirectoryURLs.add(modulesDirectoryURL);
                collectJARFiles(modulesDirectory, jarURLs, filter, true);
            }

            // Collect files under $TUSCANY_HOME/lib
            File libDirectory = new File(directoryFile, "lib");
            URL libDirectoryURL = libDirectory.toURI().toURL();
            if (!jarDirectoryURLs.contains(libDirectoryURL) && libDirectory.exists()) {
                jarDirectoryURLs.add(libDirectoryURL);
                collectJARFiles(libDirectory, jarURLs, filter, true);
            }
        }
    }

    /**
     * Collect JAR files in the given directory
     * @param directory
     * @param urls
     * @param filter
     * @param recursive
     * @throws MalformedURLException
     */
    private static void collectJARFiles(File directory, Collection urls, FilenameFilter filter, boolean recursive) throws MalformedURLException {
        File[] files = directory.listFiles(filter);
        if (files != null) {
            int count = 0;
            for (File file: files) {
                if (recursive && file.isDirectory()) {
                    collectJARFiles(file, urls, filter, recursive);
                } else if (file.isFile()) {
                    urls.add(file.toURI().toURL());
                    count++;
                }
            }
            if (count != 0 && logger.isLoggable(Level.FINE)) {
                logger.fine("Runtime classpath: "+ count + " JAR" + (count > 1? "s":"")+ " from " + directory.toString());
            }
        }
    }

    /**
     * A file name filter used to filter JAR files.
     */
    private static class StandAloneJARFileNameFilter implements FilenameFilter {

        public boolean accept(File dir, String name) {
            if(new File(dir, name).isDirectory()) {
                return true;
            }
            name = name.toLowerCase();

            // Exclude tuscany-sca-all and tuscany-sca-manifest as they duplicate
            // code in the individual runtime module JARs
            if (name.startsWith("tuscany-sca-all")) {
                return false;
            }
            if (name.startsWith("tuscany-sca-manifest")) {
                return false;
            }

            if ("features".equals(dir.getName()) && name.startsWith("equinox-manifest")) {
                return false;
            }

            // Filter out the Tomcat and Webapp hosts
            if (name.startsWith("tuscany-host-tomcat") ||
                name.startsWith("tuscany-host-webapp")) {
                //FIXME This is temporary
                return false;
            }

            // Include JAR and MAR files
            if (name.endsWith(".jar")) {
                return true;
            }
            if (name.endsWith(".mar")) {
                return true;
            }
            return false;
        }
    }

    /**
     * A file name filter used to filter JAR files.
     */
    private static class WebAppJARFileNameFilter extends StandAloneJARFileNameFilter {

        @Override
        public boolean accept(File dir, String name) {
            if (!super.accept(dir, name)) {
                return false;
            }
            name = name.toLowerCase();

            // Exclude servlet-api JARs
            if (name.startsWith("servlet-api")) {
                return false;
            }

            // Exclude the Tomcat and Jetty hosts
            if (name.startsWith("tuscany-host-tomcat") || name.startsWith("tuscany-host-jetty")) {
                //FIXME This is temporary
                return false;
            }

            return true;
        }
    }


    /**
     * Creates a new node.
     *
     * @param compositeURI
     * @param contributions
     * @throws LauncherException
     */
    static Object node(String configurationURI, String compositeURI, String compositeContent, Contribution[] contributions, ClassLoader contributionClassLoader) throws LauncherException {
        ClassLoader tccl = Thread.currentThread().getContextClassLoader();
        try {

            // Set up runtime ClassLoader
            ClassLoader runtimeClassLoader = runtimeClassLoader(Thread.currentThread().getContextClassLoader(),
                                                                new StandAloneJARFileNameFilter());
            if (runtimeClassLoader != null) {
                Thread.currentThread().setContextClassLoader(runtimeClassLoader);
            }

            // Use Java reflection to create the node as only the runtime class
            // loader knows the runtime classes required by the node
            String className = NODE_FACTORY;
            Class bootstrapClass;
            if (runtimeClassLoader != null) {
                bootstrapClass = Class.forName(className, true, runtimeClassLoader);
            } else {
                bootstrapClass = Class.forName(className);
            }

            Object node =
                createNode(bootstrapClass,
                           configurationURI,
                           compositeURI,
                           compositeContent,
                           contributions,
                           contributionClassLoader);

            return node;

        } catch (Exception e) {
            NodeLauncher.logger.log(Level.SEVERE, "SCA Node could not be created", e);
            throw new LauncherException(e);
        } finally {
            Thread.currentThread().setContextClassLoader(tccl);
        }
    }

    private static Object createNode(Class bootstrapClass,
                                     String configurationURI,
                                     String compositeURI,
                                     String compositeContent,
                                     Contribution[] contributions,
                                     ClassLoader contributionClassLoader) throws NoSuchMethodException,
        IllegalAccessException, InvocationTargetException, MalformedURLException {
        Method newInstance = bootstrapClass.getMethod("newInstance");
        Object nodeFactory = newInstance.invoke(null);

        Object node;
        if (configurationURI != null) {

            URL url = null;
            URI uri = URI.create(configurationURI);
            if (uri.getScheme() == null) {
                uri = new File(configurationURI).toURI();
            }
            url = uri.toURL();

            // NodeFactory.createNode(URL)
            Method create = bootstrapClass.getMethod("createNode", URL.class);
            node = create.invoke(nodeFactory, url);

        } else if (contributionClassLoader != null) {

            // NodeFactory.createNode(String, ClassLoader)
            Method create = bootstrapClass.getMethod("createNode", String.class, ClassLoader.class);
            node = create.invoke(nodeFactory, compositeURI, contributionClassLoader);

        } else if (compositeContent != null) {

            // NodeFactory.createNode(Reader, Stringp[], String[])
            Method create = bootstrapClass.getMethod("createNode", Reader.class, String[].class, String[].class);
            String[] uris = new String[contributions.length];
            String[] locations = new String[contributions.length];
            for (int i = 0; i < contributions.length; i++) {
                uris[i] = contributions[i].getURI();
                locations[i] = contributions[i].getLocation();
            }
            node = create.invoke(nodeFactory, compositeContent, uris, locations);

        } else {

            // NodeFactory.createNode(String, Stringp[], String[])
            Method create = bootstrapClass.getMethod("createNode", String.class, String[].class, String[].class);
            String[] uris = new String[contributions.length];
            String[] locations = new String[contributions.length];
            for (int i = 0; i < contributions.length; i++) {
                uris[i] = contributions[i].getURI();
                locations[i] = contributions[i].getLocation();
            }
            node = create.invoke(nodeFactory, compositeURI, uris, locations);
        }
        return node;
    }

    /**
     * Creates a new node daemon.
     *
     * @throws LauncherException
     */
    static Object nodeDaemon() throws LauncherException {
        ClassLoader tccl = Thread.currentThread().getContextClassLoader();
        try {
            // Set up runtime ClassLoader
            ClassLoader runtimeClassLoader = runtimeClassLoader(Thread.currentThread().getContextClassLoader(),
                                                                new StandAloneJARFileNameFilter());
            if (runtimeClassLoader != null) {
                Thread.currentThread().setContextClassLoader(runtimeClassLoader);
            }

            // Use Java reflection to create the node daemon as only the runtime class
            // loader knows the runtime classes required by the node
            String className = "org.apache.tuscany.sca.implementation.node.launcher.NodeImplementationDaemonBootstrap";
            Class bootstrapClass;
            if (runtimeClassLoader != null) {
                bootstrapClass = Class.forName(className, true, runtimeClassLoader);
            } else {
                bootstrapClass = Class.forName(className);
            }
            Object bootstrap = bootstrapClass.getConstructor().newInstance();

            Object nodeDaemon = bootstrapClass.getMethod("getNode").invoke(bootstrap);
            return nodeDaemon;

        } catch (Exception e) {
            NodeDaemonLauncher.logger.log(Level.SEVERE, "SCA Node Daemon could not be created", e);
            throw new LauncherException(e);
        } finally {
            Thread.currentThread().setContextClassLoader(tccl);
        }
    }

    /**
     * Creates a new domain manager.
     *
     * @throws LauncherException
     */
    static Object domainManager(String rootDirectory) throws LauncherException {
        ClassLoader tccl = Thread.currentThread().getContextClassLoader();
        try {
            // Set up runtime ClassLoader
            ClassLoader runtimeClassLoader = runtimeClassLoader(Thread.currentThread().getContextClassLoader(),
                                                                new StandAloneJARFileNameFilter());
            if (runtimeClassLoader != null) {
                Thread.currentThread().setContextClassLoader(runtimeClassLoader);
            }

            // Use Java reflection to create the node daemon as only the runtime class
            // loader knows the runtime classes required by the node
            String className = "org.apache.tuscany.sca.domain.manager.launcher.DomainManagerLauncherBootstrap";
            Class bootstrapClass;
            if (runtimeClassLoader != null) {
                bootstrapClass = Class.forName(className, true, runtimeClassLoader);
            } else {
                bootstrapClass = Class.forName(className);
            }
            Constructor constructor = bootstrapClass.getConstructor(String.class);
            Object bootstrap = constructor.newInstance(rootDirectory);

            Object domainManager = bootstrapClass.getMethod("getNode").invoke(bootstrap);
            return domainManager;

        } catch (Exception e) {
            DomainManagerLauncher.logger.log(Level.SEVERE, "SCA Domain Manager could not be created", e);
            throw new LauncherException(e);
        } finally {
            Thread.currentThread().setContextClassLoader(tccl);
        }
    }

    /**
     * Simple URL class loader for the runtime JARs
     */
    private static class RuntimeClassLoader extends URLClassLoader {
        private static final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        private ClassLoader parent;

        /**
         * Constructs a new class loader.
         * @param urls
         * @param parent
         */
        private RuntimeClassLoader(URL[] urls, ClassLoader parent) {
            super(urls);
            this.parent = parent;
        }

        @Override
        public URL findResource(String name) {
            URL url = super.findResource(name);
            if (url == null) {
                url = parent.getResource(name);
            }
            return url;
        }

        @Override
        public Enumeration findResources(String name) throws IOException {
            Enumeration resources = super.findResources(name);
            Enumeration parentResources = parent.getResources(name);
            List allResources = new ArrayList();
            for (; resources.hasMoreElements(); ) {
                allResources.add(resources.nextElement());
            }
            for (; parentResources.hasMoreElements(); ) {
                allResources.add(parentResources.nextElement());
            }
            return Collections.enumeration(allResources);
        }

        @Override
        protected Class findClass(String name) throws ClassNotFoundException {
            Class cl;

            // First try to load the class using the parent classloader
            try {
                cl = parent.loadClass(name);
                ClassLoader loadedBy = cl.getClassLoader();

                // If the class was not loaded directly by the parent classloader
                // or the system classloader try to load a local version of the class
                // using our RuntimeClassloader instead
                if (loadedBy != parent &&
                    loadedBy != systemClassLoader &&
                    loadedBy != null) {

                    try {
                        cl = super.findClass(name);
                    } catch (ClassNotFoundException e) {
                        // No class alternative was found in our RuntimeClassloader,
                        // use the class found in the parent classloader hierarchy
                    }
                }
            } catch (ClassNotFoundException e) {

                // The class was not found by the parent class loader, try
                // to load it using our RuntimeClassloader
                cl = super.findClass(name);
            }

            return cl;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy