001: /* ProcessUtils.java
002: *
003: * $Id: ProcessUtils.java 4223 2006-05-02 02:54:20Z stack-sf $
004: *
005: * Created Jul 19, 2005
006: *
007: * Copyright (C) 2005 Internet Archive.
008: *
009: * This file is part of the Heritrix web crawler (crawler.archive.org).
010: *
011: * Heritrix is free software; you can redistribute it and/or modify
012: * it under the terms of the GNU Lesser Public License as published by
013: * the Free Software Foundation; either version 2.1 of the License, or
014: * any later version.
015: *
016: * Heritrix is distributed in the hope that it will be useful,
017: * but WITHOUT ANY WARRANTY; without even the implied warranty of
018: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
019: * GNU Lesser Public License for more details.
020: *
021: * You should have received a copy of the GNU Lesser Public License
022: * along with Heritrix; if not, write to the Free Software
023: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024: */
025: package org.archive.util;
026:
027: import java.io.BufferedReader;
028: import java.io.IOException;
029: import java.io.InputStream;
030: import java.io.InputStreamReader;
031: import java.util.logging.Level;
032: import java.util.logging.Logger;
033:
034: /**
035: * Class to run an external process.
036: * @author stack
037: * @version $Date: 2006-05-02 02:54:20 +0000 (Tue, 02 May 2006) $ $Revision: 4223 $
038: */
039: public class ProcessUtils {
040: private static final Logger LOGGER = Logger
041: .getLogger(ProcessUtils.class.getName());
042:
043: protected ProcessUtils() {
044: super ();
045: }
046:
047: /**
048: * Thread to gobble up an output stream.
049: * See http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html
050: */
051: protected class StreamGobbler extends Thread {
052: private final InputStream is;
053: private final StringBuffer sink = new StringBuffer();
054:
055: StreamGobbler(InputStream is, String name) {
056: this .is = is;
057: setName(name);
058: }
059:
060: public void run() {
061: try {
062: BufferedReader br = new BufferedReader(
063: new InputStreamReader(this .is));
064: for (String line = null; (line = br.readLine()) != null;) {
065: this .sink.append(line);
066: }
067: } catch (IOException ioe) {
068: ioe.printStackTrace();
069: }
070: }
071:
072: public String getSink() {
073: return this .sink.toString();
074: }
075: }
076:
077: /**
078: * Data structure to hold result of a process exec.
079: * @author stack
080: * @version $Date: 2006-05-02 02:54:20 +0000 (Tue, 02 May 2006) $ $Revision: 4223 $
081: */
082: public class ProcessResult {
083: private final String[] args;
084: private final int result;
085: private final String stdout;
086: private final String stderr;
087:
088: protected ProcessResult(String[] args, int result,
089: String stdout, String stderr) {
090: this .args = args;
091: this .result = result;
092: this .stderr = stderr;
093: this .stdout = stdout;
094: }
095:
096: public int getResult() {
097: return this .result;
098: }
099:
100: public String getStdout() {
101: return this .stdout;
102: }
103:
104: public String getStderr() {
105: return this .stderr;
106: }
107:
108: public String toString() {
109: StringBuffer sb = new StringBuffer();
110: for (int i = 0; i < this .args.length; i++) {
111: sb.append(this .args[i]);
112: sb.append(", ");
113: }
114: return sb.toString()
115: + " exit code: "
116: + this .result
117: + ((this .stderr != null && this .stderr.length() > 0) ? "\nSTDERR: "
118: + this .stderr
119: : "")
120: + ((this .stdout != null && this .stdout.length() > 0) ? "\nSTDOUT: "
121: + this .stdout
122: : "");
123: }
124: }
125:
126: /**
127: * Runs process.
128: * @param args List of process args.
129: * @return A ProcessResult data structure.
130: * @throws IOException If interrupted, we throw an IOException. If non-zero
131: * exit code, we throw an IOException (This may need to change).
132: */
133: public static ProcessUtils.ProcessResult exec(String[] args)
134: throws IOException {
135: Process p = Runtime.getRuntime().exec(args);
136: ProcessUtils pu = new ProcessUtils();
137: // Gobble up any output.
138: StreamGobbler err = pu.new StreamGobbler(p.getErrorStream(),
139: "stderr");
140: err.setDaemon(true);
141: err.start();
142: StreamGobbler out = pu.new StreamGobbler(p.getInputStream(),
143: "stdout");
144: out.setDaemon(true);
145: out.start();
146: int exitVal;
147: try {
148: exitVal = p.waitFor();
149: } catch (InterruptedException e) {
150: throw new IOException("Wait on process " + args
151: + " interrupted: " + e.getMessage());
152: }
153: ProcessUtils.ProcessResult result = pu.new ProcessResult(args,
154: exitVal, out.getSink(), err.getSink());
155: if (exitVal != 0) {
156: throw new IOException(result.toString());
157: } else if (LOGGER.isLoggable(Level.INFO)) {
158: LOGGER.info(result.toString());
159: }
160: return result;
161: }
162: }
|