08e4e2fc57
string-valued preferences built atop java.util.Properties. How it works: the jvm is asked first, and then the user's prefs file, if it exists, then the system-wide prefs file, and then the built-in preferences. Finally, for robustness, a default may be optionally hard-coded in the source. I made several things configurable, too: the default Tibetan keyboard the default font sizes and faces whether you want developer-only features enabled Savant's file extension (.savant) etc. The only known problems are the following: The default location for the user's preferences file is windows-specific, arbitrary, and not in the user documentation. Likewise for the location of the system-wide preferences file. You can change them using 'java -D', though. There is no "Save preferences" option yet, and closing the program does not save preferences either.
200 lines
8.8 KiB
Java
200 lines
8.8 KiB
Java
/*
|
|
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 java.io.File;
|
|
|
|
import org.thdl.util.TeeStream;
|
|
import org.thdl.util.ThdlOptions;
|
|
|
|
/**
|
|
* 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)
|
|
+ "\nAn 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.debug property to true (using <code>'java
|
|
* -Dthdl.debug=true'</code> or the properties files) 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.debug option 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 (ThdlOptions.getBooleanOption("thdl.debug"))
|
|
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.debug set to true (developers: use 'ant -Dthdl.debug=false' to prevent this), or because you set the thdl.debug preference to true in one of the preferences files, 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"); // FIXME yes you can when Java Web Start is up and running
|
|
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 (ThdlOptions.getBooleanOption("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
|
|
* (prefix + suffix). Be sure the log file name is a relative
|
|
* path, because we may put this file into an arbitrary
|
|
* directory. */
|
|
public static void attemptToSetUpLogFile(String prefix, String suffix) {
|
|
if (ThdlOptions.getBooleanOption("thdl.disable.log.file"))
|
|
return;
|
|
// Else:
|
|
final String tempDirProp = "thdl.use.temp.file.directory.for.log";
|
|
final String logDirProp = "thdl.log.directory";
|
|
File logFile = null;
|
|
|
|
if (ThdlOptions.getBooleanOption(tempDirProp)) {
|
|
/* The log file won't be named 'jskad.log', it'll be named
|
|
'jskad-SAKFJDS3134.log', and they'll all just pile up,
|
|
because we don't deleteOnExit. */
|
|
|
|
/* First, ensure that the user hasn't set conflicting options. */
|
|
try {
|
|
if (!("".equals(ThdlOptions.getStringOption("thdl.log.directory",
|
|
""))))
|
|
throw new Error("You cannot set the property "
|
|
+ tempDirProp + " and the property "
|
|
+ logDirProp
|
|
+ " at the same time because they both affect the same thing, the location of the log file.");
|
|
} catch (Exception e) {
|
|
/* SecurityExceptions, e.g., will trigger this. */
|
|
|
|
/* Leave logDir null. */
|
|
} catch (Error e) {
|
|
throw e;
|
|
}
|
|
|
|
/* Now, create the temporary file. */
|
|
try {
|
|
logFile = File.createTempFile(prefix, suffix);
|
|
} catch (Exception e) {
|
|
noteIffyCode();
|
|
}
|
|
} else {
|
|
/* If the user has set the system property
|
|
thdl.log.directory, respect their choice. */
|
|
String logDir = null;
|
|
try {
|
|
logDir = ThdlOptions.getStringOption(logDirProp, "");
|
|
} catch (Exception e) {
|
|
/* SecurityExceptions, e.g., will trigger this. We
|
|
leave logDir null. */
|
|
noteIffyCode();
|
|
}
|
|
if (!("".equals(ThdlOptions.getStringOption("thdl.log.directory",
|
|
"")))) {
|
|
logFile = new File(logDir, prefix + suffix);
|
|
} else {
|
|
/* Create the log file in the current directory. For
|
|
Windows users, this is often the desktop.
|
|
|
|
FIXME: by default, put the log file in a smarter place.
|
|
*/
|
|
logFile = new File(prefix + suffix);
|
|
}
|
|
}
|
|
try {
|
|
PrintStream logFilePrintStream
|
|
= new PrintStream(new FileOutputStream(logFile));
|
|
System.out.println("Logging to "
|
|
+ logFile.getAbsolutePath().toString()
|
|
+ "; please include the contents of this file in any bug reports.");
|
|
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();
|
|
}
|
|
}
|
|
};
|