/******************************************************************************* * Copyright (c) 2004, 2010 BREDEX GmbH. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * BREDEX GmbH - initial API and implementation and/or initial documentation *******************************************************************************/ package org.eclipse.jubula.rc.common; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.StringTokenizer; import org.eclipse.jubula.tools.internal.constants.AUTServerExitConstants; /** * @author BREDEX GmbH * @created 10.11.2005 */ public class AutServerLauncher { /** <code>PATH_SEPARATOR</code> */ public static final String PATH_SEPARATOR = System.getProperty("path.separator"); //$NON-NLS-1$ /** * name for environment variable that should be set if old/classic class * loading should be used */ private static final String ENV_VAR_USE_CLASSIC_CLASSLOADER = "TEST_USE_CLASSIC_CL"; //$NON-NLS-1$ /** * hidden constructor */ private AutServerLauncher() { super(); } /** * Sets the classpaths, <br> * creates a ClassLoader for the AUTServer with its own classpath,<br> * loads the AUTServer with the created ClassLoader <br> * and calls the main-method of the AUTServer via Reflection.<br> * @param args Arguments of the main method * {@inheritDoc} */ public static void main(String[] args) { // create separate classloader for the AUT-Server // with Ext-ClassLoader as parent (if using "old/classic" class loading) // or App-ClassLoader as parent (if using "new/default" class loading). // ClassPath is AUT-Server-Path WITHOUT AUT-Path! URL[] urls = PathSplitter.createUrls( args[Constants.ARG_AUTSERVER_CLASSPATH]); URLClassLoader autServerClassLoader; String useClassicClassLoaderValue = null; try { // Unfortunately, we cannot use our EnvironmentUtils here // because it's not on the classpath yet. useClassicClassLoaderValue = System.getenv(ENV_VAR_USE_CLASSIC_CLASSLOADER); } catch (Throwable t) { // OK, looks like we won't be able to access environment variables. // We'll just assume that the variable wasn't set. } if (useClassicClassLoaderValue == null) { // Use JVM property as fallback useClassicClassLoaderValue = System.getProperty(ENV_VAR_USE_CLASSIC_CLASSLOADER); } if (useClassicClassLoaderValue != null) { // Use the old class loading autServerClassLoader = new UrlClassicClassLoader(urls, ClassLoader.getSystemClassLoader().getParent()); } else { // Use the new class loading autServerClassLoader = new UrlDefaultClassLoader(urls, ClassLoader.getSystemClassLoader()); } Thread.currentThread().setContextClassLoader(autServerClassLoader); try { // the AUTServer is loaded with a separate ClassLoader because // the AUT MUST NOT know the classpath of the AUTServer!!! Class autServerClass = autServerClassLoader .loadClass(Constants.AUTSERVER_CLASSNAME); Method mainMethod = autServerClass.getMethod("main", //$NON-NLS-1$ new Class[] {args.getClass()}); mainMethod.invoke(null, new Object[] {args}); } catch (ClassNotFoundException e) { e.printStackTrace(); System.exit(AUTServerExitConstants.AUT_START_ERROR_CNFE); } catch (IllegalAccessException e) { e.printStackTrace(); System.exit(AUTServerExitConstants.AUT_START_ERROR_IACCE); } catch (SecurityException e) { e.printStackTrace(); System.exit(AUTServerExitConstants .EXIT_SECURITY_VIOLATION_REFLECTION); } catch (NoSuchMethodException e) { e.printStackTrace(); System.exit(AUTServerExitConstants.AUT_START_ERROR_NSME); } catch (IllegalArgumentException e) { e.printStackTrace(); System.exit(AUTServerExitConstants.AUT_START_ERROR_IARGE); } catch (InvocationTargetException e) { e.printStackTrace(); System.exit(AUTServerExitConstants.AUT_START_ERROR_INVTE); } } /** * This ClassLoader tries to load the classes first. * It overrides the parent delegation! * * @author BREDEX GmbH * @created 16.01.2006 */ private static class UrlClassicClassLoader extends URLClassLoader { /** * Constructor * @param urls URL[] * @param parent ClassLoader */ public UrlClassicClassLoader(URL[] urls, ClassLoader parent) { super(urls, parent); } /** * Tries to load the given class first.<br> * <b>This method is the first of the ClassLoader hierarchy to load the class. * It overrides the parent-delegation!</b><br> * If this method fails to load the class, it calls super.loadClass(...). * {@inheritDoc} * @param name * @param resolve * @return * @throws ClassNotFoundException */ protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { // First, check if the class has already been loaded Class c = findLoadedClass(name); if (c == null) { try { // don't override parent delegation, if class is from a special package // e.g. "org.elipse.swt." // FIXME Clemens: pass a list of special packages as parameter in constructors if (name.startsWith("org.eclipse.swt")) { //$NON-NLS-1$ return super.loadClass(name, resolve); } // overriding parent delegation! c = findClass(name); } catch (ClassNotFoundException e) { // if not found, normal behavior of class loading return super.loadClass(name, resolve); } catch (SecurityException e) { return super.loadClass(name, resolve); } } if (resolve) { resolveClass(c); } return c; } /** * {@inheritDoc} * @param name * @return * @throws ClassNotFoundException */ public Class loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); } } /** * This ClassLoader tries to load the classes first. * It overrides the parent delegation! * * @author BREDEX GmbH * @created 01.12.2009 */ private static class UrlDefaultClassLoader extends URLClassLoader { /** * Constructor * @param urls URL[] * @param parent ClassLoader */ public UrlDefaultClassLoader(URL[] urls, ClassLoader parent) { super(urls, parent); } /** * Tries to load the given class first.<br> * <b>This method is the first of the ClassLoader hierarchy to load the class. * It overrides the parent-delegation!</b><br> * If this method fails to load the class, it calls super.loadClass(...). * {@inheritDoc} * @param name * @param resolve * @return * @throws ClassNotFoundException */ protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { // First, check if the class has already been loaded Class c = findLoadedClass(name); if (c == null) { try { // overriding parent delegation! c = findClass(name); } catch (ClassNotFoundException e) { // if not found, normal behaviour of class loading return super.loadClass(name, resolve); } catch (SecurityException e) { return super.loadClass(name, resolve); } } if (resolve) { resolveClass(c); } return c; } /** * {@inheritDoc} * @param name * @return * @throws ClassNotFoundException */ public Class loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); } /** * Overrides the standard way of finding a resource, which is to first * check the parent class loader. Instead, we first try to find the * resource ourselves. If we are unable to find it, we then fall back * to the parent class loader. * * {@inheritDoc} */ public URL getResource(String name) { URL resourceUrl = findResource(name); return resourceUrl != null ? resourceUrl : super.getResource(name); } } /** * @author BREDEX GmbH * @created 27.10.2005 */ private static class PathSplitter { /** * utility constructor */ private PathSplitter() { // utility class } /** * Splits the given String with paths separated with * Operating-System-Path-Separators into an Array of Strings * @param paths the paths to split * @return an Array of split paths */ private static String[] split(String paths) { String pathSeparator = System.getProperty("path.separator"); //$NON-NLS-1$ StringTokenizer pathElems = new StringTokenizer(paths, pathSeparator); String[] pathElements = new String[pathElems.countTokens()]; int i = 0; while (pathElems.hasMoreTokens()) { pathElements[i] = pathElems.nextToken(); i++; } return pathElements; } /** * @param classpath a classpath separated with OS-depending separators * @return an URL array of the given classpath. */ public static URL[] createUrls(String classpath) { String[] paths = PathSplitter.split(classpath); final int pathLength = paths.length; URL[] urls = new URL[pathLength]; try { for (int i = 0; i < pathLength; i++) { File file = new File(paths[i]); URL url = file.toURL(); urls[i] = url; } } catch (MalformedURLException e) { return new URL[0]; } return urls; } } }