Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
MuleBootstrap |
|
| 5.0;5 |
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 | 0 | super(); |
37 | 0 | } |
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 | 0 | File muleHome = null; |
49 | ||
50 | 0 | 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 | 0 | if (muleHomeVar != null && !muleHomeVar.trim().equals("") && !muleHomeVar.equals("%MULE_HOME%")) |
54 | { | |
55 | 0 | muleHome = new File(muleHomeVar).getCanonicalFile(); |
56 | } | |
57 | 0 | if (muleHome == null || !muleHome.exists() || !muleHome.isDirectory()) |
58 | { | |
59 | 0 | throw new IllegalArgumentException( |
60 | "Either MULE_HOME is not set or does not contain a valid directory."); | |
61 | } | |
62 | ||
63 | File muleBase; | |
64 | ||
65 | 0 | String muleBaseVar = System.getProperty("mule.base"); |
66 | 0 | if (muleBaseVar != null && !muleBaseVar.trim().equals("") && !muleBaseVar.equals("%MULE_BASE%")) |
67 | { | |
68 | 0 | muleBase = new File(muleBaseVar).getCanonicalFile(); |
69 | } | |
70 | else | |
71 | { | |
72 | 0 | muleBase = muleHome; |
73 | } | |
74 | ||
75 | // Build up a list of libraries from $MULE_HOME/lib/* and add them to the | |
76 | // classpath. | |
77 | 0 | DefaultMuleClassPathConfig classPath = new DefaultMuleClassPathConfig(muleHome, muleBase); |
78 | 0 | 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 | 0 | if (ReflectionHelper.getResource("META-INF/mule/license.props", MuleBootstrap.class) == null) |
83 | { | |
84 | 0 | 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 | 0 | if (!licenseHandler.getAcceptance()) |
89 | { | |
90 | 0 | 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 | 0 | if (!ReflectionHelper.isClassOnPath("javax.activation.DataSource", MuleBootstrap.class)) |
100 | { | |
101 | 0 | LibraryDownloader downloader = new LibraryDownloader(muleBase); |
102 | 0 | 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 | 0 | String mainClassName = null; |
108 | ||
109 | try | |
110 | { | |
111 | 0 | final String[][] cliOptions = ReflectionHelper.getCliOptions(); |
112 | 0 | mainClassName = ReflectionHelper.getCommandLineOption("main", args, cliOptions); |
113 | } | |
114 | 0 | catch (Exception e) |
115 | { | |
116 | 0 | System.out.println(e.toString()); |
117 | 0 | ReflectionHelper.wrapperStop(-1); |
118 | 0 | } |
119 | ||
120 | 0 | if (mainClassName == null) |
121 | { | |
122 | 0 | mainClassName = MuleServer.class.getName(); |
123 | } | |
124 | ||
125 | // Add the main class name as the first argument to the Wrapper. | |
126 | 0 | String[] appArgs = new String[args.length + 1]; |
127 | 0 | appArgs[0] = mainClassName; |
128 | 0 | System.arraycopy(args, 0, appArgs, 1, args.length); |
129 | ||
130 | // Call the wrapper | |
131 | 0 | ReflectionHelper.wrapperMain(appArgs); |
132 | 0 | } |
133 | ||
134 | private static void addLibrariesToClasspath(List urls) | |
135 | throws NoSuchMethodException, IllegalAccessException, InvocationTargetException | |
136 | { | |
137 | ||
138 | 0 | ClassLoader sys = ClassLoader.getSystemClassLoader(); |
139 | 0 | if (!(sys instanceof URLClassLoader)) |
140 | { | |
141 | 0 | 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 | 0 | 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 | 0 | Class refClass = URLClassLoader.class; |
169 | 0 | Method methodAddUrl = refClass.getDeclaredMethod("addURL", new Class[]{URL.class}); |
170 | 0 | methodAddUrl.setAccessible(true); |
171 | 0 | for (Iterator it = urls.iterator(); it.hasNext();) |
172 | { | |
173 | 0 | URL url = (URL)it.next(); |
174 | // System.out.println("Adding: " + url.toExternalForm()); | |
175 | 0 | methodAddUrl.invoke(sysCl, new Object[]{url}); |
176 | } | |
177 | 0 | } |
178 | } |