KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xml > utils > synthetic > JavaUtils


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: JavaUtils.java,v 1.7 2004/02/17 04:23:24 minchau Exp $
18  */

19
20 package org.apache.xml.utils.synthetic;
21
22 import java.io.IOException JavaDoc;
23
24 /**
25  * This class supports invoking Java compilation from within
26  * a Java program. Recent versions of the Java environment have
27  * provided such an API (in tools.jar). But that isn't available
28  * on all platforms, and a fallback to the command line may be needed
29  * (though this too may not always be available, eg. for security
30  * reasons).
31  * <p>
32  * There's an additional complication in some environments --
33  * such as Microsoft's VJ++ -- where the classpath as seen in
34  * the System Properties may not be the one the user expects.
35  * The code here is parameterized to try to deal with that.
36  * @xsl.usage internal
37  */

38 public class JavaUtils
39 {
40         // One-time flag for whether we could dynamically load compiler API
41
private static boolean cantLoadCompiler=false;
42
43         // Debug flag - generates debug stuff if true.
44
private static boolean debug = false;
45   
46         /** Control whether compilation occurs with the -g option
47          * (debugging information included in generated classfile).
48          * This is an attribute, rather than a parameter on the compile
49          * method, largely because it tends to be an all-or-nothing decision;
50          * generally you're either doing program development and want it,
51          * or running in production mode and don't. But that may not match
52          * the needs of future users...
53          * <p>
54          * TODO: Consider whether debug should be a parameter.
55          *
56          * @param boolean newDebug True to request debugging data,
57          * false to request optimized output. (It's uncommon to
58          * want both or neither!)
59          */

60         public static void setDebug(boolean newDebug)
61         {
62             debug=newDebug;
63         }
64
65         /** Try to compile a .java file on disk. This will first attempt to
66          * use the sun.java.tools.javac() method, then (if that is unavailable)
67          * fall back upon shelling out to a command line and running javac
68          * there.
69          * <p>
70          * NOTE: This must be _compiled_ with sun.java.tools.* (tools.jar)
71          * available. We could change that to use reflection instead, if we
72          * accept some overhead... minor compared to the cost of running the
73          * compiler!
74          * <p>
75          * This has complications on some platforms. For example, under
76          * Microsoft Visual Java ++ (at least, as installed on my test system),
77          * I found that I had to specify paths to both javac and xerces.jar
78          * rather than counting on the shell's path and classpath having
79          * been set to reach these. For that reason I've parameterized this
80          * method with a few system properties, so you can adapt it to your
81          * own system's needs without modifying the code:
82          * <dl>
83          * <dt>org.apache.xml.utils.synthetic.javac
84          * <dd>Command line issued to invoke the compiler. Defaults to "javac",
85          * which should work in most systems. In VJ++, try setting it to
86          * "cmd /c %JAVA_HOME%\\bin\javac.exe"
87          * <dt>org.apache.xml.utils.synthetic.moreclasspath
88          * <dd>Additional classpath, to be prepended to the one retrieved from
89          * java.class.path. Defaults to "" (empty). In VJ++, try setting it to
90          * point to your copy of xerces.jar, which may not be found otherwise.
91          * TODO: Reconsider prepend versus append!
92          * </dl>
93          *
94          * @param String fileName Which .java file to compile. Note that this may
95          * be relative to the "current directory".
96          * @param String classPath Additional places to look for classes that
97          * this .java file depends upon. Becomes the javac command's
98          * -classpath parameter value.
99          * @return boolean True iff compilation succeeded.
100          */

101         public static boolean JDKcompile(String JavaDoc fileName, String JavaDoc classPath)
102         {
103                 String JavaDoc moreClassPath=
104                         System.getProperty("org.apache.xml.utils.synthetic.moreclasspath","")
105                         .trim();
106                 if(moreClassPath.length()>0)
107                         classPath=moreClassPath+';'+classPath;
108                                                                                                   
109                 if (debug)
110                 {
111                         System.err.println ("JavaEngine: Compiling " + fileName);
112                         System.err.println ("JavaEngine: Classpath is " + classPath);
113                 }
114     
115                 String JavaDoc code_option = debug ? "-g" : "-O";
116
117                 // Start by trying Sun's compiler API
118
if(!cantLoadCompiler)
119                 {
120                         String JavaDoc args[] = {
121                                 code_option,
122                             "-classpath", classPath,
123                                 fileName
124                         };
125                                 
126 // try
127
// {
128
// return new sun.tools.javac.Main(System.err, "javac").compile(args);
129
// }
130
// catch (Throwable th)
131
// {
132
// System.err.println("INFORMATIONAL: Unable to load Java compiler API (eg tools.jar).");
133
// System.err.println("\tSwitching to command-line invocation.");
134
// cantLoadCompiler=true;
135
// }
136
}
137     
138                 // FALLTHRU:
139
// Can't load javac() method; try shelling out to the command
140
// line and invoking it via exec().
141
String JavaDoc javac_command=
142                         System.getProperty("org.apache.xml.utils.synthetic.javac","javac");
143             String JavaDoc args[] = {
144                         javac_command,
145                         code_option,
146                         "-classpath", classPath,
147                         fileName
148                         };
149                 try
150                 {
151                         Process JavaDoc p=java.lang.Runtime.getRuntime().exec(args);
152                         int compileOK=waitHardFor(p); // pause for debugging...
153
return compileOK==0; //0 == no error reported
154
}
155                 catch(IOException JavaDoc e)
156                 {
157                         System.err.println("ERROR: IO exception during exec(javac).");
158                 }
159                 catch(SecurityException JavaDoc e)
160                 {
161                         System.err.println("ERROR: Unable to create subprocess to exec(javac).");
162                 }
163                 
164                 // FALLTHRU: All attempts failed.
165
return false;
166         }
167
168   /** Subroutine: Like p.waitFor, but discards the InterruptedException
169    * and goes right back into a wait. I don't want to report compiler
170    * success or failure until it really has succeeded or failed... I think.
171    * @param Process p to be waited for
172    * @return the exitValue() of the process.
173    */

174   static int waitHardFor(java.lang.Process JavaDoc p)
175   {
176     boolean done=false;
177     while(!done)
178         try
179         {
180             p.waitFor();
181             done=true;
182         }
183         catch(InterruptedException JavaDoc e)
184         {
185             System.err.println("(Compiler process wait interrupted and resumed)");
186         }
187      int ev=p.exitValue(); // Pause for debugging...
188
return ev;
189   }
190         
191 }
192
Popular Tags