001: /*
002: * ChainBuilder ESB
003: * Visual Enterprise Integration
004: *
005: * Copyright (C) 2006 Bostech Corporation
006: *
007: * This program is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License as published by the
009: * Free Software Foundation; either version 2 of the License, or (at your option)
010: * any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
014: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
015: * for more details.
016: *
017: * You should have received a copy of the GNU General Public License along with
018: * this program; if not, write to the Free Software Foundation, Inc.,
019: * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: *
021: *
022: * $Id: JavaUtils.java 6618 2007-04-11 01:05:28Z zjin $
023: */
024: package com.bostechcorp.cbesb.common.util;
025:
026: /*
027: * The Apache Software License, Version 1.1
028: *
029: *
030: * Copyright (c) 1999 The Apache Software Foundation. All rights
031: * reserved.
032: *
033: * Redistribution and use in source and binary forms, with or without
034: * modification, are permitted provided that the following conditions
035: * are met:
036: *
037: * 1. Redistributions of source code must retain the above copyright
038: * notice, this list of conditions and the following disclaimer.
039: *
040: * 2. Redistributions in binary form must reproduce the above copyright
041: * notice, this list of conditions and the following disclaimer in
042: * the documentation and/or other materials provided with the
043: * distribution.
044: *
045: * 3. The end-user documentation included with the redistribution,
046: * if any, must include the following acknowledgment:
047: * "This product includes software developed by the
048: * Apache Software Foundation (http://www.apache.org/)."
049: * Alternately, this acknowledgment may appear in the software itself,
050: * if and wherever such third-party acknowledgments normally appear.
051: *
052: * 4. The names "Xalan" and "Apache Software Foundation" must
053: * not be used to endorse or promote products derived from this
054: * software without prior written permission. For written
055: * permission, please contact apache@apache.org.
056: *
057: * 5. Products derived from this software may not be called "Apache",
058: * nor may "Apache" appear in their name, without prior written
059: * permission of the Apache Software Foundation.
060: *
061: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
062: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
063: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
064: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
065: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
066: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
067: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
068: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
069: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
070: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
071: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
072: * SUCH DAMAGE.
073: * ====================================================================
074: *
075: * This software consists of voluntary contributions made by many
076: * individuals on behalf of the Apache Software Foundation and was
077: * originally based on software copyright (c) 1999, Lotus
078: * Development Corporation., http://www.lotus.com. For more
079: * information on the Apache Software Foundation, please see
080: * <http://www.apache.org/>.
081: *
082: * $Id: JavaUtils.java 6618 2007-04-11 01:05:28Z zjin $
083: */
084:
085: import java.io.IOException;
086:
087: import org.apache.commons.logging.Log;
088: import org.apache.commons.logging.LogFactory;
089:
090: /** This class supports invoking Java compilation from within
091: * a Java program. Recent versions of the Java environment have
092: * provided such an API (in tools.jar). But that isn't available
093: * on all platforms, and a fallback to the command line may be needed
094: * (though this too may not always be available, eg. for security
095: * reasons).
096: * <p>
097: * There's an additional complication in some environments --
098: * such as Microsoft's VJ -- where the classpath as seen in
099: * the System Properties may not be the one the user expects.
100: * The code here is parameterized to try to deal with that.
101: */
102: public class JavaUtils {
103:
104: // One-time flag for whether we could dynamically load compiler API
105: private static boolean cantLoadCompiler = false;
106:
107: protected static transient Log logger = LogFactory
108: .getLog(JavaUtils.class);
109:
110: // Debug flag - generates debug stuff if true.
111: private static boolean debug = false;
112:
113: /** Control whether compilation occurs with the -g option
114: * (debugging information included in generated classfile).
115: * This is an attribute, rather than a parameter on the compile
116: * method, largely because it tends to be an all-or-nothing decision;
117: * generally you're either doing program development and want it,
118: * or running in production mode and don't. But that may not match
119: * the needs of future users...
120: * <p>
121: * TODO: Consider whether debug should be a parameter.
122: *
123: * @param boolean newDebug True to request debugging data,
124: * false to request optimized output. (It's uncommon to
125: * want both or neither!)
126: */
127: public static void setDebug(boolean newDebug) {
128: debug = newDebug;
129: }
130:
131: /** Try to compile a .java file on disk. This will first attempt to
132: * use the sun.java.tools.javac() method, then (if that is unavailable)
133: * fall back upon shelling out to a command line and running javac
134: * there.
135: * <p>
136: * NOTE: This must be _compiled_ with sun.java.tools.* (tools.jar)
137: * available. We could change that to use reflection instead, if we
138: * accept some overhead... minor compared to the cost of running the
139: * compiler!
140: * <p>
141: * This has complications on some platforms. For example, under
142: * Microsoft Visual Java (at least, as installed on my test system),
143: * I found that I had to specify paths to both javac and xerces.jar
144: * rather than counting on the shell's path and classpath having
145: * been set to reach these. For that reason I've parameterized this
146: * method with a few system properties, so you can adapt it to your
147: * own system's needs without modifying the code:
148: * <dl>
149: * <dt>org.apache.xalan.utils.synthetic.javac
150: * <dd>Command line issued to invoke the compiler. Defaults to "javac",
151: * which should work in most systems. In VJ, try setting it to
152: * "cmd /c %JAVA_HOME%\\bin\javac.exe"
153: * <dt>org.apache.xalan.utils.synthetic.moreclasspath
154: * <dd>Additional classpath, to be prepended to the one retrieved from
155: * java.class.path. Defaults to "" (empty). In VJ, try setting it to
156: * point to your copy of xerces.jar, which may not be found otherwise.
157: * TODO: Reconsider prepend versus append!
158: * </dl>
159: *
160: * @param String fileName Which .java file to compile. Note that this may
161: * be relative to the "current directory".
162: * @param String classPath Additional places to look for classes that
163: * this .java file depends upon. Becomes the javac command's
164: * -classpath parameter value.
165: * @return boolean True iff compilation succeeded.
166: */
167: public static boolean JDKcompile(String fileName, String classPath,
168: String dir) {
169: // String moreClassPath=
170: // System.getProperty("org.apache.xalan.util.synthetic.moreclasspath","")
171: // .trim();
172:
173: String moreClassPath = System
174: .getProperty(
175: "org.apache.xalan.util.synthetic.moreclasspath",
176: "../com.bostechcorp.cbesb.common.util/target/classes;../com.bostechcorp.cbesb.runtime.transformer/target/classes;"
177: + "../com.bostechcorp.cbesb.external.libs/org.eclipse.emf.common_2.2.0.v200606271057.jar;../com.bostechcorp.cbesb.external.libs/org.eclipse.emf.ecore_2.2.0.v200606271057.jar;../com.bostechcorp.cbesb.external.libs/org.eclipse.xsd_2.2.0.v200606271057.jar");
178: if (moreClassPath.length() > 0)
179: classPath = moreClassPath + ';' + classPath;
180:
181: if (debug) {
182: System.err.println("JavaEngine: Compiling " + fileName);
183: System.err.println("JavaEngine: Classpath is " + classPath);
184: }
185:
186: String dir_option = ".";
187:
188: if (dir.length() > 0) {
189: dir_option = dir;
190: }
191:
192: String code_option = debug ? "-g" : "-O";
193:
194: // Start by trying Sun's compiler API
195:
196: if (!cantLoadCompiler) {
197: String args[] = { code_option, "-d", dir_option,
198: "-classpath", classPath, fileName };
199:
200: try {
201: return new sun.tools.javac.Main(System.err, "javac")
202: .compile(args);
203: } catch (Throwable th) {
204: logger
205: .error("WARNING: Unable to load Java 1.1 compiler.\tSwitching to command-line invocation."
206: + th.getMessage());
207: if (logger.isDebugEnabled()) {
208: logger.debug("Exception in JDKcompile():", th);
209: }
210: cantLoadCompiler = true;
211: }
212: }
213:
214: // FALLTHRU:
215: // Can't load javac() method; try shelling out to the command
216: // line and invoking it via exec().
217: String javac_command = System.getProperty(
218: "org.apache.xalan.util.synthetic.javac", "javac");
219: String args[] = { javac_command, code_option, "-d", dir_option,
220: "-classpath", classPath, fileName };
221: try {
222: Process p = java.lang.Runtime.getRuntime().exec(args);
223: int compileOK = waitHardFor(p); // pause for debugging...
224: return compileOK == 0; //0 == no error reported
225: } catch (IOException e) {
226: System.err
227: .println("ERROR: IO exception during exec(javac).");
228: } catch (SecurityException e) {
229: System.err
230: .println("ERROR: Unable to create subprocess to exec(javac).");
231: }
232:
233: // FALLTHRU: All attempts failed.
234: return false;
235: }
236:
237: /** Subroutine: Like p.waitFor, but discards the InterruptedException
238: * and goes right back into a wait. I don't want to report compiler
239: * success or failure until it really has succeeded or failed... I think.
240: * @param Process p to be waited for
241: * @return the exitValue() of the process.
242: */
243: static int waitHardFor(java.lang.Process p) {
244: boolean done = false;
245: while (!done)
246: try {
247: p.waitFor();
248: done = true;
249: } catch (InterruptedException e) {
250: System.err
251: .println("(Compiler process wait interrupted and resumed)");
252: }
253: int ev = p.exitValue(); // Pause for debugging...
254: if (debug) {
255: System.err
256: .println("JavaEngine: Compiling ExitValue: " + ev);
257: }
258: return ev;
259: }
260:
261: }
|