/* * 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.launcher; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FilenameFilter; import java.io.IOException; 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.Enumeration; import java.util.HashSet; import java.util.Properties; import java.util.Set; import java.util.jar.JarFile; import java.util.jar.Manifest; public class LauncherMain { private static final String DEFAULT_PROPERTY_FILENAME = "default.config"; private static final String CONFIG_CLASSPATH = "classpath"; private static final String CONFIG_MAIN_CLASS = "mainClass"; private static final String CONFIG_ARG_JAR_MAIN = "[firstArgJarManifestMainClass]"; private static final String LAUNCHER_ARGS = "launcherArgs"; public static void main(String[] args) throws SecurityException, IllegalArgumentException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, URISyntaxException, IOException { Properties launcherProperties = getLauncherProperties(args); setSystemProperties(launcherProperties); ClassLoader classLoader = getClassLoader(launcherProperties); String mainClassName = getMainClass(launcherProperties, classLoader); String[] mainArgs = getMainArgs(launcherProperties); invokeMainMethod(mainClassName, classLoader, mainArgs); } private static void setSystemProperties(Properties launcherProperties) throws URISyntaxException { for (Enumeration<?> e = launcherProperties.propertyNames(); e.hasMoreElements();) { String pn = (String) e.nextElement(); if (pn.startsWith("-D")) { System.setProperty(pn.substring(2), keywordExpand(launcherProperties.getProperty(pn))); } } } private static String keywordExpand(String property) throws URISyntaxException { if (property.contains("{TUSCANY_HOME}")) { property = property.replace("{TUSCANY_HOME}", getLauncherFolder().getParentFile().getAbsolutePath()); } return property; } private static String[] getMainArgs(Properties launcherProperties) { String[] mainArgs = (String[])launcherProperties.get(LAUNCHER_ARGS); if (mainArgs == null) { mainArgs = new String[0]; } return mainArgs; } private static String getMainClass(Properties launcherProperties, ClassLoader classLoader) { String mainClassName; String[] args = getMainArgs(launcherProperties); if (args.length > 0) { try { Class.forName(args[0], true, classLoader); mainClassName = args[0]; String[] args2 = new String[args.length-1]; System.arraycopy(args, 1, args2, 0, args.length-1); launcherProperties.put(LAUNCHER_ARGS, args2); } catch (ClassNotFoundException e) { mainClassName = launcherProperties.getProperty(CONFIG_MAIN_CLASS); } } else { mainClassName = launcherProperties.getProperty(CONFIG_MAIN_CLASS); } if (mainClassName.startsWith(CONFIG_ARG_JAR_MAIN + "|")) { mainClassName = mainClassName.substring(CONFIG_ARG_JAR_MAIN.length()+1); } return mainClassName; } private static void invokeMainMethod(String className, ClassLoader classLoader, String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { ClassLoader tccl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(classLoader); Class mainClass = Class.forName(className, true, classLoader); Method m = mainClass.getMethod("main", new Class[]{ args.getClass() }); m.invoke(null, new Object[]{args}); } finally { Thread.currentThread().setContextClassLoader(tccl); } } private static ClassLoader getClassLoader(Properties launcherProperties) throws URISyntaxException, IOException { Set<URL> jarURLs = new HashSet<URL>(); for (Enumeration<?> e = launcherProperties.propertyNames(); e.hasMoreElements();) { String pn = (String) e.nextElement(); if (pn.startsWith(CONFIG_CLASSPATH)) { jarURLs.addAll(getJARs(launcherProperties.getProperty(pn), launcherProperties)); } else if (pn.equals(CONFIG_MAIN_CLASS) && launcherProperties.getProperty(pn).startsWith(CONFIG_ARG_JAR_MAIN)) { if (firstArgJarHasManifestMainClass(launcherProperties)) { jarURLs.add(firstArgJarManifestMainClass(launcherProperties)); } } } ClassLoader parentCL = Thread.currentThread().getContextClassLoader(); if (parentCL == null) { parentCL = LauncherMain.class.getClassLoader(); } return new URLClassLoader(jarURLs.toArray(new URL[]{}), parentCL); } private static void argJars(Set<URL> jarURLs, Properties launcherProperties) throws IOException { String[] args = (String[])launcherProperties.get(LAUNCHER_ARGS); if (args != null && args.length > 0) { for (String a : args) { File f = new File(a); if (!f.exists()) { throw new FileNotFoundException(args[0]); } jarURLs.add(f.toURI().toURL()); } } launcherProperties.put(LAUNCHER_ARGS, new String[]{}); } private static URL firstArgJarManifestMainClass(Properties launcherProperties) throws IOException { String[] args = (String[])launcherProperties.get(LAUNCHER_ARGS); if (args.length < 1) { throw new IllegalArgumentException("must specifiy a jar file"); } File f = new File(args[0]); if (!f.exists()) { throw new FileNotFoundException(args[0]); } JarFile jar = new JarFile(f); String mfc = jar.getManifest().getMainAttributes().getValue("Main-Class"); if (mfc == null || mfc.length() < 1) { throw new IllegalArgumentException("first jar file missing manifest Main-Class attribute"); } launcherProperties.setProperty(CONFIG_MAIN_CLASS, mfc); return f.toURL(); } private static boolean firstArgJarHasManifestMainClass(Properties launcherProperties) throws IOException { String[] args = (String[])launcherProperties.get(LAUNCHER_ARGS); if (args.length < 1) { return false; } File f = new File(args[0]); if (!f.exists() || f.isDirectory()) { return false; } JarFile jar = new JarFile(f); Manifest mf = jar.getManifest(); if (mf != null) { String mfc = jar.getManifest().getMainAttributes().getValue("Main-Class"); return mfc != null && mfc.length() > 0; } else { return false; } } /** * Gets the jars matching a config classpath property * property values may be an explicit jar name or use an asterix wildcard for * all jars in a folder, or a double asterix '**' for all jars in a folder and its subfolders * @throws URISyntaxException */ private static Set<URL> getJARs(String classpathValue, Properties launcherProperties) throws URISyntaxException { Set<URL> jarURLs = new HashSet<URL>(); if (classpathValue.endsWith("**")) { File folder = new File(classpathValue.substring(0, classpathValue.length()-2)); if (!folder.isAbsolute()) { folder = new File(getLauncherFolder().getParent(), folder.getName()); } jarURLs.addAll(getFolderJars(folder)); jarURLs.addAll(getSubFolderJars(folder)); } else if (classpathValue.endsWith("*")) { File folder = new File(classpathValue.substring(0, classpathValue.length()-1)); if (!folder.isAbsolute()) { folder = new File(getLauncherFolder(), folder.getName()); } jarURLs.addAll(getFolderJars(folder)); } else { File f = new File(classpathValue); if (!f.isAbsolute()) { f = new File(getLauncherFolder(), classpathValue); } try { jarURLs.add(f.toURI().toURL()); } catch (MalformedURLException e) { throw new RuntimeException("Exception getting JAR URL", e); } } return jarURLs; } /** * Gets all the jars in a folder */ private static Set<URL> getFolderJars(File folder) { Set<URL> jarURLs = new HashSet<URL>(); if (folder.exists() && folder.isDirectory()) { File[] files = folder.listFiles(new FilenameFilter(){ public boolean accept(File dir, String name) { return name.endsWith(".jar"); }}); for (File f : files) { try { jarURLs.add(f.toURI().toURL()); } catch (MalformedURLException e) { throw new RuntimeException("Exception getting JAR URL", e); } } } return jarURLs; } /** * Recursively gets all the jars in a folder and its subfolders */ private static Set<URL> getSubFolderJars(File folder) { Set<URL> jarURLs = new HashSet<URL>(); if (folder.exists() && folder.isDirectory()) { File[] files = folder.listFiles(new FileFilter(){ public boolean accept(File pathname) { return pathname.isDirectory(); }}); for (File f : files) { jarURLs.addAll(getFolderJars(f)); jarURLs.addAll(getSubFolderJars(f)); } } return jarURLs; } /** * Read the config properties for this launcher invocation * (Either default.config or the 1st cmd line argument suffixed with ".config" if that file exists */ private static Properties getLauncherProperties(String[] args) throws URISyntaxException, FileNotFoundException { Properties properties = new Properties(); File f; if (args.length > 0) { f = new File(getLauncherFolder(), args[0] + ".config"); if (f.exists()) { String[] args2 = new String[args.length-1]; System.arraycopy(args, 1, args2, 0, args.length-1); args = args2; } else { f = new File(getLauncherFolder(), DEFAULT_PROPERTY_FILENAME); } } else { f = new File(getLauncherFolder(), DEFAULT_PROPERTY_FILENAME); } if (!f.exists()) { // throw new FileNotFoundException(f.getName()); if (args.length > 0 && "client".equals(args[0])) { properties.put("mainClass", "org.apache.tuscany.sca.client.javascript.TuscanyShell"); String[] args2 = new String[args.length-1]; System.arraycopy(args, 1, args2, 0, args.length-1); args = args2; } else { properties.put("mainClass", "[firstArgJarManifestMainClass]|org.apache.tuscany.sca.domain.node.DomainNodeMain"); } } else { try { FileInputStream fis = new FileInputStream(f); properties.load(fis); fis.close(); } catch (IOException e) { throw new RuntimeException(e); } } properties.put(LAUNCHER_ARGS, args); return properties; } /** * Find the folder that contains the launcher jar */ private static File getLauncherFolder() throws URISyntaxException { File folder = null; String resource = LauncherMain.class.getName().replace('.', '/') + ".class"; URL url = LauncherMain.class.getClassLoader().getResource(resource); if (url != null) { URI uri = url.toURI(); String scheme = uri.getScheme(); if (uri.getScheme().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()) { folder = file; } } } } folder = folder.getParentFile(); return folder; } }