| /* |
| * 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.lang.reflect.Constructor; |
| import java.lang.reflect.InvocationTargetException; |
| 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.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$ $Date$ |
| */ |
| final class NodeLauncherUtil { |
| 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 { |
| |
| // Build list of runtime JARs |
| Set<URL> jarDirectoryURLs = new HashSet<URL>(); |
| List<URL> jarURLs = new ArrayList<URL>(); |
| |
| // 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()) { |
| |
| // Collect JAR files from the directory containing the input JAR |
| // (e.g. the Tuscany modules directory) |
| URL jarDirectoryURL = jarDirectory.toURI().toURL(); |
| jarDirectoryURLs.add(jarDirectoryURL); |
| collectJARFiles(jarDirectory, jarURLs, filter); |
| |
| File homeDirectory = jarDirectory.getParentFile(); |
| if (homeDirectory != null && homeDirectory.exists()) { |
| |
| // Collect JARs from the ../modules directory |
| File modulesDirectory = new File(homeDirectory, "modules"); |
| URL modulesDirectoryURL = modulesDirectory.toURI().toURL(); |
| if (!jarDirectoryURLs.contains(modulesDirectoryURL) && modulesDirectory.exists()) { |
| jarDirectoryURLs.add(modulesDirectoryURL); |
| collectJARFiles(modulesDirectory, jarURLs, filter); |
| } |
| |
| // Collect JARs from the ../lib directory |
| File libDirectory = new File(homeDirectory, "lib"); |
| URL libDirectoryURL = libDirectory.toURI().toURL(); |
| if (!jarDirectoryURLs.contains(libDirectoryURL) && libDirectory.exists()) { |
| jarDirectoryURLs.add(libDirectoryURL); |
| collectJARFiles(libDirectory, 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()) { |
| |
| // 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<URL> jarDirectoryURLs, List<URL> 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); |
| |
| // 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); |
| } |
| |
| // 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); |
| } |
| } |
| } |
| |
| /** |
| * Collect JAR files in the given directory |
| * @param directory |
| * @param urls |
| * @param filter |
| * @throws MalformedURLException |
| */ |
| private static void collectJARFiles(File directory, List<URL> urls, FilenameFilter filter) throws MalformedURLException { |
| String[] files = directory.list(filter); |
| if (files != null) { |
| URL directoryURL = new URL(directory.toURI().toString() + "/"); |
| int count = 0; |
| for (String file: files) { |
| URL url = new URL(directoryURL, file); |
| urls.add(url); |
| count++; |
| } |
| if (count != 0) { |
| 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) { |
| 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; |
| } |
| |
| // 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 = "org.apache.tuscany.sca.implementation.node.launcher.NodeImplementationLauncherBootstrap"; |
| Class<?> bootstrapClass; |
| if (runtimeClassLoader != null) { |
| bootstrapClass = Class.forName(className, true, runtimeClassLoader); |
| } else { |
| bootstrapClass = Class.forName(className); |
| } |
| |
| Object bootstrap; |
| if (configurationURI != null) { |
| |
| // Construct the node with a configuration URI |
| bootstrap = bootstrapClass.getConstructor(String.class).newInstance(configurationURI); |
| |
| } else if (contributionClassLoader != null) { |
| |
| // Construct the node with a compositeURI and a classloader |
| Constructor<?> constructor = bootstrapClass.getConstructor(String.class, ClassLoader.class); |
| bootstrap = constructor.newInstance(compositeURI, contributionClassLoader); |
| |
| } else if (compositeContent != null) { |
| |
| // Construct the node with a composite URI, the composite content and |
| // the URIs and locations of a list of contributions |
| Constructor<?> constructor = bootstrapClass.getConstructor(String.class, 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(); |
| } |
| bootstrap = constructor.newInstance(compositeURI, compositeContent, uris, locations); |
| |
| } else { |
| |
| // Construct the node with a composite URI and the URIs and |
| // locations of a list of contributions |
| Constructor<?> constructor = bootstrapClass.getConstructor(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(); |
| } |
| bootstrap = constructor.newInstance(compositeURI, uris, locations); |
| } |
| |
| Object node = bootstrapClass.getMethod("getNode").invoke(bootstrap); |
| return node; |
| |
| } catch (Exception e) { |
| Throwable ce = e instanceof InvocationTargetException ? e.getCause() : e; |
| if (ce.getClass().getName().equals("org.osoa.sca.ServiceRuntimeException") && |
| ce.getCause() != null && |
| ce.getCause().getClass().getName().equals("org.apache.tuscany.sca.monitor.MonitorRuntimeException")) { |
| NodeLauncher.logger.log(Level.SEVERE, "SCA Node could not be created"); |
| throw new LauncherException("SCA Node could not be created"); |
| } |
| NodeLauncher.logger.log(Level.SEVERE, "SCA Node could not be created", e); |
| throw new LauncherException(e); |
| } finally { |
| Thread.currentThread().setContextClassLoader(tccl); |
| } |
| } |
| |
| /** |
| * 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<URL> findResources(String name) throws IOException { |
| Enumeration<URL> resources = super.findResources(name); |
| Enumeration<URL> parentResources = parent.getResources(name); |
| List<URL> allResources = new ArrayList<URL>(); |
| 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; |
| } |
| } |
| |
| } |