All Downloads are FREE. Search and download functionalities are using the official Maven repository.

brooklyn.util.stream.StreamGobbler Maven / Gradle / Ivy

Go to download

Utility classes and methods developed for Brooklyn but not dependendent on Brooklyn or much else

There is a newer version: 0.7.0-M1
Show newest version
package brooklyn.util.stream;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.concurrent.atomic.AtomicBoolean;

import org.slf4j.Logger;

public class StreamGobbler extends Thread implements Closeable {
	
    protected final InputStream stream;
    protected final PrintStream out;
    protected final Logger log;
    private final AtomicBoolean running = new AtomicBoolean(true);
    
    public StreamGobbler(InputStream stream, OutputStream out, Logger log) {
        this(stream, out != null ? new PrintStream(out) : null, log);
    }

    public StreamGobbler(InputStream stream, PrintStream out, Logger log) {
        this.stream = stream;
        this.out = out;
        this.log = log;
    }
    
    @Override
    public void close() {
        running.set(false);
        interrupt();
    }

    /**
     * @deprecate Use close() instead.
     */
    @Deprecated
    public void shutdown() {
        close();
    }

    String logPrefix = "";
    String printPrefix = "";
    public StreamGobbler setPrefix(String prefix) {
        setLogPrefix(prefix);
        setPrintPrefix(prefix);
		return this;
	}
    public StreamGobbler setPrintPrefix(String prefix) {
        printPrefix = prefix;
        return this;
    }
    public StreamGobbler setLogPrefix(String prefix) {
        logPrefix = prefix;
        return this;
    }    
    
    @Override
    public void run() {
        int c = -1;
        try {
            while (running.get() && (c=stream.read())>=0) {
                onChar(c);
            }
            onClose();
        } catch (IOException e) {
        	onClose();
        	//TODO parametrise log level, for this error, and for normal messages
        	if (log!=null && log.isTraceEnabled()) log.trace(logPrefix+"exception reading from stream ("+e+")");
        }
    }
    
    private final StringBuilder lineSoFar = new StringBuilder(16);
    public void onChar(int c) {
    	if (c=='\n' || c=='\r') {
    		if (lineSoFar.length()>0)
    		    //suppress blank lines, so that we can treat either newline char as a line separator
    		    //(eg to show curl updates frequently)
    		    onLine(lineSoFar.toString());
    		lineSoFar.setLength(0);
    	} else {
    		lineSoFar.append((char)c);
    	}
    }
    
    public void onLine(String line) {
    	//right trim, in case there is \r or other funnies
    	while (line.length()>0 && Character.isWhitespace(line.charAt(line.length()-1)))
    		line = line.substring(0, line.length()-1);
    	//right trim, in case there is \r or other funnies
    	while (line.length()>0 && (line.charAt(0)=='\n' || line.charAt(0)=='\r'))
    		line = line.substring(1);
    	if (!line.isEmpty()) {
    	    if (out!=null) out.println(printPrefix+line);
    	    if (log!=null && log.isDebugEnabled()) log.debug(logPrefix+line);
    	}
    }
    
    public void onClose() {
        onLine(lineSoFar.toString());
        if (out!=null) out.flush();
        lineSoFar.setLength(0);
        finished = true;
        synchronized (this) { notifyAll(); }
    }
    
    private volatile boolean finished = false;

    /** convenience -- equivalent to calling join() */
    public void blockUntilFinished() throws InterruptedException {
        synchronized (this) { while (!finished) wait(); }
    }

    /** convenience -- similar to !Thread.isAlive() */
    public boolean isFinished() {
        return finished;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy