/* Copyright 2006 by Sean Luke Licensed under the Academic Free License version 3.0 See the file "LICENSE" for more information */ package ec.util; import java.io.*; import java.util.Vector; import java.util.Enumeration; /* * Output.java * Created: Sat Aug 7 15:30:54 1999 * */ /** *
Outputs and logs system messages, errors, and other various * items printed as a result of a run. * *
Output maintains zero or more logs, which contain Writers which * write out stuff. Each log has an associated verbosity; if request * is made to write text to a log, and the text's maximal verbosity * is lower than the verbosity of the log, the log will not write it. * Each Output instance also has an instance-level global verbosity; * incoming requests to write text are additionally subject to this * verbosity test. Lastly, the Output class itself has a global * verbosity as well. This last verbosity is useful for shutting * down writing to all logs in the entire system in a simple way. * *
When the system fails for some reason and must be started back * up from a checkpoint, Output's log files may be overwritten. Output * offers three approaches here. First, Output can clear the log file * and overwrite it. Second, Output can append to the existing log file; * because checkpoints are only done occasionally, this may result in * duplicate outputs to a file, so keep this in mind. Third, Output can * keep certain written text, typically announcements, in memory; * this text gets written out into the checkpoint file, and so it is sound. * *
There are several kinds of announcements, in different levels * of importance. * *
Output will also store all announcements in memory by default so as to reproduce
* them if it's restarted from a checkpoint. You can change this behavior also by
*
* @author Sean Luke
* @version 1.0
*/
public class Output implements Serializable
{
boolean errors;
Vector logs = new Vector();
Vector announcements = new Vector();
// boolean flush = true;
boolean store = true;
String filePrefix = "";
public static final int ALL_LOGS = -1;
/** Total verbosity */
public static final int V_VERBOSE = 0;
/** Don't print messages */
public static final int V_NO_MESSAGES = 1000;
/** Don't print warnings or messages */
public static final int V_NO_WARNINGS = 2000;
/** The standard verbosity to use if you don't want common reporting (like statistics) */
public static final int V_NO_GENERAL = 3000;
/** Don't print warnings, messages, or simple errors */
public static final int V_NO_ERRORS = 4000;
/** No verbosity at all, not even system messages or fatal errors*/
public static final int V_TOTALLY_SILENT = 5000;
public void setFilePrefix(String filePrefix) {
this.filePrefix = filePrefix;
}
protected void finalize() throws Throwable
{
// flush the logs
close();
// do super.finalize, just for good style
super.finalize();
}
private void exitWithError()
{
// flush logs first
close();
// exit
System.exit(1);
}
/** Closes the logs -- ONLY call this if you are preparing to quit */
public synchronized void close()
{
// just in case
flush();
Enumeration e = logs.elements();
while(e.hasMoreElements())
{
Log log = (Log)e.nextElement();
if (!log.isLoggingToSystemOut)
log.writer.close();
}
}
/** Flushes the logs */
public synchronized void flush()
{
Enumeration e = logs.elements();
while(e.hasMoreElements())
{
Log log = (Log)e.nextElement();
log.writer.flush();
}
// just in case...
System.out.flush();
System.err.flush();
}
/** Creates a new, verbose, empty Output object.
@deprecated Verbosity no longer has an effect.
*/
public Output(boolean storeAnnouncementsInMemory, int _verbosity)
{
this(storeAnnouncementsInMemory);
}
/** Creates a new, verbose, empty Output object. */
public Output(boolean storeAnnouncementsInMemory)
{
errors = false;
store = storeAnnouncementsInMemory;
}
/** Sets whether the Output flushes its announcements.
@deprecated We now always flush
*/
public synchronized void setFlush(boolean v)
{
// flush = v;
}
/* Returns the Output's flushing behavior.
@deprecated We now always flush
*/
public synchronized boolean getFlush()
{
// return flush;
return true;
}
/** Sets whether the Output stores its announcements.*/
public synchronized void setStore(boolean v)
{
store = v;
}
/* Returns the Output's storing behavior. */
public synchronized boolean getStore()
{
return store;
}
/** Sets the Output object's general verbosity to v.
@deprecated Verbosity no longer has an effect.
*/
public synchronized void setVerbosity(int v)
{
// verbosity = v;
}
/** Returns the Output object's general verbosity
@deprecated Verbosity no longer has an effect.
*/
public synchronized int getVerbosity()
{
return V_VERBOSE;
}
/** Creates a new log of minimal verbosity verbosity and adds it
to Output. This log will write to the file file, and may
or may not post announcements to the log. If the log must be
reset upon restarting from a checkpoint, it will append to the file
or erase the file and start over depending on appendOnRestart.
If appendOnRestart is false and postAnnouncements is
true, then this log will repost all the announcements on restarting
from a checkpoint. Returns the position of the log in Output's
collection of logs -- you should use this to access the log always;
never store the log itself, which may go away upon a system restart.
The log can be compressed with gzip, but you cannot appendOnRestart
and compress at the same time.
@deprecated Verbosity no longer has an effect.
*/
public synchronized int addLog(File file,
int _verbosity,
boolean postAnnouncements,
boolean appendOnRestart,
boolean gzip) throws IOException
{
if (filePrefix != null && filePrefix.length()>0)
file = new File(file.getParent(),filePrefix+file.getName());
logs.addElement(new Log(file,postAnnouncements,appendOnRestart,gzip));
return logs.size()-1;
}
/** Creates a new log of minimal verbosity verbosity and adds it
to Output. This log will write to the file file, and may
or may not post announcements to the log. If the log must be
reset upon restarting from a checkpoint, it will append to the file
or erase the file and start over depending on appendOnRestart.
If appendOnRestart is false and postAnnouncements is
true, then this log will repost all the announcements on restarting
from a checkpoint. Returns the position of the log in Output's
collection of logs -- you should use this to access the log always;
never store the log itself, which may go away upon a system restart.
@deprecated Verbosity no longer has an effect
*/
public synchronized int addLog(File file,
int _verbosity,
boolean postAnnouncements,
boolean appendOnRestart) throws IOException
{
return addLog(file, postAnnouncements, appendOnRestart, false);
}
/** Creates a new log and adds it
to Output. This log will write to the file file, and may
or may not post announcements to the log. If the log must be
reset upon restarting from a checkpoint, it will append to the file
or erase the file and start over depending on appendOnRestart.
If appendOnRestart is false and postAnnouncements is
true, then this log will repost all the announcements on restarting
from a checkpoint. Returns the position of the log in Output's
collection of logs -- you should use this to access the log always;
never store the log itself, which may go away upon a system restart.
The log can be compressed with gzip, but you cannot appendOnRestart
and compress at the same time.
*/
public synchronized int addLog(File file,
boolean postAnnouncements,
boolean appendOnRestart,
boolean gzip) throws IOException
{
return addLog(file, V_VERBOSE, postAnnouncements, appendOnRestart, gzip);
}
/** Creates a new log and adds it
to Output. This log will write to the file file, and you may
not post announcements to the log. If the log must be
reset upon restarting from a checkpoint, it will append to the file
or erase the file and start over depending on appendOnRestart.
Returns the position of the log in Output's
collection of logs -- you should use this to access the log always;
never store the log itself, which may go away upon a system restart.
The log can be compressed with gzip, but you cannot appendOnRestart
and compress at the same time.*/
public synchronized int addLog(File file,
boolean appendOnRestart,
boolean gzip) throws IOException
{
return addLog(file, false, appendOnRestart, gzip);
}
/** Creates a new log and adds it
to Output. This log will write to the file file, and you may
not post announcements to the log. If the log must be
reset upon restarting from a checkpoint, it will append to the file
or erase the file and start over depending on appendOnRestart.
Returns the position of the log in Output's
collection of logs -- you should use this to access the log always;
never store the log itself, which may go away upon a system restart. */
public synchronized int addLog(File file,
boolean appendOnRestart) throws IOException
{
return addLog(file, false, appendOnRestart, false);
}
/** Creates a new log of minimal verbosity verbosity and adds it
to Output. This log will write to stdout (descriptor == Log.D_STDOUT)
or stderr (descriptor == Log.D_STDERR), and may or may not
post announcements to the log. Returns the position of the
log in Output's
collection of logs -- you should use this to access the log always;
never store the log itself, which may go away upon a system restart.
@deprecated Verbosity no longer has an effect
*/
public synchronized int addLog(int descriptor,
int _verbosity,
boolean postAnnouncements)
{
logs.addElement(new Log(descriptor,postAnnouncements));
return logs.size()-1;
}
/** Creates a new log and adds it
to Output. This log will write to stdout (descriptor == Log.D_STDOUT)
or stderr (descriptor == Log.D_STDERR), and may or may not
post announcements to the log. Returns the position of the
log in Output's
collection of logs -- you should use this to access the log always;
never store the log itself, which may go away upon a system restart.
*/
public synchronized int addLog(int descriptor,
boolean postAnnouncements)
{
return addLog(descriptor, V_VERBOSE, postAnnouncements);
}
/** Creates a new log of minimal verbosity verbosity and adds it
to Output. This log may or may not post announcements to
the log, and if it does, it additionally may or may not repost
all of its announcements to the log upon a restart. The log
writes to writer, which is reset upon system restart by
restarter. Returns the position of the log in Output's
collection of logs -- you should use this to access the log always;
never store the log itself, which may go away upon a system restart.
@deprecated Verbosity no longer has an effect
*/
public synchronized int addLog(Writer writer,
LogRestarter restarter,
int _verbosity,
boolean postAnnouncements,
boolean repostAnnouncements)
{
logs.addElement(new Log(writer,restarter,postAnnouncements,repostAnnouncements));
return logs.size()-1;
}
/** Creates a new log and adds it
to Output. This log may or may not post announcements to
the log, and if it does, it additionally may or may not repost
all of its announcements to the log upon a restart. The log
writes to writer, which is reset upon system restart by
restarter. Returns the position of the log in Output's
collection of logs -- you should use this to access the log always;
never store the log itself, which may go away upon a system restart.
*/
public synchronized int addLog(Writer writer,
LogRestarter restarter,
boolean postAnnouncements,
boolean repostAnnouncements)
{
logs.addElement(new Log(writer,restarter,postAnnouncements,repostAnnouncements));
return logs.size()-1;
}
/** Adds the given log to Output. In general you shouldn't use this
method unless you really really need something custom.
Returns the position of the log in Output's
collection of logs -- you should use this to access the log always;
never store the log itself, which may go away upon a system restart. */
public synchronized int addLog(Log l)
{
logs.addElement(l);
return logs.size()-1;
}
/** Returns the number of logs currently posted. */
public synchronized int numLogs()
{
return logs.size();
}
/** Returns the given log. */
public synchronized Log log(int x)
{
return (Log)logs.elementAt(x);
}
/** Removes the given log. */
public synchronized Log removeLog(int x)
{
Log l = log(x);
logs.removeElementAt(x);
return l;
}
/** Prints an initial error to System.err. This is only to
be used by ec.Evolve in starting up the system. */
public static void initialError(String s)
{
System.err.println("STARTUP ERROR:\n" + s);
// just in case...
System.out.flush();
System.err.flush();
System.exit(1);
}
/** Prints an initial error to System.err. This is only to
be used by ec.Evolve in starting up the system. */
public static void initialError(String s, Parameter p1)
{
System.err.println("STARTUP ERROR:\n" + s);
if (p1!=null) System.err.println("PARAMETER: " + p1);
// just in case...
System.out.flush();
System.err.flush();
System.exit(1);
}
/** Prints an initial error to System.err. This is only to
be used by ec.Evolve in starting up the system. */
public static void initialError(String s, Parameter p1, Parameter p2)
{
System.err.println("STARTUP ERROR:\n" + s);
if (p1!=null) System.err.println("PARAMETER: " + p1);
if (p2!=null && p1!=null) System.err.println(" ALSO: " + p2);
// just in case...
System.out.flush();
System.err.flush();
System.exit(1);
}
/** Prints an initial message to System.err. This is only to
be used by ec.Evolve in starting up the system. These messages are not logged. */
public static void initialMessage(String s)
{
System.err.println(s);
System.err.flush();
}
/** Posts a system message. */
public synchronized void systemMessage(String s)
{
println(s, V_NO_MESSAGES ,ALL_LOGS, true);
}
/** Posts a fatal error. This causes the system to exit. */
public synchronized void fatal(String s)
{
println("FATAL ERROR:\n"+s, ALL_LOGS, true);
exitWithError();
}
/** Posts a fatal error. This causes the system to exit. */
public synchronized void fatal(String s, Parameter p1)
{
println("FATAL ERROR:\n"+s, ALL_LOGS, true);
if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
exitWithError();
}
/** Posts a fatal error. This causes the system to exit. */
public synchronized void fatal(String s, Parameter p1, Parameter p2)
{
println("FATAL ERROR:\n"+s, ALL_LOGS, true);
if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
if (p2!=null && p1!=null) println(" ALSO: " + p2, ALL_LOGS, true);
else println("PARAMETER: " + p2, ALL_LOGS, true);
exitWithError();
}
/** Posts a simple error. This causes the error flag to be raised as well. */
public synchronized void error(String s)
{
println("ERROR:\n"+s, ALL_LOGS, true);
errors = true;
}
/** Posts a simple error. This causes the error flag to be raised as well. */
public synchronized void error(String s, Parameter p1)
{
println("ERROR:\n"+s, ALL_LOGS, true);
if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
errors = true;
}
/** Posts a simple error. This causes the error flag to be raised as well. */
public synchronized void error(String s, Parameter p1, Parameter p2)
{
println("ERROR:\n"+s, ALL_LOGS, true);
if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
if (p2!=null && p1!=null) println(" ALSO: " + p2, ALL_LOGS, true);
else println("PARAMETER: " + p2, ALL_LOGS, true);
errors = true;
}
/** Posts a warning. */
public synchronized void warning(String s, Parameter p1, Parameter p2)
{
println("WARNING:\n"+s, ALL_LOGS, true);
if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
if (p2!=null && p1!=null) println(" ALSO: " + p2, ALL_LOGS, true);
else println("PARAMETER: " + p2, ALL_LOGS, true);
}
/** Posts a warning. */
public synchronized void warning(String s, Parameter p1)
{
println("WARNING:\n"+s, ALL_LOGS, true);
if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
}
/** Posts a warning. */
public synchronized void warning(String s)
{
println("WARNING:\n"+s, ALL_LOGS, true);
}
java.util.HashSet oneTimeWarnings = new java.util.HashSet();
/** Posts a warning one time only. */
public synchronized void warnOnce(String s)
{
if (!oneTimeWarnings.contains(s))
{
oneTimeWarnings.add(s);
println("ONCE-ONLY WARNING:\n"+s, ALL_LOGS, true);
}
}
public synchronized void warnOnce(String s, Parameter p1)
{
if (!oneTimeWarnings.contains(s))
{
oneTimeWarnings.add(s);
println("ONCE-ONLY WARNING:\n"+s, ALL_LOGS, true);
if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
}
}
public synchronized void warnOnce(String s, Parameter p1, Parameter p2)
{
if (!oneTimeWarnings.contains(s))
{
oneTimeWarnings.add(s);
println("ONCE-ONLY WARNING:\n"+s, ALL_LOGS, true);
if (p1!=null) println("PARAMETER: " + p1, ALL_LOGS, true);
if (p2!=null && p1!=null) println(" ALSO: " + p2, ALL_LOGS, true);
else println("PARAMETER: " + p2, ALL_LOGS, true);
}
}
/** Posts a message. */
public synchronized void message(String s)
{
println(s, ALL_LOGS, true);
}
/** Forces a file-based log to reopen, erasing its previous contents.
non-file logs ignore this. */
public synchronized void reopen(int _log) throws IOException
{
Log oldlog = (Log)logs.elementAt(_log);
logs.setElementAt(oldlog.reopen(),_log);
}
/** Forces one or more file-based logs to reopen, erasing
their previous contents. non-file logs ignore this. */
public synchronized void reopen(int[] _logs) throws IOException
{
for(int x=0;x<_logs.length;x++)
{
Log oldlog = (Log)logs.elementAt(_logs[x]);
logs.setElementAt(oldlog.reopen(),_logs[x]);
}
}
/** Prints a message to a given log, with a certain verbosity.
_announcement indicates that the message is an announcement.
@deprecated Verbosity no longer has an effect
*/
synchronized void println(String s,
int _verbosity,
Log log,
boolean _announcement,
boolean _reposting) throws OutputException
{
if (log.writer==null) throw new OutputException("Log with a null writer: " + log);
if (!log.postAnnouncements && _announcement) return; // don't write it
// if (log.verbosity >= _verbosity) return; // don't write it
// if (verbosity >= _verbosity) return; // don't write it
// now write it
log.writer.println(s);
// if (flush)
// always flush
log.writer.flush();
//...and stash it in memory maybe
if (store && _announcement && !_reposting)
announcements.addElement(new Announcement(s));
}
/** Prints a message to a given log,
with a certain verbosity. If log==ALL_LOGS, posted to all logs which accept announcements.
@deprecated Verbosity no longer has an effect
*/
synchronized void println(String s,
int _verbosity,
int log,
boolean _announcement) throws OutputException
{
if (log==ALL_LOGS) for (int x = 0; x