001: /*
002: * BEGIN_HEADER - DO NOT EDIT
003: *
004: * The contents of this file are subject to the terms
005: * of the Common Development and Distribution License
006: * (the "License"). You may not use this file except
007: * in compliance with the License.
008: *
009: * You can obtain a copy of the license at
010: * https://open-esb.dev.java.net/public/CDDLv1.0.html.
011: * See the License for the specific language governing
012: * permissions and limitations under the License.
013: *
014: * When distributing Covered Code, include this CDDL
015: * HEADER in each file and include the License file at
016: * https://open-esb.dev.java.net/public/CDDLv1.0.html.
017: * If applicable add the following below this CDDL HEADER,
018: * with the fields enclosed by brackets "[]" replaced with
019: * your own identifying information: Portions Copyright
020: * [year] [name of copyright owner]
021: */
022:
023: /*
024: * @(#)JSEJBIBootstrap.java
025: * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
026: *
027: * END_HEADER - DO NOT EDIT
028: */
029: package com.sun.jbi.framework.jse;
030:
031: import java.io.File;
032: import java.lang.reflect.Constructor;
033: import java.lang.reflect.Method;
034: import java.net.URL;
035: import java.net.URLClassLoader;
036: import java.util.ArrayList;
037: import java.util.List;
038: import java.util.Properties;
039: import java.util.logging.Logger;
040:
041: import javax.management.MBeanServerConnection;
042: import javax.management.ObjectName;
043: import javax.management.remote.JMXConnector;
044: import javax.management.remote.JMXConnectorFactory;
045: import javax.management.remote.JMXServiceURL;
046:
047: /**
048: * Provides support for running JBI from the command-line.
049: *
050: * @author Sun Microsystems, Inc.
051: */
052: public class JSEJBIBootstrap implements Runnable {
053: /** JSR208 interfaces. */
054: private static final String JBI_JAR_NAME = "jbi.jar";
055: /** JBI runtime interfaces exposed to components. */
056: private static final String JBI_EXT_JAR_NAME = "jbi-ext.jar";
057:
058: /** Name of the top-level class of the JBI runtime framework. */
059: private static final String JBI_FRAMEWORK_CLASS_NAME = "com.sun.jbi.framework.jse.JSEJBIFramework";
060:
061: /** Runtime life cycle commands. */
062: private static final String START = "start";
063: private static final String STOP = "stop";
064:
065: /** Environment property used to override install root location. */
066: private static final String INSTALL_ROOT = "install.root";
067: /** Environment property used for instance name. */
068: public static final String INSTANCE_NAME = "instance.name";
069: /** Environment property used for JMX connector port setting. */
070: private static final String CONNECTOR_PORT = "connector.port";
071: /** Default connector port. */
072: private static final String DEFAULT_CONNECTOR_PORT = "8699";
073: /** Default instance name. */
074: private static final String DEFAULT_INSTANCE_NAME = "server";
075:
076: /** List of jars that should not be included in the runtime classloader. */
077: private List<String> mBlacklistJars = new ArrayList<String>();
078:
079: /** ClassLoader used for JBI runtime classes. These classes are not
080: * part of the component classloader hierarchy.
081: */
082: private ClassLoader mFrameworkClassLoader;
083:
084: /** ClassLoader for clases in lib/ext that become part of the component
085: * classloader hierarchy.
086: */
087: private ClassLoader mExtensionClassLoader;
088:
089: /** JBI installation directory. */
090: private File mJbiInstallDir;
091:
092: /** JBI Framework implementation */
093: private Object mJbiFramework;
094:
095: /** Environment properties */
096: private Properties mEnvironment;
097:
098: private Logger mLog = Logger.getLogger(this .getClass().getPackage()
099: .getName());
100:
101: /** Runs the JBI framework in stand-alone mode under Java SE. System
102: * properties defined at the command-line with '-D' are passed into the
103: * framework as environment properties.
104: * @param args not used at this time
105: * @throws Exception framework failed to initialize
106: */
107: public static void main(String[] args) {
108: JSEJBIBootstrap jbiBootstrap = new JSEJBIBootstrap(System
109: .getProperties());
110:
111: try {
112: jbiBootstrap.createJBIFramework();
113:
114: // Are we starting or stopping? Default to start.
115: if (args != null && args.length > 0
116: && STOP.equalsIgnoreCase(args[0])) {
117: jbiBootstrap.unloadJBIFramework();
118: } else {
119: jbiBootstrap.loadJBIFramework();
120: }
121: } catch (Exception ex) {
122: System.err.println(ex.getMessage());
123: }
124: }
125:
126: /** Create a new JSEJBIBootstrap instance with the specified environment.
127: * @param env environment properties
128: */
129: public JSEJBIBootstrap(Properties env) {
130: mEnvironment = env;
131:
132: // setup blacklist jars
133: mBlacklistJars.add(JBI_JAR_NAME);
134: mBlacklistJars.add(JBI_EXT_JAR_NAME);
135:
136: // If connector port is not specified, set a 'smart' value
137: if (mEnvironment.getProperty(CONNECTOR_PORT) == null) {
138: mEnvironment.setProperty(CONNECTOR_PORT,
139: DEFAULT_CONNECTOR_PORT);
140: }
141:
142: // If install root is not set, default to current working directory
143: String installPath = mEnvironment.getProperty(INSTALL_ROOT);
144: if (installPath == null) {
145: File installDir = new File(System.getProperty("user.dir"));
146: // account for javaw launch from a double-click on the jar
147: if (installDir.getName().equals("lib")) {
148: installDir = installDir.getParentFile();
149: }
150:
151: installPath = installDir.getAbsolutePath();
152: }
153:
154: mJbiInstallDir = new File(installPath);
155:
156: // quick sanity check on the install root
157: if (!mJbiInstallDir.isDirectory()
158: || !new File(mJbiInstallDir, "lib/jbi_rt.jar").exists()) {
159: throw new RuntimeException("Invalid JBI install root: "
160: + mJbiInstallDir.getAbsolutePath());
161: }
162:
163: // pass this information along to the core framework
164: mEnvironment.setProperty(INSTALL_ROOT, mJbiInstallDir
165: .getAbsolutePath());
166: }
167:
168: /** Shutdown hook to allow the JBI framework to exit gracefully in the
169: * event of an abrupt shutdown (e.g. ^C).
170: */
171: public void run() {
172: try {
173: // Using System.out because the loggers appear to be gone at this point
174: System.out
175: .println("Unloading JBI framework in response to VM termination.");
176: invoke(mJbiFramework, "unload");
177: System.out.println("JBI framework shutdown complete.");
178: } catch (Throwable t) {
179: mLog.severe("Failed to unload JBI framework: "
180: + t.toString());
181: }
182: }
183:
184: /** Loads the JBI framework using the Java SE platform wrapper. If the
185: * framework loads successfully, this method adds a shutdown hook to
186: * allow for civilized clean-up when the VM terminates.
187: */
188: void loadJBIFramework() {
189: try {
190: invoke(mJbiFramework, "load");
191:
192: //Add a shutdown hook to call unload when the VM exits
193: Runtime.getRuntime().addShutdownHook(new Thread(this ));
194: } catch (Throwable t) {
195: mLog
196: .severe("Failed to load JBI framework: "
197: + t.toString());
198: }
199: }
200:
201: /** Unloads the JBI framework using the Java SE platform wrapper. This is
202: * always a remote call, since the framework has (presumably) been loaded
203: * previously by another process.
204: */
205: void unloadJBIFramework() {
206: String errMsg = null;
207: JMXServiceURL serviceURL;
208: int jmxConnectorPort;
209:
210: try {
211: // Which port is the connector server running on?
212: jmxConnectorPort = Integer
213: .parseInt(mEnvironment.getProperty(CONNECTOR_PORT,
214: DEFAULT_CONNECTOR_PORT));
215:
216: serviceURL = (JMXServiceURL) invoke(mJbiFramework,
217: "getServiceURL", new Integer(jmxConnectorPort));
218:
219: JMXConnector jmxConn = JMXConnectorFactory
220: .connect(serviceURL);
221: MBeanServerConnection mbsConn = jmxConn
222: .getMBeanServerConnection();
223: ObjectName fwMBeanName = new ObjectName("com.sun.jbi.jse",
224: "instance", mEnvironment.getProperty(INSTANCE_NAME,
225: DEFAULT_INSTANCE_NAME));
226: mbsConn.invoke(fwMBeanName, "unload", new Object[0],
227: new String[0]);
228:
229: } catch (NumberFormatException nfEx) {
230: mLog.severe("Invalid JMX connector port value. "
231: + nfEx.getMessage());
232: } catch (javax.management.MBeanException mbEx) {
233: errMsg = mbEx.getTargetException().toString();
234: } catch (Throwable t) {
235: errMsg = t.toString();
236: }
237:
238: if (errMsg != null) {
239: System.err.println("Failed to unload JBI framework: "
240: + errMsg);
241: } else {
242: System.out.println("JBI framework has been unloaded.");
243: }
244: }
245:
246: /** Creates the JBI framework using the appropriate classloading structure.
247: */
248: private void createJBIFramework() throws Exception {
249: Class fwClass;
250: Constructor fwCtor;
251:
252: try {
253: createExtensionClassLoader();
254: createFrameworkClassLoader();
255:
256: // Set the thread context classloader to the extension classloader
257: Thread.currentThread().setContextClassLoader(
258: mExtensionClassLoader);
259:
260: fwClass = mFrameworkClassLoader
261: .loadClass(JBI_FRAMEWORK_CLASS_NAME);
262: fwCtor = fwClass.getDeclaredConstructor(Properties.class);
263: mJbiFramework = fwCtor.newInstance(mEnvironment);
264: } catch (Exception ex) {
265: throw new Exception("Failed to create JBI framework: "
266: + ex.getMessage());
267: }
268: }
269:
270: /** Creates a separate runtime classloader to avoid namespace pollution
271: * between the component classloading hierarchy and the JBI implementation.
272: * At present, this method is greedy and includes any file in the lib/
273: * directory in the runtime classpath.
274: */
275: private void createFrameworkClassLoader() {
276: ArrayList<URL> cpList = new ArrayList<URL>();
277: URL[] cpURLs = new URL[0];
278: File libDir = new File(mJbiInstallDir, "lib");
279:
280: // Everything in the lib directory goes into the classpath
281: for (File lib : libDir.listFiles()) {
282: try {
283: if (mBlacklistJars.contains(lib.getName())) {
284: // skip blacklisted jars
285: continue;
286: }
287:
288: cpList.add(lib.toURL());
289: } catch (java.net.MalformedURLException urlEx) {
290: mLog.warning("Bad library URL: " + urlEx.getMessage());
291: }
292: }
293:
294: cpURLs = cpList.toArray(cpURLs);
295: mFrameworkClassLoader = new URLClassLoader(cpURLs,
296: mExtensionClassLoader);
297: }
298:
299: /** Creates a separate extension classloader for the component classloading
300: * chain. All jars added in the lib/ext directory are automatically added
301: * to this classloader's classpath.
302: */
303: private void createExtensionClassLoader() {
304: ArrayList<URL> cpList = new ArrayList<URL>();
305: URL[] cpURLs = new URL[0];
306: File libDir = new File(mJbiInstallDir, "lib/ext");
307:
308: if (libDir.exists() || libDir.isDirectory()) {
309: try {
310: // Add the top-level ext directory
311: cpList.add(libDir.toURL());
312:
313: // Everything in the lib/ext directory goes into the classpath
314: for (File lib : libDir.listFiles()) {
315: cpList.add(lib.toURL());
316: }
317: } catch (java.net.MalformedURLException urlEx) {
318: mLog.warning("Bad library URL: " + urlEx.getMessage());
319: }
320: }
321:
322: cpURLs = cpList.toArray(cpURLs);
323: mExtensionClassLoader = new URLClassLoader(cpURLs, getClass()
324: .getClassLoader());
325: }
326:
327: /** Utility method to invoke a method using reflection. This is kind of
328: * a sloppy implementation, since we don't account for overloaded methods.
329: * @param obj contains the method to be invoked
330: * @param method name of the method to be invoked
331: * @param params parameters, if any
332: * @return returned object, if any
333: */
334: private Object invoke(Object obj, String method, Object... params)
335: throws Throwable {
336: Object result = null;
337:
338: try {
339: for (Method m : obj.getClass().getDeclaredMethods()) {
340: if (m.getName().equals(method)) {
341: result = m.invoke(obj, params);
342: break;
343: }
344: }
345:
346: return result;
347: } catch (java.lang.reflect.InvocationTargetException itEx) {
348: throw itEx.getTargetException();
349: }
350: }
351: }
|