From ae754de7faf707f4ca495733a4db78d0beb98577 Mon Sep 17 00:00:00 2001
From: Gianluca
Date: Fri, 29 Mar 2024 13:51:13 +0100
Subject: [PATCH] Fix inclusion of croftsoft source code
---
.../com/croftsfot/core/applet/AppletLib.java | 110 ++++
.../com/croftsfot/core/applet/package.html | 7 +
.../com/croftsfot/core/io/EchoReader.java | 116 +++++
.../java/com/croftsfot/core/io/Encoder.java | 28 +
.../java/com/croftsfot/core/io/FileLib.java | 355 +++++++++++++
.../java/com/croftsfot/core/io/Parser.java | 38 ++
.../croftsfot/core/io/SerializableCoder.java | 58 +++
.../croftsfot/core/io/SerializableLib.java | 477 ++++++++++++++++++
.../java/com/croftsfot/core/io/StreamLib.java | 152 ++++++
.../com/croftsfot/core/io/StringCoder.java | 62 +++
.../java/com/croftsfot/core/io/package.html | 5 +
.../java/com/croftsfot/core/jnlp/JnlpLib.java | 137 +++++
.../com/croftsfot/core/jnlp/JnlpProxy.java | 115 +++++
.../com/croftsfot/core/jnlp/JnlpServices.java | 58 +++
.../croftsfot/core/jnlp/JnlpServicesImpl.java | 216 ++++++++
.../java/com/croftsfot/core/jnlp/package.html | 7 +
.../com/croftsfot/core/lang/ClassLib.java | 193 +++++++
.../core/lang/EnumUnknownException.java | 41 ++
.../core/lang/ExternalAccessException.java | 105 ++++
.../com/croftsfot/core/lang/Listener.java | 23 +
.../core/lang/NullArgumentException.java | 103 ++++
.../croftsfot/core/lang/NullException.java | 72 +++
.../com/croftsfot/core/lang/ObjectLib.java | 44 ++
.../java/com/croftsfot/core/lang/Pair.java | 90 ++++
.../com/croftsfot/core/lang/StringLib.java | 167 ++++++
.../com/croftsfot/core/lang/Testable.java | 67 +++
.../com/croftsfot/core/lang/ThreadLib.java | 40 ++
.../com/croftsfot/core/lang/ThrowableLib.java | 52 ++
.../croftsfot/core/lang/classloader/Boot.java | 199 ++++++++
.../lang/classloader/CacheClassLoader.java | 218 ++++++++
.../core/lang/classloader/ClassLoaderLib.java | 35 ++
.../lang/classloader/CustomClassLoader.java | 126 +++++
.../lang/classloader/DialogClassLoader.java | 96 ++++
.../core/lang/classloader/NetClassLoader.java | 202 ++++++++
.../core/lang/classloader/package.html | 5 +
.../core/lang/ex/ExceptionHandler.java | 28 +
.../core/lang/ex/ExceptionListener.java | 22 +
.../core/lang/ex/PrintExceptionListener.java | 26 +
.../com/croftsfot/core/lang/ex/package.html | 5 +
.../core/lang/lifecycle/AppletLifecycle.java | 48 ++
.../core/lang/lifecycle/Commissionable.java | 22 +
.../lang/lifecycle/CompositeLifecycle.java | 63 +++
.../core/lang/lifecycle/Destroyable.java | 23 +
.../core/lang/lifecycle/Initializable.java | 23 +
.../lifecycle/InitializationException.java | 81 +++
.../core/lang/lifecycle/Lifecycle.java | 22 +
.../lang/lifecycle/LifecycleEnforcer.java | 357 +++++++++++++
.../core/lang/lifecycle/LifecycleLib.java | 236 +++++++++
.../core/lang/lifecycle/Resumable.java | 22 +
.../core/lang/lifecycle/Startable.java | 23 +
.../core/lang/lifecycle/Stoppable.java | 23 +
.../core/lang/lifecycle/Updatable.java | 23 +
.../core/lang/lifecycle/UpdateRunner.java | 44 ++
.../core/lang/lifecycle/package.html | 5 +
.../java/com/croftsfot/core/lang/package.html | 5 +
.../core/lang/reflect/MethodLib.java | 55 ++
.../croftsfot/core/lang/reflect/package.html | 5 +
.../java/com/croftsfot/core/math/Counter.java | 66 +++
.../com/croftsfot/core/math/FinanceLib.java | 304 +++++++++++
.../croftsfot/core/math/MathConstants.java | 34 ++
.../java/com/croftsfot/core/math/MathLib.java | 293 +++++++++++
.../java/com/croftsfot/core/math/Matrix.java | 387 ++++++++++++++
.../java/com/croftsfot/core/math/Point2D.java | 75 +++
.../java/com/croftsfot/core/math/Point3d.java | 150 ++++++
.../com/croftsfot/core/math/RandomLib.java | 130 +++++
.../croftsfot/core/math/axis/AxisAngle.java | 50 ++
.../core/math/axis/AxisAngleImp.java | 152 ++++++
.../core/math/axis/AxisAngleLib.java | 154 ++++++
.../core/math/axis/AxisAngleMut.java | 34 ++
.../core/math/axis/AxisAngleTest.java | 72 +++
.../com/croftsfot/core/math/axis/package.html | 5 +
.../com/croftsfot/core/math/geom/Circle.java | 205 ++++++++
.../core/math/geom/CircleAccessor.java | 39 ++
.../croftsfot/core/math/geom/Point2DD.java | 196 +++++++
.../croftsfot/core/math/geom/Point3DD.java | 174 +++++++
.../croftsfot/core/math/geom/Point3DI.java | 150 ++++++
.../com/croftsfot/core/math/geom/PointXY.java | 38 ++
.../croftsfot/core/math/geom/PointXYZ.java | 26 +
.../croftsfot/core/math/geom/ShapeLib.java | 74 +++
.../com/croftsfot/core/math/geom/package.html | 5 +
.../croftsfot/core/math/matrix/Matrix.java | 45 ++
.../croftsfot/core/math/matrix/Matrix3x3.java | 32 ++
.../core/math/matrix/Matrix3x3Imp.java | 123 +++++
.../core/math/matrix/Matrix3x3Lib.java | 244 +++++++++
.../core/math/matrix/Matrix3x3Mut.java | 22 +
.../croftsfot/core/math/matrix/MatrixImp.java | 271 ++++++++++
.../croftsfot/core/math/matrix/MatrixLib.java | 292 +++++++++++
.../croftsfot/core/math/matrix/MatrixMut.java | 37 ++
.../core/math/matrix/MatrixTest.java | 214 ++++++++
.../croftsfot/core/math/matrix/package.html | 5 +
.../java/com/croftsfot/core/math/package.html | 5 +
.../com/croftsfot/core/math/quat/Quat.java | 52 ++
.../com/croftsfot/core/math/quat/QuatImp.java | 133 +++++
.../com/croftsfot/core/math/quat/QuatLib.java | 192 +++++++
.../com/croftsfot/core/math/quat/QuatMut.java | 30 ++
.../croftsfot/core/math/quat/QuatTest.java | 87 ++++
.../com/croftsfot/core/math/quat/package.html | 5 +
97 files changed, 9582 insertions(+)
create mode 100644 src/main/java/com/croftsfot/core/applet/AppletLib.java
create mode 100644 src/main/java/com/croftsfot/core/applet/package.html
create mode 100644 src/main/java/com/croftsfot/core/io/EchoReader.java
create mode 100644 src/main/java/com/croftsfot/core/io/Encoder.java
create mode 100644 src/main/java/com/croftsfot/core/io/FileLib.java
create mode 100644 src/main/java/com/croftsfot/core/io/Parser.java
create mode 100644 src/main/java/com/croftsfot/core/io/SerializableCoder.java
create mode 100644 src/main/java/com/croftsfot/core/io/SerializableLib.java
create mode 100644 src/main/java/com/croftsfot/core/io/StreamLib.java
create mode 100644 src/main/java/com/croftsfot/core/io/StringCoder.java
create mode 100644 src/main/java/com/croftsfot/core/io/package.html
create mode 100644 src/main/java/com/croftsfot/core/jnlp/JnlpLib.java
create mode 100644 src/main/java/com/croftsfot/core/jnlp/JnlpProxy.java
create mode 100644 src/main/java/com/croftsfot/core/jnlp/JnlpServices.java
create mode 100644 src/main/java/com/croftsfot/core/jnlp/JnlpServicesImpl.java
create mode 100644 src/main/java/com/croftsfot/core/jnlp/package.html
create mode 100644 src/main/java/com/croftsfot/core/lang/ClassLib.java
create mode 100644 src/main/java/com/croftsfot/core/lang/EnumUnknownException.java
create mode 100644 src/main/java/com/croftsfot/core/lang/ExternalAccessException.java
create mode 100644 src/main/java/com/croftsfot/core/lang/Listener.java
create mode 100644 src/main/java/com/croftsfot/core/lang/NullArgumentException.java
create mode 100644 src/main/java/com/croftsfot/core/lang/NullException.java
create mode 100644 src/main/java/com/croftsfot/core/lang/ObjectLib.java
create mode 100644 src/main/java/com/croftsfot/core/lang/Pair.java
create mode 100644 src/main/java/com/croftsfot/core/lang/StringLib.java
create mode 100644 src/main/java/com/croftsfot/core/lang/Testable.java
create mode 100644 src/main/java/com/croftsfot/core/lang/ThreadLib.java
create mode 100644 src/main/java/com/croftsfot/core/lang/ThrowableLib.java
create mode 100644 src/main/java/com/croftsfot/core/lang/classloader/Boot.java
create mode 100644 src/main/java/com/croftsfot/core/lang/classloader/CacheClassLoader.java
create mode 100644 src/main/java/com/croftsfot/core/lang/classloader/ClassLoaderLib.java
create mode 100644 src/main/java/com/croftsfot/core/lang/classloader/CustomClassLoader.java
create mode 100644 src/main/java/com/croftsfot/core/lang/classloader/DialogClassLoader.java
create mode 100644 src/main/java/com/croftsfot/core/lang/classloader/NetClassLoader.java
create mode 100644 src/main/java/com/croftsfot/core/lang/classloader/package.html
create mode 100644 src/main/java/com/croftsfot/core/lang/ex/ExceptionHandler.java
create mode 100644 src/main/java/com/croftsfot/core/lang/ex/ExceptionListener.java
create mode 100644 src/main/java/com/croftsfot/core/lang/ex/PrintExceptionListener.java
create mode 100644 src/main/java/com/croftsfot/core/lang/ex/package.html
create mode 100644 src/main/java/com/croftsfot/core/lang/lifecycle/AppletLifecycle.java
create mode 100644 src/main/java/com/croftsfot/core/lang/lifecycle/Commissionable.java
create mode 100644 src/main/java/com/croftsfot/core/lang/lifecycle/CompositeLifecycle.java
create mode 100644 src/main/java/com/croftsfot/core/lang/lifecycle/Destroyable.java
create mode 100644 src/main/java/com/croftsfot/core/lang/lifecycle/Initializable.java
create mode 100644 src/main/java/com/croftsfot/core/lang/lifecycle/InitializationException.java
create mode 100644 src/main/java/com/croftsfot/core/lang/lifecycle/Lifecycle.java
create mode 100644 src/main/java/com/croftsfot/core/lang/lifecycle/LifecycleEnforcer.java
create mode 100644 src/main/java/com/croftsfot/core/lang/lifecycle/LifecycleLib.java
create mode 100644 src/main/java/com/croftsfot/core/lang/lifecycle/Resumable.java
create mode 100644 src/main/java/com/croftsfot/core/lang/lifecycle/Startable.java
create mode 100644 src/main/java/com/croftsfot/core/lang/lifecycle/Stoppable.java
create mode 100644 src/main/java/com/croftsfot/core/lang/lifecycle/Updatable.java
create mode 100644 src/main/java/com/croftsfot/core/lang/lifecycle/UpdateRunner.java
create mode 100644 src/main/java/com/croftsfot/core/lang/lifecycle/package.html
create mode 100644 src/main/java/com/croftsfot/core/lang/package.html
create mode 100644 src/main/java/com/croftsfot/core/lang/reflect/MethodLib.java
create mode 100644 src/main/java/com/croftsfot/core/lang/reflect/package.html
create mode 100644 src/main/java/com/croftsfot/core/math/Counter.java
create mode 100644 src/main/java/com/croftsfot/core/math/FinanceLib.java
create mode 100644 src/main/java/com/croftsfot/core/math/MathConstants.java
create mode 100644 src/main/java/com/croftsfot/core/math/MathLib.java
create mode 100644 src/main/java/com/croftsfot/core/math/Matrix.java
create mode 100644 src/main/java/com/croftsfot/core/math/Point2D.java
create mode 100644 src/main/java/com/croftsfot/core/math/Point3d.java
create mode 100644 src/main/java/com/croftsfot/core/math/RandomLib.java
create mode 100644 src/main/java/com/croftsfot/core/math/axis/AxisAngle.java
create mode 100644 src/main/java/com/croftsfot/core/math/axis/AxisAngleImp.java
create mode 100644 src/main/java/com/croftsfot/core/math/axis/AxisAngleLib.java
create mode 100644 src/main/java/com/croftsfot/core/math/axis/AxisAngleMut.java
create mode 100644 src/main/java/com/croftsfot/core/math/axis/AxisAngleTest.java
create mode 100644 src/main/java/com/croftsfot/core/math/axis/package.html
create mode 100644 src/main/java/com/croftsfot/core/math/geom/Circle.java
create mode 100644 src/main/java/com/croftsfot/core/math/geom/CircleAccessor.java
create mode 100644 src/main/java/com/croftsfot/core/math/geom/Point2DD.java
create mode 100644 src/main/java/com/croftsfot/core/math/geom/Point3DD.java
create mode 100644 src/main/java/com/croftsfot/core/math/geom/Point3DI.java
create mode 100644 src/main/java/com/croftsfot/core/math/geom/PointXY.java
create mode 100644 src/main/java/com/croftsfot/core/math/geom/PointXYZ.java
create mode 100644 src/main/java/com/croftsfot/core/math/geom/ShapeLib.java
create mode 100644 src/main/java/com/croftsfot/core/math/geom/package.html
create mode 100644 src/main/java/com/croftsfot/core/math/matrix/Matrix.java
create mode 100644 src/main/java/com/croftsfot/core/math/matrix/Matrix3x3.java
create mode 100644 src/main/java/com/croftsfot/core/math/matrix/Matrix3x3Imp.java
create mode 100644 src/main/java/com/croftsfot/core/math/matrix/Matrix3x3Lib.java
create mode 100644 src/main/java/com/croftsfot/core/math/matrix/Matrix3x3Mut.java
create mode 100644 src/main/java/com/croftsfot/core/math/matrix/MatrixImp.java
create mode 100644 src/main/java/com/croftsfot/core/math/matrix/MatrixLib.java
create mode 100644 src/main/java/com/croftsfot/core/math/matrix/MatrixMut.java
create mode 100644 src/main/java/com/croftsfot/core/math/matrix/MatrixTest.java
create mode 100644 src/main/java/com/croftsfot/core/math/matrix/package.html
create mode 100644 src/main/java/com/croftsfot/core/math/package.html
create mode 100644 src/main/java/com/croftsfot/core/math/quat/Quat.java
create mode 100644 src/main/java/com/croftsfot/core/math/quat/QuatImp.java
create mode 100644 src/main/java/com/croftsfot/core/math/quat/QuatLib.java
create mode 100644 src/main/java/com/croftsfot/core/math/quat/QuatMut.java
create mode 100644 src/main/java/com/croftsfot/core/math/quat/QuatTest.java
create mode 100644 src/main/java/com/croftsfot/core/math/quat/package.html
diff --git a/src/main/java/com/croftsfot/core/applet/AppletLib.java b/src/main/java/com/croftsfot/core/applet/AppletLib.java
new file mode 100644
index 0000000..bf350cf
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/applet/AppletLib.java
@@ -0,0 +1,110 @@
+ package com.croftsoft.core.applet;
+
+ import java.applet.*;
+ import java.io.*;
+
+ import com.croftsoft.core.io.SerializableLib;
+ import com.croftsoft.core.lang.NullArgumentException;
+
+ /*********************************************************************
+ * Static library methods for manipulating Applets.
+ *
+ * @version
+ * $Id: AppletLib.java,v 1.3 2008/09/28 21:50:42 croft Exp $
+ * @since
+ * 2002-12-22
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class AppletLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ /*********************************************************************
+ * Loads GZIP compressed data.
+ *********************************************************************/
+ public static Serializable loadSerializableUsingAppletPersistence (
+ Applet applet,
+ String key )
+ throws ClassNotFoundException, IOException,
+ UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( applet, "null applet" );
+
+ NullArgumentException.check ( key, "null key" );
+
+ AppletContext appletContext = null;
+
+ try
+ {
+ appletContext = applet.getAppletContext ( );
+ }
+ catch ( NullPointerException ex )
+ {
+ // ignore
+ }
+
+ if ( appletContext == null )
+ {
+ throw new UnsupportedOperationException ( "null AppletContext" );
+ }
+
+ InputStream inputStream = appletContext.getStream ( key );
+
+ if ( inputStream == null )
+ {
+ return null;
+ }
+
+ return SerializableLib.load ( inputStream );
+ }
+
+ /*********************************************************************
+ * Saves data using GZIP compression.
+ *********************************************************************/
+ public static void saveSerializableUsingAppletPersistence (
+ Applet applet,
+ String key,
+ Serializable serializable )
+ throws IOException, UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( applet, "null applet" );
+
+ NullArgumentException.check ( key, "null key" );
+
+ NullArgumentException.check ( serializable, "null serializable" );
+
+ AppletContext appletContext = null;
+
+ try
+ {
+ appletContext = applet.getAppletContext ( );
+ }
+ catch ( NullPointerException ex )
+ {
+ // ignore
+ }
+
+ if ( appletContext == null )
+ {
+ throw new UnsupportedOperationException ( "null AppletContext" );
+ }
+
+ InputStream inputStream = new ByteArrayInputStream (
+ SerializableLib.compress ( serializable ) );
+
+ appletContext.setStream ( key, inputStream );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ private AppletLib ( ) { /* empty */ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/applet/package.html b/src/main/java/com/croftsfot/core/applet/package.html
new file mode 100644
index 0000000..34001b8
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/applet/package.html
@@ -0,0 +1,7 @@
+
+
+
+
+Applet manipulation code.
+
+
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/io/EchoReader.java b/src/main/java/com/croftsfot/core/io/EchoReader.java
new file mode 100644
index 0000000..67a405b
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/io/EchoReader.java
@@ -0,0 +1,116 @@
+ package com.croftsoft.core.io;
+
+ import java.io.*;
+
+ import com.croftsoft.core.lang.NullArgumentException;
+
+ /*********************************************************************
+ * A FilterReader that echoes characters read to a Writer.
+ *
+ *
+ *
+ * @version
+ * 2002-09-19
+ * @since
+ * 2002-09-19
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class EchoReader
+ extends FilterReader
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private final Writer echoWriter;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * Main constructor.
+ *********************************************************************/
+ public EchoReader (
+ Reader in,
+ Writer echoWriter )
+ //////////////////////////////////////////////////////////////////////
+ {
+ super ( in );
+
+ NullArgumentException.check ( this.echoWriter = echoWriter );
+ }
+
+ /*********************************************************************
+ * Echoes to the standard output.
+ * this ( in, new PrintWriter ( System.out ) );
+ *********************************************************************/
+ public EchoReader ( Reader in )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this ( in, new PrintWriter ( System.out ) );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public int read ( )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ int ch = super.read ( );
+
+ if ( ch > -1 )
+ {
+ echoWriter.write ( ch );
+ }
+
+ return ch;
+ }
+
+ public int read (
+ char [ ] cbuf,
+ int off,
+ int len )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ int count = super.read ( cbuf, off, len );
+
+ if ( count > -1 )
+ {
+ echoWriter.write ( cbuf, off, count );
+ }
+
+ return count;
+ }
+
+ public int read ( char [ ] cbuf )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ int count = super.read ( cbuf );
+
+ if ( count > -1 )
+ {
+ echoWriter.write ( cbuf, 0, count );
+ }
+
+ return count;
+ }
+
+ /*********************************************************************
+ * Flushes the echoWriter in addition to closing the input.
+ *********************************************************************/
+ public void close ( )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ super.close ( );
+
+ echoWriter.flush ( );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/io/Encoder.java b/src/main/java/com/croftsfot/core/io/Encoder.java
new file mode 100644
index 0000000..d007299
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/io/Encoder.java
@@ -0,0 +1,28 @@
+ package com.croftsoft.core.io;
+
+ import java.io.*;
+
+ /*********************************************************************
+ * A generic interface for Object encoders.
+ *
+ * @see
+ * Parser
+ * @version
+ * 2003-05-13
+ * @since
+ * 2000-03-23
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface Encoder
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public byte [ ] encode ( Object object )
+ throws IOException;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/io/FileLib.java b/src/main/java/com/croftsfot/core/io/FileLib.java
new file mode 100644
index 0000000..2bb122f
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/io/FileLib.java
@@ -0,0 +1,355 @@
+ package com.croftsoft.core.io;
+
+ import java.io.*;
+ import java.util.*;
+
+ import com.croftsoft.core.lang.NullArgumentException;
+
+ /*********************************************************************
+ * A library of static methods to manipulate File objects.
+ *
+ *
+ *
+ * @version
+ * 2001-06-10
+ * @since
+ * 1999-08-15
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class FileLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ /*********************************************************************
+ * Test method.
+ *********************************************************************/
+ public static void main ( String [ ] args )
+ //////////////////////////////////////////////////////////////////////
+ {
+ File file = findFile ( args [ 0 ], args [ 1 ], true );
+ System.out.println ( file );
+ }
+
+ /*********************************************************************
+ * Returns null if the file does not already exist.
+ *********************************************************************/
+ public static File findFile (
+ String dirname, String filename, boolean ignoreFilenameCase )
+ //////////////////////////////////////////////////////////////////////
+ {
+ File file = new File ( dirname, filename );
+ if ( file.exists ( ) ) return file;
+ if ( !ignoreFilenameCase ) return null;
+
+ File dir = null;
+
+ if ( dirname != null )
+ {
+ dir = new File ( dirname );
+ if ( !dir.exists ( ) ) return null;
+ if ( !dir.isDirectory ( ) )
+ {
+ throw new IllegalArgumentException (
+ "\"" + dirname + "\" is not a directory." );
+ }
+ }
+
+ if ( dir == null ) dir = new File ( "." );
+
+ String [ ] files = dir.list ( );
+ for ( int i = 0; i < files.length; i++ )
+ {
+ if ( files [ i ].equalsIgnoreCase ( filename ) )
+ {
+ return new File ( dir, files [ i ] );
+ }
+ }
+
+ return null;
+ }
+
+ /*********************************************************************
+ * Parses out the file name extension.
+ *
+ * @return
+ * Returns null if file name does not have a period;
+ * returns the empty String ("") if the file name has only one period
+ * and it is the last character;
+ * otherwise returns everything after the first period.
+ *********************************************************************/
+ public static String getExtension ( File file )
+ //////////////////////////////////////////////////////////////////////
+ {
+ String name = file.getName ( );
+ int i = name.indexOf ( '.' );
+ if ( i < 0 ) return null;
+ return name.substring ( i + 1, name.length ( ) - i - 1 );
+ }
+
+ /*********************************************************************
+ * Creates the parent directories for a file specified by a combined
+ * path and filename String.
+ * The name after the last separator in pathFilename is not created
+ * as a directory and is typically a filename.
+ * Used when the normal File.mkdirs() operation would mistakenly create
+ * directories for the parent directories plus a directory with the
+ * same name as the filename instead of just directories for the
+ * parent directories when given the combined path and filename.
+ * The pathFilename may be just a filename without a path or a
+ * a file in the root directory; in these cases, no directory will
+ * be created.
+ *********************************************************************/
+ public static boolean makeParents ( String pathFilename )
+ //////////////////////////////////////////////////////////////////////
+ {
+ File file = new File ( pathFilename );
+
+ String parent = file.getParent ( );
+
+ if ( parent == null )
+ {
+ return false;
+ }
+
+ File dir = new File ( parent );
+
+ return dir.mkdirs ( );
+ }
+
+ /*********************************************************************
+ * Replaces instances of oldString with newString in the inFile.
+ *
+ * Creates a temporary file (inFile + ".tmp") in the process.
+ *
+ * @return
+ * Returns true if the file was updated.
+ *********************************************************************/
+ public static boolean replaceStrings (
+ File file, String oldString, String newString )
+ throws FileNotFoundException, IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ byte [ ] oldBytes = oldString.getBytes ( );
+ byte [ ] newBytes = newString.getBytes ( );
+ return replaceBytes ( file, oldBytes, newBytes );
+ }
+
+ /*********************************************************************
+ * Replaces instances of oldBytes with newBytes in the inFile.
+ *
+ * Creates a temporary file (inFile + ".tmp") in the process.
+ *
+ * @return
+ * Returns true if the file was updated.
+ *********************************************************************/
+ public static boolean replaceBytes (
+ File file, byte [ ] oldBytes, byte [ ] newBytes )
+ throws FileNotFoundException, IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ String fileName = file.getCanonicalPath ( );
+ String tmpFileName = fileName + ".tmp";
+ File tmpFile = new File ( tmpFileName );
+ if ( tmpFile.exists ( ) )
+ {
+ throw new IOException ( "Temporary file \"" + tmpFileName
+ + "\" already exists." );
+ }
+ try
+ {
+ boolean hasChanged
+ = replaceBytes ( file, tmpFile, oldBytes, newBytes );
+ if ( !hasChanged ) return false;
+ if ( !file.delete ( ) )
+ {
+ throw new IOException ( "Unable to delete to replace \""
+ + fileName + "\"." );
+ }
+ if ( !tmpFile.renameTo ( new File ( fileName ) ) )
+ {
+ throw new IOException ( "Original file deleted but unable"
+ + " to rename the updated file to the original name (\""
+ + fileName + "\", \"" + tmpFileName + "\")." );
+ }
+ }
+ finally
+ {
+ tmpFile.delete ( );
+ }
+ return true;
+ }
+
+ /*********************************************************************
+ * Copies inFile to outFile with the replacement of occurrences of
+ * oldString with newString.
+ *
+ * Any pre-existing outFile is overwritten.
+ *
+ * @return
+ * Returns true if outFile differs from inFile.
+ *********************************************************************/
+ public static boolean replaceStrings (
+ File inFile, File outFile, String oldString, String newString )
+ throws FileNotFoundException, IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ byte [ ] oldBytes = oldString.getBytes ( );
+ byte [ ] newBytes = newString.getBytes ( );
+ return replaceBytes ( inFile, outFile, oldBytes, newBytes );
+ }
+
+ /*********************************************************************
+ * Copies inFile to outFile with the replacement of occurrences of
+ * oldBytes with newBytes.
+ *
+ * Any pre-existing outFile is overwritten.
+ *
+ * @return
+ * Returns true if outFile differs from inFile.
+ *********************************************************************/
+ public static boolean replaceBytes (
+ File inFile,
+ File outFile,
+ byte [ ] oldBytes,
+ byte [ ] newBytes )
+ throws FileNotFoundException, IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( ( inFile == null )
+ || ( outFile == null )
+ || ( oldBytes == null )
+ || ( newBytes == null ) )
+ {
+ throw new IllegalArgumentException ( "null argument" );
+ }
+
+ if ( !inFile.isFile ( ) )
+ {
+ throw new IllegalArgumentException (
+ "\"" + inFile.getCanonicalPath ( ) + "\" is not a file." );
+ }
+/*
+ if ( !outFile.isFile ( ) )
+ {
+ throw new IllegalArgumentException (
+ "\"" + outFile.getCanonicalPath ( ) + "\" is not a file." );
+ }
+*/
+
+ BufferedInputStream in = new BufferedInputStream (
+ new FileInputStream ( inFile ) );
+ BufferedOutputStream out = new BufferedOutputStream (
+ new FileOutputStream ( outFile ) );
+
+ boolean hasChanged
+ = StreamLib.replaceBytes ( in, out, oldBytes, newBytes );
+
+ out.close ( );
+ in.close ( );
+
+ return hasChanged;
+ }
+
+ /*********************************************************************
+ * Loads the text file content into a String.
+ *********************************************************************/
+ public static String loadTextFile ( String filename )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( filename == null )
+ {
+ throw new IllegalArgumentException ( "null filename" );
+ }
+
+ FileReader in = null;
+
+ StringWriter out = null;
+
+ try
+ {
+ in = new FileReader ( filename );
+
+ out = new StringWriter ( );
+
+ int i;
+
+ while ( ( i = in.read ( ) ) > -1 )
+ {
+ out.write ( ( byte ) i );
+ }
+
+ out.flush ( );
+
+ return out.toString ( );
+ }
+ finally
+ {
+ try { in.close ( ); } catch ( Exception ex ) { }
+
+ try { out.close ( ); } catch ( Exception ex ) { }
+ }
+ }
+
+ /*********************************************************************
+ * Strips off the file name extension.
+ *********************************************************************/
+ public static String pareExtension ( String fileName )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( fileName == null )
+ {
+ throw new IllegalArgumentException ( "null" );
+ }
+
+ int index = fileName.lastIndexOf ( '.' );
+
+ if ( index < 0 )
+ {
+ return fileName;
+ }
+
+ return fileName.substring ( 0, index );
+ }
+
+ /*********************************************************************
+ * Saves text to a file.
+ *********************************************************************/
+ public static void saveTextFile (
+ String filename,
+ String text )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( filename );
+
+ NullArgumentException.check ( text );
+
+ FileWriter fileWriter = null;
+
+ try
+ {
+ fileWriter = new FileWriter ( filename );
+
+ fileWriter.write ( text );
+ }
+ finally
+ {
+ if ( fileWriter != null )
+ {
+ fileWriter.close ( );
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ private FileLib ( ) { }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/io/Parser.java b/src/main/java/com/croftsfot/core/io/Parser.java
new file mode 100644
index 0000000..72c2cb3
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/io/Parser.java
@@ -0,0 +1,38 @@
+ package com.croftsoft.core.io;
+
+ import java.io.*;
+
+ /*********************************************************************
+ *
+ * A generic interface for Object parsers.
+ *
+ *
+ *
+ * @see
+ * Encoder
+ * @version
+ * 2003-05-14
+ * @since
+ * 2000-03-23
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface Parser
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ /*********************************************************************
+ * @param contentLength
+ *
+ * -1 if unknown.
+ *********************************************************************/
+ public Object parse (
+ InputStream inputStream,
+ int contentLength )
+ throws IOException;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/io/SerializableCoder.java b/src/main/java/com/croftsfot/core/io/SerializableCoder.java
new file mode 100644
index 0000000..ab3df07
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/io/SerializableCoder.java
@@ -0,0 +1,58 @@
+ package com.croftsoft.core.io;
+
+ import java.io.*;
+
+ /*********************************************************************
+ * An Encoder and Parser implementation that uses object serialization.
+ *
+ * @version
+ * 2003-05-28
+ * @since
+ * 2003-05-13
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class SerializableCoder
+ implements Encoder, Parser
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public static final SerializableCoder INSTANCE
+ = new SerializableCoder ( );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public byte [ ] encode ( Object object )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ return SerializableLib.compress ( ( Serializable ) object );
+ }
+
+ public Object parse (
+ InputStream inputStream,
+ int contentLength )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ return SerializableLib.load ( inputStream );
+ }
+ catch ( ClassNotFoundException ex )
+ {
+ throw ( IOException ) new IOException ( ).initCause ( ex );
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ private SerializableCoder ( ) { }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/io/SerializableLib.java b/src/main/java/com/croftsfot/core/io/SerializableLib.java
new file mode 100644
index 0000000..e264e86
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/io/SerializableLib.java
@@ -0,0 +1,477 @@
+ package com.croftsoft.core.io;
+
+ import java.applet.*;
+ import java.io.*;
+ import java.util.zip.*;
+
+ import com.croftsoft.core.applet.AppletLib;
+ import com.croftsoft.core.jnlp.JnlpLib;
+ import com.croftsoft.core.lang.NullArgumentException;
+ import com.croftsoft.core.lang.Testable;
+
+ /*********************************************************************
+ * Saves and loads Serializable objects using GZIP compression.
+ *
+ * @version
+ * 2003-06-13
+ * @since
+ * 2001-04-25
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class SerializableLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private static final String PROPERTY_USER_HOME = "user.home";
+
+ //////////////////////////////////////////////////////////////////////
+ // test methods
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * Displays the result of test().
+ *********************************************************************/
+ public static void main ( String [ ] args )
+ throws Exception
+ //////////////////////////////////////////////////////////////////////
+ {
+ System.out.println ( test ( args ) );
+ }
+
+ public static boolean test ( String [ ] args )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ final String TEST = "CroftSoft";
+
+ if ( !TEST.equals (
+ load ( new ByteArrayInputStream ( compress ( TEST ) ) ) ) )
+ {
+ return false;
+ }
+
+ String testCopy = ( String ) copy ( TEST );
+
+ if ( ( testCopy == TEST )
+ || !testCopy.equals ( TEST ) )
+ {
+ return false;
+ }
+ }
+ catch ( Exception ex )
+ {
+ ex.printStackTrace ( );
+
+ return false;
+ }
+
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public static byte [ ] compress ( Serializable serializable )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( serializable );
+
+ ByteArrayOutputStream byteArrayOutputStream
+ = new ByteArrayOutputStream ( );
+
+ save ( serializable, byteArrayOutputStream );
+
+ return byteArrayOutputStream.toByteArray ( );
+ }
+
+ public static Serializable copy ( Serializable serializable )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ ByteArrayOutputStream byteArrayOutputStream
+ = new ByteArrayOutputStream ( );
+
+ ObjectOutputStream objectOutputStream
+ = new ObjectOutputStream ( byteArrayOutputStream );
+
+ objectOutputStream.writeObject ( serializable );
+
+ byte [ ] bytes = byteArrayOutputStream.toByteArray ( );
+
+ ByteArrayInputStream byteArrayInputStream
+ = new ByteArrayInputStream ( bytes );
+
+ ObjectInputStream objectInputStream
+ = new ObjectInputStream ( byteArrayInputStream );
+
+ try
+ {
+ return ( Serializable ) objectInputStream.readObject ( );
+ }
+ catch ( ClassNotFoundException ex )
+ {
+ // This should never happen since the same classes are used.
+
+ throw new RuntimeException ( );
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // load methods
+ //////////////////////////////////////////////////////////////////////
+
+ public static Serializable load ( InputStream inputStream )
+ throws ClassNotFoundException, IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( inputStream );
+
+ ObjectInputStream objectInputStream = null;
+
+ try
+ {
+ objectInputStream
+ = new ObjectInputStream (
+ new GZIPInputStream (
+ new BufferedInputStream ( inputStream ) ) );
+
+ return ( Serializable ) objectInputStream.readObject ( );
+ }
+ finally
+ {
+ if ( objectInputStream != null )
+ {
+ objectInputStream.close ( );
+ }
+ else
+ {
+ inputStream.close ( );
+ }
+ }
+ }
+
+ public static Serializable load ( String filename )
+ throws ClassNotFoundException, IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( filename );
+
+ return load ( new FileInputStream ( filename ) );
+ }
+
+ public static Serializable load (
+ String primaryFilename,
+ String fallbackFilename )
+ throws ClassNotFoundException, IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( primaryFilename );
+
+ if ( fallbackFilename == null )
+ {
+ return load ( primaryFilename );
+ }
+
+ try
+ {
+ return load ( primaryFilename );
+ }
+ catch ( FileNotFoundException ex )
+ {
+ }
+ catch ( Exception ex )
+ {
+ ex.printStackTrace ( );
+ }
+
+ return load ( fallbackFilename );
+ }
+
+ public static Serializable load (
+ ClassLoader classLoader,
+ String filename )
+ throws ClassNotFoundException, IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( classLoader );
+
+ NullArgumentException.check ( filename );
+
+ InputStream inputStream
+ = classLoader.getResourceAsStream ( filename );
+
+ if ( inputStream == null )
+ {
+ return null;
+ }
+
+ return load ( inputStream );
+ }
+
+ public static Serializable load (
+ String primaryFilename,
+ String fallbackFilename,
+ String fileContentsSpec,
+ Applet applet,
+ String persistenceKey,
+ ClassLoader classLoader,
+ String resourcePathFilename )
+ throws ClassNotFoundException, IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ Serializable serializable = null;
+
+ if ( primaryFilename != null )
+ {
+ try
+ {
+ String userHomeDir = System.getProperty ( PROPERTY_USER_HOME );
+
+ String primaryPath
+ = userHomeDir + File.separator + primaryFilename;
+
+ if ( fallbackFilename != null )
+ {
+ String fallbackPath
+ = userHomeDir + File.separator + fallbackFilename;
+
+ serializable
+ = ( Serializable ) load ( primaryPath, fallbackPath );
+ }
+ else
+ {
+ serializable = ( Serializable ) load ( primaryPath );
+ }
+ }
+ catch ( FileNotFoundException ex )
+ {
+ }
+ catch ( SecurityException ex )
+ {
+ }
+ }
+
+ if ( ( serializable == null )
+ && ( fileContentsSpec != null ) )
+ {
+ try
+ {
+ serializable = ( Serializable )
+ JnlpLib.loadSerializableUsingPersistenceService (
+ fileContentsSpec );
+ }
+ catch ( UnsupportedOperationException ex )
+ {
+ }
+ }
+
+ if ( ( serializable == null )
+ && ( applet != null )
+ && ( persistenceKey != null ) )
+ {
+ try
+ {
+ serializable = ( Serializable )
+ AppletLib.loadSerializableUsingAppletPersistence (
+ applet, persistenceKey );
+ }
+ catch ( UnsupportedOperationException ex )
+ {
+ }
+ }
+
+ if ( ( serializable == null )
+ && ( classLoader != null )
+ && ( resourcePathFilename != null ) )
+ {
+ serializable
+ = ( Serializable ) load ( classLoader, resourcePathFilename );
+ }
+
+ return serializable;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // save methods
+ //////////////////////////////////////////////////////////////////////
+
+ public static void save (
+ Serializable serializable,
+ OutputStream outputStream )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( serializable );
+
+ NullArgumentException.check ( outputStream );
+
+ ObjectOutputStream objectOutputStream = null;
+
+ try
+ {
+ objectOutputStream = new ObjectOutputStream (
+ new GZIPOutputStream (
+ new BufferedOutputStream ( outputStream ) ) );
+
+ objectOutputStream.writeObject ( serializable );
+ }
+ finally
+ {
+ if ( objectOutputStream != null )
+ {
+ objectOutputStream.close ( );
+ }
+ else
+ {
+ outputStream.close ( );
+ }
+ }
+ }
+
+ public static void save (
+ Serializable serializable,
+ String filename,
+ boolean makeDirs )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( serializable );
+
+ NullArgumentException.check ( filename );
+
+ if ( makeDirs )
+ {
+ FileLib.makeParents ( filename );
+ }
+
+ save ( serializable, new FileOutputStream ( filename ) );
+ }
+
+ public static void save (
+ Serializable serializable,
+ String filename )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ save ( serializable, filename, true );
+ }
+
+ public static void save (
+ Serializable serializable,
+ String latestFilename,
+ String backupFilename )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( serializable );
+
+ NullArgumentException.check ( latestFilename );
+
+ NullArgumentException.check ( backupFilename );
+
+ File latestFile = new File ( latestFilename );
+
+ if ( latestFile.exists ( ) )
+ {
+ File backupFile = new File ( backupFilename );
+
+ if ( backupFile.exists ( ) )
+ {
+ backupFile.delete ( );
+ }
+ else
+ {
+ FileLib.makeParents ( backupFilename );
+ }
+
+ latestFile.renameTo ( backupFile );
+ }
+
+ save ( serializable, latestFilename );
+ }
+
+ public static boolean save (
+ Serializable serializable,
+ String latestFilename,
+ String backupFilename,
+ String fileContentsSpec,
+ Applet applet,
+ String persistenceKey )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( serializable );
+
+ if ( latestFilename != null )
+ {
+ try
+ {
+ String userHomeDir = System.getProperty ( PROPERTY_USER_HOME );
+
+ String latestPath
+ = userHomeDir + File.separator + latestFilename;
+
+ if ( backupFilename != null )
+ {
+ String backupPath
+ = userHomeDir + File.separator + backupFilename;
+
+ save ( serializable, latestPath, backupPath );
+ }
+ else
+ {
+ save ( serializable, latestPath );
+ }
+
+ return true;
+ }
+ catch ( SecurityException ex )
+ {
+ }
+ }
+
+ if ( fileContentsSpec != null )
+ {
+ try
+ {
+ JnlpLib.saveSerializableUsingPersistenceService (
+ fileContentsSpec, serializable );
+
+ return true;
+ }
+ catch ( UnsupportedOperationException ex )
+ {
+ }
+ }
+
+ if ( ( applet != null )
+ && ( persistenceKey != null ) )
+ {
+ try
+ {
+ AppletLib.saveSerializableUsingAppletPersistence (
+ applet, persistenceKey, serializable );
+
+ return true;
+ }
+ catch ( UnsupportedOperationException ex )
+ {
+ }
+ }
+
+ return false;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ private SerializableLib ( ) { }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/io/StreamLib.java b/src/main/java/com/croftsfot/core/io/StreamLib.java
new file mode 100644
index 0000000..ea15963
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/io/StreamLib.java
@@ -0,0 +1,152 @@
+ package com.croftsoft.core.io;
+
+ import java.io.*;
+ import java.util.*;
+
+ /*********************************************************************
+ *
+ * A library of static methods for the manipulation of input and
+ * output streams.
+ *
+ *
+ *
+ * @version
+ * 2000-04-30
+ * @since
+ * 1999-08-15
+ * @author
+ * David W. Croft
+ *********************************************************************/
+
+ public final class StreamLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private StreamLib ( ) { }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public static void main ( String [ ] args )
+ //////////////////////////////////////////////////////////////////////
+ {
+ System.out.println ( System.getProperty ( "file.encoding" ) );
+ }
+
+ /*********************************************************************
+ * Replaces bytes in a stream as it is being copied from the
+ * InputStream to the OutputStream.
+ *
+ *
+ *
+ * Does not automatically close the streams after completion.
+ * Maintains an internal buffer with the same size as oldBytes.
+ *
+ * @return
+ * Returns true if bytes were replaced.
+ *********************************************************************/
+ public static boolean replaceBytes (
+ InputStream in,
+ OutputStream out,
+ byte [ ] oldBytes,
+ byte [ ] newBytes )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ byte [ ] bufBytes = new byte [ oldBytes.length ];
+
+ boolean hasChanged = false;
+
+ int i;
+
+ byte b;
+
+ int index = 0;
+
+ while ( ( i = in.read ( ) ) > -1 )
+ {
+ b = ( byte ) i;
+
+ if ( b == oldBytes [ index ] )
+ {
+ if ( index + 1 < bufBytes.length )
+ {
+ bufBytes [ index++ ] = b;
+ }
+ else
+ {
+ out.write ( newBytes );
+
+ hasChanged = true;
+
+ index = 0;
+ }
+ }
+ else
+ {
+ out.write ( bufBytes, 0, index );
+
+ out.write ( b );
+
+ index = 0;
+ }
+ }
+
+ return hasChanged;
+ }
+
+ /*********************************************************************
+ * Converts the bytes of the InputStream to a String.
+ *
+ *
+ *
+ * Does not automatically close the stream after completion.
+ *********************************************************************/
+ public static String toString (
+ InputStream inputStream,
+ String encoding )
+ throws IOException, UnsupportedEncodingException
+ //////////////////////////////////////////////////////////////////////
+ {
+ ByteArrayOutputStream byteArrayOutputStream
+ = new ByteArrayOutputStream ( );
+
+ int i;
+
+ while ( ( i = inputStream.read ( ) ) > -1 )
+ {
+ byteArrayOutputStream.write ( i );
+ }
+
+ return byteArrayOutputStream.toString ( encoding );
+ }
+
+ /*********************************************************************
+ * Converts the bytes of the InputStream to a String.
+ *
+ *
+ *
+ * Does not automatically close the stream after completion.
+ *********************************************************************/
+ public static String toString (
+ InputStream inputStream )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ ByteArrayOutputStream byteArrayOutputStream
+ = new ByteArrayOutputStream ( );
+
+ int i;
+
+ while ( ( i = inputStream.read ( ) ) > -1 )
+ {
+ byteArrayOutputStream.write ( i );
+ }
+
+ return byteArrayOutputStream.toString ( );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/io/StringCoder.java b/src/main/java/com/croftsfot/core/io/StringCoder.java
new file mode 100644
index 0000000..c758173
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/io/StringCoder.java
@@ -0,0 +1,62 @@
+ package com.croftsoft.core.io;
+
+ import java.io.*;
+
+ import com.croftsoft.core.lang.NullArgumentException;
+
+ /*********************************************************************
+ * A String Encoder and Parser.
+ *
+ * @version
+ * 2003-06-02
+ * @since
+ * 2003-06-01
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class StringCoder
+ implements Encoder, Parser
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public static final String US_ASCII = "US-ASCII";
+
+ public static final String UTF_8 = "UTF-8";
+
+ //
+
+ private final String charSetName;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public StringCoder ( String charSetName )
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( this.charSetName = charSetName );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public byte [ ] encode ( Object object )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ return object.toString ( ).getBytes ( charSetName );
+ }
+
+ public Object parse (
+ InputStream inputStream,
+ int contentLength )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ return StreamLib.toString ( inputStream, charSetName );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/io/package.html b/src/main/java/com/croftsfot/core/io/package.html
new file mode 100644
index 0000000..35409e5
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/io/package.html
@@ -0,0 +1,5 @@
+
+
+Package java.io input/output support.
+
+
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/jnlp/JnlpLib.java b/src/main/java/com/croftsfot/core/jnlp/JnlpLib.java
new file mode 100644
index 0000000..8ffb47b
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/jnlp/JnlpLib.java
@@ -0,0 +1,137 @@
+ package com.croftsoft.core.jnlp;
+
+ import java.io.*;
+ import java.net.*;
+
+ /*********************************************************************
+ * Static library methods for JNLP.
+ *
+ * @version
+ * 2002-12-22
+ * @since
+ * 2002-12-22
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class JnlpLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public static final JnlpServices JNLP_SERVICES
+ = createJnlpServices ( );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public static URL createFileContentsURL ( String fileContentsSpec )
+ throws MalformedURLException, UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ check ( );
+
+ return JNLP_SERVICES.createFileContentsURL ( fileContentsSpec );
+ }
+
+ public static URL getCodeBase ( )
+ throws UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ check ( );
+
+ return JNLP_SERVICES.getCodeBase ( );
+ }
+
+ public static byte [ ] loadBytesUsingPersistenceService (
+ String fileContentsSpec )
+ throws IOException, UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ check ( );
+
+ return JNLP_SERVICES.loadBytesUsingPersistenceService (
+ fileContentsSpec );
+ }
+
+ public static Serializable loadSerializableUsingPersistenceService (
+ String fileContentsSpec )
+ throws ClassNotFoundException, IOException,
+ UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ check ( );
+
+ return JNLP_SERVICES.loadSerializableUsingPersistenceService (
+ fileContentsSpec );
+ }
+
+ public static void saveBytesUsingPersistenceService (
+ String fileContentsSpec,
+ byte [ ] bytes )
+ throws IOException, UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ check ( );
+
+ JNLP_SERVICES.saveBytesUsingPersistenceService (
+ fileContentsSpec, bytes );
+ }
+
+ public static void saveSerializableUsingPersistenceService (
+ String fileContentsSpec,
+ Serializable serializable )
+ throws IOException, UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ check ( );
+
+ JNLP_SERVICES.saveSerializableUsingPersistenceService (
+ fileContentsSpec, serializable );
+ }
+
+ public static boolean showDocument ( URL url )
+ throws UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ check ( );
+
+ return JNLP_SERVICES.showDocument ( url );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ private static void check ( )
+ throws UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( JNLP_SERVICES == null )
+ {
+ throw new UnsupportedOperationException ( );
+ }
+ }
+
+ private static JnlpServices createJnlpServices ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ return ( JnlpServices )
+ Class.forName ( JnlpServices.IMPL_CLASS_NAME ).newInstance ( );
+ }
+ catch ( Exception ex )
+ {
+ return null;
+ }
+ catch ( NoClassDefFoundError er )
+ {
+ return null;
+ }
+ }
+
+ private JnlpLib ( ) { }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/jnlp/JnlpProxy.java b/src/main/java/com/croftsfot/core/jnlp/JnlpProxy.java
new file mode 100644
index 0000000..5ce917a
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/jnlp/JnlpProxy.java
@@ -0,0 +1,115 @@
+ package com.croftsoft.core.jnlp;
+
+ import java.lang.reflect.*;
+ import java.net.*;
+
+ /*********************************************************************
+ * Uses reflection to access JNLP services.
+ *
+ * @see
+ *
+ * Launching a Browser from Java
+ *
+ * @version
+ * 2001-10-23
+ * @since
+ * 2001-08-31
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class JnlpProxy
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private static final Object basicServiceObject
+ = getBasicServiceObject ( );
+
+ private static final Class basicServiceClass
+ = getBasicServiceClass ( );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public static void main ( String [ ] args )
+ throws Exception
+ //////////////////////////////////////////////////////////////////////
+ {
+ showDocument ( new URL ( args [ 0 ] ) );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public static boolean showDocument ( URL url )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( basicServiceObject == null )
+ {
+ return false;
+ }
+
+ try
+ {
+ Method method = basicServiceClass.getMethod (
+ "showDocument", new Class [ ] { URL.class } );
+
+ Boolean resultBoolean = ( Boolean )
+ method.invoke ( basicServiceObject, new Object [ ] { url } );
+
+ return resultBoolean.booleanValue ( );
+ }
+ catch ( Exception ex )
+ {
+ ex.printStackTrace ( );
+
+ throw new RuntimeException ( ex.getMessage ( ) );
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ private static Object getBasicServiceObject ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ Class serviceManagerClass
+ = Class.forName ( "javax.jnlp.ServiceManager" );
+
+ Method lookupMethod = serviceManagerClass.getMethod ( "lookup",
+ new Class [ ] { String.class } );
+
+ return lookupMethod.invoke (
+ null, new Object [ ] { "javax.jnlp.BasicService" } );
+ }
+ catch ( Exception ex )
+ {
+ return null;
+ }
+ }
+
+ private static Class getBasicServiceClass ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ return Class.forName ( "javax.jnlp.BasicService" );
+ }
+ catch ( Exception ex )
+ {
+ return null;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ private JnlpProxy ( ) { }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/jnlp/JnlpServices.java b/src/main/java/com/croftsfot/core/jnlp/JnlpServices.java
new file mode 100644
index 0000000..614ff05
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/jnlp/JnlpServices.java
@@ -0,0 +1,58 @@
+ package com.croftsoft.core.jnlp;
+
+ import java.io.*;
+ import java.net.*;
+
+ /*********************************************************************
+ * Interface for JnlpServicesImpl.
+ *
+ * @version
+ * 2002-12-22
+ * @since
+ * 2002-12-21
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface JnlpServices
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public static final String IMPL_CLASS_NAME
+ = "com.croftsoft.core.jnlp.JnlpServicesImpl";
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public URL createFileContentsURL ( String fileContentsSpec )
+ throws MalformedURLException, UnsupportedOperationException;
+
+ public URL getCodeBase ( )
+ throws UnsupportedOperationException;
+
+ public byte [ ] loadBytesUsingPersistenceService (
+ String fileContentsSpec )
+ throws IOException, UnsupportedOperationException;
+
+ public Serializable loadSerializableUsingPersistenceService (
+ String fileContentsSpec )
+ throws ClassNotFoundException, IOException,
+ UnsupportedOperationException;
+
+ public void saveBytesUsingPersistenceService (
+ String fileContentsSpec,
+ byte [ ] bytes )
+ throws IOException, UnsupportedOperationException;
+
+ public void saveSerializableUsingPersistenceService (
+ String fileContentsSpec,
+ Serializable serializable )
+ throws IOException, UnsupportedOperationException;
+
+ public boolean showDocument ( URL url )
+ throws UnsupportedOperationException;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/jnlp/JnlpServicesImpl.java b/src/main/java/com/croftsfot/core/jnlp/JnlpServicesImpl.java
new file mode 100644
index 0000000..6d1a390
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/jnlp/JnlpServicesImpl.java
@@ -0,0 +1,216 @@
+ package com.croftsoft.core.jnlp;
+
+ import java.io.*;
+ import java.net.*;
+
+ import javax.jnlp.*;
+
+ import com.croftsoft.core.io.SerializableLib;
+
+ /*********************************************************************
+ * JNLP Services.
+ *
+ * @version
+ * $Date: 2008/04/19 21:27:13 $
+ * @since
+ * 2002-12-21
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class JnlpServicesImpl
+ implements JnlpServices
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public URL createFileContentsURL ( String fileContentsSpec )
+ throws MalformedURLException, UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ return new URL ( getCodeBase ( ), fileContentsSpec );
+ }
+
+ public URL getCodeBase ( )
+ throws UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ BasicService basicService = ( BasicService )
+ ServiceManager.lookup ( "javax.jnlp.BasicService" );
+
+ return basicService.getCodeBase ( );
+ }
+ catch ( UnavailableServiceException ex )
+ {
+ throw ( UnsupportedOperationException )
+ new UnsupportedOperationException ( ).initCause ( ex );
+ }
+ }
+
+ /*********************************************************************
+ * Loads a byte array.
+ *********************************************************************/
+ public byte [ ] loadBytesUsingPersistenceService (
+ String fileContentsSpec )
+ throws IOException, UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ InputStream inputStream = null;
+
+ try
+ {
+ PersistenceService persistenceService = ( PersistenceService )
+ ServiceManager.lookup ( "javax.jnlp.PersistenceService" );
+
+ FileContents fileContents = persistenceService.get (
+ createFileContentsURL ( fileContentsSpec ) );
+
+ ByteArrayOutputStream byteArrayOutputStream
+ = new ByteArrayOutputStream ( );
+
+ inputStream
+ = new BufferedInputStream ( fileContents.getInputStream ( ) );
+
+ int i;
+
+ while ( ( i = inputStream.read ( ) ) > -1 )
+ {
+ byteArrayOutputStream.write ( i );
+ }
+
+ return byteArrayOutputStream.toByteArray ( );
+ }
+ catch ( FileNotFoundException ex )
+ {
+ return null;
+ }
+ catch ( UnavailableServiceException ex )
+ {
+ throw ( UnsupportedOperationException )
+ new UnsupportedOperationException ( ).initCause ( ex );
+ }
+ finally
+ {
+ if ( inputStream != null )
+ {
+ inputStream.close ( );
+ }
+ }
+ }
+
+ /*********************************************************************
+ * Loads GZIP compressed data.
+ *********************************************************************/
+ public Serializable loadSerializableUsingPersistenceService (
+ String fileContentsSpec )
+ throws ClassNotFoundException, IOException,
+ UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ PersistenceService persistenceService = ( PersistenceService )
+ ServiceManager.lookup ( "javax.jnlp.PersistenceService" );
+
+ FileContents fileContents = persistenceService.get (
+ createFileContentsURL ( fileContentsSpec ) );
+
+ return SerializableLib.load ( fileContents.getInputStream ( ) );
+ }
+ catch ( FileNotFoundException ex )
+ {
+ return null;
+ }
+ catch ( UnavailableServiceException ex )
+ {
+ throw ( UnsupportedOperationException )
+ new UnsupportedOperationException ( ).initCause ( ex );
+ }
+ }
+
+ public void saveBytesUsingPersistenceService (
+ String fileContentsSpec,
+ byte [ ] bytes )
+ throws IOException, UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ BufferedOutputStream bufferedOutputStream = null;
+
+ try
+ {
+ PersistenceService persistenceService = ( PersistenceService )
+ ServiceManager.lookup ( "javax.jnlp.PersistenceService" );
+
+ URL fileContentsURL
+ = createFileContentsURL ( fileContentsSpec );
+
+ try
+ {
+ persistenceService.delete ( fileContentsURL );
+ }
+ catch ( FileNotFoundException ex )
+ {
+ // ignore
+ }
+
+ persistenceService.create ( fileContentsURL, bytes.length );
+
+ FileContents fileContents
+ = persistenceService.get ( fileContentsURL );
+
+ bufferedOutputStream = new BufferedOutputStream (
+ fileContents.getOutputStream ( true ) );
+
+ bufferedOutputStream.write ( bytes );
+ }
+ catch ( UnavailableServiceException ex )
+ {
+ throw ( UnsupportedOperationException )
+ new UnsupportedOperationException ( ).initCause ( ex );
+ }
+ finally
+ {
+ if ( bufferedOutputStream != null )
+ {
+ bufferedOutputStream.close ( );
+ }
+ }
+ }
+
+ /*********************************************************************
+ * Saves data using GZIP compression.
+ *********************************************************************/
+ public void saveSerializableUsingPersistenceService (
+ String fileContentsSpec,
+ Serializable serializable )
+ throws IOException, UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ saveBytesUsingPersistenceService (
+ fileContentsSpec,
+ SerializableLib.compress ( serializable ) );
+ }
+
+ public boolean showDocument ( URL url )
+ throws UnsupportedOperationException
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ BasicService basicService = ( BasicService )
+ ServiceManager.lookup ( "javax.jnlp.BasicService" );
+
+ return basicService.showDocument ( url );
+ }
+ catch ( UnavailableServiceException ex )
+ {
+ throw ( UnsupportedOperationException )
+ new UnsupportedOperationException ( ).initCause ( ex );
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/jnlp/package.html b/src/main/java/com/croftsfot/core/jnlp/package.html
new file mode 100644
index 0000000..f0d3a25
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/jnlp/package.html
@@ -0,0 +1,7 @@
+
+
+
+
+Package javax.jnlp Java Network Launching Protocol (JNLP) support classes.
+
+
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/lang/ClassLib.java b/src/main/java/com/croftsfot/core/lang/ClassLib.java
new file mode 100644
index 0000000..fe8a8d2
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/ClassLib.java
@@ -0,0 +1,193 @@
+ package com.croftsoft.core.lang;
+
+ import java.awt.*;
+ import java.io.*;
+
+ /*********************************************************************
+ * Static methods to complement the java.lang.Class methods.
+ *
+ * @see
+ * java.lang.Class
+ *
+ * @version
+ * 2002-10-29
+ * @since
+ * 2001-07-24
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class ClassLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public static void main ( String [ ] args )
+ //////////////////////////////////////////////////////////////////////
+ {
+ System.out.println ( test ( args ) );
+ }
+
+ public static boolean test ( String [ ] args )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return "ClassLib".equals ( getShortName ( ClassLib.class ) );
+ }
+
+ /*********************************************************************
+ * Loads a resource into memory as a String.
+ *
+ *
+ * Useful for loading a text file from a JAR on the classpath.
+ *
+ *
+ *
+ * Implemented using Class.getResourceAsStream(). Review of the
+ * documentation of this method is advised in order to understand the
+ * relative search path.
+ *
+ *
+ * @param relativeClass
+ *
+ * The Class used for the text file search.
+ *
+ * @param filename
+ *
+ * The path to the file, usually started by "/".
+ *
+ * @see
+ * java.lang.Class#getResourceAsStream(java.lang.String)
+ *********************************************************************/
+ public static String getResourceAsText (
+ Class relativeClass,
+ String filename )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( relativeClass );
+
+ NullArgumentException.check ( filename );
+
+ BufferedInputStream bufferedInputStream = null;
+
+ StringWriter out = null;
+
+ try
+ {
+ bufferedInputStream = new BufferedInputStream (
+ relativeClass.getResourceAsStream ( filename ) );
+
+ out = new StringWriter ( );
+
+ int i;
+
+ while ( ( i = bufferedInputStream.read ( ) ) > -1 )
+ {
+ out.write ( ( byte ) i );
+ }
+
+ out.flush ( );
+
+ return out.toString ( );
+ }
+ finally
+ {
+ if ( bufferedInputStream != null )
+ {
+ bufferedInputStream.close ( );
+ }
+
+ if ( out != null )
+ {
+ out.close ( );
+ }
+ }
+ }
+
+ /*********************************************************************
+ * Loads an Image as a class resource.
+ *
+ *
+ * Useful for when you need to load an image file from a JAR.
+ *
+ *
+ * @see
+ * "Zukowski,
+ *
+ * Definitive Guide to Swing for Java 2,
+ * Second Edition, 2000, p107."
+ *********************************************************************/
+ public static Image getResourceAsImage (
+ Class relativeClass,
+ String filename )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( relativeClass );
+
+ NullArgumentException.check ( filename );
+
+ BufferedInputStream bufferedInputStream = null;
+
+ ByteArrayOutputStream byteArrayOutputStream = null;
+
+ try
+ {
+ bufferedInputStream = new BufferedInputStream (
+ relativeClass.getResourceAsStream ( filename ) );
+
+ byteArrayOutputStream = new ByteArrayOutputStream ( );
+
+ int c;
+
+ while ( ( c = bufferedInputStream.read ( ) ) > -1 )
+ {
+ byteArrayOutputStream.write ( c );
+ }
+
+ byteArrayOutputStream.flush ( );
+
+ return Toolkit.getDefaultToolkit ( ).createImage (
+ byteArrayOutputStream.toByteArray ( ) );
+ }
+ finally
+ {
+ if ( bufferedInputStream != null )
+ {
+ bufferedInputStream.close ( );
+ }
+
+ if ( byteArrayOutputStream != null )
+ {
+ byteArrayOutputStream.close ( );
+ }
+ }
+ }
+
+ /*********************************************************************
+ * Returns the name of the Class without the package prefix.
+ *
+ *
+ * For example, this method would return "ClassLib" for
+ * class com.croftsoft.core.lang.ClassLib.
+ *
+ *
+ * @see
+ * java.lang.Class#getName(java.lang.String)
+ *********************************************************************/
+ public static String getShortName ( Class c )
+ //////////////////////////////////////////////////////////////////////
+ {
+ String longName = c.getName ( );
+
+ return longName.substring ( longName.lastIndexOf ( '.' ) + 1 );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ private ClassLib ( ) { }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/EnumUnknownException.java b/src/main/java/com/croftsfot/core/lang/EnumUnknownException.java
new file mode 100644
index 0000000..4157a03
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/EnumUnknownException.java
@@ -0,0 +1,41 @@
+ package com.croftsoft.core.lang;
+
+ /***********************************************************************
+ * An unknown Enum value was provided.
+ *
+ * Throw this RuntimeException in the default case of an enum switch.
+ *
+ * @version
+ * $Id: EnumUnknownException.java,v 1.1 2008/05/16 18:39:07 croft Exp $
+ * @since
+ * 2008-05-16
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public class EnumUnknownException
+ extends RuntimeException
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ private static final long serialVersionUID = 0L;
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+
+ public EnumUnknownException ( final Enum> enumValue )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ super ( enumValue.name ( ) );
+ }
+
+ public EnumUnknownException ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ // empty
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/lang/ExternalAccessException.java b/src/main/java/com/croftsfot/core/lang/ExternalAccessException.java
new file mode 100644
index 0000000..4b8c059
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/ExternalAccessException.java
@@ -0,0 +1,105 @@
+ package com.croftsoft.core.lang;
+
+ /*********************************************************************
+ * Indicates an Exception while accessing an external resource.
+ *
+ *
+ * Useful for propagating an SQLException or RemoteException through
+ * a Data Access Object (DAO) interface. Define the data accessor
+ * interface methods so that they throw ExternalAccessException instead
+ * of SQLException, RemoteException, IOException, or any other
+ * Exception indicating external access failure. Since the calling
+ * application no longer needs to be hard-coded to handle an Exception
+ * subclass specific to the data access mechanism, the mechanism can be
+ * easily replaced, at run-time if desired, simply by instantiating a
+ * different concrete implementation of the data accessor interface.
+ *
+ *
+ *
+ * The original Exception is passed into the ExternalAccessException as
+ * a constructor argument. The Exception stack trace is stored as a
+ * String within the ExternalAccessException in order to facilitate
+ * serialization and persistence without the need to transport class
+ * files.
+ *
+ *
+ * @see
+ *
+ * Sun Java Center J2EE Patterns: Data Access Object
+ *
+ * @see
+ *
+ * "A Note on Distributed Computing"
+ *
+ * @version
+ * 2001-06-21
+ * @since
+ * 2001-02-28
+ * @author
+ * David W. Croft
+ *********************************************************************/
+
+ public final class ExternalAccessException
+ extends Exception
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private static final long serialVersionUID = 1L;
+
+ private String rootExceptionStackTrace;
+
+ //////////////////////////////////////////////////////////////////////
+ // constructor methods
+ //////////////////////////////////////////////////////////////////////
+
+ public ExternalAccessException (
+ String message,
+ Exception rootException )
+ //////////////////////////////////////////////////////////////////////
+ {
+ super ( message );
+
+ if ( rootException != null )
+ {
+ this.rootExceptionStackTrace
+ = ThrowableLib.getStackTrace ( rootException );
+ }
+ else
+ {
+ this.rootExceptionStackTrace = null;
+ }
+ }
+
+ public ExternalAccessException ( Exception rootException )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this (
+ rootException != null ? rootException.getMessage ( ) : null,
+ rootException );
+ }
+
+ public ExternalAccessException ( String message )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this ( message, null );
+ }
+
+ public ExternalAccessException ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this ( null, null );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public String getRootExceptionStackTrace ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return rootExceptionStackTrace;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/lang/Listener.java b/src/main/java/com/croftsfot/core/lang/Listener.java
new file mode 100644
index 0000000..f066b3d
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/Listener.java
@@ -0,0 +1,23 @@
+ package com.croftsoft.core.lang;
+
+ /*********************************************************************
+ * Generic listener.
+ *
+ * @version
+ * $Id: Listener.java,v 1.1 2006/01/07 02:20:25 croft Exp $
+ * @since
+ * 2006-01-06
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface Listener
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public void listen ( T t );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/NullArgumentException.java b/src/main/java/com/croftsfot/core/lang/NullArgumentException.java
new file mode 100644
index 0000000..4ccd52c
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/NullArgumentException.java
@@ -0,0 +1,103 @@
+ package com.croftsoft.core.lang;
+
+ /*********************************************************************
+ * Thrown to indicate that a method has been passed a null argument.
+ *
+ *
+ * The static convenience method check() is a useful shorthand
+ * notation for checking whether object constructor method arguments
+ * are null:
+ *
+ * public Book ( String title )
+ * {
+ * NullArgumentException.check ( this.title = title, "null title" );
+ * }
+ *
+ *
+ *
+ * @version
+ * $Date: 2008/02/10 22:53:21 $
+ * @since
+ * 2001-02-16
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class NullArgumentException
+ extends IllegalArgumentException
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private static final long serialVersionUID = 0L;
+
+ //////////////////////////////////////////////////////////////////////
+ // public static methods
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * Checks whether the argument is null.
+ *
+ * @throws NullArgumentException
+ *
+ * If the argument is null.
+ *********************************************************************/
+ public static void check ( Object argument )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( argument == null )
+ {
+ throw new NullArgumentException ( );
+ }
+ }
+
+ /*********************************************************************
+ * Checks whether the argument is null.
+ *
+ * @param detailMessage
+ *
+ * The detail message provided if a NullArgumentExcepton is created.
+ *
+ * @throws NullArgumentException
+ *
+ * If the argument is null.
+ *********************************************************************/
+ public static void check (
+ Object argument,
+ String detailMessage )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( argument == null )
+ {
+ throw new NullArgumentException ( detailMessage );
+ }
+ }
+
+ public static void checkArgs ( Object... args )
+ //////////////////////////////////////////////////////////////////////
+ {
+ for ( Object argument : args )
+ {
+ check ( argument );
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // public constructor methods
+ //////////////////////////////////////////////////////////////////////
+
+ public NullArgumentException ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ // empty
+ }
+
+ public NullArgumentException ( String detailMessage )
+ //////////////////////////////////////////////////////////////////////
+ {
+ super ( detailMessage );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/NullException.java b/src/main/java/com/croftsfot/core/lang/NullException.java
new file mode 100644
index 0000000..dab4852
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/NullException.java
@@ -0,0 +1,72 @@
+ package com.croftsoft.core.lang;
+
+ /**********************************************************************
+ * A RuntimeException that is thrown when the arguments are null.
+ *
+ *
+ * The static convenience method check() is a useful shorthand
+ * notation for checking whether object constructor method arguments
+ * are null:
+ *
+ * public Book (
+ * final String title,
+ * final String author )
+ * {
+ * NullException.check (
+ * this.title = title,
+ * this.author = author );
+ * }
+ *
+ *
+ *
+ * @version
+ * $Id: NullException.java,v 1.1 2008/02/10 22:53:21 croft Exp $
+ * @since
+ * 2008-02-10
+ * @author
+ * David Wallace Croft
+ **********************************************************************/
+
+ public final class NullException
+ extends RuntimeException
+ ///////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////
+ {
+
+ private static final long serialVersionUID = 0L;
+
+ ///////////////////////////////////////////////////////////////////////
+ // public static methods
+ ///////////////////////////////////////////////////////////////////////
+
+ public static void check ( Object... args )
+ ///////////////////////////////////////////////////////////////////////
+ {
+ for ( final Object arg : args )
+ {
+ if ( arg == null )
+ {
+ throw new NullException ( );
+ }
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // public constructor methods
+ ///////////////////////////////////////////////////////////////////////
+
+ public NullException ( )
+ ///////////////////////////////////////////////////////////////////////
+ {
+ // empty
+ }
+
+ public NullException ( String detailMessage )
+ ///////////////////////////////////////////////////////////////////////
+ {
+ super ( detailMessage );
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/lang/ObjectLib.java b/src/main/java/com/croftsfot/core/lang/ObjectLib.java
new file mode 100644
index 0000000..549343a
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/ObjectLib.java
@@ -0,0 +1,44 @@
+ package com.croftsoft.core.lang;
+
+ /*********************************************************************
+ * A collection of static methods to manipulate java.lang.Object.
+ *
+ * @version
+ * 2002-02-06
+ * @since
+ * 2001-03-23
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class ObjectLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public static final Object [ ] EMPTY_OBJECT_ARRAY
+ = new Object [ ] { };
+
+ /*********************************************************************
+ * Determines if the objects are equal or are both null.
+ *
+ * @return
+ * object1 == null ? object2 == null : object1.equals ( object2 );
+ *********************************************************************/
+ public static boolean equivalent (
+ Object object1,
+ Object object2 )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return
+ object1 == null ? object2 == null : object1.equals ( object2 );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ private ObjectLib ( ) { }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/Pair.java b/src/main/java/com/croftsfot/core/lang/Pair.java
new file mode 100644
index 0000000..5834c8b
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/Pair.java
@@ -0,0 +1,90 @@
+ package com.croftsoft.core.lang;
+
+ import java.io.Serializable;
+
+ import com.croftsoft.core.lang.NullArgumentException;
+
+ /*********************************************************************
+ * An immutable name-value pair where name is never null.
+ *
+ *
+ * Java 1.1 compatible.
+ *
+ *
+ * @version
+ * 2001-09-13
+ * @since
+ * 2001-06-07
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class Pair
+ implements Serializable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private static final long serialVersionUID = 1L;
+
+ public final String name;
+
+ public final String value;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public String getName ( ) { return name; }
+
+ public String getValue ( ) { return value; }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * Converts an array of names to an array of Pairs with null values.
+ *********************************************************************/
+ public static Pair [ ] toPairs ( String [ ] names )
+ //////////////////////////////////////////////////////////////////////
+ {
+ Pair [ ] pairs = new Pair [ names.length ];
+
+ for ( int i = 0; i < names.length; i++ )
+ {
+ pairs [ i ] = new Pair ( names [ i ], null );
+ }
+
+ return pairs;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * Constructor method.
+ *
+ * @param name
+ *
+ * Must not be null.
+ *
+ * @param value
+ *
+ * May be null.
+ *
+ * @throws NullArgumentException
+ *
+ * If name is null.
+ *********************************************************************/
+ public Pair (
+ String name,
+ String value )
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( this.name = name );
+
+ this.value = value;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/StringLib.java b/src/main/java/com/croftsfot/core/lang/StringLib.java
new file mode 100644
index 0000000..becaf5e
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/StringLib.java
@@ -0,0 +1,167 @@
+ package com.croftsoft.core.lang;
+
+ import java.io.*;
+ import java.util.*;
+
+ /*********************************************************************
+ * A collection of static methods to manipulate java.lang.String.
+ *
+ * @version
+ * 2001-08-15
+ * @since
+ * 1998-10-04
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public class StringLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public static final String [ ] ZERO_LENGTH_STRING_ARRAY
+ = new String [ ] { };
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public static void main ( String [ ] args )
+ //////////////////////////////////////////////////////////////////////
+ {
+ System.out.println ( replace ( "0", "0", "12345" ) );
+ System.out.println ( replace ( "1abc5", "abc", "234" ) );
+ System.out.println ( replace ( "1a", "a", "2345" ) );
+ System.out.println ( replace ( "1235", "23", "234" ) );
+ }
+
+ /*********************************************************************
+ * @see #padRight
+ *********************************************************************/
+ public static String padLeft ( String s, char c, int length )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( s == null ) return null;
+ if ( s.length ( ) >= length ) return new String ( s );
+ while ( s.length ( ) < length ) s = c + s;
+ return s;
+ }
+
+ /*********************************************************************
+ * @see #padLeft
+ *********************************************************************/
+ public static String padRight ( String s, char c, int length )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( s == null ) return null;
+ if ( s.length ( ) >= length ) return new String ( s );
+ while ( s.length ( ) < length ) s = s + c;
+ return s;
+ }
+
+ /*********************************************************************
+ * Returns a String with the characters between
+ * fromIndex and toIndex removed, inclusive.
+ *********************************************************************/
+ public static String remove (
+ String s, int fromIndex, int toIndex )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return s.substring ( 0, fromIndex ) + s.substring ( toIndex + 1 );
+ }
+
+ /*********************************************************************
+ * Replaces substrings in a String.
+ * Replaces every instance of oldSub in s with
+ * newSub.
+ *********************************************************************/
+ public static String replace (
+ String s, String oldSub, String newSub )
+ //////////////////////////////////////////////////////////////////////
+ // When Java 1.2 comes out, use StringBuffer.replace().
+ //////////////////////////////////////////////////////////////////////
+ {
+ StringBuffer sb = new StringBuffer ( );
+ int index;
+ int remnantIndex = 0;
+ while ( ( index = s.indexOf ( oldSub, remnantIndex ) ) > -1 )
+ {
+ if ( index > remnantIndex )
+ {
+ sb.append ( s.substring ( remnantIndex, index ) );
+ }
+ sb.append ( newSub );
+ remnantIndex = index + oldSub.length ( );
+ }
+ sb.append ( s.substring ( remnantIndex ) );
+ return sb.toString ( );
+ }
+
+ /*********************************************************************
+ * Breaks a String at the ends of lines.
+ * The original text is broken into an array of String at the
+ * end-of-line delimiters such as carriage return, linefeed, or the
+ * carriage return/linefeed pair.
+ * This is returned as an array of String without the delimiters.
+ *********************************************************************/
+ public static String [ ] toStringArray ( String text )
+ //////////////////////////////////////////////////////////////////////
+ {
+ Vector stringVector = new Vector ( );
+
+ BufferedReader bufferedReader
+ = new BufferedReader ( new StringReader ( text ) );
+
+ String line;
+
+ try
+ {
+ while ( ( line = bufferedReader.readLine ( ) ) != null )
+ {
+ stringVector.addElement ( line );
+ }
+ }
+ catch ( IOException ex )
+ {
+ // this should never happen
+ }
+
+ String [ ] stringArray = new String [ stringVector.size ( ) ];
+
+ stringVector.copyInto ( stringArray );
+
+ return stringArray;
+ }
+
+ /*********************************************************************
+ * Returns null if the trimming operation results in the empty String.
+ *
+ * @param s
+ *
+ * May be null.
+ *
+ * @return
+ *
+ * Returns the argument trimmed or null if the argument is null
+ * or the argument trimmed is "".
+ *********************************************************************/
+ public static String trimToNull ( String s )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( s == null )
+ {
+ return null;
+ }
+
+ s = s.trim ( );
+
+ return "".equals ( s ) ? null : s;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ private StringLib ( ) { }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/Testable.java b/src/main/java/com/croftsfot/core/lang/Testable.java
new file mode 100644
index 0000000..f4d355b
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/Testable.java
@@ -0,0 +1,67 @@
+ package com.croftsoft.core.lang;
+
+ /*********************************************************************
+ * A semantic interface indicating the class has a static test method.
+ *
+ *
+ * When a class implements this semantic marker interface, it indicates
+ * that it defines a static test method with the following signature:
+ *
+ * public static boolean test ( String [ ] args )
+ *
+ *
+ *
+ *
+ * This method performs one or more unit self-tests for the class that
+ * it is defined in, returning true if the tests were successful and
+ * false if otherwise. It may perform white-box or black-box testing.
+ *
+ *
+ *
+ * When provided with a null or empty String array argument, it
+ * performs its default test.
+ * The default test must not have persistent side-effects such as
+ * creating files or modifying static variables nor attempt operations
+ * that have nuisance effects.
+ * The default test may write to the standard output and the standard
+ * error to facilitate debugging.
+ * If provided with a non-empty String array argument, it may run
+ * tests that have persistent side-effects.
+ *
+ *
+ *
+ * The test method can be called by the class main method, passing the
+ * command-line arguments as the test method arguments. This makes it
+ * easy to test the class from the command-line during development.
+ * Note that if no command-line arguments are specified, the argument
+ * is an empty String array and the default test will be run.
+ *
+ *
+ * public static void main ( String [ ] args )
+ * {
+ * System.out.println ( test ( args ) );
+ * }
+ *
+ *
+ *
+ *
+ *
+ * Automated testing of all the classes in a library can be performed
+ * using reflection to test if a class implements the interface
+ * Testable. If the class does, its test method can be called using
+ * reflection and the boolean result reported along with anything
+ * written to the standard output and standard error. If a class
+ * contains a test method that conforms to the required signature but
+ * it does not implement the semantic interface Testable, the test
+ * method should not be executed as the similarity may be coincidental.
+ *
+ *
+ * @version
+ * 2003-03-12
+ * @since
+ * 2003-03-12
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface Testable { }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/lang/ThreadLib.java b/src/main/java/com/croftsfot/core/lang/ThreadLib.java
new file mode 100644
index 0000000..0c9aa0e
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/ThreadLib.java
@@ -0,0 +1,40 @@
+ package com.croftsoft.core.lang;
+
+ /*********************************************************************
+ * A collection of static methods to manipulate Thread objects.
+ *
+ * @version
+ * 1999-10-02
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public class ThreadLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ /*********************************************************************
+ * Puts the current Thread to sleep for a number of milliseconds.
+ *
+ * @return
+ * Returns false if InterruptedException was thrown.
+ *********************************************************************/
+ public static boolean sleep ( long millis )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ Thread.currentThread ( ).sleep ( millis );
+ }
+ catch ( InterruptedException ex )
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/ThrowableLib.java b/src/main/java/com/croftsfot/core/lang/ThrowableLib.java
new file mode 100644
index 0000000..5406b7c
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/ThrowableLib.java
@@ -0,0 +1,52 @@
+ package com.croftsoft.core.lang;
+
+ import java.io.*;
+
+ /*********************************************************************
+ * A collection of static methods to manipulate java.lang.Throwable.
+ *
+ * @version
+ * 2001-05-18
+ * @since
+ * 2001-05-18
+ * @author
+ * David W. Croft
+ *********************************************************************/
+
+ public final class ThrowableLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public static void main ( String [ ] args )
+ //////////////////////////////////////////////////////////////////////
+ {
+ System.out.println ( getStackTrace ( new RuntimeException ( ) ) );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * Returns the stack trace as a String.
+ *********************************************************************/
+ public static String getStackTrace ( Throwable throwable )
+ //////////////////////////////////////////////////////////////////////
+ {
+ StringWriter stringWriter = new StringWriter ( );
+
+ PrintWriter printWriter = new PrintWriter ( stringWriter );
+
+ throwable.printStackTrace ( printWriter );
+
+ return stringWriter.toString ( );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ private ThrowableLib ( ) { }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/classloader/Boot.java b/src/main/java/com/croftsfot/core/lang/classloader/Boot.java
new file mode 100644
index 0000000..a5d2ef6
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/classloader/Boot.java
@@ -0,0 +1,199 @@
+ package com.croftsoft.core.lang.classloader;
+
+ import java.io.*;
+ import java.lang.reflect.*;
+ import java.net.*;
+
+ /*********************************************************************
+ * The Boot ClassLoader bootstraps a main class downloaded directly off
+ * of a web site. The argument to this program is the URL of the
+ * main class bytecode file. Any additional arguments are passed to
+ * the downloaded class.
+ *
+ *
+ *
+ * The Boot class can be readily distributed to a wide audience since
+ * it is small and simple. With a little customization, it can be
+ * hard-coded to download from a particular URL. It can also be used
+ * as a "seed" class by having it invoke a persistent resource loader.
+ *
+ *
+ *
+ * @version
+ * 1999-11-27
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public class Boot extends ClassLoader
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public static void main ( String [ ] args )
+ throws Exception
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( args.length < 1 )
+ {
+ System.out.println (
+ "\nBoot (1999-11-27) David Wallace Croft (croft@orbs.com)" );
+ System.out.println (
+ "Updates available from \"http://www.orbs.com/\".\n" );
+ System.out.println (
+ "Bootstraps the main(args) method of a class available "
+ + "from a web site." );
+ System.out.println (
+ "Arguments: URL [other...]" );
+ System.out.println ( "Example: java -jar boot.jar "
+ + "http://www.orbs.com/lib/Main.class username password" );
+ return;
+ }
+
+ byte [ ] data = downloadBytes ( new URL ( args [ 0 ] ) );
+ if ( data == null )
+ {
+ System.out.println (
+ "Unable to download \"" + args [ 0 ] + "\"." );
+ return;
+ }
+
+ String [ ] shiftedArgs = new String [ args.length - 1 ];
+ for ( int i = 0; i < shiftedArgs.length; i++ )
+ {
+ shiftedArgs [ i ] = args [ i + 1 ];
+ }
+
+ new Boot ( ).bootstrap ( data, shiftedArgs );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * Returns null upon failure.
+ *********************************************************************/
+ public static byte [ ] downloadBytes ( URL url )
+ //////////////////////////////////////////////////////////////////////
+ {
+ InputStream inputStream = null;
+ BufferedInputStream in = null;
+ ByteArrayOutputStream out = null;
+
+ try
+ {
+ inputStream = downloadStream ( url );
+ if ( inputStream == null ) return null;
+ in = new BufferedInputStream ( inputStream );
+ out = new ByteArrayOutputStream ( );
+ int i;
+ while ( ( i = in.read ( ) ) > -1 ) out.write ( i );
+ out.close ( );
+ in.close ( );
+ return out.toByteArray ( );
+ }
+ catch ( Exception ex )
+ {
+ try { in.close ( ); } catch ( Exception ex1 ) { }
+ try { inputStream.close ( ); } catch ( Exception ex1 ) { }
+ try { out.close ( ); } catch ( Exception ex1 ) { }
+ return null;
+ }
+ }
+
+ /*********************************************************************
+ * Returns null upon failure.
+ *********************************************************************/
+ public static InputStream downloadStream ( URL url )
+ //////////////////////////////////////////////////////////////////////
+ {
+ InputStream inputStream = null;
+ try
+ {
+ URLConnection urlConnection = url.openConnection ( );
+ if ( urlConnection instanceof HttpURLConnection )
+ {
+ HttpURLConnection httpURLConnection
+ = ( HttpURLConnection ) urlConnection;
+ httpURLConnection.setFollowRedirects ( true );
+ httpURLConnection.setRequestMethod ( "GET" );
+ int responseCode = httpURLConnection.getResponseCode ( );
+ if ( responseCode != HttpURLConnection.HTTP_OK ) return null;
+ }
+ return urlConnection.getInputStream ( );
+ }
+ catch ( Exception ex )
+ {
+ try { inputStream.close ( ); } catch ( Exception ex1 ) { }
+ return null;
+ }
+ }
+
+ /*********************************************************************
+ * Uses reflection to invoke the main(args) method of a class.
+ *********************************************************************/
+ public static void invokeMain ( Class c, String [ ] args )
+ throws IllegalAccessException
+ //////////////////////////////////////////////////////////////////////
+ {
+ Method method;
+ try
+ {
+ method = c.getMethod (
+ "main", new Class [ ] { String [ ].class } );
+ }
+ catch ( NoSuchMethodException ex )
+ {
+ System.out.println ( "No \"main(args)\" method in class \""
+ + c.getName ( ) + "\"." );
+ return;
+ }
+ try
+ {
+ method.invoke ( null, new Object [ ] { args } );
+ }
+ catch ( InvocationTargetException ex )
+ {
+ Throwable t = ex.getTargetException ( );
+ System.err.println (
+ "\"main()\" method exited with exception \"" + t + "\"." );
+ t.printStackTrace ( );
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * Converts the data to a Class and then invokes its main(args) method.
+ *********************************************************************/
+ public void bootstrap ( byte [ ] data, String [ ] args )
+ throws IllegalAccessException
+ //////////////////////////////////////////////////////////////////////
+ {
+ Class c = defineClass ( data, 0, data.length );
+ invokeMain ( c, args );
+ }
+
+ /*********************************************************************
+ * Returns the Class of the given name.
+ *********************************************************************/
+ public Class loadClass ( String name, boolean resolve )
+ //////////////////////////////////////////////////////////////////////
+ {
+ Class c = findLoadedClass ( name );
+ if ( c != null ) return c;
+
+ try
+ {
+ return findSystemClass ( name );
+ }
+ catch ( ClassNotFoundException ex )
+ {
+ return null;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/classloader/CacheClassLoader.java b/src/main/java/com/croftsfot/core/lang/classloader/CacheClassLoader.java
new file mode 100644
index 0000000..6fd5d2b
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/classloader/CacheClassLoader.java
@@ -0,0 +1,218 @@
+ package com.croftsoft.core.lang.classloader;
+
+ import java.io.*;
+ import java.lang.reflect.*;
+ import java.net.*;
+ import java.util.*;
+
+ /*********************************************************************
+ *
+ * @version
+ * 1998-05-30
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public class CacheClassLoader extends NetClassLoader
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ /** A list of pathnames of cached files keyed by remote URL name. */
+ protected Hashtable cacheHashtable = new Hashtable ( );
+
+ protected File cacheDir;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * Loads a remote class and launches its main() method.
+ *
+ * @param
+ * Command-line arguments:
+ *
+ * - The URL name for the codebase.
+ *
- The name of the class with the "main(args)" method.
+ *
- The name of the local persistent resource cache directory.
+ *
- Subsequent arguments to be passed to the invoked main method.
+ *
+ * Example
+ *********************************************************************/
+ public static void main ( String [ ] args )
+ throws Exception
+ //////////////////////////////////////////////////////////////////////
+ {
+ String [ ] shiftedArgs = new String [ args.length - 3 ];
+ for ( int i = 3; i < args.length; i++ )
+ {
+ shiftedArgs [ i - 3 ] = args [ i ];
+ }
+
+ launchMain ( args [ 0 ], args [ 1 ], args [ 2 ], shiftedArgs );
+ }
+
+ /*********************************************************************
+ * Loads a remote class and launches its main() method.
+ *********************************************************************/
+ public static void launchMain (
+ String codebaseURLName,
+ String mainClassName,
+ String cacheDirName,
+ String [ ] args )
+ throws ClassNotFoundException,
+ IllegalAccessException,
+ MalformedURLException
+ //////////////////////////////////////////////////////////////////////
+ {
+ URL codebaseURL = new URL ( codebaseURLName );
+ File cacheDir = new File ( cacheDirName );
+ CacheClassLoader cacheClassLoader
+ = new CacheClassLoader ( codebaseURL, cacheDir );
+ Class c = cacheClassLoader.loadClass ( mainClassName );
+ cacheClassLoader.invokeMain ( c, args );
+ }
+
+ /*********************************************************************
+ * Ex: "http://www.mysticmayhem.com/lib/",
+ * "C:\jcache\www.mysticmayhem.com\"
+ *********************************************************************/
+ public CacheClassLoader ( URL codebaseURL, File cacheDir )
+ //////////////////////////////////////////////////////////////////////
+ {
+ super ( codebaseURL );
+
+ if ( !cacheDir.exists ( ) )
+ {
+ throw new IllegalArgumentException ( "directory \"" + cacheDir
+ + "\" does not exist" );
+ }
+ if ( !cacheDir.isDirectory ( ) )
+ {
+ throw new IllegalArgumentException ( "cacheDir \"" + cacheDir
+ + "\" must be a directory" );
+ }
+ this.cacheDir = cacheDir;
+ }
+
+ /*********************************************************************
+ *********************************************************************/
+ public synchronized InputStream getResourceAsStream ( String name )
+ //////////////////////////////////////////////////////////////////////
+ {
+ InputStream inputStream = null;
+ BufferedInputStream in = null;
+ BufferedOutputStream out = null;
+
+ try
+ {
+ URL url = getResource ( name );
+ String remoteName = url.toExternalForm ( );
+ String localName = ( String ) cacheHashtable.get ( remoteName );
+ if ( localName != null )
+ {
+System.out.println ( "Retrieving \"" + localName + "\"..." );
+ return new FileInputStream ( localName );
+ }
+
+ String host = url.getHost ( );
+ String prot = url.getProtocol ( );
+ int port = url.getPort ( );
+
+ File cacheFile = new File ( cacheDir, prot + File.separator
+ + host + File.separator + "port"
+ + ( port == -1 ? "" : Integer.toString ( port ) )
+ + File.separator + name );
+ cacheFile = new File ( cacheFile.getCanonicalPath ( ) );
+ localName = cacheFile.getCanonicalPath ( );
+
+System.out.println ( "Comparing \"" + localName + "\"..." );
+ URLConnection urlConnection = url.openConnection ( );
+ if ( cacheFile.exists ( ) )
+ {
+ urlConnection.setIfModifiedSince (
+ cacheFile.lastModified ( ) );
+ }
+
+ if ( urlConnection instanceof HttpURLConnection )
+ {
+ HttpURLConnection httpURLConnection
+ = ( HttpURLConnection ) urlConnection;
+
+ httpURLConnection.setFollowRedirects ( true );
+ httpURLConnection.setRequestMethod ( "GET" );
+
+ int responseCode = httpURLConnection.getResponseCode ( );
+System.out.println (
+ httpURLConnection.getResponseMessage ( )
+ + ", " + httpURLConnection.getContentLength ( ) + " bytes"
+ + ", " + new Date ( httpURLConnection.getDate ( ) )
+ + ", " + new Date ( httpURLConnection.getLastModified ( ) ) );
+ if ( responseCode != HttpURLConnection.HTTP_OK )
+ {
+ return null;
+ }
+ }
+
+ inputStream = urlConnection.getInputStream ( );
+ if ( inputStream == null ) return null;
+
+ if ( cacheFile.exists ( ) )
+ {
+ long lastModified = urlConnection.getLastModified ( );
+// long date = urlConnection.getDate ( );
+// long remoteDelta = date - lastModified;
+// long cacheDelta
+// = new Date ( ).getTime ( ) - cacheFile.lastModified ( );
+// long length = urlConnection.getContentLength ( );
+
+// if ( ( date > 0 )
+// && ( lastModified > 0 )
+// && ( length > -1 )
+// && ( length == cacheFile.length ( ) )
+// && ( remoteDelta >= cacheDelta ) )
+
+ if ( ( lastModified > 0 )
+ && ( lastModified < cacheFile.lastModified ( ) ) )
+ {
+ inputStream.close ( );
+ cacheHashtable.put ( remoteName, localName );
+System.out.println ( "Retrieving \"" + localName + "\"..." );
+ return new FileInputStream ( cacheFile );
+ }
+ }
+
+ File parentFile = new File ( cacheFile.getParent ( ) );
+ parentFile.mkdirs ( );
+
+ localName = cacheFile.getCanonicalPath ( );
+System.out.println ( "CACHING \"" + localName + "\"..." );
+
+ in = new BufferedInputStream ( inputStream );
+ out = new BufferedOutputStream ( new FileOutputStream (
+ cacheFile ) );
+
+ int i;
+ while ( ( i = in.read ( ) ) > -1 ) out.write ( i );
+
+ out.close ( );
+ in.close ( );
+
+ cacheHashtable.put ( remoteName, localName );
+
+System.out.println ( "Retrieving \"" + localName + "\"..." );
+ return new FileInputStream ( localName );
+ }
+ catch ( Exception ex )
+ {
+ try { inputStream.close ( ); } catch ( Exception ex1 ) { }
+ try { in.close ( ); } catch ( Exception ex1 ) { }
+ try { out.close ( ); } catch ( Exception ex1 ) { }
+ ex.printStackTrace ( );
+ return null;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/classloader/ClassLoaderLib.java b/src/main/java/com/croftsfot/core/lang/classloader/ClassLoaderLib.java
new file mode 100644
index 0000000..34a450f
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/classloader/ClassLoaderLib.java
@@ -0,0 +1,35 @@
+ package com.croftsoft.core.lang.classloader;
+
+ /*********************************************************************
+ *
+ * Static library for use with custom ClassLoaders.
+ *
+ * @version
+ * 1998-10-04
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public class ClassLoaderLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private ClassLoaderLib ( ) { }
+
+ /*********************************************************************
+ * Parses the package name out of a full class name.
+ * Returns the empty string ("") if the class is not in a package.
+ *********************************************************************/
+ public static String parsePackageName ( String className )
+ //////////////////////////////////////////////////////////////////////
+ {
+ String packageName = "";
+ int i = className.lastIndexOf ( '.' );
+ if ( i > -1 ) packageName = className.substring ( 0, i );
+ return packageName;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/classloader/CustomClassLoader.java b/src/main/java/com/croftsfot/core/lang/classloader/CustomClassLoader.java
new file mode 100644
index 0000000..d23f40d
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/classloader/CustomClassLoader.java
@@ -0,0 +1,126 @@
+ package com.croftsoft.core.lang.classloader;
+
+ /*********************************************************************
+ *
+ * Assumes that Java 1.1 is being used and classes are cached as the
+ * default behavior as part of the defineClass() method.
+ *
+ * This should be upgraded when the switch is made from Java 1.1 to
+ * Java 1.2.
+ *
+ *
+ * References
+ *
+ * Scott Oaks, Java Security, O'Reilly, 1998.
+ *
+ * @version
+ * 1998-05-25
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public abstract class CustomClassLoader extends ClassLoader
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ /*********************************************************************
+ * Parses the package name out of a full class name.
+ * Returns the empty string ("") if the class is not in a package.
+ *********************************************************************/
+ public static String parsePackageName ( String className )
+ //////////////////////////////////////////////////////////////////////
+ {
+ String packageName = "";
+ int i = className.lastIndexOf ( '.' );
+ if ( i > -1 ) packageName = className.substring ( 0, i );
+ return packageName;
+ }
+
+ /*********************************************************************
+ * Returns the Class of the given name.
+ *
+ * Calls loadClassData() if the class was not previously loaded and
+ * is not a system class.
+ *********************************************************************/
+ public Class loadClass ( String name, boolean resolve )
+ //////////////////////////////////////////////////////////////////////
+ // See Ch. 3, "Java Class Loaders", "Implementing a Class Loader",
+ // pp44-45.
+ //////////////////////////////////////////////////////////////////////
+ {
+ // Step 1 -- Check for a previously loaded class
+ Class c = findLoadedClass ( name );
+ if ( c != null ) return c;
+
+ // Step 2 -- Check to make sure that we can access this class
+ String packageName = null;
+ SecurityManager securityManager = System.getSecurityManager ( );
+ if ( securityManager != null )
+ {
+ packageName = parsePackageName ( name );
+// What if in "default" package?
+ securityManager.checkPackageAccess ( packageName );
+ }
+
+ // Step 3 -- Check for system class first
+ try
+ {
+ c = findSystemClass ( name );
+ if ( c != null ) return c;
+ }
+ catch ( ClassNotFoundException ex ) { }
+
+ // Step 4 -- Check to make sure that we can define this class
+ if ( securityManager != null )
+ {
+ securityManager.checkPackageDefinition ( packageName );
+ }
+
+ // Step 5 -- Read in the class file
+ byte [ ] data = loadClassData ( name );
+ if ( data == null ) return null;
+
+ // Step 6 and 7 -- Define the class from the data;
+ // this also passes the data through the bytecode verifier
+ c = defineClass ( name, data, 0, data.length );
+
+ // Step 8 -- Resolve the internal references of the class
+ if ( resolve ) resolveClass ( c );
+
+ return c;
+ }
+
+ /*********************************************************************
+ * Implement to load the raw bytecode from an external source.
+ * @return
+ * May return null on failure.
+ *********************************************************************/
+// Better to thrown an exception than to return null.
+ protected abstract byte [ ] loadClassData ( String name );
+
+ /*********************************************************************
+ * Calls getSystemResource(name).
+ *********************************************************************/
+/*
+ public URL getResource ( String name )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return getSystemResource ( name );
+ }
+*/
+
+ /*********************************************************************
+ * Calls getSystemResourceAsStream(name).
+ *********************************************************************/
+/*
+ public InputStream getResourceAsStream ( String name )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return getSystemResourceAsStream ( name );
+ }
+*/
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/classloader/DialogClassLoader.java b/src/main/java/com/croftsfot/core/lang/classloader/DialogClassLoader.java
new file mode 100644
index 0000000..58661cb
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/classloader/DialogClassLoader.java
@@ -0,0 +1,96 @@
+ package com.croftsoft.core.lang.classloader;
+
+ import java.awt.*;
+ import java.io.*;
+
+ /*********************************************************************
+ *
+ * @version
+ * 1998-06-03
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public class DialogClassLoader
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * Loads a remote class and launches its main() method.
+ *
+ * @param
+ * Command-line arguments:
+ *
+ * - The URL name for the codebase.
+ *
- The name of the class with the "main(args)" method.
+ *
- The name of the local persistent resource cache directory.
+ *
- Subsequent arguments to be passed to the invoked main method.
+ *
+ * Example
+ *********************************************************************/
+ public static void main ( String [ ] args )
+ throws Exception
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( args.length >= 3 )
+ {
+ CacheClassLoader.main ( args );
+ return;
+ }
+
+ ( new DialogClassLoader ( ) ).start ( );
+ }
+
+ public DialogClassLoader ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ }
+
+ public void start ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ System.out.println ( System.getProperty ( "java.class.path" ) );
+
+// Run the user's classpath searching for "mayhem.class".
+// When you find it, assume that that is the cache path.
+// Look for a settings file in that directory.
+// If there is no settings file in that directory, assume defaults and prompt.
+
+// System.out.println ( System.getProperty ( "user.home" ) );
+
+ File file0 = new File ( "." );
+ try
+ {
+ System.out.println ( file0.getCanonicalPath ( ) );
+ }
+ catch ( Exception ex ) { }
+
+ Frame frame = new Frame ( "Mystic Mayhem Installation" );
+ FileDialog fileDialog = new FileDialog (
+ frame, "Mystic Mayhem - please choose the installation directory",
+ FileDialog.SAVE );
+ fileDialog.setFile ( "mayhem" );
+ frame.setBounds ( 0, 0, 300, 300 );
+ fileDialog.show ( );
+ frame.show ( );
+ // don't forget to dispose of both
+ File file = new File ( fileDialog.getDirectory ( )
+ + File.separator + fileDialog.getFile ( ) );
+
+ try
+ {
+ System.out.println ( file.getCanonicalPath ( ) );
+ }
+ catch ( Exception ex ) { }
+
+ fileDialog.dispose ( );
+ frame.dispose ( );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/classloader/NetClassLoader.java b/src/main/java/com/croftsfot/core/lang/classloader/NetClassLoader.java
new file mode 100644
index 0000000..806a397
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/classloader/NetClassLoader.java
@@ -0,0 +1,202 @@
+ package com.croftsoft.core.lang.classloader;
+
+ import java.awt.*;
+ import java.io.*;
+ import java.lang.reflect.*;
+ import java.net.*;
+ import java.util.*;
+
+ /*********************************************************************
+ *
+ * Upgrade this source code when the switch is made from Java 1.1 to
+ * Java 1.2.
+ *
+ *
+ * References
+ *
+ * Scott Oaks, Java Security, O'Reilly, 1998.
+ *
+ * @version
+ * 1998-09-06
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public class NetClassLoader extends CustomClassLoader
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ protected URL codebaseURL;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * Loads a remote class and launches its main() method.
+ *
+ * @param
+ * Command-line arguments:
+ *
+ * - The URL for the codebase.
+ *
- The name of the class with the "main(args)" method.
+ *
- Subsequent arguments to be passed to the invoked main method.
+ *
+ * Example
+ *********************************************************************/
+ public static void main ( String [ ] args )
+ throws Exception
+ //////////////////////////////////////////////////////////////////////
+ {
+ String [ ] shiftedArgs = new String [ args.length - 2 ];
+ for ( int i = 2; i < args.length; i++ )
+ {
+ shiftedArgs [ i - 2 ] = args [ i ];
+ }
+
+ launchMain ( args [ 0 ], args [ 1 ], shiftedArgs );
+ }
+
+ /*********************************************************************
+ * Loads a remote class and launches its main() method.
+ *********************************************************************/
+ public static void launchMain (
+ String codebaseURLName,
+ String mainClassName,
+ String [ ] args )
+ throws ClassNotFoundException,
+ IllegalAccessException,
+ MalformedURLException
+ //////////////////////////////////////////////////////////////////////
+ {
+ URL codebaseURL = new URL ( codebaseURLName );
+ ClassLoader classLoader = new NetClassLoader ( codebaseURL );
+ Class c = classLoader.loadClass ( mainClassName );
+ invokeMain ( c, args );
+ }
+
+ public static void invokeMain ( Class c, String [ ] args )
+ throws IllegalAccessException
+ //////////////////////////////////////////////////////////////////////
+ {
+ Method method;
+
+ try
+ {
+ method = c.getMethod ( "main",
+ new Class [ ] { String [ ].class } );
+ }
+ catch ( NoSuchMethodException ex )
+ {
+ System.err.println ( "No main() method in class \""
+ + c.getName ( ) + "\"." );
+ return;
+ }
+
+ try
+ {
+ method.invoke ( null, new Object [ ] { args } );
+ }
+ catch ( InvocationTargetException ex )
+ {
+ Throwable t = ex.getTargetException ( );
+ System.err.println (
+ "\"main()\" method exited with exception \"" + t + "\"." );
+ t.printStackTrace ( );
+ }
+ }
+
+ /*********************************************************************
+ * Ex: "http://www.mysticmayhem.com/lib/"
+ *********************************************************************/
+ public NetClassLoader ( URL codebaseURL )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this.codebaseURL = codebaseURL;
+ }
+
+ protected byte [ ] loadClassData ( String name )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ String pathName = name.replace ( '.', '/' ) + ".class";
+ BufferedInputStream in = new BufferedInputStream (
+ getResourceAsStream ( pathName ) );
+ if ( in == null ) return null;
+ ByteArrayOutputStream out = new ByteArrayOutputStream ( );
+ int i;
+ while ( ( i = in.read ( ) ) > -1 ) out.write ( i );
+ in.close ( );
+ return out.toByteArray ( );
+ }
+ catch ( Exception ex ) { ex.printStackTrace ( ); return null; }
+ }
+
+ /*********************************************************************
+ *********************************************************************/
+ public URL getResource ( String name )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ return new URL ( codebaseURL, name );
+ }
+ catch ( Exception ex ) { ex.printStackTrace ( ); return null; }
+ }
+
+ /*********************************************************************
+ * Loads a stream from the URL given by getResource(name).
+ * Does not use a cache.
+ *********************************************************************/
+ public InputStream getResourceAsStream ( String name )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ URL url = getResource ( name );
+System.out.println ( "Loading \"" + url + "\"..." );
+ URLConnection urlConnection = url.openConnection ( );
+ if ( urlConnection instanceof HttpURLConnection )
+ {
+ HttpURLConnection httpURLConnection
+ = ( HttpURLConnection ) urlConnection;
+ httpURLConnection.setFollowRedirects ( true );
+ httpURLConnection.setRequestMethod ( "GET" );
+ int responseCode = httpURLConnection.getResponseCode ( );
+System.out.println (
+ httpURLConnection.getResponseMessage ( )
+ + ", " + httpURLConnection.getContentLength ( ) + " bytes"
+ + ", " + new Date ( httpURLConnection.getDate ( ) )
+ + ", " + new Date ( httpURLConnection.getLastModified ( ) ) );
+ if ( responseCode != HttpURLConnection.HTTP_OK )
+ {
+ return null;
+ }
+ }
+ return urlConnection.getInputStream ( );
+ }
+ catch ( Exception ex ) { ex.printStackTrace ( ); return null; }
+ }
+
+ /*********************************************************************
+ * Creates the image by calling getResourceAsStream(imageName).
+ *********************************************************************/
+ public Image createImage ( String imageName )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ InputStream inputStream = getResourceAsStream ( imageName );
+ BufferedInputStream in = new BufferedInputStream ( inputStream );
+ ByteArrayOutputStream out = new ByteArrayOutputStream ( );
+ int i;
+ while ( ( i = in.read ( ) ) > -1 ) out.write ( i );
+ byte [ ] imageData = out.toByteArray ( );
+ out.close ( );
+ in.close ( );
+ return Toolkit.getDefaultToolkit ( ).createImage ( imageData );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/classloader/package.html b/src/main/java/com/croftsfot/core/lang/classloader/package.html
new file mode 100644
index 0000000..88663b2
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/classloader/package.html
@@ -0,0 +1,5 @@
+
+
+Custom ClassLoader implementations.
+
+
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/lang/ex/ExceptionHandler.java b/src/main/java/com/croftsfot/core/lang/ex/ExceptionHandler.java
new file mode 100644
index 0000000..f275bc1
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/ex/ExceptionHandler.java
@@ -0,0 +1,28 @@
+ package com.croftsoft.core.lang.ex;
+
+ /*********************************************************************
+ * Handles Exception events.
+ *
+ *
+ *
+ * @author
+ * David Wallace Croft
+ * @version
+ * 1999-12-23
+ *********************************************************************/
+
+ public interface ExceptionHandler
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ /*********************************************************************
+ * @return
+ *
+ * Returns false if the Exception was not handled.
+ *********************************************************************/
+ public boolean handleException ( Exception ex, Object o );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/ex/ExceptionListener.java b/src/main/java/com/croftsfot/core/lang/ex/ExceptionListener.java
new file mode 100644
index 0000000..ca9dc4f
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/ex/ExceptionListener.java
@@ -0,0 +1,22 @@
+ package com.croftsoft.core.lang.ex;
+
+ /*********************************************************************
+ *
+ * A listener of Exception events.
+ *
+ * @author
+ * David Wallace Croft
+ * @version
+ * 1998-12-05
+ *********************************************************************/
+
+ public interface ExceptionListener
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public void threwException ( Object o, Exception ex );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/ex/PrintExceptionListener.java b/src/main/java/com/croftsfot/core/lang/ex/PrintExceptionListener.java
new file mode 100644
index 0000000..f26ec26
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/ex/PrintExceptionListener.java
@@ -0,0 +1,26 @@
+ package com.croftsoft.core.lang.ex;
+
+ /*********************************************************************
+ *
+ * A concrete ExceptionListener that simply calls printStackTrace().
+ *
+ * @author
+ * David Wallace Croft
+ * @version
+ * 1998-12-05
+ *********************************************************************/
+
+ public class PrintExceptionListener implements ExceptionListener
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public void threwException ( Object o, Exception ex )
+ //////////////////////////////////////////////////////////////////////
+ {
+ ex.printStackTrace ( );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/ex/package.html b/src/main/java/com/croftsfot/core/lang/ex/package.html
new file mode 100644
index 0000000..3401b15
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/ex/package.html
@@ -0,0 +1,5 @@
+
+
+Exception handling.
+
+
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/lang/lifecycle/AppletLifecycle.java b/src/main/java/com/croftsfot/core/lang/lifecycle/AppletLifecycle.java
new file mode 100644
index 0000000..3583478
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/lifecycle/AppletLifecycle.java
@@ -0,0 +1,48 @@
+ package com.croftsoft.core.lang.lifecycle;
+
+ import java.applet.Applet;
+
+ import com.croftsoft.core.lang.NullArgumentException;
+
+ /*********************************************************************
+ * Wraps the Lifecycle interface around an Applet.
+ *
+ * @version
+ * 2003-06-04
+ * @since
+ * 2003-06-04
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class AppletLifecycle
+ implements Lifecycle
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private final Applet applet;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public AppletLifecycle ( Applet applet )
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( this.applet = applet );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public void init ( ) { applet.init ( ); }
+
+ public void start ( ) { applet.start ( ); }
+
+ public void stop ( ) { applet.stop ( ); }
+
+ public void destroy ( ) { applet.destroy ( ); }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/lang/lifecycle/Commissionable.java b/src/main/java/com/croftsfot/core/lang/lifecycle/Commissionable.java
new file mode 100644
index 0000000..adc9c54
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/lifecycle/Commissionable.java
@@ -0,0 +1,22 @@
+ package com.croftsoft.core.lang.lifecycle;
+
+ /*********************************************************************
+ * Extends Initializable and Destroyable.
+ *
+ * @version
+ * 2003-09-10
+ * @since
+ * 2001-03-06
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface Commissionable
+ extends Initializable, Destroyable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/lifecycle/CompositeLifecycle.java b/src/main/java/com/croftsfot/core/lang/lifecycle/CompositeLifecycle.java
new file mode 100644
index 0000000..7ffc716
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/lifecycle/CompositeLifecycle.java
@@ -0,0 +1,63 @@
+ package com.croftsoft.core.lang.lifecycle;
+
+ import com.croftsoft.core.lang.NullArgumentException;
+
+ /*********************************************************************
+ * A Lifecycle using interface composition.
+ *
+ * @version
+ * $Id: CompositeLifecycle.java,v 1.1 2006/01/03 19:40:08 croft Exp $
+ * @since
+ * 2006-01-03
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class CompositeLifecycle
+ implements Lifecycle
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private final Initializable [ ] initializables;
+
+ private final Startable [ ] startables;
+
+ private final Stoppable [ ] stoppables;
+
+ private final Destroyable [ ] destroyables;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public CompositeLifecycle (
+ final Initializable [ ] initializables,
+ final Startable [ ] startables,
+ final Stoppable [ ] stoppables,
+ final Destroyable [ ] destroyables )
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check (
+ this.initializables = initializables );
+
+ NullArgumentException.check ( this.startables = startables );
+
+ NullArgumentException.check ( this.stoppables = stoppables );
+
+ NullArgumentException.check ( this.destroyables = destroyables );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public void init ( ) { LifecycleLib.init ( initializables ); }
+
+ public void start ( ) { LifecycleLib.start ( startables ); }
+
+ public void stop ( ) { LifecycleLib.stop ( stoppables ); }
+
+ public void destroy ( ) { LifecycleLib.destroy ( destroyables ); }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/lang/lifecycle/Destroyable.java b/src/main/java/com/croftsfot/core/lang/lifecycle/Destroyable.java
new file mode 100644
index 0000000..e9202a0
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/lifecycle/Destroyable.java
@@ -0,0 +1,23 @@
+ package com.croftsoft.core.lang.lifecycle;
+
+ /*********************************************************************
+ * Defines the destroy() method.
+ *
+ * @version
+ * 2003-09-10
+ * @since
+ * 2001-03-06
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface Destroyable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public void destroy ( );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/lifecycle/Initializable.java b/src/main/java/com/croftsfot/core/lang/lifecycle/Initializable.java
new file mode 100644
index 0000000..f7b4cec
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/lifecycle/Initializable.java
@@ -0,0 +1,23 @@
+ package com.croftsoft.core.lang.lifecycle;
+
+ /*********************************************************************
+ * Defines the init() method.
+ *
+ * @version
+ * 2003-09-10
+ * @since
+ * 2001-03-06
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface Initializable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public void init ( );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/lifecycle/InitializationException.java b/src/main/java/com/croftsfot/core/lang/lifecycle/InitializationException.java
new file mode 100644
index 0000000..704b8f9
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/lifecycle/InitializationException.java
@@ -0,0 +1,81 @@
+ package com.croftsoft.core.lang.lifecycle;
+
+ /*********************************************************************
+ * Indicates lifecycle object initialization failure.
+ *
+ *
+ * After this RuntimeException subclass is thrown by the init() method,
+ * the lifecycle object should be discarded. No methods, including the
+ * destroy() method, should be called as initialization was
+ * unsuccessful.
+ *
+ *
+ * @version
+ * 2001-03-22
+ * @version
+ * 2001-02-28
+ * @author
+ * David W. Croft
+ *********************************************************************/
+
+ public final class InitializationException extends RuntimeException
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private static final long serialVersionUID = 1L;
+
+ private String rootExceptionString;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public InitializationException (
+ String message,
+ Exception rootException )
+ //////////////////////////////////////////////////////////////////////
+ {
+ super ( message );
+
+ if ( rootException != null )
+ {
+ this.rootExceptionString = rootException.toString ( );
+ }
+ else
+ {
+ this.rootExceptionString = null;
+ }
+ }
+
+ public InitializationException ( Exception rootException )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this (
+ rootException != null ? rootException.getMessage ( ) : null,
+ rootException );
+ }
+
+ public InitializationException ( String message )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this ( message, null );
+ }
+
+ public InitializationException ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this ( null, null );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public String getRootExceptionString ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return rootExceptionString;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/lifecycle/Lifecycle.java b/src/main/java/com/croftsfot/core/lang/lifecycle/Lifecycle.java
new file mode 100644
index 0000000..e2063f3
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/lifecycle/Lifecycle.java
@@ -0,0 +1,22 @@
+ package com.croftsoft.core.lang.lifecycle;
+
+ /*********************************************************************
+ * An interface for the common Applet lifecycle methods.
+ *
+ * @version
+ * 2003-09-10
+ * @since
+ * 2001-03-06
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface Lifecycle
+ extends Commissionable, Resumable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/lifecycle/LifecycleEnforcer.java b/src/main/java/com/croftsfot/core/lang/lifecycle/LifecycleEnforcer.java
new file mode 100644
index 0000000..adf316b
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/lifecycle/LifecycleEnforcer.java
@@ -0,0 +1,357 @@
+ package com.croftsoft.core.lang.lifecycle;
+
+ /*********************************************************************
+ * Strictly enforces the Lifecycle method calling order by frameworks.
+ *
+ *
+ * Methods throw an IllegalStateException if they are called out of
+ * order. The acceptable state transition sequence is as follows:
+ *
+ *
+ * init() --> ( start() --> stop() )* --> destroy().
+ *
+ *
+ * [* start() then stop() may be called zero or more times.]
+ *
+ *
+ * LifecycleEnforcer can be used via inheritance, by delegation, or as
+ * a wrapper.
+ *
+ *
+ *
+ * When used via inheritance, LifecycleEnforcer is subclassed and
+ * the subclass methods call the corresponding superclass methods
+ * as their first actions.
+ *
+ *
+ *
+ * Inheritance example:
+ *
+ *
+ * public class ActiveResource1
+ * extends LifecycleEnforcer
+ * {
+ * public ActiveResource1 ( )
+ * {
+ * super ( ); // use the zero argument superclass constructor
+ *
+ * // insert subclass specific constructor code here
+ * }
+ *
+ * public void init ( )
+ * {
+ * super.init ( ); // may throw IllegalStateException
+ *
+ * // insert subclass specific initialization here
+ * }
+ *
+ * public void start ( )
+ * {
+ * super.start ( ); // may throw IllegalStateException
+ *
+ * // insert subclass specific start code here
+ * }
+ *
+ * public void stop ( )
+ * {
+ * super.stop ( ); // may throw IllegalStateException
+ *
+ * // insert subclass specific stop code here
+ * }
+ *
+ * public void destroy ( )
+ * {
+ * super.destroy ( ); // may throw IllegalStateException
+ *
+ * // insert subclass specific destroy code here
+ * }
+ * }
+ *
+ *
+ *
+ *
+ *
+ * When used via delegation, it is much like inheritance
+ * except that a reference is maintained to a LifecycleEnforcer
+ * instead of subclassing from it. The containing Lifecycle
+ * instance will delegate Lifecycle method calls to the delegate
+ * LifecycleEnforcer as the first action.
+ *
+ *
+ *
+ * Delegation example:
+ *
+ *
+ * public class ActiveResource2
+ * {
+ * private final Lifecycle lifecycleEnforcer;
+ *
+ * public ActiveResource1 ( )
+ * {
+ * lifecycleEnforcer = new LifecycleEnforcer ( );
+ * }
+ *
+ * public void init ( )
+ * {
+ * lifecycleEnforcer.init ( ); // may throw IllegalStateException
+ *
+ * // insert subclass specific initialization here
+ * }
+ *
+ * public void start ( )
+ * {
+ * lifecycleEnforcer.start ( ); // may throw IllegalStateException
+ *
+ * // insert subclass specific start code here
+ * }
+ *
+ * public void stop ( )
+ * {
+ * lifecycleEnforcer.stop ( ); // may throw IllegalStateException
+ *
+ * // insert subclass specific stop code here
+ * }
+ *
+ * public void destroy ( )
+ * {
+ * lifecycleEnforcer.destroy ( ); // may throw IllegalStateException
+ *
+ * // insert subclass specific destroy code here
+ * }
+ * }
+ *
+ *
+ *
+ *
+ *
+ * When used as a wrapper, LifecycleEnforcer acts as a
+ * protective exterior around a private Lifecycle instance.
+ * Calls to the lifecycle methods are delegated to the
+ * private instance only after checking for proper state
+ * transitions. The wrapper
+ * has the added benefit of effectively making all but the
+ * lifecycle methods of the private instance inaccessible by
+ * direct reference.
+ *
+ *
+ *
+ * Wrapper example:
+ *
+ *
+ * Lifecycle unprotectedLifecycle = new ActiveResource3 ( );
+ *
+ * Lifecycle protectedLifecycle
+ * = new LifecycleEnforcer ( unprotectedLifecycle );
+ *
+ * untrustedFramework.manageLifecycleObject ( protectedLifecycle );
+ *
+ *
+ *
+ *
+ * @version
+ * 2001-05-31
+ * @since
+ * 2001-03-08
+ * @author
+ * David W. Croft
+ *********************************************************************/
+
+ public class LifecycleEnforcer
+ implements Lifecycle
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public static final int STATE_UNINITIALIZED = 0;
+
+ public static final int STATE_INITIALIZED = 1;
+
+ public static final int STATE_STARTED = 2;
+
+ public static final int STATE_STOPPED = 3;
+
+ public static final int STATE_DESTROYED = 4;
+
+ private final Lifecycle lifecycle;
+
+ private int state = STATE_UNINITIALIZED;
+
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public LifecycleEnforcer ( Lifecycle lifecycle )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this.lifecycle = lifecycle;
+ }
+
+ public LifecycleEnforcer ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this.lifecycle = null;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public synchronized int getState ( ) { return state; }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public synchronized void init ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ switch ( state )
+ {
+ case STATE_UNINITIALIZED:
+
+ break;
+
+ case STATE_INITIALIZED:
+
+ // drop through
+
+ case STATE_STARTED:
+
+ // drop through
+
+ case STATE_STOPPED:
+
+ throw new IllegalStateException ( "already initialized" );
+
+ case STATE_DESTROYED:
+
+ throw new IllegalStateException ( "destroyed" );
+
+ default:
+
+ throw new IllegalStateException ( "illegal state: " + state );
+ }
+
+ if ( lifecycle != null )
+ {
+ lifecycle.init ( );
+ }
+
+ state = STATE_INITIALIZED;
+ }
+
+ public synchronized void start ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ switch ( state )
+ {
+ case STATE_UNINITIALIZED:
+
+ throw new IllegalStateException ( "not yet initialized" );
+
+ case STATE_INITIALIZED:
+
+ break;
+
+ case STATE_STARTED:
+
+ throw new IllegalStateException ( "already started" );
+
+ case STATE_STOPPED:
+
+ break;
+
+ case STATE_DESTROYED:
+
+ throw new IllegalStateException ( "destroyed" );
+
+ default:
+
+ throw new IllegalStateException ( "illegal state: " + state );
+ }
+
+ if ( lifecycle != null )
+ {
+ lifecycle.start ( );
+ }
+
+ state = STATE_STARTED;
+ }
+
+ public synchronized void stop ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ switch ( state )
+ {
+ case STATE_UNINITIALIZED:
+
+ throw new IllegalStateException ( "not yet initialized" );
+
+ case STATE_INITIALIZED:
+
+ throw new IllegalStateException ( "not yet started" );
+
+ case STATE_STARTED:
+
+ break;
+
+ case STATE_STOPPED:
+
+ throw new IllegalStateException ( "already stopped" );
+
+ case STATE_DESTROYED:
+
+ throw new IllegalStateException ( "destroyed" );
+
+ default:
+
+ throw new IllegalStateException ( "illegal state: " + state );
+ }
+
+ if ( lifecycle != null )
+ {
+ lifecycle.stop ( );
+ }
+
+ state = STATE_STOPPED;
+ }
+
+ public synchronized void destroy ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ switch ( state )
+ {
+ case STATE_UNINITIALIZED:
+
+ throw new IllegalStateException ( "not yet initialized" );
+
+ case STATE_INITIALIZED:
+
+ break;
+
+ case STATE_STARTED:
+
+ throw new IllegalStateException ( "not stopped" );
+
+ case STATE_STOPPED:
+
+ break;
+
+ case STATE_DESTROYED:
+
+ throw new IllegalStateException ( "already destroyed" );
+
+ default:
+
+ throw new IllegalStateException ( "illegal state: " + state );
+ }
+
+ if ( lifecycle != null )
+ {
+ lifecycle.destroy ( );
+ }
+
+ state = STATE_DESTROYED;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/lifecycle/LifecycleLib.java b/src/main/java/com/croftsfot/core/lang/lifecycle/LifecycleLib.java
new file mode 100644
index 0000000..3e416de
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/lifecycle/LifecycleLib.java
@@ -0,0 +1,236 @@
+ package com.croftsoft.core.lang.lifecycle;
+
+ /*********************************************************************
+ * Convenience methods for Lifecycle objects.
+ *
+ * @version
+ * $Date: 2008/04/19 21:27:13 $
+ * @since
+ * 2002-02-15
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class LifecycleLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ /*********************************************************************
+ * Initializes the initializable, catching and printing any Exception.
+ *
+ * @param initializable
+ *
+ * If null, does nothing.
+ *********************************************************************/
+ public static void init ( Initializable initializable )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ if ( initializable != null )
+ {
+ initializable.init ( );
+ }
+ }
+ catch ( Exception ex )
+ {
+ ex.printStackTrace ( );
+ }
+ }
+
+ /*********************************************************************
+ * Initializes the initializables, catching and printing any Exception.
+ *
+ * @param initializables
+ *
+ * If null, does nothing.
+ *********************************************************************/
+ public static void init ( Initializable... initializables )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( initializables != null )
+ {
+ for ( int i = 0; i < initializables.length; i++ )
+ {
+ init ( initializables [ i ] );
+ }
+ }
+ }
+
+ /*********************************************************************
+ * Starts the startable, catching and printing any Exception.
+ *
+ * @param startable
+ *
+ * If null, does nothing.
+ *********************************************************************/
+ public static void start ( Startable startable )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ if ( startable != null )
+ {
+ startable.start ( );
+ }
+ }
+ catch ( Exception ex )
+ {
+ ex.printStackTrace ( );
+ }
+ }
+
+ /*********************************************************************
+ * Starts the startables, catching and printing any Exception.
+ *
+ * @param startables
+ *
+ * If null, does nothing.
+ *********************************************************************/
+ public static void start ( Startable... startables )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( startables != null )
+ {
+ for ( int i = 0; i < startables.length; i++ )
+ {
+ start ( startables [ i ] );
+ }
+ }
+ }
+
+ /*********************************************************************
+ * Stops the stoppable, catching and printing any Exception.
+ *
+ * @param stoppable
+ *
+ * If null, does nothing.
+ *********************************************************************/
+ public static void stop ( Stoppable stoppable )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ if ( stoppable != null )
+ {
+ stoppable.stop ( );
+ }
+ }
+ catch ( Exception ex )
+ {
+ ex.printStackTrace ( );
+ }
+ }
+
+ /*********************************************************************
+ * Stops the stoppables, catching and printing any Exception.
+ *
+ * @param stoppables
+ *
+ * If null, does nothing.
+ *********************************************************************/
+ public static void stop ( Stoppable... stoppables )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( stoppables != null )
+ {
+ for ( int i = 0; i < stoppables.length; i++ )
+ {
+ stop ( stoppables [ i ] );
+ }
+ }
+ }
+
+ /*********************************************************************
+ * Destroys the destroyable, catching and printing any Exception.
+ *
+ * @param destroyable
+ *
+ * If null, does nothing.
+ *********************************************************************/
+ public static void destroy ( Destroyable destroyable )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ if ( destroyable != null )
+ {
+ destroyable.destroy ( );
+ }
+ }
+ catch ( Exception ex )
+ {
+ ex.printStackTrace ( );
+ }
+ }
+
+ /*********************************************************************
+ * Destroys the destroyables, catching and printing any Exception.
+ *
+ * @param destroyables
+ *
+ * If null, does nothing.
+ *********************************************************************/
+ public static void destroy ( Destroyable... destroyables )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( destroyables != null )
+ {
+ for ( int i = 0; i < destroyables.length; i++ )
+ {
+ destroy ( destroyables [ i ] );
+ }
+ }
+ }
+
+ /*********************************************************************
+ * Updates the updatable, catching and printing any Exception.
+ *
+ * @param updatable
+ *
+ * If null, does nothing.
+ *********************************************************************/
+ public static void update ( Updatable updatable )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ if ( updatable != null )
+ {
+ updatable.update ( );
+ }
+ }
+ catch ( Exception ex )
+ {
+ ex.printStackTrace ( );
+ }
+ }
+
+ /*********************************************************************
+ * Updates the updatables, catching and printing any Exception.
+ *
+ * @param updatables
+ *
+ * If null, does nothing.
+ *********************************************************************/
+ public static void update ( Updatable... updatables )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( updatables != null )
+ {
+ for ( int i = 0; i < updatables.length; i++ )
+ {
+ update ( updatables [ i ] );
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ private LifecycleLib ( ) { }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/lang/lifecycle/Resumable.java b/src/main/java/com/croftsfot/core/lang/lifecycle/Resumable.java
new file mode 100644
index 0000000..8eb00dd
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/lifecycle/Resumable.java
@@ -0,0 +1,22 @@
+ package com.croftsoft.core.lang.lifecycle;
+
+ /*********************************************************************
+ * Extends Startable and Stoppable.
+ *
+ * @version
+ * 2003-09-10
+ * @since
+ * 2001-03-06
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface Resumable
+ extends Startable, Stoppable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/lifecycle/Startable.java b/src/main/java/com/croftsfot/core/lang/lifecycle/Startable.java
new file mode 100644
index 0000000..ac3cd5c
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/lifecycle/Startable.java
@@ -0,0 +1,23 @@
+ package com.croftsoft.core.lang.lifecycle;
+
+ /*********************************************************************
+ * Defines the start() method.
+ *
+ * @version
+ * 2003-09-10
+ * @since
+ * 2001-03-06
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface Startable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public void start ( );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/lifecycle/Stoppable.java b/src/main/java/com/croftsfot/core/lang/lifecycle/Stoppable.java
new file mode 100644
index 0000000..645da72
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/lifecycle/Stoppable.java
@@ -0,0 +1,23 @@
+ package com.croftsoft.core.lang.lifecycle;
+
+ /*********************************************************************
+ * Defines the stop() method.
+ *
+ * @version
+ * 2003-09-10
+ * @since
+ * 2001-03-06
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface Stoppable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public void stop ( );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/lifecycle/Updatable.java b/src/main/java/com/croftsfot/core/lang/lifecycle/Updatable.java
new file mode 100644
index 0000000..61ad208
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/lifecycle/Updatable.java
@@ -0,0 +1,23 @@
+ package com.croftsoft.core.lang.lifecycle;
+
+ /*********************************************************************
+ * Defines the update() method.
+ *
+ * @version
+ * $Date: 2008/04/19 21:27:13 $
+ * @since
+ * 2005-08-12
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface Updatable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public void update ( );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/lifecycle/UpdateRunner.java b/src/main/java/com/croftsfot/core/lang/lifecycle/UpdateRunner.java
new file mode 100644
index 0000000..795fda7
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/lifecycle/UpdateRunner.java
@@ -0,0 +1,44 @@
+ package com.croftsoft.core.lang.lifecycle;
+
+ import com.croftsoft.core.lang.NullArgumentException;
+
+ /*********************************************************************
+ * A Runnable that updates Updatables.
+ *
+ * @version
+ * $Id: UpdateRunner.java,v 1.1 2006/01/03 19:05:21 croft Exp $
+ * @since
+ * 2006-01-03
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class UpdateRunner
+ implements Runnable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private final Updatable [ ] updatables;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public UpdateRunner ( Updatable [ ] updatables )
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( this.updatables = updatables );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public void run ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ LifecycleLib.update ( updatables );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/lifecycle/package.html b/src/main/java/com/croftsfot/core/lang/lifecycle/package.html
new file mode 100644
index 0000000..10b606b
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/lifecycle/package.html
@@ -0,0 +1,5 @@
+
+
+Interfaces for the common Applet lifecycle methods.
+
+
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/lang/package.html b/src/main/java/com/croftsfot/core/lang/package.html
new file mode 100644
index 0000000..1bab1bc
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/package.html
@@ -0,0 +1,5 @@
+
+
+Package java.lang support and basic classes.
+
+
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/lang/reflect/MethodLib.java b/src/main/java/com/croftsfot/core/lang/reflect/MethodLib.java
new file mode 100644
index 0000000..662e9b3
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/reflect/MethodLib.java
@@ -0,0 +1,55 @@
+ package com.croftsoft.core.lang.reflect;
+
+ import java.lang.reflect.*;
+
+ /*********************************************************************
+ *
+ * Static library to invoke methods using reflection.
+ *
+ * @version
+ * 1998-10-04
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public class MethodLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private MethodLib ( ) { }
+
+ public static void invokeMain ( Class c, String [ ] args )
+ throws IllegalAccessException
+ //////////////////////////////////////////////////////////////////////
+ {
+ Method method;
+
+ try
+ {
+ method = c.getMethod ( "main",
+ new Class [ ] { String [ ].class } );
+ }
+ catch ( NoSuchMethodException ex )
+ {
+ System.err.println ( "No main() method in class \""
+ + c.getName ( ) + "\"." );
+ return;
+ }
+
+ try
+ {
+ method.invoke ( null, new Object [ ] { args } );
+ }
+ catch ( InvocationTargetException ex )
+ {
+ Throwable t = ex.getTargetException ( );
+ System.err.println (
+ "\"main()\" method exited with exception \"" + t + "\"." );
+ t.printStackTrace ( );
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/lang/reflect/package.html b/src/main/java/com/croftsfot/core/lang/reflect/package.html
new file mode 100644
index 0000000..07bf291
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/lang/reflect/package.html
@@ -0,0 +1,5 @@
+
+
+Package java.lang.reflect reflection support.
+
+
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/Counter.java b/src/main/java/com/croftsfot/core/math/Counter.java
new file mode 100644
index 0000000..433b7e1
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/Counter.java
@@ -0,0 +1,66 @@
+ package com.croftsoft.core.math;
+
+ import java.io.Serializable;
+ import java.math.BigInteger;
+
+ import com.croftsoft.core.lang.NullArgumentException;
+
+ /*********************************************************************
+ * An incrementable integer counter with no maximum limit.
+ *
+ *
+ *
+ * @version
+ * 2001-03-30
+ * @since
+ * 2001-03-30
+ * @author
+ * David W. Croft
+ *********************************************************************/
+
+ public final class Counter
+ implements Serializable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private static final long serialVersionUID = 1L;
+
+ private BigInteger count;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public Counter ( BigInteger count )
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( this.count = count );
+ }
+
+ public Counter ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this ( BigInteger.ZERO );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public BigInteger getCount ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return count;
+ }
+
+ /*********************************************************************
+ * Synchronized.
+ *********************************************************************/
+ public synchronized BigInteger increment ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return ( count = count.add ( BigInteger.ONE ) );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/math/FinanceLib.java b/src/main/java/com/croftsfot/core/math/FinanceLib.java
new file mode 100644
index 0000000..7d1d434
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/FinanceLib.java
@@ -0,0 +1,304 @@
+ package com.croftsoft.core.math;
+
+import java.io.*;
+
+ /*********************************************************************
+ * Financial calculations.
+ *
+ * @version
+ * 2001-10-10
+ * @since
+ * 1999-08-15
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class FinanceLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public static final void testRetire (
+ double desiredSavingsInterestIncome,
+ double savingsInterestRate,
+ double inflationRate,
+ double taxRate,
+ double investmentInterestRate,
+ double yearsOfSaving )
+ //////////////////////////////////////////////////////////////////////
+ {
+
+// desiredSavingsInterestIncome
+// = savings
+// * ( savingsInterestRate * ( 1.0 - taxRate ) - inflationRate )
+// / ( 1.0 + inflationRate );
+
+ double savings
+ = desiredSavingsInterestIncome * ( 1.0 + inflationRate )
+ / ( savingsInterestRate * ( 1.0 - taxRate ) - inflationRate );
+
+ double futureValueSavings
+ = savings * Math.pow ( 1.0 + inflationRate, yearsOfSaving );
+
+ double annualSavings = annualSavingsNeeded (
+ futureValueSavings, investmentInterestRate, yearsOfSaving );
+
+ System.out.println ( savings );
+ System.out.println ( futureValueSavings );
+ System.out.println ( annualSavings );
+ System.out.println ( futureValueAnnuity (
+ annualSavings, investmentInterestRate, yearsOfSaving ) );
+ System.out.println ( presentValueAnnuity (
+ annualSavings, investmentInterestRate, yearsOfSaving ) );
+ }
+
+ /*********************************************************************
+ * Test method. Prints the future value of an annuity followed by
+ * the present value calculated three different ways.
+ *
+ * @param c Annual cash income starting one year from today.
+ * @param r Annual interest earned on income.
+ * @param t Number of years of cash income.
+ *********************************************************************/
+ public static final void testAnnuity (
+ double C,
+ double r,
+ double T )
+ //////////////////////////////////////////////////////////////////////
+ {
+ double FV = futureValueAnnuity ( C, r, T );
+ System.out.println ( FV );
+ System.out.println ( presentValue ( FV, r, T ) );
+ System.out.println ( presentValueAnnuity ( C, r, T ) );
+ double [ ] c = new double [ ( int ) T ];
+ for ( int i = 0; i < T; i++ ) c [ i ] = C;
+ System.out.println ( presentValue ( c, r ) );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * The future value of a cash flow received today.
+ *
+ * @param c Cash flow today.
+ * @param r Inflation rate.
+ * @param t Number of years from today when the value is evaluated.
+ *********************************************************************/
+ public static final double futureValue (
+ double c,
+ double r,
+ double t )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return c * Math.pow ( 1.0 + r, t );
+ }
+
+ /*********************************************************************
+ * Calculates the future value of an annuity.
+ *
+ * @param c Annual cash income starting one year from today.
+ * @param r Annual interest earned on income.
+ * @param t Number of years of cash income.
+ *********************************************************************/
+ public static final double futureValueAnnuity (
+ double c,
+ double r,
+ double t )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return c * ( ( Math.pow ( 1.0 + r, t ) - 1.0 ) / r );
+ }
+
+ /*********************************************************************
+ * The calculated discount rate where the net present value is 0.
+ *
+ * @param irrEstimate
+ *
+ * The initial estimated value for the IRR (e.g., 0.10 for 10%).
+ *
+ * @param cashFlows
+ *
+ * Array of cash flows received in the future, indexed from time = 0.
+ *********************************************************************/
+ public static final double internalRateOfReturn (
+ double irrEstimate,
+ double [ ] cashFlows )
+ //////////////////////////////////////////////////////////////////////
+ {
+ double irr = irrEstimate;
+
+ double delta = -irr * 0.1;
+
+ double oldNpv = 0.0;
+
+ while ( true )
+ {
+ double npv = netPresentValue ( irr, cashFlows );
+
+ if ( npv == 0.0 )
+ {
+ return irr;
+ }
+
+ if ( oldNpv < 0.0 )
+ {
+ if ( npv > 0.0 )
+ {
+ delta *= -0.9;
+ }
+ else if ( npv > oldNpv )
+ {
+ delta *= 1.1;
+ }
+ else if ( npv < oldNpv )
+ {
+ delta = -delta;
+ }
+ else
+ {
+ delta = 0.0;
+ }
+ }
+ else if ( oldNpv > 0.0 )
+ {
+ if ( npv < 0.0 )
+ {
+ delta *= -0.9;
+ }
+ else if ( npv < oldNpv )
+ {
+ delta *= 1.1;
+ }
+ else if ( npv > oldNpv )
+ {
+ delta = -delta;
+ }
+ else
+ {
+ delta = 0.0;
+ }
+ }
+
+/*
+System.out.println ( "irr = " + irr + ", oldNpv = " + oldNpv + ", npv = " + npv + ", delta = " + delta );
+
+try{
+new BufferedReader ( new InputStreamReader ( System.in ) ).readLine ( );
+}catch (Exception x ) { }
+*/
+
+ if ( delta == 0.0 )
+ {
+ return irr;
+ }
+
+ irr += delta;
+
+ oldNpv = npv;
+ }
+ }
+
+ /*********************************************************************
+ * The discounted value of multiple cash flows received in the future.
+ *
+ * @param discountRate
+ *
+ * The discount rate or cost of capital (e.g., 0.10 for 10%).
+ *
+ * @param cashFlows
+ *
+ * Array of cash flows received in the future, indexed from time = 0.
+ *********************************************************************/
+ public static final double netPresentValue (
+ double discountRate,
+ double [ ] cashFlows )
+ //////////////////////////////////////////////////////////////////////
+ {
+ double npv = 0.0;
+
+ for ( int i = 0; i < cashFlows.length; i++ )
+ {
+ npv += cashFlows [ i ] / Math.pow ( 1.0 + discountRate, i );
+ }
+
+ return npv;
+ }
+
+ /*********************************************************************
+ * The discounted value of a single cash flow received in the future.
+ *
+ * @param c Cash flow received in the future
+ * @param r Inflation or annual interest.
+ * @param t Number of years from today when the cash flow is received.
+ *********************************************************************/
+ public static final double presentValue (
+ double c,
+ double r,
+ double t )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return c / Math.pow ( 1.0 + r, t );
+ }
+
+ /*********************************************************************
+ * The discounted value of varying annual cash flows.
+ *
+ * @param c Array of annual cash income starting one year from today.
+ * @param r Annual interest earned on income.
+ *********************************************************************/
+ public static final double presentValue (
+ double [ ] c,
+ double r )
+ //////////////////////////////////////////////////////////////////////
+ {
+ double sum = 0.0;
+ for ( int i = 0; i < c.length; i++ )
+ {
+ sum += presentValue ( c [ i ], r, i + 1 );
+ }
+ return sum;
+ }
+
+ /*********************************************************************
+ * Calculates the present value of an annuity.
+ *
+ * @param c Annual cash income starting one year from today.
+ * @param r Inflation or annual interest.
+ * @param t Number of years of cash income.
+ *********************************************************************/
+ public static final double presentValueAnnuity (
+ double c,
+ double r,
+ double t )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return c * ( 1.0 - 1.0 / Math.pow ( 1.0 + r, t ) ) / r;
+ }
+
+ /*********************************************************************
+ * Calculates the annual savings necessary to accumulate a specified
+ * value in the future.
+ *
+ * @param f Future value desired.
+ * @param r Annual interest.
+ * @param t Number of years of savings.
+ *********************************************************************/
+ public static final double annualSavingsNeeded (
+ double f,
+ double r,
+ double t )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return f * r / ( Math.pow ( 1.0 + r, t ) - 1.0 );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ private FinanceLib ( ) { }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
+
diff --git a/src/main/java/com/croftsfot/core/math/MathConstants.java b/src/main/java/com/croftsfot/core/math/MathConstants.java
new file mode 100644
index 0000000..3607e8c
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/MathConstants.java
@@ -0,0 +1,34 @@
+ package com.croftsoft.core.math;
+
+ /***********************************************************************
+ * A collection of constants to supplement java.lang.Math.
+ *
+ * @version
+ * $Id: MathConstants.java,v 1.4 2008/08/24 00:28:36 croft Exp $
+ * @since
+ * 2002-01-27
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public interface MathConstants
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ public static final long
+ MILLISECONDS_PER_DAY = 1000 * 60 * 60 * 24,
+ MILLISECONDS_PER_SECOND = 1000,
+ NANOSECONDS_PER_MICROSECOND = 1000,
+ NANOSECONDS_PER_MILLISECOND = 1000000,
+ NANOSECONDS_PER_SECOND = 1000000000;
+
+ public static final double
+ DEGREES_PER_RADIAN = 360.0 / ( 2.0 * Math.PI ),
+ GOLDEN_RATIO = 1.618033988749894848204586,
+ SECONDS_PER_NANOSECOND = 0.000000001,
+ TWO_PI = 2 * Math.PI;
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/MathLib.java b/src/main/java/com/croftsfot/core/math/MathLib.java
new file mode 100644
index 0000000..82bfdbb
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/MathLib.java
@@ -0,0 +1,293 @@
+ package com.croftsoft.core.math;
+
+ import java.awt.geom.Point2D;
+ import java.util.*;
+
+ /*********************************************************************
+ * A collection of static methods to supplement java.lang.Math.
+ *
+ * @version
+ * $Id: MathLib.java,v 1.5 2008/08/09 02:10:33 croft Exp $
+ * @since
+ * 1998-12-27
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class MathLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public static void main ( String [ ] args )
+ //////////////////////////////////////////////////////////////////////
+ {
+ System.out.println ( test ( ) );
+ }
+
+ public static boolean test ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return ( greatestCommonFactor ( 6, 15 ) == 3 )
+ && ( log ( 1.0, 10.0 ) == 0.0 )
+ && ( log ( 10.0, 10.0 ) == 1.0 )
+ && ( log ( 100.0, 10.0 ) == 2.0 )
+ && ( log ( 0.5, 2.0 ) == -1.0 )
+ && ( log ( 1.0, 2.0 ) == 0.0 )
+ && ( log ( 2.0, 2.0 ) == 1.0 )
+ && ( log ( 4.0, 2.0 ) == 2.0 )
+ && ( wrap ( -190, -180, 360 ) == 170 )
+ && ( wrap ( -180, -180, 360 ) == -180 )
+ && ( wrap ( 180, -180, 360 ) == -180 )
+ && ( wrap ( 190, -180, 360 ) == -170 )
+ && ( wrap ( 370, -180, 360 ) == 10 )
+ && ( wrap ( -10, 0, 360 ) == 350 )
+ && ( wrap ( 0, 0, 360 ) == 0 )
+ && ( wrap ( 10, 0, 360 ) == 10 )
+ && ( wrap ( 360, 0, 360 ) == 0 )
+ && ( wrap ( 370, 0, 360 ) == 10 );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public static double clip (
+ final double value,
+ final double minimum,
+ final double maximum )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( minimum > maximum )
+ {
+ throw new IllegalArgumentException (
+ "minimum > maximum: " + minimum + ", " + maximum );
+ }
+
+ return
+ value < minimum ? minimum : value > maximum ? maximum : value;
+ }
+
+ /*********************************************************************
+ * Cumulative Distribution Function (CDF).
+ *
+ * @see
+ * http://en.wikipedia.org/wiki/Exponential_distribution
+ * #Cumulative_distribution_function
+ *********************************************************************/
+ public static double cumulative (
+ double x,
+ double lambda )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( x <= 0.0 )
+ {
+ return 0.0;
+ }
+
+ return 1.0 - Math.exp ( -lambda * x );
+ }
+
+ /*********************************************************************
+ * return cumulative ( x, 1 );
+ *********************************************************************/
+ public static double cumulative ( double x )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return cumulative ( x, 1 );
+ }
+
+ @SuppressWarnings ( "all" ) // TODO: fix argument assignment warning
+ public static List factor ( int n )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( n < 0 )
+ {
+ throw new IllegalArgumentException ( "n < 0" );
+ }
+
+ List primeList = new ArrayList ( );
+
+ if ( n == 0 )
+ {
+ primeList.add ( new Integer ( 0 ) );
+
+ return primeList;
+ }
+
+ if ( n == 1 )
+ {
+ primeList.add ( new Integer ( 1 ) );
+
+ return primeList;
+ }
+
+ for ( int i = 2; i <= n; i++ )
+ {
+ if ( n % i == 0 )
+ {
+ primeList.add ( new Integer ( i ) );
+
+ n = n / i;
+
+ i = 1;
+ }
+ }
+
+ return primeList;
+ }
+
+ public static int greatestCommonFactor (
+ int n0,
+ int n1 )
+ //////////////////////////////////////////////////////////////////////
+ {
+ int gcf = 1;
+
+ List primeList0 = factor ( n0 );
+
+ List primeList1 = factor ( n1 );
+
+ Integer [ ] primeArray0
+ = primeList0.toArray ( new Integer [ 0 ] );
+
+ for ( int i = 0; i < primeArray0.length; i++ )
+ {
+ Integer j = primeArray0 [ i ];
+
+ if ( primeList1.contains ( j ) )
+ {
+ gcf = gcf * j.intValue ( );
+
+ primeList1.remove ( j );
+ }
+ }
+
+ return gcf;
+ }
+
+ /*********************************************************************
+ * Calculates the logarithm in the given base.
+ *
+ * return Math.log ( a ) / Math.log ( base );
+ *********************************************************************/
+ public static double log (
+ double a,
+ double base )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return Math.log ( a ) / Math.log ( base );
+ }
+
+ /*********************************************************************
+ * Also known as the "logistic function".
+ *********************************************************************/
+ public static double sigmoid ( double a )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return 1.0 / ( 1.0 + Math.exp ( -a ) );
+ }
+
+ /*********************************************************************
+ * The derivative with respect to the argument.
+ *********************************************************************/
+ public static double sigmoidDerivative ( double a )
+ //////////////////////////////////////////////////////////////////////
+ {
+ double y = sigmoid ( a );
+ return y * ( 1.0 - y );
+ }
+
+ /*********************************************************************
+ * Returns +1 if positive, -1 if negative, otherwise 0.
+ *********************************************************************/
+ public static byte signum ( long l )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return ( byte ) ( l > 0 ? 1 : ( l < 0 ? -1 : 0 ) );
+ }
+
+ /*********************************************************************
+ * hyperbolic tangent = 2 * sigmoid ( 2 * a ) - 1
+ *********************************************************************/
+ public static double tanh ( double a )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return 2.0 * sigmoid ( 2.0 * a ) - 1.0;
+ }
+
+ /*********************************************************************
+ * Converts from polar to rectangular coordinates.
+ *********************************************************************/
+ public static void toRectangular (
+ double radius,
+ double angle,
+ Point2D point2D )
+ //////////////////////////////////////////////////////////////////////
+ {
+ point2D.setLocation (
+ radius * Math.cos ( angle ),
+ radius * Math.sin ( angle ) );
+ }
+
+ /*********************************************************************
+ * Converts from polar to rectangular coordinates.
+ *********************************************************************/
+ public static Point2D toRectangular (
+ double radius,
+ double angle )
+ //////////////////////////////////////////////////////////////////////
+ {
+ Point2D point2D = new Point2D.Double ( );
+
+ toRectangular ( radius, angle, point2D );
+
+ return point2D;
+ }
+
+ /*********************************************************************
+ * Wraps the value to [minimum, minimum + range).
+ *
+ * Example: wrap ( -190, -180, 360 ) ==> 170
+ * Example: wrap ( 190, -180, 360 ) ==> -10
+ * Example: wrap ( 360, -180, 360 ) ==> -180
+ *********************************************************************/
+ public static double wrap (
+ final double value,
+ final double minimum,
+ final double range )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( range <= 0 )
+ {
+ throw new IllegalArgumentException ( "range <= 0: " + range );
+ }
+
+ final double maximum = minimum + range;
+
+ if ( ( value >= minimum )
+ && ( value < maximum ) )
+ {
+ return value;
+ }
+
+ if ( value < minimum )
+ {
+ return value + Math.ceil ( ( minimum - value ) / range ) * range;
+ }
+
+ return value
+ - ( 1 + Math.floor ( ( value - maximum ) / range ) ) * range;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ private MathLib ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ // empty
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/math/Matrix.java b/src/main/java/com/croftsfot/core/math/Matrix.java
new file mode 100644
index 0000000..772c87b
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/Matrix.java
@@ -0,0 +1,387 @@
+ package com.croftsoft.core.math;
+
+ /*********************************************************************
+ *
+ * A mathematical matrix class.
+ *
+ * @version
+ * 1998-12-27
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public class Matrix
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public int rows;
+ public int cols;
+ public double [ ] [ ] data;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * Test/demo method.
+ *********************************************************************/
+ public static void main ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ Matrix left = new Matrix ( 2, 3 );
+ Matrix right = new Matrix ( 3, 4 );
+
+ for ( int index_row = 0; index_row < left.rows; index_row++ )
+ for ( int index_col = 0; index_col < left.cols; index_col++ )
+ {
+ left.data [ index_row ] [ index_col ] = index_row + index_col;
+ }
+
+ for ( int index_row = 0; index_row < right.rows; index_row++ )
+ for ( int index_col = 0; index_col < right.cols; index_col++ )
+ {
+ right.data [ index_row ] [ index_col ] = index_row + index_col;
+ }
+
+ left.display ( );
+ System.out.println ( "" );
+ right.display ( );
+ System.out.println ( "" );
+ Matrix product = multiply ( left, right );
+ product.display ( );
+ System.out.println ( "" );
+ Matrix transposed = product.transpose ( );
+ transposed.display ( );
+ System.out.println ( "" );
+ Matrix sigmoided = transposed.sigmoid ( );
+ sigmoided.display ( );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // Static methods
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * Returns a square matrix with the diagonal values set to 1.0 and
+ * all others set to 0.0.
+ *
+ * @param rows_cols
+ * The number of rows and columns on a side.
+ *********************************************************************/
+ public static Matrix identity ( int rows_cols )
+ //////////////////////////////////////////////////////////////////////
+ {
+ Matrix m = new Matrix ( rows_cols, rows_cols );
+
+ for ( int i = 0; i < rows_cols; i++ )
+ {
+ m.data [ i ] [ i ] = 1.0;
+ }
+
+ return m;
+ }
+
+ public static Matrix multiply ( Matrix left, Matrix right )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( left.cols != right.rows )
+ {
+ throw new ArrayIndexOutOfBoundsException (
+ "Matrix.multiply: left.cols != right.rows" );
+ }
+
+ Matrix product = new Matrix ( left.rows, right.cols );
+
+ for ( int index_row = 0; index_row < product.rows; index_row++ )
+ for ( int index_col = 0; index_col < product.cols; index_col++ )
+ {
+ product.data [ index_row ] [ index_col ] = 0.0;
+ for ( int index = 0; index < left.cols; index++ )
+ {
+ product.data [ index_row ] [ index_col ]
+ += left.data [ index_row ] [ index ]
+ * right.data [ index ] [ index_col ];
+ }
+ }
+
+ return product;
+ }
+
+ public static Matrix multiplyPairwise ( Matrix a, Matrix b )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( ( a.rows != b.rows ) || ( a.cols != b.cols ) )
+ {
+ throw new ArrayIndexOutOfBoundsException (
+ "Matrix.multiply_pairwise: rows or columns not equal" );
+ }
+
+ Matrix product = new Matrix ( a.rows, a.cols );
+
+ for ( int index_row = 0; index_row < a.rows; index_row++ )
+ for ( int index_col = 0; index_col < a.cols; index_col++ )
+ {
+ product.data [ index_row ] [ index_col ]
+ = a.data [ index_row ] [ index_col ]
+ * b.data [ index_row ] [ index_col ];
+ }
+
+ return product;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // Constructor methods
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * Constructs a Matrix with all of the element values set to zero.
+ *********************************************************************/
+ public Matrix ( int rows, int cols )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this.rows = rows;
+ this.cols = cols;
+ this.data = new double [ rows ] [ cols ];
+ }
+
+ /*********************************************************************
+ * Constructs a Matrix with all of the element values set to a
+ * specified constant.
+ *
+ * @param value
+ * All of the element values will be set to this constant.
+ *********************************************************************/
+ public Matrix ( int rows, int cols, double value )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this ( rows, cols );
+
+ for ( int row = 0; row < rows; row++ )
+ for ( int col = 0; col < cols; col++ )
+ {
+ data [ row ] [ col ] = value;
+ }
+ }
+
+ public Matrix ( Matrix old )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this ( old.rows, old.cols );
+ for ( int index_row = 0; index_row < this.rows; index_row++ )
+ for ( int index_col = 0; index_col < this.cols; index_col++ )
+ {
+ this.data [ index_row ] [ index_col ]
+ = old.data [ index_row ] [ index_col ];
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public Matrix add ( double addend )
+ //////////////////////////////////////////////////////////////////////
+ {
+ Matrix new_Matrix = new Matrix ( this );
+
+ for ( int index_row = 0; index_row < this.rows; index_row++ )
+ for ( int index_col = 0; index_col < this.cols; index_col++ )
+ {
+ new_Matrix.data [ index_row ] [ index_col ] += addend;
+ }
+ return new_Matrix;
+ }
+
+ public Matrix add ( Matrix addend )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( ( this.rows!= addend.rows )
+ || ( this.cols != addend.cols ) )
+ {
+ throw new ArrayIndexOutOfBoundsException (
+ "Matrix.add ( Matrix ): columns and rows not equal" );
+ }
+
+ Matrix new_Matrix = new Matrix ( this );
+
+ for ( int index_row = 0; index_row < this.rows; index_row++ )
+ for ( int index_col = 0; index_col < this.cols; index_col++ )
+ {
+ new_Matrix.data [ index_row ] [ index_col ]
+ += addend.data [ index_row ] [ index_col ];
+ }
+ return new_Matrix;
+ }
+
+ public Matrix clip ( double min, double max )
+ //////////////////////////////////////////////////////////////////////
+ {
+ Matrix new_Matrix = new Matrix ( this );
+
+ for ( int index_row = 0; index_row < this.rows; index_row++ )
+ for ( int index_col = 0; index_col < this.cols; index_col++ )
+ {
+ if ( this.data [ index_row ] [ index_col ] < min )
+ new_Matrix.data [ index_row ] [ index_col ] = min;
+ else if ( this.data [ index_row ] [ index_col ] > max )
+ new_Matrix.data [ index_row ] [ index_col ] = max;
+ }
+ return new_Matrix;
+ }
+
+ public void display ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ for ( int index_row = 0; index_row < this.rows; index_row++ )
+ {
+ String line_String = "";
+ for ( int index_col = 0; index_col < this.cols; index_col++ )
+ {
+ line_String += this.data [ index_row ] [ index_col ] + " ";
+ }
+ System.out.println ( line_String );
+ }
+ }
+
+ public Matrix multiply ( double factor )
+ //////////////////////////////////////////////////////////////////////
+ {
+ Matrix new_Matrix = new Matrix ( this );
+
+ for ( int index_row = 0; index_row < this.rows; index_row++ )
+ for ( int index_col = 0; index_col < this.cols; index_col++ )
+ {
+ new_Matrix.data [ index_row ] [ index_col ] *= factor;
+ }
+
+ return new_Matrix;
+ }
+
+ public Matrix multiply ( Matrix right )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return multiply ( this, right );
+ }
+
+ public Matrix randomizeUniform ( double min, double max )
+ //////////////////////////////////////////////////////////////////////
+ {
+ Matrix new_Matrix = new Matrix ( this.rows, this.cols );
+
+ for ( int index_row = 0; index_row < this.rows; index_row++ )
+ for ( int index_col = 0; index_col < this.cols; index_col++ )
+ {
+ new_Matrix.data [ index_row ] [ index_col ]
+ = RandomLib.uniform ( min, max );
+ }
+
+ return new_Matrix;
+ }
+
+ public Matrix sigmoid ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ Matrix new_Matrix = new Matrix ( this.rows, this.cols );
+
+ for ( int index_row = 0; index_row < this.rows; index_row++ )
+ for ( int index_col = 0; index_col < this.cols; index_col++ )
+ {
+ new_Matrix.data [ index_row ] [ index_col ]
+ = MathLib.sigmoid ( this.data [ index_row ] [ index_col ] );
+ }
+
+ return new_Matrix;
+ }
+
+ public Matrix sigmoidDerivative ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ Matrix new_Matrix = new Matrix ( this.rows, this.cols );
+
+ for ( int index_row = 0; index_row < this.rows; index_row++ )
+ for ( int index_col = 0; index_col < this.cols; index_col++ )
+ {
+ new_Matrix.data [ index_row ] [ index_col ]
+ = MathLib.sigmoidDerivative
+ ( this.data [ index_row ] [ index_col ] );
+ }
+
+ return new_Matrix;
+ }
+
+ public Matrix submatrix (
+ int row_start, int row_end,
+ int col_start, int col_end )
+ //////////////////////////////////////////////////////////////////////
+ // Note that the first row is row 0.
+ //////////////////////////////////////////////////////////////////////
+ {
+ Matrix sub
+ = new Matrix ( row_end - row_start + 1, col_end - col_start + 1 );
+ for ( int index_row = 0; index_row < sub.rows; index_row++ )
+ for ( int index_col = 0; index_col < sub.cols; index_col++ )
+ {
+ sub.data [ index_row ] [ index_col ]
+ = this.data [ index_row + row_start ] [ index_col + col_start ];
+ }
+
+ return sub;
+ }
+
+ public Matrix subtract ( Matrix subtractor )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( ( this.rows != subtractor.rows )
+ || ( this.cols != subtractor.cols ) )
+ {
+ throw new ArrayIndexOutOfBoundsException (
+ "Matrix.subtract ( Matrix ): columns and rows not equal" );
+ }
+
+ Matrix new_Matrix = new Matrix ( this );
+
+ for ( int index_row = 0; index_row < this.rows; index_row++ )
+ for ( int index_col = 0; index_col < this.cols; index_col++ )
+ {
+ new_Matrix.data [ index_row ] [ index_col ]
+ -= subtractor.data [ index_row ] [ index_col ];
+ }
+
+ return new_Matrix;
+ }
+
+ public double sum ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ double temp = 0.0;
+
+ for ( int index_row = 0; index_row < this.rows; index_row++ )
+ for ( int index_col = 0; index_col < this.cols; index_col++ )
+ {
+ temp += this.data [ index_row ] [ index_col ];
+ }
+
+ return temp;
+ }
+
+ public Matrix transpose ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ Matrix transposed = new Matrix ( this.cols, this.rows );
+
+ for ( int index_row = 0;
+ index_row < transposed.rows;
+ index_row++ )
+ for ( int index_col = 0;
+ index_col < transposed.cols;
+ index_col++ )
+ {
+ transposed.data [ index_row ] [ index_col ]
+ = this.data [ index_col ] [ index_row ];
+ }
+
+ return transposed;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/math/Point2D.java b/src/main/java/com/croftsfot/core/math/Point2D.java
new file mode 100644
index 0000000..c707d31
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/Point2D.java
@@ -0,0 +1,75 @@
+ package com.croftsoft.core.math;
+
+ import java.io.Serializable;
+
+ /*********************************************************************
+ * A point in the standard Cartesian coordinate system using doubles.
+ *
+ *
+ * This positive x-axis is to the right and the positive y-axis is up.
+ *
+ *
+ * @version
+ * 2003-03-20
+ *
+ * @since
+ * 1998-05-29
+ *
+ * @author
+ * David Wallace Croft
+ *
+ * @deprecated
+ * Use Point2DD or java.awt.geom.Point2D.Double instead.
+ *********************************************************************/
+
+ public final class Point2D
+ implements Serializable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private static final long serialVersionUID = 0L;
+
+ //
+
+ public double x;
+
+ public double y;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public Point2D (
+ double x,
+ double y )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this.x = x;
+
+ this.y = y;
+ }
+
+ public Point2D ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this ( 0.0, 0.0 );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * The angle, in radians, from this point to the target point.
+ * Note that the direction of 0 radians is along the positive x-axis
+ * and PI/2 radians is along the positive y-axis.
+ *********************************************************************/
+ public double angleTo ( Point2D target )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return Math.atan2 ( target.y - this.y, target.x - this.x );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
+
diff --git a/src/main/java/com/croftsfot/core/math/Point3d.java b/src/main/java/com/croftsfot/core/math/Point3d.java
new file mode 100644
index 0000000..3ef3500
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/Point3d.java
@@ -0,0 +1,150 @@
+ package com.croftsoft.core.math;
+
+ import java.io.Serializable;
+
+ /*********************************************************************
+ * A mutable point in three-dimensional real space (x, y, and z).
+ *
+ * @version
+ * 2003-03-30
+ * @since
+ * 2002-02-06
+ * @author
+ * David Wallace Croft
+ * @deprecated
+ * Use Point3DD instead.
+ *********************************************************************/
+
+ public final class Point3d
+ implements Cloneable, Serializable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private static final long serialVersionUID = 1L;
+
+ private double x;
+
+ private double y;
+
+ private double z;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public static boolean equivalent (
+ Point3d aPoint3d,
+ Point3d bPoint3d )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( aPoint3d == null )
+ {
+ return bPoint3d == null;
+ }
+ else
+ {
+ return aPoint3d.equals ( bPoint3d );
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public Point3d (
+ double x,
+ double y,
+ double z )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this.x = x;
+
+ this.y = y;
+
+ this.z = z;
+ }
+
+ public Point3d ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this ( 0.0, 0.0, 0.0 );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public double getX ( ) { return x; }
+
+ public double getY ( ) { return y; }
+
+ public double getZ ( ) { return z; }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public void setX ( double x ) { this.x = x; }
+
+ public void setY ( double y ) { this.y = y; }
+
+ public void setZ ( double z ) { this.z = z; }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public boolean equals ( Object other )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( other == null )
+ {
+ return false;
+ }
+
+ if ( !this.getClass ( ).equals ( other.getClass ( ) ) )
+ {
+ return false;
+ }
+
+ Point3d that = ( Point3d ) other;
+
+ return ( this.x == that.x )
+ && ( this.y == that.y )
+ && ( this.z == that.z );
+ }
+
+ public int hashCode ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ // This might be a poor choice for a hash code algorithm.
+
+ return new Double ( x ).hashCode ( )
+ ^ new Double ( y ).hashCode ( )
+ ^ new Double ( z ).hashCode ( );
+ }
+
+ public Object clone ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ return super.clone ( );
+ }
+ catch ( CloneNotSupportedException ex )
+ {
+ // This will never happen.
+
+ throw new RuntimeException ( );
+ }
+ }
+
+ public String toString ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return ""
+ + "" + x + ""
+ + "" + y + ""
+ + "" + z + ""
+ + "";
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/math/RandomLib.java b/src/main/java/com/croftsfot/core/math/RandomLib.java
new file mode 100644
index 0000000..e748c5e
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/RandomLib.java
@@ -0,0 +1,130 @@
+ package com.croftsoft.core.math;
+
+ import java.util.Random;
+
+ /*********************************************************************
+ * Random number generation methods.
+ *
+ * @version
+ * 2003-04-21
+ * @since
+ * 1999-01-31
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public class RandomLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ /** Seeded off of the current time. */
+ private static Random random = new Random ( );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * Test method; prints roll(arg0, arg1, arg2).
+ *********************************************************************/
+ public static void main ( String [ ] args )
+ //////////////////////////////////////////////////////////////////////
+ {
+ long multiplier = Long.parseLong ( args [ 0 ] );
+
+ long base = Long.parseLong ( args [ 1 ] );
+
+ long offset = Long.parseLong ( args [ 2 ] );
+
+ System.out.println ( roll ( multiplier, base, offset ) );
+ }
+
+ /*********************************************************************
+ * Returns a long between 0 (inclusive) and n (exclusive).
+ *
+ * @throws IllegalArgumentException
+ *
+ * If n is negative.
+ *********************************************************************/
+ public static long nextLong ( long n )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( n < 0 )
+ {
+ throw new IllegalArgumentException ( "negative n: " + n );
+ }
+
+ // Suppose n = 9.
+ // Numbers to be generated are 0 to 8 inclusive.
+ // Suppose Long.MAX_VALUE is 22.
+ // Factor is then 22/9 = 2.
+ // Max is then 2*9 = 18.
+ // Rolling will generate numbers between 0 and 17.
+ // Returned values will be between 0 and 8 inclusive.
+
+ long factor = Long.MAX_VALUE / n;
+
+ long max = factor * n;
+
+ long roll = -1;
+
+ while ( ( roll < 0 )
+ || ( roll >= max ) )
+ {
+ roll = random.nextLong ( );
+ }
+
+ return roll % n;
+ }
+
+ /*********************************************************************
+ * Rolls an n-sided die a specified number of times and adds an offset.
+ * For example, to roll a 6-sided die 3 times and add 4 (3d6+4),
+ * the multiplier would be 3, the base 6, and the offset 4.
+ *
+ * @param multiplier
+ * The number of times to roll the die. Must be non-negative.
+ * @param base
+ * The number of sides on the die, e.g., six.
+ * @param offset
+ * A final adjustment to add to the sum after all rolls have been
+ * made.
+ * @return
+ * Returns the sum of the rolls plus the offset.
+ * The overflow condition is not handled.
+ *********************************************************************/
+ public static long roll (
+ long multiplier,
+ long base,
+ long offset )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( multiplier < 0 )
+ {
+ throw new IllegalArgumentException (
+ "negative multiplier: " + multiplier );
+ }
+
+ long sum = 0;
+
+ for ( long i = 0; i < multiplier; i++ )
+ {
+ sum += nextLong ( base ) + 1;
+ }
+
+ return sum + offset;
+ }
+
+ /*********************************************************************
+ * Returns a double uniformly distributed between min (inclusive) and
+ * max (exclusive).
+ *********************************************************************/
+ public static double uniform ( double min, double max )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return min + ( max - min ) * random.nextDouble ( );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/math/axis/AxisAngle.java b/src/main/java/com/croftsfot/core/math/axis/AxisAngle.java
new file mode 100644
index 0000000..e476583
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/axis/AxisAngle.java
@@ -0,0 +1,50 @@
+ package com.croftsoft.core.math.axis;
+
+ import com.croftsoft.core.math.matrix.Matrix3x3Mut;
+ import com.croftsoft.core.math.quat.QuatMut;
+
+ /***********************************************************************
+ * Accessor interface for an axis-angle.
+ *
+ * @version
+ * $Id: AxisAngle.java,v 1.1 2008/05/09 18:35:55 croft Exp $
+ * @since
+ * 2008-05-09
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public interface AxisAngle
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ // accessor methods
+
+ double getDegrees ( );
+
+ double getX ( );
+
+ double getY ( );
+
+ double getZ ( );
+
+ // operand methods
+
+ boolean matches ( AxisAngle axisAngle );
+
+ boolean matches (
+ AxisAngle axisAngle,
+ double tolerance );
+
+ // calculation methods
+
+ double magnitude ( );
+
+ Matrix3x3Mut toRotationMatrix ( );
+
+ QuatMut toQuat ( );
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/axis/AxisAngleImp.java b/src/main/java/com/croftsfot/core/math/axis/AxisAngleImp.java
new file mode 100644
index 0000000..a00619e
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/axis/AxisAngleImp.java
@@ -0,0 +1,152 @@
+ package com.croftsoft.core.math.axis;
+
+ import com.croftsoft.core.math.matrix.Matrix3x3Mut;
+ import com.croftsoft.core.math.quat.QuatMut;
+
+ /***********************************************************************
+ * Implementation of interface AxisAngleMut.
+ *
+ * @version
+ * $Id: AxisAngleImp.java,v 1.2 2008/05/09 20:39:38 croft Exp $
+ * @since
+ * 2008-05-09
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public final class AxisAngleImp
+ implements AxisAngleMut
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ private double degrees, x, y, z;
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+
+ public AxisAngleImp (
+ final double degrees,
+ final double x,
+ final double y,
+ final double z )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ this.degrees = degrees;
+
+ this.x = x;
+
+ this.y = y;
+
+ this.z = z;
+ }
+
+ public AxisAngleImp ( final AxisAngle axisAngle )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ copy ( axisAngle );
+ }
+
+ public AxisAngleImp ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ this ( 0, 1, 0, 0 );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // accessor methods
+ ////////////////////////////////////////////////////////////////////////
+
+ public double getDegrees ( ) { return degrees; }
+
+ public double getX ( ) { return x; }
+
+ public double getY ( ) { return y; }
+
+ public double getZ ( ) { return z; }
+
+ ////////////////////////////////////////////////////////////////////////
+ // mutator methods
+ ////////////////////////////////////////////////////////////////////////
+
+ public void copy ( final AxisAngle axisAngle )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ degrees = axisAngle.getDegrees ( );
+
+ x = axisAngle.getX ( );
+
+ y = axisAngle.getY ( );
+
+ z = axisAngle.getZ ( );
+ }
+
+ public void normalize ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ AxisAngleLib.normalize ( this );
+ }
+
+ public void setDegrees ( final double degrees )
+ { this.degrees = degrees; }
+
+ public void setX ( final double x ) { this.x = x; }
+
+ public void setY ( final double y ) { this.y = y; }
+
+ public void setZ ( final double z ) { this.z = z; }
+
+ ////////////////////////////////////////////////////////////////////////
+ // operand methods
+ ////////////////////////////////////////////////////////////////////////
+
+ public boolean matches ( final AxisAngle axisAngle )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return AxisAngleLib.matches ( this, axisAngle );
+ }
+
+ public boolean matches (
+ final AxisAngle axisAngle,
+ final double tolerance )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return AxisAngleLib.matches ( this, axisAngle, tolerance );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // calculation methods
+ ////////////////////////////////////////////////////////////////////////
+
+ public double magnitude ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return AxisAngleLib.magnitude ( this );
+ }
+
+ public QuatMut toQuat ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return AxisAngleLib.toQuat ( this );
+ }
+
+ public Matrix3x3Mut toRotationMatrix ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return AxisAngleLib.toRotationMatrix ( this );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // overridden Object methods
+ ////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public String toString ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return AxisAngleLib.toString ( this );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/axis/AxisAngleLib.java b/src/main/java/com/croftsfot/core/math/axis/AxisAngleLib.java
new file mode 100644
index 0000000..32c8e6f
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/axis/AxisAngleLib.java
@@ -0,0 +1,154 @@
+ package com.croftsoft.core.math.axis;
+
+ import com.croftsoft.core.math.matrix.Matrix3x3Imp;
+ import com.croftsoft.core.math.matrix.Matrix3x3Mut;
+ import com.croftsoft.core.math.quat.QuatImp;
+ import com.croftsoft.core.math.quat.QuatMut;
+
+ /***********************************************************************
+ * A library of static methods to manipulate AxisAngle objects.
+ *
+ * @version
+ * $Id: AxisAngleLib.java,v 1.1 2008/05/09 18:35:55 croft Exp $
+ * @since
+ * 2008-05-09
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public final class AxisAngleLib
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ public static double magnitude ( final AxisAngle axisAngle )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final double x = axisAngle.getX ( );
+
+ final double y = axisAngle.getY ( );
+
+ final double z = axisAngle.getZ ( );
+
+ return Math.sqrt ( x * x + y * y + z * z );
+ }
+
+ public static boolean matches (
+ final AxisAngle axisAngle0,
+ final AxisAngle axisAngle1 )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return axisAngle0.getDegrees ( ) == axisAngle1.getDegrees ( )
+ && axisAngle0.getX ( ) == axisAngle1.getX ( )
+ && axisAngle0.getY ( ) == axisAngle1.getY ( )
+ && axisAngle0.getZ ( ) == axisAngle1.getZ ( );
+ }
+
+ public static boolean matches (
+ final AxisAngle axisAngle0,
+ final AxisAngle axisAngle1,
+ final double tolerance )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ if ( tolerance < 0 )
+ {
+ throw new IllegalArgumentException ( "tolerance < 0" );
+ }
+
+ return Math.abs (
+ axisAngle0.getDegrees ( ) - axisAngle1.getDegrees ( ) )
+ <= tolerance
+ && Math.abs ( axisAngle0.getX ( ) - axisAngle1.getX ( ) )
+ <= tolerance
+ && Math.abs ( axisAngle0.getY ( ) - axisAngle1.getY ( ) )
+ <= tolerance
+ && Math.abs ( axisAngle0.getZ ( ) - axisAngle1.getZ ( ) )
+ <= tolerance;
+ }
+
+ public static void normalize ( final AxisAngleMut axisAngleMut )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final double magnitude = axisAngleMut.magnitude ( );
+
+ axisAngleMut.setX ( axisAngleMut.getX ( ) / magnitude );
+
+ axisAngleMut.setY ( axisAngleMut.getY ( ) / magnitude );
+
+ axisAngleMut.setZ ( axisAngleMut.getZ ( ) / magnitude );
+ }
+
+ public static QuatMut toQuat ( final AxisAngle axisAngle )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final double halfRadians
+ = Math.toRadians ( axisAngle.getDegrees ( ) / 2 );
+
+ final double sinHalfRadians = Math.sin ( halfRadians );
+
+ return new QuatImp (
+ Math.cos ( halfRadians ),
+ sinHalfRadians * axisAngle.getX ( ),
+ sinHalfRadians * axisAngle.getY ( ),
+ sinHalfRadians * axisAngle.getZ ( ) );
+ }
+
+ public static Matrix3x3Mut toRotationMatrix (
+ final AxisAngle axisAngle )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ // return toQuat ( axisAngle ).toRotationMatrix ( );
+
+ final double degrees = axisAngle.getDegrees ( );
+
+ final double x = axisAngle.getX ( );
+
+ final double y = axisAngle.getY ( );
+
+ final double z = axisAngle.getZ ( );
+
+ final double c = Math.cos ( Math.toRadians ( degrees ) );
+
+ final double s = Math.sin ( Math.toRadians ( degrees ) );
+
+ // Lengyel, "Mathematics for 3D Game Programming & Computer Graphics",
+ // Second Edition, p80, equation 3.22.
+
+ return new Matrix3x3Imp (
+ c + ( 1 - c ) * x * x,
+ ( 1 - c ) * x * y - s * z,
+ ( 1 - c ) * x * z + s * y,
+
+ ( 1 - c ) * x * y + s * z,
+ c + ( 1 - c ) * y * y,
+ ( 1 - c ) * y * z - s * x,
+
+ ( 1 - c ) * x * z - s * y,
+ ( 1 - c ) * y * z + s * x,
+ c + ( 1 - c ) * z * z );
+ }
+
+ public static String toString ( final AxisAngle axisAngle )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return String.format (
+ "%1$1.3f; %2$1.3f, %3$1.3f, %4$1.3f",
+ new Double ( axisAngle.getDegrees ( ) ),
+ new Double ( axisAngle.getX ( ) ),
+ new Double ( axisAngle.getY ( ) ),
+ new Double ( axisAngle.getZ ( ) ) );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // private methods
+ ////////////////////////////////////////////////////////////////////////
+
+ private AxisAngleLib ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ // empty
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/axis/AxisAngleMut.java b/src/main/java/com/croftsfot/core/math/axis/AxisAngleMut.java
new file mode 100644
index 0000000..ea220ef
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/axis/AxisAngleMut.java
@@ -0,0 +1,34 @@
+ package com.croftsoft.core.math.axis;
+
+ /***********************************************************************
+ * A mutator interface for an AxisAngle.
+ *
+ * @version
+ * $Id: AxisAngleMut.java,v 1.1 2008/05/09 18:35:55 croft Exp $
+ * @since
+ * 2008-05-09
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public interface AxisAngleMut
+ extends AxisAngle
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ void copy ( AxisAngle axisAngle );
+
+ void normalize ( );
+
+ void setDegrees ( double degrees );
+
+ void setX ( double x );
+
+ void setY ( double y );
+
+ void setZ ( double z );
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/axis/AxisAngleTest.java b/src/main/java/com/croftsfot/core/math/axis/AxisAngleTest.java
new file mode 100644
index 0000000..fa5bf13
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/axis/AxisAngleTest.java
@@ -0,0 +1,72 @@
+ package com.croftsoft.core.math.axis;
+
+ import com.croftsoft.core.math.matrix.Matrix3x3;
+
+ /***********************************************************************
+ * AxisAngle test methods.
+ *
+ * @version
+ * $Id: AxisAngleTest.java,v 1.2 2008/09/20 04:12:46 croft Exp $
+ * @since
+ * 2008-05-09
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public final class AxisAngleTest
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ public static void main ( final String [ ] args )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ System.out.println ( test ( ) );
+ }
+
+ public static boolean test ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return testToRotationMatrix ( );
+ }
+
+ public static boolean testToRotationMatrix ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return testToRotationMatrix ( new AxisAngleImp ( 0, 1, 0, 0 ) )
+ && testToRotationMatrix ( new AxisAngleImp ( 180, 0, 1, 0 ) )
+ && testToRotationMatrix ( new AxisAngleImp ( 90, 0, 0, 1 ) )
+ && testToRotationMatrix ( new AxisAngleImp ( 37, 1, 0, 0 ) )
+ && testToRotationMatrix ( new AxisAngleImp ( 37, 0, 1, 0 ) )
+ && testToRotationMatrix ( new AxisAngleImp ( 37, 0, 0, 1 ) );
+ }
+
+ public static boolean testToRotationMatrix (
+ final AxisAngle axisAngle )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final Matrix3x3 rotationMatrix0 = axisAngle.toRotationMatrix ( );
+
+ final Matrix3x3 rotationMatrix1
+ = axisAngle.toQuat ( ).toRotationMatrix ( );
+
+ System.out.println ( rotationMatrix0.toString ( ) );
+
+ System.out.println ( rotationMatrix1.toString ( ) );
+
+ return rotationMatrix0.matches ( rotationMatrix1, 0.001 );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // private methods
+ ////////////////////////////////////////////////////////////////////////
+
+ private AxisAngleTest ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ // empty
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/axis/package.html b/src/main/java/com/croftsfot/core/math/axis/package.html
new file mode 100644
index 0000000..cf7514e
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/axis/package.html
@@ -0,0 +1,5 @@
+
+
+Axis-angle (used in 3D graphics).
+
+
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/geom/Circle.java b/src/main/java/com/croftsfot/core/math/geom/Circle.java
new file mode 100644
index 0000000..bf5a5ae
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/geom/Circle.java
@@ -0,0 +1,205 @@
+ package com.croftsoft.core.math.geom;
+
+ import java.awt.*;
+ import java.awt.geom.*;
+ import java.io.*;
+
+ /*********************************************************************
+ * A circle Shape.
+ *
+ * Currently extends Ellipse2D.Double as an implementation convenience
+ * but this may change in the future.
+ *
+ * @version
+ * 2003-05-13
+ * @since
+ * 2003-04-13
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public class Circle
+ extends Ellipse2D.Double
+ implements CircleAccessor, Serializable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private static final long serialVersionUID = 0L;
+
+ //
+
+ private final Point2DD center;
+
+ //
+
+ private double radius;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public Circle (
+ double centerX,
+ double centerY,
+ double radius )
+ //////////////////////////////////////////////////////////////////////
+ {
+ center = new Point2DD ( centerX, centerY );
+
+ setRadius ( radius );
+ }
+
+ public Circle ( CircleAccessor circleAccessor )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this (
+ circleAccessor.getCenterX ( ),
+ circleAccessor.getCenterY ( ),
+ circleAccessor.getRadius ( ) );
+ }
+
+ public Circle ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this ( 0.0, 0.0, 0.0 );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // accessor methods
+ //////////////////////////////////////////////////////////////////////
+
+ public PointXY getCenter ( ) { return center; }
+
+ public double getCenterX ( ) { return center.x; }
+
+ public double getCenterY ( ) { return center.y; }
+
+ public double getRadius ( ) { return radius; }
+
+ //////////////////////////////////////////////////////////////////////
+ // mutator methods
+ //////////////////////////////////////////////////////////////////////
+
+ public void setCenter (
+ double centerX,
+ double centerY )
+ //////////////////////////////////////////////////////////////////////
+ {
+ center.setXY ( centerX, centerY );
+
+ x = center.x - radius;
+
+ y = center.y - radius;
+ }
+
+ public void setCenter ( PointXY pointXY )
+ //////////////////////////////////////////////////////////////////////
+ {
+ setCenter ( pointXY.getX ( ), pointXY.getY ( ) );
+ }
+
+ public void setRadius ( double radius )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( radius < 0.0 )
+ {
+ throw new IllegalArgumentException ( "radius < 0.0: " + radius );
+ }
+
+ this.radius = radius;
+
+ x = center.x - radius;
+
+ y = center.y - radius;
+
+ width = 2 * radius;
+
+ height = 2 * radius;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // overridden Ellipse2D.Double methods
+ //////////////////////////////////////////////////////////////////////
+
+ public boolean contains (
+ double x,
+ double y )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return center.distance ( x, y ) <= radius;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public boolean intersectsCircle ( CircleAccessor circleAccessor )
+ //////////////////////////////////////////////////////////////////////
+ {
+ double distance
+ = center.distanceXY ( circleAccessor.getCenter ( ) );
+
+ return distance <= radius + circleAccessor.getRadius ( );
+ }
+
+ public boolean intersectsShape ( Shape shape )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( shape instanceof CircleAccessor )
+ {
+ return intersectsCircle ( ( CircleAccessor ) shape );
+ }
+
+ if ( radius == 0.0 )
+ {
+ return shape.contains ( center.x, center.y );
+ }
+
+ return intersects ( shape.getBounds2D ( ) );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public String toString ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return "(" + center.x + "," + center.y + "," + radius + ")";
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // private serialization methods
+ //////////////////////////////////////////////////////////////////////
+
+ private void writeObject ( ObjectOutputStream objectOutputStream )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ objectOutputStream.defaultWriteObject ( );
+
+ objectOutputStream.writeDouble ( x );
+
+ objectOutputStream.writeDouble ( y );
+
+ objectOutputStream.writeDouble ( width );
+
+ objectOutputStream.writeDouble ( height );
+ }
+
+ private void readObject ( ObjectInputStream objectInputStream )
+ throws IOException, ClassNotFoundException
+ //////////////////////////////////////////////////////////////////////
+ {
+ objectInputStream.defaultReadObject ( );
+
+ x = objectInputStream.readDouble ( );
+
+ y = objectInputStream.readDouble ( );
+
+ width = objectInputStream.readDouble ( );
+
+ height = objectInputStream.readDouble ( );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/geom/CircleAccessor.java b/src/main/java/com/croftsfot/core/math/geom/CircleAccessor.java
new file mode 100644
index 0000000..802f932
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/geom/CircleAccessor.java
@@ -0,0 +1,39 @@
+ package com.croftsoft.core.math.geom;
+
+ import java.awt.Shape;
+
+ /*********************************************************************
+ * A read-only accessor interface for a Circle.
+ *
+ * @version
+ * 2003-04-17
+ * @since
+ * 2003-04-17
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface CircleAccessor
+ extends Shape
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public PointXY getCenter ( );
+
+ public double getCenterX ( );
+
+ public double getCenterY ( );
+
+ public double getRadius ( );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public boolean intersectsCircle ( CircleAccessor circleAccessor );
+
+ public boolean intersectsShape ( Shape shape );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/geom/Point2DD.java b/src/main/java/com/croftsfot/core/math/geom/Point2DD.java
new file mode 100644
index 0000000..7fcc93f
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/geom/Point2DD.java
@@ -0,0 +1,196 @@
+ package com.croftsoft.core.math.geom;
+
+ import java.awt.Point;
+ import java.awt.geom.Point2D;
+ import java.io.*;
+
+ import com.croftsoft.core.io.SerializableLib;
+ import com.croftsoft.core.lang.Testable;
+
+ /*********************************************************************
+ * A Point2D.Double extension implementing accessor interface PointXY.
+ *
+ * @version
+ * 2003-04-13
+ *
+ * @since
+ * 2003-03-20
+ *
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public class Point2DD
+ extends Point2D.Double
+ implements PointXY, Serializable, Testable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private static final long serialVersionUID = 0L;
+
+ //////////////////////////////////////////////////////////////////////
+ // static unit test methods
+ //////////////////////////////////////////////////////////////////////
+
+ public static void main ( String [ ] args )
+ //////////////////////////////////////////////////////////////////////
+ {
+ System.out.println ( test ( args ) );
+ }
+
+ public static boolean test ( String [ ] args )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ Point2DD point2DD1 = new Point2DD ( 0, 1 );
+
+ byte [ ] bytes = SerializableLib.compress ( point2DD1 );
+
+ Point2DD point2DD2 = ( Point2DD ) SerializableLib.load (
+ new ByteArrayInputStream ( bytes ) );
+
+ System.out.println ( point2DD2 );
+
+ return point2DD2.equals ( point2DD1 );
+ }
+ catch ( Exception ex )
+ {
+ ex.printStackTrace ( );
+
+ return false;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // constructor methods
+ //////////////////////////////////////////////////////////////////////
+
+ public Point2DD (
+ double x,
+ double y )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this.x = x;
+
+ this.y = y;
+ }
+
+ public Point2DD ( PointXY pointXY )
+ //////////////////////////////////////////////////////////////////////
+ {
+ x = pointXY.getX ( );
+
+ y = pointXY.getY ( );
+ }
+
+ public Point2DD ( Point2D point2D )
+ //////////////////////////////////////////////////////////////////////
+ {
+ x = point2D.getX ( );
+
+ y = point2D.getY ( );
+ }
+
+ public Point2DD ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // mutator methods
+ //////////////////////////////////////////////////////////////////////
+
+ public void setX ( double x ) { this.x = x; }
+
+ public void setY ( double y ) { this.y = y; }
+
+ public void setXY ( PointXY pointXY )
+ //////////////////////////////////////////////////////////////////////
+ {
+ x = pointXY.getX ( );
+
+ y = pointXY.getY ( );
+ }
+
+ public void setXY (
+ double x,
+ double y )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this.x = x;
+
+ this.y = y;
+ }
+
+ public void setXY ( Point point )
+ //////////////////////////////////////////////////////////////////////
+ {
+ x = point.x;
+
+ y = point.y;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // math methods
+ //////////////////////////////////////////////////////////////////////
+
+ /*********************************************************************
+ * The angle, in radians, from this point to the other point.
+ * Note that the direction of 0 radians is along the positive x-axis
+ * and PI/2 radians is along the positive y-axis.
+ *********************************************************************/
+ public double angleTo ( PointXY otherPointXY )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return Math.atan2 (
+ otherPointXY.getY ( ) - y,
+ otherPointXY.getX ( ) - x );
+ }
+
+ public double distanceXY ( PointXY otherPointXY )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return distance ( otherPointXY.getX ( ), otherPointXY.getY ( ) );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // overridden Object methods
+ //////////////////////////////////////////////////////////////////////
+
+ public String toString ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return "(" + x + "," + y + ")";
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // private serialization methods
+ //////////////////////////////////////////////////////////////////////
+
+ private void writeObject ( ObjectOutputStream objectOutputStream )
+ throws IOException
+ //////////////////////////////////////////////////////////////////////
+ {
+ objectOutputStream.defaultWriteObject ( );
+
+ objectOutputStream.writeDouble ( x );
+
+ objectOutputStream.writeDouble ( y );
+ }
+
+ private void readObject ( ObjectInputStream objectInputStream )
+ throws IOException, ClassNotFoundException
+ //////////////////////////////////////////////////////////////////////
+ {
+ objectInputStream.defaultReadObject ( );
+
+ x = objectInputStream.readDouble ( );
+
+ y = objectInputStream.readDouble ( );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/geom/Point3DD.java b/src/main/java/com/croftsfot/core/math/geom/Point3DD.java
new file mode 100644
index 0000000..f6196c8
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/geom/Point3DD.java
@@ -0,0 +1,174 @@
+ package com.croftsoft.core.math.geom;
+
+ import java.io.*;
+
+ import com.croftsoft.core.io.SerializableLib;
+ import com.croftsoft.core.lang.NullArgumentException;
+ import com.croftsoft.core.lang.Testable;
+
+ /*********************************************************************
+ * A mutable point in three-dimensional real space (x, y, z).
+ *
+ * @version
+ * 2003-04-13
+ * @since
+ * 2002-02-06
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public class Point3DD
+ extends Point2DD
+ implements PointXYZ, Cloneable, Serializable, Testable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private static final long serialVersionUID = 0L;
+
+ //
+
+ public double z;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public static void main ( String [ ] args )
+ //////////////////////////////////////////////////////////////////////
+ {
+ System.out.println ( test ( args ) );
+ }
+
+ public static boolean test ( String [ ] args )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ Point3DD point3DD1 = new Point3DD ( 0, 1, 2 );
+
+ byte [ ] bytes = SerializableLib.compress ( point3DD1 );
+
+ Point3DD point3DD2 = ( Point3DD ) SerializableLib.load (
+ new ByteArrayInputStream ( bytes ) );
+
+ System.out.println ( point3DD2 );
+
+ return point3DD2.equals ( point3DD1 )
+ && point3DD1.equals ( ( Point3DD ) point3DD1.clone ( ) );
+ }
+ catch ( Exception ex )
+ {
+ ex.printStackTrace ( );
+
+ return false;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public Point3DD (
+ double x,
+ double y,
+ double z )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this.x = x;
+
+ this.y = y;
+
+ this.z = z;
+ }
+
+ public Point3DD ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ }
+
+ public Point3DD ( PointXYZ pointXYZ )
+ //////////////////////////////////////////////////////////////////////
+ {
+ NullArgumentException.check ( pointXYZ );
+
+ x = pointXYZ.getX ( );
+
+ y = pointXYZ.getY ( );
+
+ z = pointXYZ.getZ ( );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public double getZ ( ) { return z; }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public void setXYZ (
+ double x,
+ double y,
+ double z )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this.x = x;
+
+ this.y = y;
+
+ this.z = z;
+ }
+
+ public void setXYZ ( PointXYZ pointXYZ )
+ //////////////////////////////////////////////////////////////////////
+ {
+ x = pointXYZ.getX ( );
+
+ y = pointXYZ.getY ( );
+
+ z = pointXYZ.getZ ( );
+ }
+
+ public void setZ ( double z ) { this.z = z; }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public boolean equals ( Object other )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( other == null )
+ {
+ return false;
+ }
+
+ if ( !other.getClass ( ).equals ( Point3DD.class ) )
+ {
+ return false;
+ }
+
+ Point3DD that = ( Point3DD ) other;
+
+ return ( this.x == that.x )
+ && ( this.y == that.y )
+ && ( this.z == that.z );
+ }
+
+ public int hashCode ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ // This might be a poor choice for a hash code algorithm.
+
+ return new java.lang.Double ( x ).hashCode ( )
+ ^ new java.lang.Double ( y ).hashCode ( )
+ ^ new java.lang.Double ( z ).hashCode ( );
+ }
+
+ public String toString ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return "(" + x + "," + y + "," + z + ")";
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/math/geom/Point3DI.java b/src/main/java/com/croftsfot/core/math/geom/Point3DI.java
new file mode 100644
index 0000000..b6c2fc7
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/geom/Point3DI.java
@@ -0,0 +1,150 @@
+ package com.croftsoft.core.math.geom;
+
+ import java.io.Serializable;
+
+ /*********************************************************************
+ * A mutable point in three-dimensional integer space (x, y, and z).
+ *
+ * @version
+ * $Id: Point3DI.java,v 1.3 2008/09/20 02:51:51 croft Exp $
+ * @since
+ * 2001-03-07
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class Point3DI
+ implements Cloneable, Serializable
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ private static final long serialVersionUID = 0L;
+
+ //
+
+ private int x;
+
+ private int y;
+
+ private int z;
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public static boolean equivalent (
+ Point3DI aPoint3DI,
+ Point3DI bPoint3DI )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( aPoint3DI == null )
+ {
+ return bPoint3DI == null;
+ }
+
+ return aPoint3DI.equals ( bPoint3DI );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public Point3DI (
+ int x,
+ int y,
+ int z )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this.x = x;
+
+ this.y = y;
+
+ this.z = z;
+ }
+
+ public Point3DI ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ this ( 0, 0, 0 );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public int getX ( ) { return x; }
+
+ public int getY ( ) { return y; }
+
+ public int getZ ( ) { return z; }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ public void setX ( int x ) { this.x = x; }
+
+ public void setY ( int y ) { this.y = y; }
+
+ public void setZ ( int z ) { this.z = z; }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ @Override
+ public boolean equals ( Object other )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( other == null )
+ {
+ return false;
+ }
+
+ if ( !this.getClass ( ).equals ( other.getClass ( ) ) )
+ {
+ return false;
+ }
+
+ Point3DI that = ( Point3DI ) other;
+
+ return ( this.x == that.x )
+ && ( this.y == that.y )
+ && ( this.z == that.z );
+ }
+
+ @Override
+ public int hashCode ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ // This might be a poor choice for a hash code algorithm.
+
+ return x ^ y ^ z;
+ }
+
+ @Override
+ public Object clone ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ try
+ {
+ return super.clone ( );
+ }
+ catch ( CloneNotSupportedException ex )
+ {
+ // This will never happen.
+
+ throw new RuntimeException ( );
+ }
+ }
+
+ @Override
+ public String toString ( )
+ //////////////////////////////////////////////////////////////////////
+ {
+ return ""
+ + "" + x + ""
+ + "" + y + ""
+ + "" + z + ""
+ + "";
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
diff --git a/src/main/java/com/croftsfot/core/math/geom/PointXY.java b/src/main/java/com/croftsfot/core/math/geom/PointXY.java
new file mode 100644
index 0000000..30ae3ac
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/geom/PointXY.java
@@ -0,0 +1,38 @@
+ package com.croftsoft.core.math.geom;
+
+ /*********************************************************************
+ * A read-only accessor interface for double precision x,y coordinates.
+ *
+ * @version
+ * 2003-04-13
+ *
+ * @since
+ * 2003-03-20
+ *
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface PointXY
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public double getX ( );
+
+ public double getY ( );
+
+ //
+
+ public double angleTo ( PointXY otherPointXY );
+
+ public double distanceXY ( PointXY otherPointXY );
+
+ public double distance (
+ double otherX,
+ double otherY );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
+
diff --git a/src/main/java/com/croftsfot/core/math/geom/PointXYZ.java b/src/main/java/com/croftsfot/core/math/geom/PointXYZ.java
new file mode 100644
index 0000000..e817780
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/geom/PointXYZ.java
@@ -0,0 +1,26 @@
+ package com.croftsoft.core.math.geom;
+
+ /*********************************************************************
+ * A read-only interface for double precision (x,y,z) coordinates.
+ *
+ * @version
+ * 2003-04-13
+ *
+ * @since
+ * 2003-03-30
+ *
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public interface PointXYZ
+ extends PointXY
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public double getZ ( );
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/geom/ShapeLib.java b/src/main/java/com/croftsfot/core/math/geom/ShapeLib.java
new file mode 100644
index 0000000..7fccd03
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/geom/ShapeLib.java
@@ -0,0 +1,74 @@
+ package com.croftsoft.core.math.geom;
+
+ import java.awt.Shape;
+ import java.awt.geom.RectangularShape;
+
+ /*********************************************************************
+ * A static method library for manipulating Shape instances.
+ *
+ * @version
+ * 2003-04-17
+ * @since
+ * 2003-04-13
+ * @author
+ * David Wallace Croft
+ *********************************************************************/
+
+ public final class ShapeLib
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ {
+
+ public static Point2DD getCenter (
+ Shape shape,
+ Point2DD center )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( shape instanceof Circle )
+ {
+ Circle circle = ( Circle ) shape;
+
+ center.setXY ( circle.getCenter ( ) );
+ }
+ else if ( shape instanceof RectangularShape )
+ {
+ RectangularShape rectangularShape = ( RectangularShape ) shape;
+
+ center.setXY (
+ rectangularShape.getCenterX ( ),
+ rectangularShape.getCenterY ( ) );
+ }
+ else
+ {
+ getCenter ( shape.getBounds2D ( ), center );
+ }
+
+ return center;
+ }
+
+ public static boolean intersects (
+ Shape aShape,
+ Shape bShape )
+ //////////////////////////////////////////////////////////////////////
+ {
+ if ( aShape instanceof Circle )
+ {
+ return ( ( Circle ) aShape ).intersectsShape ( bShape );
+ }
+
+ if ( bShape instanceof Circle )
+ {
+ return ( ( Circle ) bShape ).intersectsShape ( aShape );
+ }
+
+ return aShape.intersects ( bShape.getBounds2D ( ) );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+
+ private ShapeLib ( ) { }
+
+ //////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/geom/package.html b/src/main/java/com/croftsfot/core/math/geom/package.html
new file mode 100644
index 0000000..ff516ef
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/geom/package.html
@@ -0,0 +1,5 @@
+
+
+Geometry.
+
+
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/matrix/Matrix.java b/src/main/java/com/croftsfot/core/math/matrix/Matrix.java
new file mode 100644
index 0000000..4ce27f4
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/matrix/Matrix.java
@@ -0,0 +1,45 @@
+ package com.croftsoft.core.math.matrix;
+
+ /***********************************************************************
+ * Accessor interface for a matrix of doubles.
+ *
+ * @version
+ * $Id: Matrix.java,v 1.3 2008/05/09 18:35:55 croft Exp $
+ * @since
+ * 2008-04-25
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public interface Matrix
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ MatrixMut copy ( );
+
+ double get ( int row, int column );
+
+ int getColumnCount ( );
+
+ int getRowCount ( );
+
+ boolean isIdentity ( );
+
+ boolean isSquare ( );
+
+ boolean matches ( Matrix matrix );
+
+ boolean matches (
+ Matrix matrix,
+ double tolerance );
+
+ MatrixMut multiply ( Matrix matrix );
+
+ MatrixMut multiply ( double scalar );
+
+ MatrixMut transpose ( );
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/matrix/Matrix3x3.java b/src/main/java/com/croftsfot/core/math/matrix/Matrix3x3.java
new file mode 100644
index 0000000..260d123
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/matrix/Matrix3x3.java
@@ -0,0 +1,32 @@
+ package com.croftsoft.core.math.matrix;
+
+ /***********************************************************************
+ * Accessor interface for a 3x3 matrix of doubles.
+ *
+ * @version
+ * $Id: Matrix3x3.java,v 1.5 2008/05/09 19:48:45 croft Exp $
+ * @since
+ * 2008-04-25
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public interface Matrix3x3
+ extends Matrix
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ Matrix3x3Mut multiply3x3 ( Matrix3x3 matrix3x3 );
+
+ double [ ] toEulerAngles ( );
+
+ // toAxisAngle()
+
+ // toQuat()
+
+ Matrix3x3Mut transpose3x3 ( );
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/matrix/Matrix3x3Imp.java b/src/main/java/com/croftsfot/core/math/matrix/Matrix3x3Imp.java
new file mode 100644
index 0000000..670d5e8
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/matrix/Matrix3x3Imp.java
@@ -0,0 +1,123 @@
+ package com.croftsoft.core.math.matrix;
+
+ /***********************************************************************
+ * Implementation of interface Matrix3x3Mut.
+ *
+ * @version
+ * $Id: Matrix3x3Imp.java,v 1.5 2008/05/09 19:48:45 croft Exp $
+ * @since
+ * 2008-04-25
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public final class Matrix3x3Imp
+ extends MatrixImp
+ implements Matrix3x3Mut
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ public Matrix3x3Imp ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ super ( 3, 3 );
+ }
+
+ public Matrix3x3Imp ( final Matrix matrix )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ super ( 3, 3 );
+
+ if ( matrix.getRowCount ( ) != 3 )
+ {
+ throw new IllegalArgumentException ( "rowCount != 3" );
+ }
+
+ if ( matrix.getColumnCount ( ) != 3 )
+ {
+ throw new IllegalArgumentException ( "columnCount != 3" );
+ }
+
+ for ( int row = 0; row < 3; row++ )
+ {
+ for ( int column = 0; column < 3; column++ )
+ {
+ set ( row, column, matrix.get ( row, column ) );
+ }
+ }
+ }
+
+ public Matrix3x3Imp ( final double [ ] [ ] values )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ super ( values );
+
+ if ( rowCount != 3 )
+ {
+ throw new IllegalArgumentException ( "rowCount != 3" );
+ }
+
+ if ( columnCount != 3 )
+ {
+ throw new IllegalArgumentException ( "columnCount != 3" );
+ }
+ }
+
+ public Matrix3x3Imp (
+ final double v00,
+ final double v01,
+ final double v02,
+ final double v10,
+ final double v11,
+ final double v12,
+ final double v20,
+ final double v21,
+ final double v22 )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ super ( 3, 3 );
+
+ set ( 0, 0, v00 );
+
+ set ( 0, 1, v01 );
+
+ set ( 0, 2, v02 );
+
+ set ( 1, 0, v10 );
+
+ set ( 1, 1, v11 );
+
+ set ( 1, 2, v12 );
+
+ set ( 2, 0, v20 );
+
+ set ( 2, 1, v21 );
+
+ set ( 2, 2, v22 );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+
+ public Matrix3x3Mut multiply3x3 ( final Matrix3x3 matrix3x3 )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return Matrix3x3Lib.multiply3x3 ( this, matrix3x3 );
+ }
+
+ public double [ ] toEulerAngles ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return Matrix3x3Lib.toEulerAngles ( this );
+ }
+
+ public Matrix3x3Mut transpose3x3 ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return Matrix3x3Lib.transpose3x3 ( this );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/matrix/Matrix3x3Lib.java b/src/main/java/com/croftsfot/core/math/matrix/Matrix3x3Lib.java
new file mode 100644
index 0000000..6f8bc0a
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/matrix/Matrix3x3Lib.java
@@ -0,0 +1,244 @@
+ package com.croftsoft.core.math.matrix;
+
+ /***********************************************************************
+ * A library of static methods to manipulate Matrix3x3 objects.
+ *
+ * @version
+ * $Id: Matrix3x3Lib.java,v 1.8 2008/05/09 19:48:45 croft Exp $
+ * @since
+ * 2008-04-25
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public final class Matrix3x3Lib
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ public static Matrix3x3Mut createRotationMatrix (
+ final double degreesX,
+ final double degreesY,
+ final double degreesZ )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ // Rotation matrices multiplied in this order: R = Rz * Ry * Rx
+
+ final double cx = Math.cos ( Math.toRadians ( degreesX ) );
+
+ final double sx = Math.sin ( Math.toRadians ( degreesX ) );
+
+ final double cy = Math.cos ( Math.toRadians ( degreesY ) );
+
+ final double sy = Math.sin ( Math.toRadians ( degreesY ) );
+
+ final double cz = Math.cos ( Math.toRadians ( degreesZ ) );
+
+ final double sz = Math.sin ( Math.toRadians ( degreesZ ) );
+
+ final Matrix3x3Mut matrix3x3Mut = new Matrix3x3Imp (
+ new double [ ] [ ] {
+ { cy * cz,
+ -cx * sz + sx * sy * cz,
+ sx * sz + cx * sy * cz },
+ { cy * sz,
+ cx * cz + sx * sy * sz,
+ -sx * cz + cx * sy * sz },
+ { -sy,
+ sx * cy,
+ cx * cy } } );
+
+ return matrix3x3Mut;
+ }
+
+ public static Matrix3x3Mut createRotationMatrixX (
+ final double degrees )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final double cos = Math.cos ( Math.toRadians ( degrees ) );
+
+ final double sin = Math.sin ( Math.toRadians ( degrees ) );
+
+ return new Matrix3x3Imp (
+ 1, 0, 0,
+ 0, cos, -sin,
+ 0, sin, cos );
+ }
+
+ public static Matrix3x3Mut createRotationMatrixY (
+ final double degrees )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final double cos = Math.cos ( Math.toRadians ( degrees ) );
+
+ final double sin = Math.sin ( Math.toRadians ( degrees ) );
+
+ return new Matrix3x3Imp (
+ cos, 0, sin,
+ 0, 1, 0,
+ -sin, 0, cos );
+ }
+
+ public static Matrix3x3Mut createRotationMatrixZ (
+ final double degrees )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final double cos = Math.cos ( Math.toRadians ( degrees ) );
+
+ final double sin = Math.sin ( Math.toRadians ( degrees ) );
+
+ return new Matrix3x3Imp (
+ cos, -sin, 0,
+ sin, cos, 0,
+ 0, 0, 1 );
+ }
+
+ public static Matrix3x3Mut multiply3x3 (
+ final Matrix3x3 matrix3x3a,
+ final Matrix3x3 matrix3x3b )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return new Matrix3x3Imp (
+ MatrixLib.multiply ( matrix3x3a, matrix3x3b ) );
+ }
+
+ public static double [ ] toEulerAngles ( final Matrix3x3 matrix3x3 )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ // Adapted from Dunn and Parberry, 3D Math Primer, 2002, page 204.
+
+ double sp = -matrix3x3.get ( 1, 2 );
+
+ double heading = 0.0;
+
+ double pitch = 0.0;
+
+ double bank = 0.0;
+
+ if ( Math.abs ( sp ) > 0.99999 )
+ {
+ heading = Math.atan2 (
+ -matrix3x3.get ( 2, 0 ),
+ matrix3x3.get ( 0, 0 ) );
+
+ pitch = ( Math.PI / 2.0 ) * sp;
+
+ bank = 0.0;
+ }
+ else
+ {
+ heading = Math.atan2 (
+ matrix3x3.get ( 0, 2 ),
+ matrix3x3.get ( 2, 2 ) );
+
+ pitch = Math.asin ( sp );
+
+ bank = Math.atan2 (
+ matrix3x3.get ( 1, 0 ),
+ matrix3x3.get ( 1, 1 ) );
+ }
+
+// final double [ ] canonizedEulerAngles = canonizeEulerAngles (
+// new double [ ] { heading, pitch, bank } );
+
+ // Change order from heading, pitch, bank to x, y, z
+
+ return new double [ ] {
+ Math.toDegrees ( pitch ),
+ Math.toDegrees ( heading ),
+ Math.toDegrees ( bank ) };
+
+// return new double [ ] {
+// Math.toDegrees ( canonizedEulerAngles [ 1 ] ),
+// Math.toDegrees ( canonizedEulerAngles [ 0 ] ),
+// Math.toDegrees ( canonizedEulerAngles [ 2 ] ) };
+ }
+
+ public static Matrix3x3Mut transpose3x3 ( final Matrix3x3 matrix3x3 )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return new Matrix3x3Imp (
+ matrix3x3.get ( 0, 0 ),
+ matrix3x3.get ( 1, 0 ),
+ matrix3x3.get ( 2, 0 ),
+ matrix3x3.get ( 0, 1 ),
+ matrix3x3.get ( 1, 1 ),
+ matrix3x3.get ( 2, 1 ),
+ matrix3x3.get ( 0, 2 ),
+ matrix3x3.get ( 1, 2 ),
+ matrix3x3.get ( 2, 2 ) );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // private methods
+ ////////////////////////////////////////////////////////////////////////
+
+// private static double [ ] canonizeEulerAngles (
+// final double [ ] eulerAngles )
+// //////////////////////////////////////////////////////////////////////
+// {
+// // Adapted from Dunn and Parberry, 3D Math Primer, 2002, page 201.
+//
+// double heading = eulerAngles [ 0 ];
+//
+// double pitch = wrapPi ( eulerAngles [ 1 ] );
+//
+// double bank = eulerAngles [ 2 ];
+//
+// if ( pitch < -( Math.PI / 2 ) )
+// {
+// pitch = -Math.PI - pitch;
+//
+// heading += Math.PI;
+//
+// bank += Math.PI;
+// }
+// else if ( pitch > ( Math.PI / 2 ) )
+// {
+// pitch = Math.PI - pitch;
+//
+// heading += Math.PI;
+//
+// bank += Math.PI;
+// }
+//
+// if ( Math.abs ( pitch ) > ( Math.PI / 2 ) - 1e-4 )
+// {
+// heading += bank;
+//
+// bank = 0;
+// }
+// else
+// {
+// bank = wrapPi ( bank );
+// }
+//
+// heading = wrapPi ( heading );
+//
+// return new double [ ] { heading, pitch, bank };
+// }
+//
+// private static double wrapPi ( double theta )
+// //////////////////////////////////////////////////////////////////////
+// {
+// if ( theta > Math.PI )
+// {
+// while ( theta > Math.PI ) theta -= Math.PI;
+// }
+// else if ( theta < -Math.PI )
+// {
+// while ( theta < -Math.PI ) theta += Math.PI;
+// }
+//
+// return theta;
+// }
+
+ private Matrix3x3Lib ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ // empty
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/matrix/Matrix3x3Mut.java b/src/main/java/com/croftsfot/core/math/matrix/Matrix3x3Mut.java
new file mode 100644
index 0000000..1d4676f
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/matrix/Matrix3x3Mut.java
@@ -0,0 +1,22 @@
+ package com.croftsoft.core.math.matrix;
+
+ /***********************************************************************
+ * A mutable 3x3 matrix of doubles.
+ *
+ * @version
+ * $Id: Matrix3x3Mut.java,v 1.1 2008/04/26 02:40:41 croft Exp $
+ * @since
+ * 2008-04-25
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public interface Matrix3x3Mut
+ extends MatrixMut, Matrix3x3
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/matrix/MatrixImp.java b/src/main/java/com/croftsfot/core/math/matrix/MatrixImp.java
new file mode 100644
index 0000000..2991272
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/matrix/MatrixImp.java
@@ -0,0 +1,271 @@
+ package com.croftsoft.core.math.matrix;
+
+ /***********************************************************************
+ * Implementation of interface MatrixMut.
+ *
+ * @version
+ * $Id: MatrixImp.java,v 1.5 2008/05/09 18:35:56 croft Exp $
+ * @since
+ * 2008-04-25
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public class MatrixImp
+ implements MatrixMut
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ protected final int
+ rowCount,
+ columnCount;
+
+ protected final double [ ] [ ] values;
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+
+ public MatrixImp (
+ final int rowCount,
+ final int columnCount )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ if ( rowCount < 1 )
+ {
+ throw new IllegalArgumentException ( "rowCount < 1" );
+ }
+
+ if ( columnCount < 1 )
+ {
+ throw new IllegalArgumentException ( "columnCount < 1" );
+ }
+
+ this.rowCount = rowCount;
+
+ this.columnCount = columnCount;
+
+ values = new double [ rowCount ] [ columnCount ];
+ }
+
+ public MatrixImp ( final Matrix matrix )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ this ( matrix.getRowCount ( ), matrix.getColumnCount ( ) );
+
+ for ( int row = 0; row < rowCount; row++ )
+ {
+ for ( int column = 0; column < columnCount; column++ )
+ {
+ set ( row, column, matrix.get ( row, column ) );
+ }
+ }
+ }
+
+ public MatrixImp ( final double [ ] [ ] values )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ rowCount = values.length;
+
+ columnCount = values [ 0 ].length;
+
+ if ( rowCount < 1 )
+ {
+ throw new IllegalArgumentException ( "rowCount < 1" );
+ }
+
+ if ( columnCount < 1 )
+ {
+ throw new IllegalArgumentException ( "columnCount < 1" );
+ }
+
+ this.values = new double [ rowCount ] [ columnCount ];
+
+ for ( int row = 0; row < rowCount; row++ )
+ {
+ if ( values [ row ].length != columnCount )
+ {
+ throw new IllegalArgumentException (
+ "values[" + row + "].length != values[0].length" );
+ }
+
+ for ( int column = 0; column < columnCount; column++ )
+ {
+
+ this.values [ row ] [ column ] = values [ row ] [ column ];
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // accessor methods
+ ////////////////////////////////////////////////////////////////////////
+
+ public double get (
+ final int row,
+ final int column )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return values [ row ] [ column ];
+ }
+
+ public int getRowCount ( ) { return rowCount; }
+
+ public int getColumnCount ( ) { return columnCount; }
+
+ ////////////////////////////////////////////////////////////////////////
+ // operand methods
+ ////////////////////////////////////////////////////////////////////////
+
+ public boolean isIdentity ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ if ( rowCount != columnCount )
+ {
+ return false;
+ }
+
+ for ( int row = 0; row < rowCount; row++ )
+ {
+ for ( int column = 0; column < columnCount; column++ )
+ {
+ final double value = values [ row ] [ column ];
+
+ if ( row == column )
+ {
+ if ( value != 1 )
+ {
+ return false;
+ }
+ }
+ else if ( value != 0 )
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public boolean isSquare ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return rowCount == columnCount;
+ }
+
+ public boolean matches ( final Matrix matrix )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return MatrixLib.matches ( this, matrix );
+ }
+
+ public boolean matches (
+ final Matrix matrix,
+ final double tolerance )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return MatrixLib.matches ( this, matrix, tolerance );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+
+ public MatrixMut copy ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return new MatrixImp ( this );
+ }
+
+ public MatrixMut multiply ( final Matrix matrix )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return MatrixLib.multiply ( this, matrix );
+ }
+
+ public MatrixMut multiply ( final double scalar )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return MatrixLib.multiply ( this, scalar );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // mutator methods
+ ////////////////////////////////////////////////////////////////////////
+
+ public void copyToSelf ( final Matrix copy )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ MatrixLib.copyToSelf ( this, copy );
+ }
+
+ public void multiplyToSelf ( final double scalar )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ for ( int row = 0; row < rowCount; row++ )
+ {
+ for ( int column = 0; column < columnCount; column++ )
+ {
+ values [ row ] [ column ] = values [ row ] [ column ] * scalar;
+ }
+ }
+ }
+
+ public void multiplyToSelf ( final Matrix matrix )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ MatrixLib.multiplyToSelf ( this, matrix );
+ }
+
+ public void set (
+ final int row,
+ final int column,
+ final double value )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ values [ row ] [ column ] = value;
+ }
+
+ public void setIdentity ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ if ( rowCount != columnCount )
+ {
+ throw new IllegalArgumentException ( "rowCount != columnCount" );
+ }
+
+ for ( int row = 0; row < rowCount; row++ )
+ {
+ for ( int column = 0; column < columnCount; column++ )
+ {
+ values [ row ] [ column ] = row == column ? 1 : 0;
+ }
+ }
+ }
+
+ public MatrixMut transpose ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return MatrixLib.transpose ( this );
+ }
+
+ public void transposeSelf ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ MatrixLib.transposeSelf ( this );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // overridden Object methods
+ ////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public String toString ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return MatrixLib.toString ( this );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/matrix/MatrixLib.java b/src/main/java/com/croftsfot/core/math/matrix/MatrixLib.java
new file mode 100644
index 0000000..9cc6b97
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/matrix/MatrixLib.java
@@ -0,0 +1,292 @@
+ package com.croftsoft.core.math.matrix;
+
+ /***********************************************************************
+ * A library of static methods to manipulate Matrix objects.
+ *
+ * @version
+ * $Id: MatrixLib.java,v 1.4 2008/05/09 18:35:55 croft Exp $
+ * @since
+ * 2008-04-25
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public final class MatrixLib
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ public static void copyToSelf (
+ final MatrixMut matrixMut,
+ final Matrix matrix )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final int rowCount = matrixMut.getRowCount ( );
+
+ final int columnCount = matrixMut.getColumnCount ( );
+
+ if ( rowCount != matrix.getRowCount ( ) )
+ {
+ throw new IllegalArgumentException ( "rowCount not equal" );
+ }
+
+ if ( columnCount != matrix.getColumnCount ( ) )
+ {
+ throw new IllegalArgumentException ( "columnCount not equal" );
+ }
+
+ for ( int row = 0; row < rowCount; row++ )
+ {
+ for ( int column = 0; column < columnCount; column++ )
+ {
+ matrixMut.set ( row, column, matrix.get ( row, column ) );
+ }
+ }
+ }
+
+ public static boolean matches (
+ final Matrix matrix0,
+ final Matrix matrix1 )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final int rowCount = matrix0.getRowCount ( );
+
+ if ( rowCount != matrix1.getRowCount ( ) )
+ {
+ return false;
+ }
+
+ final int columnCount = matrix0.getColumnCount ( );
+
+ if ( columnCount != matrix1.getColumnCount ( ) )
+ {
+ return false;
+ }
+
+ for ( int row = 0; row < rowCount; row++ )
+ {
+ for ( int column = 0; column < columnCount; column++ )
+ {
+ if ( matrix0.get ( row, column ) != matrix1.get ( row, column ) )
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean matches (
+ final Matrix matrix0,
+ final Matrix matrix1,
+ final double tolerance )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ if ( tolerance < 0 )
+ {
+ throw new IllegalArgumentException ( "tolerance < 0" );
+ }
+
+ final int rowCount = matrix0.getRowCount ( );
+
+ if ( rowCount != matrix1.getRowCount ( ) )
+ {
+ return false;
+ }
+
+ final int columnCount = matrix0.getColumnCount ( );
+
+ if ( columnCount != matrix1.getColumnCount ( ) )
+ {
+ return false;
+ }
+
+ for ( int row = 0; row < rowCount; row++ )
+ {
+ for ( int column = 0; column < columnCount; column++ )
+ {
+ if ( Math.abs ( matrix0.get ( row, column )
+ - matrix1.get ( row, column ) ) > tolerance )
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static MatrixMut multiply (
+ final Matrix matrix,
+ final double scalar )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final MatrixMut scaledCopy = matrix.copy ( );
+
+ final int rowCount = matrix.getRowCount ( );
+
+ final int columnCount = matrix.getColumnCount ( );
+
+ for ( int row = 0; row < rowCount; row++ )
+ {
+ for ( int column = 0; column < columnCount; column++ )
+ {
+ scaledCopy.set (
+ row,
+ column,
+ matrix.get ( row, column ) * scalar );
+ }
+ }
+
+ return scaledCopy;
+ }
+
+ public static MatrixMut multiply (
+ final Matrix matrixAcc0,
+ final Matrix matrixAcc1 )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final int rowCount0 = matrixAcc0.getRowCount ( );
+
+ final int columnCount0 = matrixAcc0.getColumnCount ( );
+
+ final int rowCount1 = matrixAcc1.getRowCount ( );
+
+ final int columnCount1 = matrixAcc1.getColumnCount ( );
+
+ if ( columnCount0 != rowCount1 )
+ {
+ throw new IllegalArgumentException ( "columnCount0 != rowCount1" );
+ }
+
+ final MatrixMut matrixMut
+ = new MatrixImp ( rowCount0, columnCount1 );
+
+ for ( int row = 0; row < rowCount0; row++ )
+ {
+ for ( int column = 0; column < columnCount1; column++ )
+ {
+ double value = 0;
+
+ for ( int i = 0; i < columnCount0; i++ )
+ {
+ value += matrixAcc0.get ( row, i )
+ * matrixAcc1.get ( i, column );
+ }
+
+ matrixMut.set ( row, column, value );
+ }
+ }
+
+ return matrixMut;
+ }
+
+ public static void multiplyToSelf (
+ final MatrixMut matrixMut,
+ final Matrix matrix )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ if ( !matrixMut.isSquare ( ) )
+ {
+ throw new IllegalArgumentException ( "matrixMut is not square" );
+ }
+
+ if ( !matrix.isSquare ( ) )
+ {
+ throw new IllegalArgumentException ( "matrix is not square" );
+ }
+
+ matrixMut.copyToSelf ( multiply ( matrixMut, matrix ) );
+ }
+
+ public static String toString ( final Matrix matrix )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final StringBuilder stringBuilder = new StringBuilder ( );
+
+ final int rowCount = matrix.getRowCount ( );
+
+ final int columnCount = matrix.getColumnCount ( );
+
+ for ( int row = 0; row < rowCount; row++ )
+ {
+ for ( int column = 0; column < columnCount; column++ )
+ {
+ stringBuilder.append (
+ String.format (
+ "%1$1.3f",
+ new Double ( matrix.get ( row, column ) ) ) );
+
+ if ( column != columnCount - 1 )
+ {
+ stringBuilder.append ( ", " );
+ }
+ else if ( row != rowCount - 1 )
+ {
+ stringBuilder.append ( "; " );
+ }
+ }
+ }
+
+ return stringBuilder.toString ( );
+ }
+
+ public static MatrixMut transpose ( final Matrix matrix )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final int rowCount = matrix.getRowCount ( );
+
+ final int columnCount = matrix.getColumnCount ( );
+
+ final MatrixMut matrixMut = new MatrixImp ( columnCount, rowCount );
+
+ for ( int row = 0; row < rowCount; row++ )
+ {
+ for ( int column = 0; column < columnCount; column++ )
+ {
+ matrixMut.set ( column, row, matrix.get ( row, column ) );
+ }
+ }
+
+ return matrixMut;
+ }
+
+ public static void transposeSelf ( final MatrixMut matrixMut )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ if ( !matrixMut.isSquare ( ) )
+ {
+ throw new IllegalArgumentException ( "matrix is not square" );
+ }
+
+ final int rowCount = matrixMut.getRowCount ( );
+
+ for ( int row = 0; row < rowCount; row++ )
+ {
+ for ( int column = 0; column < row; column++ )
+ {
+ final double valueRC = matrixMut.get ( row, column );
+
+ final double valueCR = matrixMut.get ( column, row );
+
+ matrixMut.set ( row, column, valueCR );
+
+ matrixMut.set ( column, row, valueRC );
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // private methods
+ ////////////////////////////////////////////////////////////////////////
+
+ private MatrixLib ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ // empty
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/matrix/MatrixMut.java b/src/main/java/com/croftsfot/core/math/matrix/MatrixMut.java
new file mode 100644
index 0000000..4a69ae8
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/matrix/MatrixMut.java
@@ -0,0 +1,37 @@
+ package com.croftsoft.core.math.matrix;
+
+ /***********************************************************************
+ * A mutable matrix of doubles.
+ *
+ * @version
+ * $Id: MatrixMut.java,v 1.2 2008/05/03 00:35:31 croft Exp $
+ * @since
+ * 2008-04-25
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public interface MatrixMut
+ extends Matrix
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ void copyToSelf ( Matrix matrix );
+
+ void multiplyToSelf ( double scalar );
+
+ void multiplyToSelf ( Matrix matrix );
+
+ void set (
+ int row,
+ int column,
+ double value );
+
+ void setIdentity ( );
+
+ void transposeSelf ( );
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/matrix/MatrixTest.java b/src/main/java/com/croftsfot/core/math/matrix/MatrixTest.java
new file mode 100644
index 0000000..fe55f04
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/matrix/MatrixTest.java
@@ -0,0 +1,214 @@
+ package com.croftsoft.core.math.matrix;
+
+ /***********************************************************************
+ * Matrix test methods.
+ *
+ * @version
+ * $Id: MatrixTest.java,v 1.9 2008/05/03 02:48:38 croft Exp $
+ * @since
+ * 2008-04-19
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public final class MatrixTest
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ public static void main ( final String [ ] args )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ System.out.println ( test ( ) );
+ }
+
+ public static boolean test ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ System.out.println (
+ Matrix3x3Lib.createRotationMatrixX ( 0 ).toString ( ) );
+
+ System.out.println (
+ Matrix3x3Lib.createRotationMatrixY ( 180 ).toString ( ) );
+
+ System.out.println (
+ Matrix3x3Lib.createRotationMatrixZ ( 270 ).toString ( ) );
+
+ System.out.println (
+ Matrix3x3Lib.createRotationMatrix ( 0, 180, 270 ).toString ( ) );
+
+ final MatrixMut matrixB = new MatrixImp ( 2, 2 );
+
+ matrixB.set ( 0, 0, 0 );
+
+ matrixB.set ( 0, 1, 1 );
+
+ matrixB.set ( 1, 0, -2 );
+
+ matrixB.set ( 1, 1, 5 );
+
+ final MatrixMut matrixD = new MatrixImp (
+ new double [ ] [ ] {
+ { -1, 0, 3 },
+ { 5, 7, 2 } } );
+
+ System.out.println ( matrixB );
+
+ System.out.println ( matrixD );
+
+ System.out.println ( matrixB.multiply ( matrixD ) );
+
+ final Matrix3x3 rotationMatrix
+ = Matrix3x3Lib.createRotationMatrix ( 90, 90, 90 );
+
+ final double [ ] eulerAngles
+ = Matrix3x3Lib.toEulerAngles ( rotationMatrix );
+
+ for ( int i = 0; i < 3; i++ )
+ {
+ System.out.print ( eulerAngles [ i ] + ", " );
+ }
+
+ System.out.println ( "" );
+
+ return testTranspose ( )
+ && testRotation ( 90, 90, 90 )
+ && testRotation ( 0, 0, 0 )
+ && testRotation ( 180, 0, 0 )
+ && testRotation ( 360, 180, 270 )
+ && testRotation ( -90, -180, 0 );
+ }
+
+ public static boolean testRotation (
+ final double degreesX,
+ final double degreesY,
+ final double degreesZ )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final double cy = Math.cos ( Math.toRadians ( degreesY ) );
+
+ final double sy = Math.sin ( Math.toRadians ( degreesY ) );
+
+ final double cz = Math.cos ( Math.toRadians ( degreesZ ) );
+
+ final double sz = Math.sin ( Math.toRadians ( degreesZ ) );
+
+ final Matrix3x3Mut rotationZY0 = new Matrix3x3Imp (
+ new double [ ] [ ] {
+ { cy * cz, -sz, sy * cz },
+ { cy * sz, cz, sy * sz },
+ { -sy, 0, cy } } );
+
+ final Matrix rotationZY1
+ = Matrix3x3Lib.createRotationMatrixZ ( degreesZ ).multiply (
+ Matrix3x3Lib.createRotationMatrixY ( degreesY ) );
+
+ if ( !rotationZY0.matches ( rotationZY1 ) )
+ {
+ System.out.println ( "rotation test 1 failed" );
+
+ return false;
+ }
+
+ final Matrix3x3Mut rotationMatrix
+ = Matrix3x3Lib.createRotationMatrixZ ( degreesZ );
+
+ rotationMatrix.multiplyToSelf (
+ Matrix3x3Lib.createRotationMatrixY ( degreesY ) );
+
+ rotationMatrix.multiplyToSelf (
+ Matrix3x3Lib.createRotationMatrixX ( degreesX ) );
+
+ System.out.print ( "expected ...: " );
+
+ System.out.println ( rotationMatrix );
+
+ System.out.print ( "actual .....: " );
+
+ final Matrix3x3 actualRotationMatrix
+ = Matrix3x3Lib.createRotationMatrix (
+ degreesX,
+ degreesY,
+ degreesZ );
+
+ System.out.println ( actualRotationMatrix );
+
+ if ( !rotationMatrix.matches ( actualRotationMatrix ) )
+ {
+ System.out.println ( "rotation test 2 failed" );
+
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean testTranspose ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final Matrix matrix3x4 = new MatrixImp (
+ new double [ ] [ ] {
+ { 1, 2, 3, 4 },
+ { 5, 6, 7, 8 },
+ { 9, 10, 11, 12 } } );
+
+ final Matrix matrix4x3 = new MatrixImp (
+ new double [ ] [ ] {
+ { 1, 5, 9 },
+ { 2, 6, 10 },
+ { 3, 7, 11 },
+ { 4, 8, 12 } } );
+
+ if ( !matrix3x4.matches ( matrix4x3.transpose ( ) ) )
+ {
+ System.out.println ( "transpose test 1 failed" );
+
+ return false;
+ }
+
+ final MatrixMut matrix4x4Mut = new MatrixImp (
+ new double [ ] [ ] {
+ { 1, 2, 3, 4 },
+ { 5, 6, 7, 8 },
+ { 9, 10, 11, 12 },
+ { 13, 14, 15, 16 } } );
+
+ final Matrix matrix4x4 = new MatrixImp (
+ new double [ ] [ ] {
+ { 1, 5, 9, 13 },
+ { 2, 6, 10, 14 },
+ { 3, 7, 11, 15 },
+ { 4, 8, 12, 16 } } );
+
+ if ( !matrix4x4Mut.transpose ( ).matches ( matrix4x4 ) )
+ {
+ System.out.println ( "transpose test 2 failed" );
+
+ return false;
+ }
+
+ matrix4x4Mut.transposeSelf ( );
+
+ if ( !matrix4x4Mut.matches ( matrix4x4 ) )
+ {
+ System.out.println ( "transpose test 3 failed" );
+
+ return false;
+ }
+
+ return true;
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // private methods
+ ////////////////////////////////////////////////////////////////////////
+
+ private MatrixTest ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ // empty
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/matrix/package.html b/src/main/java/com/croftsfot/core/math/matrix/package.html
new file mode 100644
index 0000000..b76ad0a
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/matrix/package.html
@@ -0,0 +1,5 @@
+
+
+Matrices (including 3D graphics functions).
+
+
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/package.html b/src/main/java/com/croftsfot/core/math/package.html
new file mode 100644
index 0000000..be33d58
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/package.html
@@ -0,0 +1,5 @@
+
+
+Mathematics and constants.
+
+
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/quat/Quat.java b/src/main/java/com/croftsfot/core/math/quat/Quat.java
new file mode 100644
index 0000000..a0c9594
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/quat/Quat.java
@@ -0,0 +1,52 @@
+ package com.croftsoft.core.math.quat;
+
+ import com.croftsoft.core.math.axis.AxisAngleMut;
+ import com.croftsoft.core.math.matrix.Matrix3x3Mut;
+
+ /***********************************************************************
+ * Accessor interface for a quaternion.
+ *
+ * @version
+ * $Id: Quat.java,v 1.8 2008/05/09 18:35:56 croft Exp $
+ * @since
+ * 2008-05-02
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public interface Quat
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ // accessor methods
+
+ double getW ( );
+
+ double getX ( );
+
+ double getY ( );
+
+ double getZ ( );
+
+ // operand methods
+
+ boolean matches ( Quat quat );
+
+ boolean matches (
+ Quat quat,
+ double tolerance );
+
+ // calculation methods
+
+ double dotProduct ( Quat quat );
+
+ QuatMut multiply ( Quat quat );
+
+ AxisAngleMut toAxisAngle ( );
+
+ Matrix3x3Mut toRotationMatrix ( );
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/quat/QuatImp.java b/src/main/java/com/croftsfot/core/math/quat/QuatImp.java
new file mode 100644
index 0000000..36160cd
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/quat/QuatImp.java
@@ -0,0 +1,133 @@
+ package com.croftsoft.core.math.quat;
+
+ import com.croftsoft.core.math.axis.AxisAngleMut;
+ import com.croftsoft.core.math.matrix.Matrix3x3Mut;
+
+ /***********************************************************************
+ * Implementation of interface QuatMut.
+ *
+ * @version
+ * $Id: QuatImp.java,v 1.7 2008/05/09 18:35:56 croft Exp $
+ * @since
+ * 2008-05-02
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public final class QuatImp
+ implements QuatMut
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ private double w, x, y, z;
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+
+ public QuatImp (
+ final double w,
+ final double x,
+ final double y,
+ final double z )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ this.w = w;
+
+ this.x = x;
+
+ this.y = y;
+
+ this.z = z;
+ }
+
+ public QuatImp ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ this ( 1, 0, 0, 0 );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // accessor methods
+ ////////////////////////////////////////////////////////////////////////
+
+ public double getW ( ) { return w; }
+
+ public double getX ( ) { return x; }
+
+ public double getY ( ) { return y; }
+
+ public double getZ ( ) { return z; }
+
+ ////////////////////////////////////////////////////////////////////////
+ // mutator methods
+ ////////////////////////////////////////////////////////////////////////
+
+ public void setW ( final double w ) { this.w = w; }
+
+ public void setX ( final double x ) { this.x = x; }
+
+ public void setY ( final double y ) { this.y = y; }
+
+ public void setZ ( final double z ) { this.z = z; }
+
+ ////////////////////////////////////////////////////////////////////////
+ // operand methods
+ ////////////////////////////////////////////////////////////////////////
+
+ public boolean matches ( final Quat quat )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return QuatLib.matches ( this, quat );
+ }
+
+ public boolean matches (
+ final Quat quat,
+ final double tolerance )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return QuatLib.matches ( this, quat, tolerance );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // overridden Object methods
+ ////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public String toString ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return QuatLib.toString ( this );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // calculation methods
+ ////////////////////////////////////////////////////////////////////////
+
+ public double dotProduct ( final Quat quat )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return QuatLib.dotProduct ( this, quat );
+ }
+
+ public QuatMut multiply ( final Quat quat )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return QuatLib.multiply ( this, quat );
+ }
+
+ public AxisAngleMut toAxisAngle ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return QuatLib.toAxisAngle ( this );
+ }
+
+ public Matrix3x3Mut toRotationMatrix ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return QuatLib.toRotationMatrix ( this );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/quat/QuatLib.java b/src/main/java/com/croftsfot/core/math/quat/QuatLib.java
new file mode 100644
index 0000000..f3041ca
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/quat/QuatLib.java
@@ -0,0 +1,192 @@
+ package com.croftsoft.core.math.quat;
+
+ import com.croftsoft.core.math.axis.AxisAngleImp;
+ import com.croftsoft.core.math.axis.AxisAngleMut;
+ import com.croftsoft.core.math.matrix.Matrix3x3Imp;
+ import com.croftsoft.core.math.matrix.Matrix3x3Mut;
+
+ /***********************************************************************
+ * A library of static methods to manipulate Quat objects.
+ *
+ * @version
+ * $Id: QuatLib.java,v 1.10 2008/09/20 02:51:51 croft Exp $
+ * @since
+ * 2008-05-02
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public final class QuatLib
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ public static double dotProduct (
+ final Quat quat0,
+ final Quat quat1 )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return quat0.getW ( ) * quat1.getW ( )
+ * quat0.getX ( ) * quat1.getX ( )
+ * quat0.getY ( ) * quat1.getY ( )
+ * quat0.getZ ( ) * quat1.getZ ( );
+ }
+
+ public static QuatMut fromEulerAngles (
+ final double degreesX,
+ final double degreesY,
+ final double degreesZ )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final Quat quatX = new AxisAngleImp ( degreesX, 0, 0, 1 ).toQuat ( );
+
+ final Quat quatY = new AxisAngleImp ( degreesY, 0, 1, 0 ).toQuat ( );
+
+ final Quat quatZ = new AxisAngleImp ( degreesZ, 0, 0, 1 ).toQuat ( );
+
+ return quatZ.multiply ( quatY ).multiply ( quatX );
+ }
+
+ public static boolean matches (
+ final Quat quat0,
+ final Quat quat1 )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return quat0.getW ( ) == quat1.getW ( )
+ && quat0.getX ( ) == quat1.getX ( )
+ && quat0.getY ( ) == quat1.getY ( )
+ && quat0.getZ ( ) == quat1.getZ ( );
+ }
+
+ public static boolean matches (
+ final Quat quat0,
+ final Quat quat1,
+ final double tolerance )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ if ( tolerance < 0 )
+ {
+ throw new IllegalArgumentException ( "tolerance < 0" );
+ }
+
+ return Math.abs ( quat0.getW ( ) - quat1.getW ( ) ) <= tolerance
+ && Math.abs ( quat0.getX ( ) - quat1.getX ( ) ) <= tolerance
+ && Math.abs ( quat0.getY ( ) - quat1.getY ( ) ) <= tolerance
+ && Math.abs ( quat0.getZ ( ) - quat1.getZ ( ) ) <= tolerance;
+ }
+
+ public static QuatMut multiply (
+ final Quat quat0,
+ final Quat quat1 )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final double w0 = quat0.getW ( );
+
+ final double x0 = quat0.getX ( );
+
+ final double y0 = quat0.getY ( );
+
+ final double z0 = quat0.getZ ( );
+
+ final double w1 = quat1.getW ( );
+
+ final double x1 = quat1.getX ( );
+
+ final double y1 = quat1.getY ( );
+
+ final double z1 = quat1.getZ ( );
+
+ return new QuatImp (
+ w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1,
+ y0 * z1 - z0 * y1 + w0 * x1 + x0 * w1,
+ z0 * x1 - x0 * z1 + w0 * y1 + y0 * w1,
+ x0 * y1 - y0 * x1 + w0 * z1 + z0 * w1 );
+ }
+
+ public static AxisAngleMut toAxisAngle ( final Quat quat )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final double w = quat.getW ( );
+
+ final double sinThetaOver2Sq = 1 - w * w;
+
+ if ( sinThetaOver2Sq <= 0 )
+ {
+ return new AxisAngleImp ( );
+ }
+
+ final double oneOverSinThetaOver2
+ = 1 / Math.sqrt ( sinThetaOver2Sq );
+
+ return new AxisAngleImp (
+ Math.toDegrees ( 2 * Math.acos ( w ) ),
+ quat.getX ( ) * oneOverSinThetaOver2,
+ quat.getY ( ) * oneOverSinThetaOver2,
+ quat.getZ ( ) * oneOverSinThetaOver2 );
+ }
+
+ public static Matrix3x3Mut toRotationMatrix ( final Quat quat )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final double w = quat.getW ( );
+
+ final double x = quat.getX ( );
+
+ final double y = quat.getY ( );
+
+ final double z = quat.getZ ( );
+
+ final double wx = w * x;
+
+ final double wy = w * y;
+
+ final double wz = w * z;
+
+ final double xx = x * x;
+
+ final double xy = x * y;
+
+ final double xz = x * z;
+
+ final double yy = y * y;
+
+ final double yz = y * z;
+
+ final double zz = z * z;
+
+ return new Matrix3x3Imp (
+ 1 - 2 * ( yy + zz ),
+ 2 * ( xy - wz ),
+ 2 * ( wy + xz ),
+ 2 * ( xy + wz ),
+ 1 - 2 * ( xx + zz ),
+ 2 * ( yz - wx ),
+ 2 * ( xz - wy ),
+ 2 * ( yz + wx ),
+ 1 - 2 * ( xx + yy ) );
+ }
+
+ public static String toString ( final Quat quat )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return String.format (
+ "%1$1.3f; %2$1.3f, %3$1.3f, %4$1.3f",
+ new Double ( quat.getW ( ) ),
+ new Double ( quat.getX ( ) ),
+ new Double ( quat.getY ( ) ),
+ new Double ( quat.getZ ( ) ) );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // private methods
+ ////////////////////////////////////////////////////////////////////////
+
+ private QuatLib ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ // empty
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/quat/QuatMut.java b/src/main/java/com/croftsfot/core/math/quat/QuatMut.java
new file mode 100644
index 0000000..fa6a592
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/quat/QuatMut.java
@@ -0,0 +1,30 @@
+ package com.croftsoft.core.math.quat;
+
+ /***********************************************************************
+ * A mutator interface for a Quat.
+ *
+ * @version
+ * $Id: QuatMut.java,v 1.1 2008/05/03 02:14:15 croft Exp $
+ * @since
+ * 2008-05-02
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public interface QuatMut
+ extends Quat
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ void setW ( double w );
+
+ void setX ( double x );
+
+ void setY ( double y );
+
+ void setZ ( double z );
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/quat/QuatTest.java b/src/main/java/com/croftsfot/core/math/quat/QuatTest.java
new file mode 100644
index 0000000..f0f2d18
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/quat/QuatTest.java
@@ -0,0 +1,87 @@
+ package com.croftsoft.core.math.quat;
+
+ import com.croftsoft.core.math.axis.AxisAngle;
+
+ /***********************************************************************
+ * Quat test methods.
+ *
+ * @version
+ * $Id: QuatTest.java,v 1.6 2008/09/20 04:12:46 croft Exp $
+ * @since
+ * 2008-05-02
+ * @author
+ * David Wallace Croft
+ ***********************************************************************/
+
+ public final class QuatTest
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ {
+
+ public static void main ( final String [ ] args )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ System.out.println ( test ( ) );
+ }
+
+ public static boolean test ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ return testMultiply ( );
+ }
+
+ public static boolean testMultiply ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ final Quat quatX90 = QuatLib.fromEulerAngles ( 90, 0, 0 );
+
+ System.out.println ( "X90 ...........: " + quatX90 );
+
+ final Quat quatX180 = QuatLib.fromEulerAngles ( 180, 0, 0 );
+
+ System.out.println ( "X180 ..........: " + quatX180 );
+
+ final Quat quatX90X90 = quatX90.multiply ( quatX90 );
+
+ System.out.println ( "X90,X90 .......: " + quatX90X90 );
+
+ final Quat quatY90 = QuatLib.fromEulerAngles ( 0, 90, 0 );
+
+ System.out.println ( "Y90 ...........: " + quatY90 );
+
+ final Quat quatZ90 = QuatLib.fromEulerAngles ( 0, 0, 90 );
+
+ System.out.println ( "Z90 ...........: " + quatZ90 );
+
+ final Quat quatX90Y90Z90 = QuatLib.fromEulerAngles ( 90, 90, 90 );
+
+ System.out.println ( "X90,Y90,Z90 ...: " + quatX90Y90Z90 );
+
+ final AxisAngle axisAngle = quatX90Y90Z90.toAxisAngle ( );
+
+ System.out.printf (
+ "rotation degrees = %1$1.3f\n",
+ new Double ( axisAngle.getDegrees ( ) ) );
+
+ System.out.printf (
+ "rotation axis = %1$1.3f %2$1.3f %3$1.3f\n",
+ new Double ( axisAngle.getX ( ) ),
+ new Double ( axisAngle.getY ( ) ),
+ new Double ( axisAngle.getZ ( ) ) );
+
+ return quatX180.matches ( quatX90X90, 0.001 );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // private methods
+ ////////////////////////////////////////////////////////////////////////
+
+ private QuatTest ( )
+ ////////////////////////////////////////////////////////////////////////
+ {
+ // empty
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ }
\ No newline at end of file
diff --git a/src/main/java/com/croftsfot/core/math/quat/package.html b/src/main/java/com/croftsfot/core/math/quat/package.html
new file mode 100644
index 0000000..11d39fd
--- /dev/null
+++ b/src/main/java/com/croftsfot/core/math/quat/package.html
@@ -0,0 +1,5 @@
+
+
+Quaternions (used in 3D graphics).
+
+
\ No newline at end of file