jkesselm 00/10/26 15:00:53
Modified: java/src/org/apache/xalan/utils/synthetic JavaUtils.java Log: Generalizing, esp. to deal with MSVJ++ Revision Changes Path 1.2 +216 -66 xml-xalan/java/src/org/apache/xalan/utils/synthetic/JavaUtils.java Index: JavaUtils.java =================================================================== RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/utils/synthetic/JavaUtils.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- JavaUtils.java 2000/10/13 02:33:14 1.1 +++ JavaUtils.java 2000/10/26 22:00:52 1.2 @@ -1,79 +1,229 @@ -/* $Id: JavaUtils.java,v 1.1 2000/10/13 02:33:14 sboag Exp $ */ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 1999 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Xalan" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact [EMAIL PROTECTED] + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999, Lotus + * Development Corporation., http://www.lotus.com. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + * $Id: JavaUtils.java,v 1.2 2000/10/26 22:00:52 jkesselm Exp $ + */ package org.apache.xalan.utils.synthetic; import java.io.IOException; +/** This class supports invoking Java compilation from within + * a Java program. Recent versions of the Java environment have + * provided such an API (in tools.jar). But that isn't available + * on all platforms, and a fallback to the command line may be needed + * (though this too may not always be available, eg. for security + * reasons). + * <p> + * There's an additional complication in some environments -- + * such as Microsoft's VJ++ -- where the classpath as seen in + * the System Properties may not be the one the user expects. + * The code here is parameterized to try to deal with that. + */ public class JavaUtils { - // Debug flag - generates debug stuff if true. - private static boolean debug = false; + // One-time flag for whether we could dynamically load compiler API + private static boolean cantLoadCompiler=false; - // Temporarily copied from JavaEngine... - private static boolean cantLoadCompiler=false; // One-time flag for following - - // ADDED BY JKESS; callers want control over the -g option. - public static void setDebug(boolean newDebug) - { - debug=newDebug; - } - - public static boolean JDKcompile(String fileName, String classPath) - { - if (debug) - { - System.err.println ("JavaEngine: Compiling " + fileName); - System.err.println ("JavaEngine: Classpath is " + classPath); - } + // Debug flag - generates debug stuff if true. + private static boolean debug = false; + + /** Control whether compilation occurs with the -g option + * (debugging information included in generated classfile). + * This is an attribute, rather than a parameter on the compile + * method, largely because it tends to be an all-or-nothing decision; + * generally you're either doing program development and want it, + * or running in production mode and don't. But that may not match + * the needs of future users... + * <p> + * TODO: Consider whether debug should be a parameter. + * + * @param boolean newDebug True to request debugging data, + * false to request optimized output. (It's uncommon to + * want both or neither!) + */ + public static void setDebug(boolean newDebug) + { + debug=newDebug; + } + + /** Try to compile a .java file on disk. This will first attempt to + * use the sun.java.tools.javac() method, then (if that is unavailable) + * fall back upon shelling out to a command line and running javac + * there. + * <p> + * NOTE: This must be _compiled_ with sun.java.tools.* (tools.jar) + * available. We could change that to use reflection instead, if we + * accept some overhead... minor compared to the cost of running the + * compiler! + * <p> + * This has complications on some platforms. For example, under + * Microsoft Visual Java ++ (at least, as installed on my test system), + * I found that I had to specify paths to both javac and xerces.jar + * rather than counting on the shell's path and classpath having + * been set to reach these. For that reason I've parameterized this + * method with a few system properties, so you can adapt it to your + * own system's needs without modifying the code: + * <dl> + * <dt>org.apache.xalan.utils.synthetic.javac + * <dd>Command line issued to invoke the compiler. Defaults to "javac", + * which should work in most systems. In VJ++, try setting it to + * "cmd /c %JAVA_HOME%\\bin\javac.exe" + * <dt>org.apache.xalan.utils.synthetic.moreclasspath + * <dd>Additional classpath, to be prepended to the one retrieved from + * java.class.path. Defaults to "" (empty). In VJ++, try setting it to + * point to your copy of xerces.jar, which may not be found otherwise. + * TODO: Reconsider prepend versus append! + * </dl> + * + * @param String fileName Which .java file to compile. Note that this may + * be relative to the "current directory". + * @param String classPath Additional places to look for classes that + * this .java file depends upon. Becomes the javac command's + * -classpath parameter value. + * @return boolean True iff compilation succeeded. + */ + public static boolean JDKcompile(String fileName, String classPath) + { + String moreClassPath= + System.getProperty("org.apache.xalan.util.synthetic.moreclasspath","") + .trim(); + if(moreClassPath.length()>0) + classPath=moreClassPath+';'+classPath; + + if (debug) + { + System.err.println ("JavaEngine: Compiling " + fileName); + System.err.println ("JavaEngine: Classpath is " + classPath); + } - String option = debug ? "-g" : "-O"; + String code_option = debug ? "-g" : "-O"; - if(!cantLoadCompiler) - { - String args[] = { - option, - "-classpath", - classPath, - fileName - }; - try - { - return new sun.tools.javac.Main(System.err, "javac").compile(args); - } - catch (Throwable th) - { - System.err.println("WARNING: Unable to load Java 1.1 compiler."); - System.err.println("\tSwitching to command-line invocation."); - cantLoadCompiler=true; - } - } + // Start by trying Sun's compiler API + if(!cantLoadCompiler) + { + String args[] = { + code_option, + "-classpath", classPath, + fileName + }; + + try + { + return new sun.tools.javac.Main(System.err, "javac").compile(args); + } + catch (Throwable th) + { + System.err.println("WARNING: Unable to load Java 1.1 compiler."); + System.err.println("\tSwitching to command-line invocation."); + cantLoadCompiler=true; + } + } - // Can't load javac; try exec'ing it. - String args[] = { - "javac", - option, - "-classpath", - classPath, - fileName - }; - try - { - Process p=java.lang.Runtime.getRuntime().exec(args); - p.waitFor(); - return(p.exitValue()!=0); - } - catch(IOException e) - { - System.err.println("ERROR: IO exception during exec(javac)."); - } - catch(SecurityException e) - { - System.err.println("ERROR: Unable to create subprocess to exec(javac)."); - } - catch(InterruptedException e) - { - System.err.println("ERROR: Wait for exec(javac) was interrupted."); - } - return false; + // FALLTHRU: + // Can't load javac() method; try shelling out to the command + // line and invoking it via exec(). + String javac_command= + System.getProperty("org.apache.xalan.util.synthetic.javac","javac"); + String args[] = { + javac_command, + code_option, + "-classpath", classPath, + fileName + }; + try + { + Process p=java.lang.Runtime.getRuntime().exec(args); + int compileOK=waitHardFor(p); // pause for debugging... + return compileOK==0; //0 == no error reported + } + catch(IOException e) + { + System.err.println("ERROR: IO exception during exec(javac)."); + } + catch(SecurityException e) + { + System.err.println("ERROR: Unable to create subprocess to exec(javac)."); + } + + // FALLTHRU: All attempts failed. + return false; + } + + /** Subroutine: Like p.waitFor, but discards the InterruptedException + * and goes right back into a wait. I don't want to report compiler + * success or failure until it really has succeeded or failed... I think. + * @param Process p to be waited for + * @return the exitValue() of the process. + */ + static int waitHardFor(java.lang.Process p) + { + boolean done=false; + while(!done) + try + { + p.waitFor(); + done=true; + } + catch(InterruptedException e) + { + System.err.println("(Compiler process wait interrupted and resumed)"); + } + int ev=p.exitValue(); // Pause for debugging... + return ev; } + }
