/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Tee.java * Copyright (C) 2005-2012 University of Waikato, Hamilton, New Zealand * */ package weka.core; import java.io.PrintStream; import java.util.Date; import java.util.Vector; /** * This class pipelines print/println's to several PrintStreams. Useful for * redirecting System.out and System.err to files etc.<br/> * E.g., for redirecting stderr/stdout to files with timestamps and:<br/> * <pre> * import java.io.*; * import weka.core.Tee; * * ... * // stdout * Tee teeOut = new Tee(System.out); * teeOut.add(new PrintStream(new FileOutputStream("out.txt")), true); * System.setOut(teeOut); * * // stderr * Tee teeErr = new Tee(System.err); * teeErr.add(new PrintStream(new FileOutputStream("err.txt")), true); * System.setOut(teeErr); * ... * </pre> * * @author FracPete (fracpete at waikato dot ac dot nz) * @version $Revision: 8034 $ */ public class Tee extends PrintStream implements RevisionHandler { /** the different PrintStreams. */ protected Vector<PrintStream> m_Streams = new Vector<PrintStream>(); /** whether to add timestamps or not. */ protected Vector<Boolean> m_Timestamps = new Vector<Boolean>(); /** whether to add a prefix or not. */ protected Vector<String> m_Prefixes = new Vector<String>(); /** the default printstream. */ protected PrintStream m_Default = null; /** * initializes the object, with a default printstream. */ public Tee() { this(null); } /** * initializes the object with the given default printstream, e.g., * System.out. * * @param def the default printstream, remains also after calling clear() */ public Tee(PrintStream def) { super(def); m_Default = def; clear(); } /** * removes all streams and places the default printstream, if any, again in * the list. * * @see #getDefault() */ public void clear() { m_Streams.clear(); m_Timestamps.clear(); m_Prefixes.clear(); if (getDefault() != null) add(getDefault()); } /** * returns the default printstrean, can be NULL. * * @return the default printstream * @see #m_Default */ public PrintStream getDefault() { return m_Default; } /** * adds the given PrintStream to the list of streams, with NO timestamp and * NO prefix. * * @param p the printstream to add */ public void add(PrintStream p) { add(p, false); } /** * adds the given PrintStream to the list of streams, with NO prefix. * * @param p the printstream to add * @param timestamp whether to use timestamps or not */ public void add(PrintStream p, boolean timestamp) { add(p, timestamp, ""); } /** * adds the given PrintStream to the list of streams. * * @param p the printstream to add * @param timestamp whether to use timestamps or not * @param prefix the prefix to use */ public void add(PrintStream p, boolean timestamp, String prefix) { if (m_Streams.contains(p)) remove(p); // make sure it's not null if (prefix == null) prefix = ""; m_Streams.add(p); m_Timestamps.add(new Boolean(timestamp)); m_Prefixes.add(prefix); } /** * returns the specified PrintStream from the list. * * @param index the index of the PrintStream to return * @return the specified PrintStream, or null if invalid index */ public PrintStream get(int index) { if ( (index >= 0) && (index < size()) ) return (PrintStream) m_Streams.get(index); else return null; } /** * removes the given PrintStream from the list. * * @param p the PrintStream to remove * @return returns the removed PrintStream if it could be removed, null otherwise */ public PrintStream remove(PrintStream p) { int index; if (contains(p)) { index = m_Streams.indexOf(p); m_Timestamps.remove(index); m_Prefixes.remove(index); return (PrintStream) m_Streams.remove(index); } else { return null; } } /** * removes the given PrintStream from the list. * * @param index the index of the PrintStream to remove * @return returns the removed PrintStream if it could be removed, null otherwise */ public PrintStream remove(int index) { if ( (index >= 0) && (index < size()) ) { m_Timestamps.remove(index); m_Prefixes.remove(index); return (PrintStream) m_Streams.remove(index); } else { return null; } } /** * checks whether the given PrintStream is already in the list. * * @param p the PrintStream to look for * @return true if the PrintStream is in the list */ public boolean contains(PrintStream p) { return m_Streams.contains(p); } /** * returns the number of streams currently in the list. * * @return the number of streams in the list */ public int size() { return m_Streams.size(); } /** * prints the prefix/timestamp (timestampe only to those streams that want * one). */ private void printHeader() { for (int i = 0; i < size(); i++) { // prefix if (!((String) m_Prefixes.get(i)).equals("")) ((PrintStream) m_Streams.get(i)).print("[" + m_Prefixes.get(i) + "]\t"); // timestamp if (((Boolean) m_Timestamps.get(i)).booleanValue()) ((PrintStream) m_Streams.get(i)).print("[" + new Date() + "]\t"); } } /** * flushes all the printstreams. */ public void flush() { for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).flush(); } /** * prints the given int to the streams. * * @param x the object to print */ public void print(int x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).print(x); flush(); } /** * prints the given long to the streams. * * @param x the object to print */ public void print(long x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).print(x); flush(); } /** * prints the given float to the streams. * * @param x the object to print */ public void print(float x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).print(x); flush(); } /** * prints the given double to the streams. * * @param x the object to print */ public void print(double x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).print(x); flush(); } /** * prints the given boolean to the streams. * * @param x the object to print */ public void print(boolean x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).print(x); flush(); } /** * prints the given char to the streams. * * @param x the object to print */ public void print(char x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).print(x); flush(); } /** * prints the given char array to the streams. * * @param x the object to print */ public void print(char[] x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).print(x); flush(); } /** * prints the given string to the streams. * * @param x the object to print */ public void print(String x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).print(x); flush(); } /** * prints the given object to the streams. * * @param x the object to print */ public void print(Object x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).print(x); flush(); } /** * prints a new line to the streams. */ public void println() { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).println(); flush(); } /** * prints the given int to the streams. * * @param x the object to print */ public void println(int x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).println(x); flush(); } /** * prints the given long to the streams. * * @param x the object to print */ public void println(long x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).println(x); flush(); } /** * prints the given float to the streams. * * @param x the object to print */ public void println(float x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).println(x); flush(); } /** * prints the given double to the streams. * * @param x the object to print */ public void println(double x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).println(x); flush(); } /** * prints the given boolean to the streams. * * @param x the object to print */ public void println(boolean x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).println(x); flush(); } /** * prints the given char to the streams. * * @param x the object to print */ public void println(char x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).println(x); flush(); } /** * prints the given char array to the streams. * * @param x the object to print */ public void println(char[] x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).println(x); flush(); } /** * prints the given string to the streams. * * @param x the object to print */ public void println(String x) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).println(x); flush(); } /** * prints the given object to the streams (for Throwables we print the stack * trace). * * @param x the object to print */ public void println(Object x) { String line; Throwable t; StackTraceElement[] trace; int i; if (x instanceof Throwable) { t = (Throwable) x; trace = t.getStackTrace(); line = t.toString() + "\n"; for (i = 0; i < trace.length; i++) line += "\t" + trace[i].toString() + "\n"; x = line; } printHeader(); for (i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).println(x); flush(); } /** * Writes <code>len</code> bytes from the specified byte array starting at * offset <code>off</code> to this stream. If automatic flushing is * enabled then the <code>flush</code> method will be invoked. * * <p> Note that the bytes will be written as given; to write characters * that will be translated according to the platform's default character * encoding, use the <code>print(char)</code> or <code>println(char)</code> * methods. * * @param buf A byte array * @param off Offset from which to start taking bytes * @param len Number of bytes to write */ public void write(byte buf[], int off, int len) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).write(buf, off, len); flush(); } /** * Writes the specified byte to this stream. If the byte is a newline and * automatic flushing is enabled then the <code>flush</code> method will be * invoked. * * <p> Note that the byte is written as given; to write a character that * will be translated according to the platform's default character * encoding, use the <code>print(char)</code> or <code>println(char)</code> * methods. * * @param b The byte to be written * @see #print(char) * @see #println(char) */ public void write(int b) { printHeader(); for (int i = 0; i < size(); i++) ((PrintStream) m_Streams.get(i)).write(b); flush(); } /** * returns only the classname and the number of streams. * * @return only the classname and the number of streams */ public String toString() { return this.getClass().getName() + ": " + m_Streams.size(); } /** * Returns the revision string. * * @return the revision */ public String getRevision() { return RevisionUtils.extract("$Revision: 8034 $"); } }