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: + *

    + *
  1. The URL name for the codebase. + *
  2. The name of the class with the "main(args)" method. + *
  3. The name of the local persistent resource cache directory. + *
  4. 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: + *

    + *
  1. The URL name for the codebase. + *
  2. The name of the class with the "main(args)" method. + *
  3. The name of the local persistent resource cache directory. + *
  4. 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: + *

    + *
  1. The URL for the codebase. + *
  2. The name of the class with the "main(args)" method. + *
  3. 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