001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: Cmd.java 6657 2005-04-27 12:28:21Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.common;
025:
026: import java.io.BufferedReader;
027: import java.io.IOException;
028: import java.io.InputStreamReader;
029: import java.io.PrintStream;
030: import java.util.Enumeration;
031: import java.util.Iterator;
032: import java.util.List;
033: import java.util.Vector;
034:
035: import org.objectweb.util.monolog.api.BasicLevel;
036:
037: /**
038: * This class allows to run a command in sub-process.
039: * @author Helene Joanin : Initial developer
040: * @author Christophe Ney : Fix to handle arguments containing white spaces.
041: * @author Nozomi Matsumura : GenIC i18n problem. GenIC invoke javac and javac's output has non asc-ii characters,
042: * javac's output did not show collectly.
043: * @author Guillaume Tulloup : Invoke directly the com.sun.tools.javac.Main.compile() method to work around a limitation on Windows.
044: * (See bug #100587)
045: * @author Helene Joanin : Invoke directly the com.sun.tools.rmic.Main.compile() method to work around a limitation on Windows.
046: */
047:
048: public class Cmd {
049:
050: /**
051: * Class name of the sun javac compiler
052: */
053: private static final String COMPILER_CLASS_NAME = "com.sun.tools.javac.Main";
054: /**
055: * Class name of the sun rmic compiler
056: */
057: private static final String RMICOMPILER_CLASS_NAME = "sun.rmi.rmic.Main";
058:
059: /**
060: * Command arguments list (included the command name)
061: */
062: private Vector mCmd = new Vector();
063:
064: /**
065: * Command environment variables
066: */
067: private String[] mEnv = null;
068:
069: /**
070: * Invoke (or not) the compile method of the corresponding sun compiler class
071: */
072: private boolean tryToInvoke = false;
073:
074: /**
075: * Construtor method of Cmd class.
076: * @param cmd command
077: * @param invoke try to invoke directly the method of the java class of the
078: * command
079: */
080: public Cmd(String cmd, boolean invoke) {
081: mCmd.addElement(cmd);
082: tryToInvoke = invoke;
083: }
084:
085: /**
086: * Construtor method of Cmd class. Equivalent to Cmd(cmd, false).
087: * @param cmd command
088: */
089: public Cmd(String cmd) {
090: this (cmd, false);
091: }
092:
093: /**
094: * Construtor method of Cmd class.
095: * @param cmd command
096: * @param env environment of the command
097: * @param invoke invoke the compile method of the class instead of execute the command
098: */
099: public Cmd(String cmd, String[] env, boolean invoke) {
100: mCmd.addElement(cmd);
101: mEnv = env;
102: tryToInvoke = invoke;
103: }
104:
105: /**
106: * Add a new argument to the command.
107: * @param arg argument added to the tail of the command argument list
108: */
109: public void addArgument(String arg) {
110: mCmd.addElement(arg);
111: }
112:
113: /**
114: * Add a new argument to the command.
115: * @param args argument added to the tail of the command argument list
116: */
117: public void addArguments(List args) {
118: for (Iterator it = args.iterator(); it.hasNext();) {
119: mCmd.addElement(it.next());
120: }
121: }
122:
123: /**
124: * Execute the command. (In case of the exit value of the command is not 0,
125: * the output and error streams of the command is traced.)
126: * @return false if the command cannot be executed, or if its exit value is
127: * not 0.
128: */
129: public boolean run() {
130:
131: if (tryToInvoke && (((String) mCmd.get(0)).endsWith("javac"))) {
132: // Bug #100587 fixed to work around a limitation on Windows
133: return compile();
134: }
135: if (tryToInvoke && (((String) mCmd.get(0)).endsWith("rmic"))) {
136: return rmicompile();
137: }
138:
139: RunnableStreamListener out, err;
140: Process proc = null;
141: boolean val = true;
142: try {
143: String[] cmd = new String[mCmd.size()];
144: mCmd.copyInto(cmd);
145: proc = Runtime.getRuntime().exec(cmd, mEnv);
146: } catch (IOException e) {
147: TraceCore.logger.log(BasicLevel.ERROR, "exception", e);
148: return (false);
149: }
150: out = new RunnableStreamListener(new BufferedReader(
151: new InputStreamReader(proc.getInputStream())),
152: System.out);
153: new Thread(out, "stdout listener for " + this .toString())
154: .start();
155: err = new RunnableStreamListener(new BufferedReader(
156: new InputStreamReader(proc.getErrorStream())),
157: System.err);
158: new Thread(err, "stderr listener for " + this .toString())
159: .start();
160: try {
161: val = proc.waitFor() == 0;
162: } catch (InterruptedException e) {
163: TraceCore.logger.log(BasicLevel.ERROR, "exception", e);
164: val = false;
165: } finally {
166: // destroy the process
167: if (proc != null) {
168: proc.destroy();
169: }
170: }
171:
172: return (val);
173: }
174:
175: /**
176: * invoke the compile method of the compiler javac class
177: * @return false in error case
178: */
179: private boolean compile() {
180: // first arg should not be added because it's the name of the command
181: String[] args = new String[mCmd.size() - 1];
182: for (int i = 0; i < mCmd.size() - 1; i++) {
183: args[i] = (String) mCmd.get(i + 1);
184: }
185:
186: try {
187: // Use reflection
188: Class c = Class.forName(COMPILER_CLASS_NAME);
189: Object compiler = c.newInstance();
190: java.lang.reflect.Method compile = c.getMethod("compile",
191: new Class[] { (new String[] {}).getClass() });
192: int result = ((Integer) compile.invoke(compiler,
193: new Object[] { args })).intValue();
194: return (result == 0);
195: } catch (Exception e) {
196: TraceCore.logger.log(BasicLevel.ERROR, "exception", e);
197: return false;
198: }
199: }
200:
201: /**
202: * invoke the main method of the rmi compiler rmic class
203: * @return false in error case
204: */
205: private boolean rmicompile() {
206: // first arg should not be added because it's the name of the command
207: String[] args = new String[mCmd.size() - 1];
208: for (int i = 0; i < mCmd.size() - 1; i++) {
209: args[i] = (String) mCmd.get(i + 1);
210: }
211:
212: try {
213: // Use reflection
214: Class c = Class.forName(RMICOMPILER_CLASS_NAME);
215: Object compiler = c.newInstance();
216: java.lang.reflect.Method compile = c.getMethod("compile",
217: new Class[] { (new String[] {}).getClass() });
218: int result = ((Integer) compile.invoke(compiler,
219: new Object[] { args })).intValue();
220: return (result == 0);
221: } catch (Exception e) {
222: TraceCore.logger.log(BasicLevel.ERROR, "exception", e);
223: return false;
224: }
225: }
226:
227: /**
228: * @return iterator over the command line
229: */
230: public Iterator getCommandLine() {
231: return mCmd.iterator();
232: }
233:
234: /**
235: * @return the string representation of the object for UI purpose
236: */
237: public String toString() {
238: StringBuffer buf = new StringBuffer();
239: Enumeration e = mCmd.elements();
240: while (e.hasMoreElements()) {
241: String arg = (String) e.nextElement();
242: if (arg == null) {
243: arg = "null";
244: }
245: for (int i = 0; i < arg.length(); i++) {
246: if (Character.isWhitespace(arg.charAt(i))) {
247: arg = "\"" + arg + "\"";
248: break;
249: }
250: }
251: buf.append(arg);
252: buf.append(' ');
253: }
254: return buf.toString().trim();
255: }
256:
257: }
258:
259: /**
260: * To run the command happily, and to swallow the stdout from the process
261: */
262: class RunnableStreamListener implements Runnable {
263:
264: BufferedReader in_;
265:
266: PrintStream stream_;
267:
268: RunnableStreamListener(BufferedReader in, PrintStream stream) {
269: in_ = in;
270: stream_ = stream;
271: }
272:
273: public void run() {
274: String line;
275: try {
276: while ((line = in_.readLine()) != null) {
277: stream_.println(line);
278: }
279: } catch (IOException e) {
280: stream_.println(e.toString());
281: }
282:
283: }
284: }
|