Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/tuneology/avm/Native.java


1   /*
2     Native.java
3   
4     Copyright (C) 2002 Fran Taylor
5   
6     This file is part of java-avm.
7   
8     java-avm is free software; you can redistribute it and/or modify it
9     under the terms of the GNU Lesser General Public License as
10    published by the Free Software Foundation; either version 2 of the
11    License, or (at your option) any later version.
12  
13    java-avm is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17  
18    You should have received a copy of the GNU Lesser General Public
19    License along with java-avm; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21    USA
22  
23    $Id: Native.java,v 1.5 2002/11/06 09:22:57 xnarf Exp $
24  
25  */
26  
27  package com.tuneology.avm;
28  
29  import java.util.*;
30  import java.io.*;
31  
32  /**
33   * This class extends the System and Runtime classes to provide 
34   * extra functionality.
35   * 
36   * @author Fran Taylor
37   *
38   * @version $Id: Native.java,v 1.5 2002/11/06 09:22:57 xnarf Exp $
39   */
40  public class Native {
41      private Native() { }
42      /**
43       * This class gets called for each line of output generated by the program.
44       *
45       * @author Fran Taylor
46       */
47      public interface LineReader {
48    /** 
49           * Called by runCommand when a line of output is generated by a process.
50           *
51     * @param str The line of output from the program.
52     * @param e True if the line is from stderr, false if from stdout.
53     * @return false to stop running the program, true otherwise.
54           * @throws IOException if an error occurs parsing the input.
55     */
56          public boolean processLine(String str, boolean e) throws Exception;
57      }
58      /**
59       * This class is called for each line of output generated by a shell program.
60       *
61       * @author Fran Taylor
62       */
63      public interface Logger {
64          /**
65           * Called for each line of output generated by the process.
66           * 
67           * @param str the string to add to the log
68           */
69    public void addMessage(String str);
70      }
71      /**
72       * Returns the list of arguments quoted in a single string, for logging purposes.
73       * 
74       * @param cmd the argument array.
75       * @return the quoted list of arguments as a single string.
76       */
77      public static String getArgString(String[] cmd) {
78          String retval = "cmd: ";
79          retval = "cmd: \"" + cmd[0] + "\"\n";
80          for(int i = 1; i < cmd.length; i++) {
81              retval += "arg: \"" + cmd[i] + "\"\n";
82          }
83          return retval;
84      }
85      /**
86       * Returns the list of arguments quoted in a single string, for logging purposes.
87       * 
88       * @param cmd the String arguments.
89       * @return the quoted list of arguments as a single string.
90       */
91      public static String getArgString(Vector cmd) {
92          String retval = "cmd: ";
93          retval = "cmd: \"" + ((String) cmd.get(0)) + "\"\n";
94          for(int i = 1; i < cmd.size(); i++) {
95              retval += "arg: \"" + ((String) cmd.get(i)) + "\"\n";
96          }
97          return retval;
98      }
99      /**
100      * Parses the user input and returns it in the form of
101      * a vector of strings, ready to pass to runCommand.
102      * Values within double quotes are preserved as is
103      * otherwise, spaces delimit args.
104      * 
105      * @param str The string to be parsed.
106      # @return a vector containing string arguments.
107      */
108     public static Vector parseUserInput(String str) {
109         // surely there's a better way...
110         // StringTokenizer isn't powerful enough
111         Vector v = new Vector();
112         int mx = str.length();
113         for(int ind = 0; ind < mx; ind++) {
114             int q1 = str.indexOf("\"", ind);
115             if (q1 != -1) {
116                 int q2 = str.indexOf("\"", q1 + 1);
117                 if (q2 != -1) {
118                     String arg = str.substring(q1 + 1, q2 - q1);
119                     v.add(arg);
120                     ind = q2 + 1;
121                     continue;
122                 } 
123                 // only one double quote. ignore it.
124             }
125             // skip over whitespace
126             for( ; (ind < mx) && (str.charAt(ind) == ' '); ind++);
127             int p = ind;
128             // skip forward to a space
129             for( ; (p < mx) && (str.charAt(p) != ' '); p++);
130             String arg = str.substring(ind, p);
131             v.add(arg);
132             ind = p;
133         }
134         return v;
135     }
136     public static Process exec(String[] cmd) throws IOException {
137         logger.addMessage(logCmd(cmd, null));
138         return Runtime.getRuntime().exec(cmd);
139     }
140     /** 
141      * Runs the specified external program.  Blocks until the program exits.
142      *
143      * @param cmd the shell command to run
144      * @param dir the directory in which to run it, or null for the current directory.
145      * @param lrdr the line reader used to parse the user input (optional).
146      * @param logOutput true if the process's output is to be logged, false if its output is not to be logged.
147      * @return The value returned by the process.
148      * @throws Exception if an error occurs
149      */
150     public static int runCommand(String cmd, File dir, Native.LineReader lrdr, boolean logOutput) throws Exception {
151         String logStr = logCmd(cmd, dir);
152   int retval = -1;
153         long startTime = System.currentTimeMillis();
154         retval = runCommand(Runtime.getRuntime().exec(cmd, null, dir), logStr, lrdr, logOutput, startTime);
155   return retval;
156     }
157     /** 
158      * Runs the specified external program. Blocks until the program exits.
159      *
160      * @param v The shell command to run, as a vector of strings.
161      * @param dir the directory in which to run it, or null for the current directory.
162      * @param lrdr the line reader used to parse the user input (optional).
163      * @param logOutput true if the process's output is to be logged, false if its output is not to be logged.
164      * @return The value returned by the process.
165      * @throws Exception if an error occurs
166      */
167     public static int runCommand(Vector v, File dir, Native.LineReader lrdr, boolean logOutput) throws Exception {
168   String[] cmd = new String[v.size()];
169   for(int i = 0; i < v.size(); i++) cmd[i] = (String) v.get(i);
170   return runCommand(cmd, dir, lrdr, logOutput);
171     }
172     /** 
173      * Runs the specified external program. Blocks until the program exits.
174      *
175      * @param cmd The shell command to run, as an array of strings.
176      * @param dir the directory in which to run it, or null for the current directory.
177      * @param lrdr the line reader used to parse the user input (optional).
178      * @param logOutput true if the process's output is to be logged, false if its output is not to be logged.
179      * @return The value returned by the process.
180      * @throws Exception if an error occurs
181      */
182     public static int runCommand(String[] cmd, File dir, Native.LineReader lrdr, boolean logOutput) throws Exception {
183         String logStr = logCmd(cmd, dir);
184   int retval = -1;
185         long startTime = System.currentTimeMillis();
186         retval = runCommand(Runtime.getRuntime().exec(cmd, null, dir), logStr, lrdr, logOutput, startTime);
187   return retval;
188     }
189     /** 
190      * Takes a vector of strings and creates an array of strings. 
191      *
192      * @param v A vector containing strings.
193      * @return An array made of the strings in the vector.
194      */
195     public static String[] getStringArray(Vector v) {
196   String[] cmd = new String[v.size()];
197   for(int i = 0; i < v.size(); i++) cmd[i] = (String) v.get(i);
198   return cmd;
199     }
200     /**
201      * For Unix only: executes the mkfifo command.
202      *
203      * @param f the file pointing to the fifo to be created.
204      * @throws Exception If there was an error executing the mkfifo command.
205      */
206     static public void mkfifo(File f) throws Exception {
207         Vector cmd = getMkfifoCmd();
208         cmd.add(f.getCanonicalPath());
209         Native.runCommand(cmd, null, null, true);
210     }
211     /**
212      * Returns true if the pathname specifies an executable program.
213      * 
214      * @param path A pathname.
215      * @return true if the path is an executable file.
216      */
217     public static boolean isExecutable(String path) {
218         if (isWindows) {
219             String lcpath = path.toLowerCase();
220             return lcpath.endsWith(".com") || lcpath.endsWith(".exe");
221         } else {
222             return i_isExecutable(path);
223         }
224     }
225     /**
226      * Sets the shell command used for mkfifo.
227      *
228      * @param s the mkfifo command.
229      */
230     static public void setMkfifoCmd(String s) { mkfifoCmd = s; }
231     /**
232      * All process I/O is logged to this interface. 
233      * 
234      * @param l the logger object.
235      */
236     static public void setLogger(Logger l) { logger = l; }
237     /**
238      * Returns a string from the resource bundle.
239      *
240      * @param str the identifier for the string.
241      * @return the resource string.
242      */
243     static public String getResourceString(String str) { return resources.getString(str); }
244     /**
245      * Returns the mkfifo command.
246      * 
247      * @return the mkfifo command.
248      */
249     static Vector getMkfifoCmd() { return parseUserInput(mkfifoCmd); }
250     private static boolean processLine(Native.LineReader rdr, String str) throws Exception {
251         if (!rdr.processLine(str, true)) {
252             return false;
253         }
254         return true;
255     }
256     private static String logCmd(String cmd, File dir) {
257         String cmdStr = "";
258   if (dir != null) cmdStr += "dir: " + dir.getPath() + " ";
259         cmdStr += "cmd: " + cmd;
260         return cmdStr;
261     }
262     private static String logCmd(String[] cmd, File dir) {
263         String str = "";
264   if (dir != null) str += "dir: " + dir.getPath() + " ";
265         str += "cmd: " + cmd[0];
266         int firstArg = 1;
267         if (cmd[0].indexOf("sudo") != -1) {
268             str += " " + cmd[1];
269             firstArg++;
270         }
271         str += "\n";
272         if (cmd.length > firstArg) {
273             for(int i = firstArg; i < cmd.length; i++) {
274                 str += "arg: \"" + cmd[i] + "\"\n";
275             }
276         }
277   str += "\n";
278         return str;
279     }
280     private static class ProcReader extends Thread {
281         ProcReader(BufferedReader errRdr, Native.LineReader rdr, Process proc) { 
282             this.errRdr = errRdr; 
283             lrdr = rdr;  
284             this.proc = proc;
285             logBuf = new StringBuffer();
286             ex = null;
287         }
288         public void run() {
289             String str;
290             try {
291                 while((str = errRdr.readLine()) != null) {
292                     logBuf.append(str + "\n");
293                     if (lrdr != null) {
294                         try {
295                             if (!processLine(lrdr, str)) {
296                                 proc.destroy();
297                                 break;  
298                             }
299                         } catch (IOException ex) {
300                             this.ex = ex;
301                         }
302                     }
303                 }
304             } catch (Exception ex) {
305                 this.ex = ex;
306             }
307         }
308         private BufferedReader errRdr;
309         private LineReader lrdr;
310         private Process proc;
311         StringBuffer logBuf;
312         Exception ex;
313     }
314     private static int runCommand(final Process proc, String logStr, final Native.LineReader lrdr, boolean logOutput, long startTime) 
315         throws Exception {
316   final StringBuffer logBuf = new StringBuffer(logStr);
317   BufferedReader rdr = new BufferedReader(new InputStreamReader(proc.getInputStream()));
318   final BufferedReader errRdr = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
319   ProcReader th = new ProcReader(errRdr, lrdr, proc);
320         int retval = 0;
321         long endTime = -1;
322   String str;
323   th.start();
324         try {
325             while((str = rdr.readLine()) != null) {
326                 if (logOutput) 
327                     logBuf.append(str + "\n");
328                 if (lrdr != null) {
329                     if (!processLine(lrdr, str)) {
330                         proc.destroy();
331                         break;
332                     }
333                 }
334             }
335             retval = proc.waitFor();
336         } catch (Exception ex) {
337             proc.destroy();
338             try { retval = proc.waitFor(); } catch (InterruptedException exx) { }
339         }
340         endTime = System.currentTimeMillis();
341         th.join();
342         if (logger != null) {
343             logger.addMessage(logBuf.toString());
344             logger.addMessage("Execution time: " + (endTime - startTime) + " msec\n");
345         }
346         if (th.ex != null) {
347             logBuf.append(th.logBuf.toString());
348             throw th.ex;
349         }
350         return retval;
351     }
352     static private native boolean i_isExecutable(String path);
353 
354     /** True if the jvm is running on some sort of Windows. */
355     static public final boolean isWindows;
356     /** True if the jvm is running on Linux. */
357     static public final boolean isLinux;
358     /** True if the jvm is running on Solaris. */
359     static public final boolean isSolaris;
360     /** For linux, contains the name and version of the distribution. */
361     static public final String distName;
362     /** Contains the version information for java-avm. */
363     static public final String version = "java-avm 0.1a1 - Copyright (C) 2002 Fran Taylor";
364 
365     static private final String osName;
366     static private String mkfifoCmd;
367     private static Logger logger;
368     static private ResourceBundle resources;
369     static {
370         // what kind of OS are we on?
371   osName = System.getProperty("os.name");
372   isWindows = (osName.indexOf("indows") != -1);
373   isLinux = (osName.indexOf("inux") != -1);
374         isSolaris = (osName.indexOf("olaris") != -1);
375         String name = "";
376         try {
377             resources = ResourceBundle.getBundle("resources.Native");
378         } catch (MissingResourceException e) {
379             System.err.println("Can't find resource");
380             System.exit(1);
381         } 
382         if (isLinux) {
383             try {
384                 // which distribution?  Get first non-blank
385                 // line in /etc/issue
386                 String str;
387                 BufferedReader rdr = new BufferedReader(new FileReader("/etc/issue"));
388                 while((str = rdr.readLine()) != null) {
389                     if (str.trim().equals(""))
390                         continue;
391                     name = str;
392                     break;
393                 }
394             } catch (Exception ex) {
395             }
396         }
397         distName = name;
398     }
399 }
400 
401 /*
402    Local Variables:
403    mode:java
404    indent-tabs-mode:nil 
405    c-basic-offset:4 
406    c-indent-level:4 
407    c-continued-statement-offset:4 
408    c-brace-offset:-4 
409    c-brace-imaginary-offset:-4 
410    c-argdecl-indent:0
411    c-label-offset:0
412    End:
413 */