/** * Copyright 2007-2008 University Of Southern California * * Licensed 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 edu.isi.pegasus.common.util; import edu.isi.pegasus.common.logging.LogManagerFactory; import edu.isi.pegasus.common.logging.LogManager; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.io.BufferedReader; import java.io.IOException; /** * A Stream gobbler class to take care of reading from a stream and optionally * write out to another stream. Allows for non blocking reads on both stdout * and stderr, when invoking a process through Runtime.exec(). * Also, the user can specify a callback that is called whenever anything * is read from the stream. * * @author Karan Vahi */ public class StreamGobbler extends Thread { /** * The input stream that is to be read from. */ private InputStream mIPStream; /** * The output stream to which the contents have to be redirected to. */ private OutputStream mOPStream; /** * The callback to be used. */ private StreamGobblerCallback mCallback; /** * The prompt that is to be written to the output stream. */ private String mPrompt; /** * A boolean indicating whether the thread has started or not. */ private boolean mStarted; /** * The handle to the logging object. */ private LogManager mLogger; /** * The overloaded constructor. * * @param is the input stream from which to read from. * @param callback the callback to call when a line is read. */ public StreamGobbler(InputStream is, StreamGobblerCallback callback) { this.mIPStream = is; mCallback = callback; mLogger = LogManagerFactory.loadSingletonInstance( ); //set the prompt to nothing mPrompt = ""; } /** * Sets the output stream to which to redirect the contents of the input * stream. * * @param ops the output stream. * @param prompt the prompt for the output stream. */ public void redirect ( OutputStream ops , String prompt ){ if( mStarted ){ //should throw a specific VTor exception throw new RuntimeException("The thread has already started execution"); } mOPStream = ops; mPrompt = ( prompt == null ) ? "" : prompt; } /** * The main method of the gobbler, that does all the work. */ public void run() { try{ mStarted = true; PrintWriter pw = ( mOPStream == null) ? null : new PrintWriter(mOPStream); boolean redirect = !(pw == null); InputStreamReader isr = new InputStreamReader(mIPStream); BufferedReader br = new BufferedReader(isr); String line = null; while ( (line = br.readLine()) != null) { //redirect to output stream if (redirect) pw.println(mPrompt + line); //callout to the callback mCallback.work( line ); //be nice and sleep this.sleep(5); } } catch( IOException e){ mLogger.log(" While reading in StreamGobbler ",e, LogManager.ERROR_MESSAGE_LEVEL); } catch ( InterruptedException e ){ //ignore } finally{ mStarted = false; } } /** * Closes the open connections to the streams whenever this object * is destroyed. */ protected void finalize(){ close(); } /** * Closes the underneath input and output stream that were opened. */ public void close(){ //close the input stream try{ if( mIPStream != null) mIPStream.close(); }catch(IOException e){ //ignore }finally{ mIPStream = null; } //close the output stream try{ if( mOPStream != null) mOPStream.close(); }catch(IOException e){ //ignore }finally{ mOPStream = null; } } }