1 /* 2 * $Id: MuleBootstrap.java 7976 2007-08-21 14:26:13Z dirk.olmes $ 3 * -------------------------------------------------------------------------------------- 4 * Copyright (c) MuleSource, Inc. All rights reserved. http://www.mulesource.com 5 * 6 * The software in this package is published under the terms of the CPAL v1.0 7 * license, a copy of which has been included with this distribution in the 8 * LICENSE.txt file. 9 */ 10 11 package org.mule.modules.boot; 12 13 import org.mule.MuleServer; 14 15 import java.io.File; 16 import java.lang.reflect.InvocationTargetException; 17 import java.lang.reflect.Method; 18 import java.net.URL; 19 import java.net.URLClassLoader; 20 import java.util.Iterator; 21 import java.util.List; 22 23 /** 24 * Determine which is the main class to run and delegate control to the Java Service 25 * Wrapper. <p/> MuleBootstrap class is responsible for constructing Mule's classpath 26 * from the Mule home folder. 27 */ 28 public class MuleBootstrap 29 { 30 31 /** 32 * Do not instantiate MuleBootstrap. 33 */ 34 private MuleBootstrap() 35 { 36 super(); 37 } 38 39 /** 40 * Entry point. 41 * 42 * @param args command-line arguments 43 * @throws Exception in case of any fatal problem 44 */ 45 public static void main(String args[]) throws Exception 46 { 47 // Make sure MULE_HOME is set. 48 File muleHome = null; 49 50 String muleHomeVar = System.getProperty("mule.home"); 51 // Note: we can't use StringUtils.isBlank() here because we don't have that 52 // library yet. 53 if (muleHomeVar != null && !muleHomeVar.trim().equals("") && !muleHomeVar.equals("%MULE_HOME%")) 54 { 55 muleHome = new File(muleHomeVar).getCanonicalFile(); 56 } 57 if (muleHome == null || !muleHome.exists() || !muleHome.isDirectory()) 58 { 59 throw new IllegalArgumentException( 60 "Either MULE_HOME is not set or does not contain a valid directory."); 61 } 62 63 File muleBase; 64 65 String muleBaseVar = System.getProperty("mule.base"); 66 if (muleBaseVar != null && !muleBaseVar.trim().equals("") && !muleBaseVar.equals("%MULE_BASE%")) 67 { 68 muleBase = new File(muleBaseVar).getCanonicalFile(); 69 } 70 else 71 { 72 muleBase = muleHome; 73 } 74 75 // Build up a list of libraries from $MULE_HOME/lib/* and add them to the 76 // classpath. 77 DefaultMuleClassPathConfig classPath = new DefaultMuleClassPathConfig(muleHome, muleBase); 78 addLibrariesToClasspath(classPath.getURLs()); 79 80 // If the license ack file isn't on the classpath, we need to 81 // display the EULA and make sure the user accepts it before continuing 82 if (ReflectionHelper.getResource("META-INF/mule/license.props", MuleBootstrap.class) == null) 83 { 84 LicenseHandler licenseHandler = new LicenseHandler(muleHome, muleBase); 85 // If the user didn't accept the license, then we have to exit 86 // Exiting this way insures that the wrapper won't try again 87 // (by default it'll try to start 3 times) 88 if (!licenseHandler.getAcceptance()) 89 { 90 ReflectionHelper.wrapperStop(-1); 91 } 92 } 93 94 // One-time download to get libraries not included in the Mule distribution 95 // due to silly licensing restrictions. 96 // 97 // Now we will download these libraries to MULE_BASE/lib/user. In 98 // a standard installation, MULE_BASE will be MULE_HOME. 99 if (!ReflectionHelper.isClassOnPath("javax.activation.DataSource", MuleBootstrap.class)) 100 { 101 LibraryDownloader downloader = new LibraryDownloader(muleBase); 102 addLibrariesToClasspath(downloader.downloadLibraries()); 103 } 104 105 // the core jar has been added dynamically, this construct will run with 106 // a new Mule classpath now 107 String mainClassName = null; 108 109 try 110 { 111 final String[][] cliOptions = ReflectionHelper.getCliOptions(); 112 mainClassName = ReflectionHelper.getCommandLineOption("main", args, cliOptions); 113 } 114 catch (Exception e) 115 { 116 System.out.println(e.toString()); 117 ReflectionHelper.wrapperStop(-1); 118 } 119 120 if (mainClassName == null) 121 { 122 mainClassName = MuleServer.class.getName(); 123 } 124 125 // Add the main class name as the first argument to the Wrapper. 126 String[] appArgs = new String[args.length + 1]; 127 appArgs[0] = mainClassName; 128 System.arraycopy(args, 0, appArgs, 1, args.length); 129 130 // Call the wrapper 131 ReflectionHelper.wrapperMain(appArgs); 132 } 133 134 private static void addLibrariesToClasspath(List urls) 135 throws NoSuchMethodException, IllegalAccessException, InvocationTargetException 136 { 137 138 ClassLoader sys = ClassLoader.getSystemClassLoader(); 139 if (!(sys instanceof URLClassLoader)) 140 { 141 throw new IllegalArgumentException( 142 "PANIC: Mule has been started with an unsupported classloader: " + sys.getClass().getName() 143 + ". " + "Please report this error to user<at>mule<dot>codehaus<dot>org"); 144 } 145 146 // system classloader is in this case the one that launched the application, 147 // which is usually something like a JDK-vendor proprietary AppClassLoader 148 URLClassLoader sysCl = (URLClassLoader)sys; 149 150 /* 151 * IMPORTANT NOTE: The more 'natural' way would be to create a custom 152 * URLClassLoader and configure it, but then there's a chicken-and-egg 153 * problem, as all classes MuleBootstrap depends on would have been loaded by 154 * a parent classloader, and not ours. There's no straightforward way to 155 * change this, and is documented in a Sun's classloader guide. The solution 156 * would've involved overriding the ClassLoader.findClass() method and 157 * modifying the semantics to be child-first, but that way we are calling for 158 * trouble. Hacking the primordial classloader is a bit brutal, but works 159 * perfectly in case of running from the command-line as a standalone app. 160 * All Mule embedding options then delegate the classpath config to the 161 * embedder (a developer embedding Mule in the app), thus classloaders are 162 * not modified in those scenarios. 163 */ 164 165 // get a Method ref from the normal class, but invoke on a proprietary parent 166 // object, 167 // as this method is usually protected in those classloaders 168 Class refClass = URLClassLoader.class; 169 Method methodAddUrl = refClass.getDeclaredMethod("addURL", new Class[]{URL.class}); 170 methodAddUrl.setAccessible(true); 171 for (Iterator it = urls.iterator(); it.hasNext();) 172 { 173 URL url = (URL)it.next(); 174 // System.out.println("Adding: " + url.toExternalForm()); 175 methodAddUrl.invoke(sysCl, new Object[]{url}); 176 } 177 } 178 }