/* * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package org.apache.geode.internal; import java.io.*; import java.util.*; import org.apache.geode.internal.i18n.LocalizedStrings; /** * A ProcessOutputReader will read both stdout and stderr from a {@link java.lang.Process} process. * The constructor does not return until all output from the process has been read and the process * has exited. * * */ public class ProcessOutputReader { private int exitCode; private String output; /** * Creates a process output reader for the given process. * * @param p the process whose output should be read. */ public ProcessOutputReader(final Process p) { final List lines = Collections.synchronizedList(new ArrayList()); class ProcessStreamReader extends Thread { private BufferedReader reader; public int linecount = 0; public ProcessStreamReader(InputStream stream) { reader = new BufferedReader(new InputStreamReader(stream)); } @Override public void run() { try { String line; while ((line = reader.readLine()) != null) { linecount++; lines.add(line); } reader.close(); } catch (Exception e) { } } }; ProcessStreamReader stdout = new ProcessStreamReader(p.getInputStream()); ProcessStreamReader stderr = new ProcessStreamReader(p.getErrorStream()); stdout.start(); stderr.start(); try { stderr.join(); } catch (InterruptedException ignore) { Thread.currentThread().interrupt(); } try { stdout.join(); } catch (InterruptedException ignore) { Thread.currentThread().interrupt(); } this.exitCode = 0; int retryCount = 9; while (retryCount > 0) { retryCount--; try { exitCode = p.exitValue(); break; } catch (IllegalThreadStateException e) { // due to bugs in Process we may not be able to get // a process's exit value. // We can't use Process.waitFor() because it can hang forever if (retryCount == 0) { if (stderr.linecount > 0) { // The process wrote to stderr so manufacture // an error exist code lines.add( LocalizedStrings.ProcessOutputReader_FAILED_TO_GET_EXIT_STATUS_AND_IT_WROTE_TO_STDERR_SO_SETTING_EXIT_STATUS_TO_1 .toLocalizedString()); exitCode = 1; } } else { // We need to wait around to give a chance for // the child to be reaped.See bug 19682 try { Thread.sleep(1000); } catch (InterruptedException ignore) { Thread.currentThread().interrupt(); // TODO a cancellation check here? } } } } java.io.StringWriter sw = new java.io.StringWriter(); PrintWriter pw = new PrintWriter(sw); Iterator it = lines.iterator(); while (it.hasNext()) { pw.println((String) it.next()); } pw.close(); try { sw.close(); } catch (java.io.IOException ignore) { } StringBuffer buf = sw.getBuffer(); if (buf != null && buf.length() > 0) { this.output = sw.toString(); } else { this.output = ""; } } /** * Gets the process's exit status code. A code equal to 0 indicates all is well. */ public int getExitCode() { return exitCode; } /** * Gets everything the process wrote to both stdout and stderr. */ public String getOutput() { return output; } }