Added Javadoc files overview.html and several package.html files.

Added a "Quit" option to Savant's File menu.  Factored out the Close
option in doing so.

Exceptions in many action listeners are now handled by
org.thdl.util.ThdlActionListener or org.thdl.util.ThdlAbstractAction.

Many exceptions that we used to just log now optionally cause aborts.
This option is on by default for developers using 'ant savant-run'-style
targets, but it is off for users.

An erroneous CLASSPATH now causes a useful error message in almost
all situations.

Fixed some typos and bad links in Javadoc comments.

Added a simple assertion facility, but the overhead is suffered even in
release builds.

Factored out the code that sets up log files like savant.log and jskad.log.
This commit is contained in:
dchandler 2002-10-06 18:23:27 +00:00
parent 14adf0d607
commit 403f21c8db
47 changed files with 2439 additions and 1567 deletions

View file

@ -22,7 +22,9 @@ import java.io.PrintStream;
/**
* All writes to this print stream are copied to two print streams of
* your choice. */
* your choice.
* @author David Chandler
*/
public class TeeStream extends PrintStream {
private PrintStream out;
public TeeStream(PrintStream out1, PrintStream out2) {

View file

@ -0,0 +1,85 @@
/*
The contents of this file are subject to the THDL Open Community License
Version 1.0 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License on the THDL web site
(http://www.thdl.org/).
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific terms governing rights and limitations under the
License.
The Initial Developer of this software is the Tibetan and Himalayan Digital
Library (THDL). Portions created by the THDL are Copyright 2001 THDL.
All Rights Reserved.
Contributor(s): ______________________________________.
*/
package org.thdl.util;
import javax.swing.AbstractAction;
import javax.swing.Icon;
import java.awt.event.ActionEvent;
import org.thdl.util.ThdlDebug;
/**
* This ActionListener is like any other except in the way that it
* handles exceptions or errors thrown during the execution of
* <code>actionPerformed()</code>. Because event listeners are on
* threads, an exception during <code>actionPerformed()</code> is just
* printed out on the console by
* <code>java.awt.EventDispatchThread.run()</code>. It does not cause
* the program to terminate. In our code, it helps developers more
* quickly get to the root of a problem if the program terminates as
* soon after a problem as possible.
*
* Thus, this class calls <code>System.exit(1)</code> when an
* exception is throw by <code>theRealActionPerformed()</code>, which
* is the method that subclasses should implement.
*
* @see ThdlActionListener
*
* @author David Chandler
*
* There is a pertinent Usenet thread at <code>http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=utf-8&threadm=6ntgl6%244hl%241%40tarantula.europe.shiva.com&rnum=2&prev=/groups%3Fq%3Dexception%2BactionPerformed%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3Dutf-8%26selm%3D6ntgl6%25244hl%25241%2540tarantula.europe.shiva.com%26rnum%3D2</code>.
*/
public class ThdlAbstractAction extends AbstractAction {
/** Just calls the super's constructor with the same args. */
public ThdlAbstractAction(String s, Icon i) {
super(s, i);
}
/** Subclasses don't override this. Instead, they override
* <code>theRealActionPerformed()</code>.
* @see #actionPerformed(ActionEvent)
*/
public final void actionPerformed(ActionEvent e) {
try {
theRealActionPerformed(e);
} catch (NoClassDefFoundError err) {
/* This is an especially common exception, and is in fact
the motivating force behind the ThdlActionListener
class and this class. Handle it well so that users
know what's up: */
ThdlDebug.handleClasspathError(null, err);
} catch (Throwable t) {
System.err.println("THDL_ERR 107: This application failed due to the following exception: ");
t.printStackTrace(System.err);
System.exit(1);
}
}
/** Subclasses should override this method to do the real action
* performed.
* @see #actionPerformed(ActionEvent)
*/
protected void theRealActionPerformed(ActionEvent e)
throws Throwable
{
/* do nothing */
}
}

View file

@ -0,0 +1,157 @@
/*
The contents of this file are subject to the THDL Open Community License
Version 1.0 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License on the THDL web site
(http://www.thdl.org/).
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific terms governing rights and limitations under the
License.
The Initial Developer of this software is the Tibetan and Himalayan Digital
Library (THDL). Portions created by the THDL are Copyright 2001 THDL.
All Rights Reserved.
Contributor(s): ______________________________________.
*/
package org.thdl.util;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import org.thdl.util.ThdlDebug;
/**
* This ActionListener is like any other except in the way that it
* handles exceptions or errors thrown during the execution of
* <code>actionPerformed()</code>. Because event listeners are on
* threads, an exception during <code>actionPerformed()</code> is just
* printed out on the console by
* <code>java.awt.EventDispatchThread.run()</code>. It does not cause
* the program to terminate. In our code, it helps developers more
* quickly get to the root of a problem if the program terminates as
* soon after a problem as possible.
*
* Thus, this class calls <code>System.exit(1)</code> when an
* exception is throw by <code>theRealActionPerformed()</code>, which
* is the method that subclasses should implement.
*
* @see ThdlAbstractAction
*
* @author David Chandler
*
* Here is a pertinent Usenet thread from <code>http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=utf-8&threadm=6ntgl6%244hl%241%40tarantula.europe.shiva.com&rnum=2&prev=/groups%3Fq%3Dexception%2BactionPerformed%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3Dutf-8%26selm%3D6ntgl6%25244hl%25241%2540tarantula.europe.shiva.com%26rnum%3D2</code>:
<pre>
From: Denis (denisb@europe.shiva.com)
Subject: Exception in event handlers
View this article only
Newsgroups: comp.lang.java.gui, comp.lang.java.help, comp.lang.java.programmer
Date: 1998/07/07
Hi everyone !
I've got a wee question regarding propagation of exceptions in event
handlers :
here's the fun :
Say, you've got a method A() that is called from within an event handler
(mostly it'll be in actionPerformed(ActionEvent) from ActionListener
interface).
Now this A() method produces an exception. This exception will be propagated
up to the caller of actionPerformed which is into the event handler queue.
This exception never gets propagated higher than the handler (and produces a
message "exception occured in event handler")
Now I would like this exception NOT to be caught there but to propagate
until the program terminates or it is caught somewhere else.
Is there a way to do that ? There's no mean to re-throw that exception as
the event handler is part of the core java.
Basically what I would like to do is catch ANY exception that occurs in a
java application in order to display a message box, without having to put
try{} catch{} blocks all other the place...
Thanks for any help on that
Chunk of code to illustrate :
class MyClass extends Object implements ActionListener {
// blah blah
public void actionPerformed(ActionEvent event) {
A(); //May throw an exception here but the actionPerformed is called
// from the event handler and the exception is caught into it
//So the actionPerformed finishes because of the exception but the
// rest of the app is likely to be in an unstable state, but still running
}
// So here the exception has been caught without an explicit try{}
// catch{} WHICH I DONT WANT
//You then can happily do something else....even if A() failed....
}//MyClass
Message 2 in thread
From: David Holmes (dholmes@mri.mq.edu.au)
Subject: Re: Exception in event handlers
View this article only
Newsgroups: comp.lang.java.gui, comp.lang.java.help, comp.lang.java.programmer
Date: 1998/07/09
Denis &lt;denisb@europe.shiva.com&gt; wrote in article
&lt;6ntgl6$4hl$1@tarantula.europe.shiva.com&gt;...
&gt; Now I would like this exception NOT to be caught there but to propagate
> until the program terminates or it is caught somewhere else.
Once an exception is caught it is up to the catcher what to do with it. The
event dispatch thread simply catches the exception and tells you about it.
There is no way to make this exception go any further - indeed there is
nowhere further for it to go. Exceptions occur per-thread and if the thread
doesn't catch it the thread will terminate. A more sophisticated event
mechanism might allow you to register a handler/listener to take some
action when this occurred but the current AWT does not.
David
</pre>
*/
public class ThdlActionListener implements ActionListener {
/** Subclasses don't override this. Instead, they override
* <code>theRealActionPerformed()</code>.
* @see #actionPerformed(ActionEvent)
*/
public final void actionPerformed(ActionEvent e) {
try {
theRealActionPerformed(e);
} catch (NoClassDefFoundError err) {
/* This is an especially common exception, and is in fact
the motivating force behind the ThdlActionListener
class. Handle it well so that users know what's up: */
ThdlDebug.handleClasspathError(null, err);
} catch (Throwable t) {
System.err.println("THDL_ERR 106: This application failed due to the following exception: ");
t.printStackTrace(System.err);
System.exit(1);
}
}
/** Subclasses should override this method to do the real action
* performed by this action listener.
* @see #actionPerformed(ActionEvent)
*/
protected void theRealActionPerformed(ActionEvent e)
throws Throwable
{
/* do nothing */
}
}

View file

@ -0,0 +1,136 @@
/*
The contents of this file are subject to the THDL Open Community License
Version 1.0 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License on the THDL web site
(http://www.thdl.org/).
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific terms governing rights and limitations under the
License.
The Initial Developer of this software is the Tibetan and Himalayan Digital
Library (THDL). Portions created by the THDL are Copyright 2001 THDL.
All Rights Reserved.
Contributor(s): ______________________________________.
*/
package org.thdl.util;
import java.io.PrintStream;
import java.io.FileOutputStream;
import org.thdl.util.TeeStream;
/**
* This uninstantiable class provides assertions and the like in a
* JVM-version-independent fashion.
* @author David Chandler
*/
public class ThdlDebug {
/* FIXME: make this configurable. */
static final String contactMsg
= " Please visit http://thdltools.sf.net/ or contact thdltools-devel@lists.sourceforge.net and give us a bug report so that we can improve the quality of this software.";
/** Do not instantiate this class. */
private ThdlDebug() { }
/** Throws an unchecked exception if condition is not true. Note that
* unlike a real assertion, this happens always. We can certainly
* use AspectJ (with which I, DC, am intimately familiar) to avoid
* the overhead of such things in release builds if performance
* becomes a real issue. */
public static void verify(boolean condition) {
verify(null, condition);
}
/** Throws an unchecked exception if condition is not true. The
* exception's message will include the string msg if msg is not
* null. Note that unlike a real assertion, this happens always.
* We can certainly use AspectJ (with which I, DC, am intimately
* familiar) to avoid the overhead of such things in release
* builds if performance becomes a real issue.
*
* Throws a THDL-specific exception so that you can catch these
* specially in case you want to ignore them.
*
* @throws ThdlLazyException if condition is not true */
public static void verify(String msg, boolean condition)
throws ThdlLazyException
{
if (!condition) {
throw new ThdlLazyException(new Error(((msg == null)
? "THDL Tools sanity check: "
: msg)
+ "An assertion failed. This means that there is a bug in this software."
+ contactMsg));
}
}
/** Call this from control-flow paths that are not well thought
* out. For example, if you have to catch an IOException, but
* you're fairly certain that it'll never be thrown, call this
* function if it is indeed thrown. Developers can set the
* THDL_DIE_EAGERLY property to true (using <code>'java
* -DTHDL_DIE_ON_IFFY_CODE=true'</code>) in order to test the
* code's robustness.
*
* Throws a THDL-specific exception so that you can catch these
* specially in case you want to ignore them.
*
* @throws ThdlLazyException if the THDL_DIE_ON_IFFY_CODE system
* property is set to "true" */
public static void noteIffyCode()
throws ThdlLazyException
{
/* FIXME: find all calls to this function and rethink or shore
up the calling code. */
if (Boolean.getBoolean("THDL_DIE_ON_IFFY_CODE"))
throw new ThdlLazyException(new Error("You've reached some iffy code, some code that's not well thought-out. Because you invoked the Java runtime environment with the property THDL_DIE_ON_IFFY_CODE set to true (developers: use 'ant -Dthdl.die.on.iffy=false' to prevent this), the program is now aborting."));
}
/** Exits the program with a message that the CLASSPATH is not set
properly. */
public static void handleClasspathError(String whoseWhat, Throwable error) {
System.err.println(((whoseWhat == null) ? "Your CLASSPATH" : whoseWhat)
+ " is not set properly.");
/* FIXME */
System.err.println("Note that Savant and QuillDriver CANNOT be invoked via the");
System.err.println("'java -jar Savant-xyz.jar' option, because that silently ignores");
System.err.println("the CLASSPATH. This means that double-clicking them won't work");
System.err.println("either, because we don't set the JARs' manifest files to contain");
System.err.println("Class-path attributes. See installation instructions."); /* FIXME: we don't HAVE installation instructions, do we? */
System.err.println("");
System.err.println("Details: Missing class: "
+ ((error == null)
? "unknown!" : error.getMessage()));
if (Boolean.getBoolean("THDL_DEBUG")) {
System.err.println("Details: Stack trace: "
+ ((error == null)
? "unknown!" : error.getMessage()));
error.printStackTrace(System.err);
}
System.exit(1);
}
/** Sets it up so that a call to System.out or System.err prints
* to standard output/error but ALSO prints to the log file named
* logFile. */
public static void attemptToSetUpLogFile(String logFile) {
try {
PrintStream logFilePrintStream
= new PrintStream(new FileOutputStream(logFile));
PrintStream psOut = new TeeStream(System.out, logFilePrintStream);
PrintStream psErr = new TeeStream(System.err, logFilePrintStream);
System.setErr(psErr);
System.setOut(psOut);
} catch (Exception e) {
/* don't let this stop us. */
noteIffyCode();
}
}
};

View file

@ -0,0 +1,22 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<!--
@(#)package.html
Copyright 2001-2002 Tibetan and Himalayan Digital Library
This software is the confidential and proprietary information of
the Tibetan and Himalayan Digital Library. You shall use such
information only in accordance with the terms of the license
agreement you entered into with the THDL.
-->
</head>
<body bgcolor="white">
Provides classes and methods not specific to any one application.
<p>
These classes aim to be of general use to the THDL's Java programs.
</body>
</html>