diff options
Diffstat (limited to 'projects/net.wotonomy.datastore/src/main/java')
14 files changed, 2482 insertions, 0 deletions
diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataIndex.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataIndex.java new file mode 100644 index 0000000..89fa1eb --- /dev/null +++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataIndex.java @@ -0,0 +1,111 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2000 Michael Powers + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, see http://www.gnu.org +*/ + +package net.wotonomy.datastore; + +import java.io.Serializable; +import java.util.List; + +/** +* A DataIndex maintains a list of objects associated with values. +* The objects can then be retrieved based on the values. This class +* should not be much more complex than a simple map or list because +* the DataSoup is responsible for populating it. +*/ +public interface DataIndex extends Serializable +{ + /** + * Gets the name of this index. The DataSoup uses this to + * uniquely refer to this index. + * @return The name of this index. + */ + public String getName(); + + /** + * The property managed by this index. This is the property + * used when the DataSoup builds and rebuilds this index. + * @return The property managed by this index. + */ + public String getProperty(); + + /** + * Adds an object to be associated with the specified value. + * @param anObject A data object, usually but not always a DataKey. + * @param newValue The property value to be associated with the data object. + * @return The data object that was inserted, or null if an error occurred. + */ + public Object addObject( Object anObject, Object newValue ); + + /** + * Updates an object previously associated with the specified + * value to be associated with the specified new value. + * @param anObject A data object, usually but not always a DataKey. + * @param oldValue The value currently associated with the data object. + * @param newValue The value to be associated with the data object. + * @return The data object that was updated, or null if an error occurred. + */ + public Object updateObject( Object anObject, + Object oldValue, Object newValue ); + + /** + * Removes an object from the index. + * @param anObject A data object, usually but not always a DataKey. + * @param oldValue The value currently associated with the data object. + * @return The data object that was removed, or null if not found or error. + */ + public Object removeObject( Object anObject, Object oldValue ); + + /** + * Removes all objects from the index. Usually called before + * rebuilding the index. + */ + public void clear(); + + /** + * Returns all objects in the index whose associated values fall + * between the two specified values, inclusive. + * @param beginValue The beginning value, or null for all values + * up to an including the end key. + * @param endValue The ending value, or null for all values + * since and including the begin key. + * @return A List of the matching objects, ordered in increasing + * value, or null for invalid query parameters or other error. + */ + public List query( Object beginValue, Object endValue ); + +} + +/* + * $Log$ + * Revision 1.2 2006/02/19 16:26:19 cgruber + * Move non-unit-test code to tests project + * Fix up code to work with proper imports + * Fix maven dependencies. + * + * Revision 1.1 2006/02/16 13:18:56 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.1.1.1 2000/12/21 15:46:50 mpowers + * Contributing wotonomy. + * + * Revision 1.2 2000/12/20 16:25:35 michael + * Added log to all files. + * + * + */ + diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataKey.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataKey.java new file mode 100644 index 0000000..6fe574f --- /dev/null +++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataKey.java @@ -0,0 +1,142 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2000 Michael Powers + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, see http://www.gnu.org +*/ + +package net.wotonomy.datastore; + +import java.io.Serializable; + +import net.wotonomy.foundation.internal.ValueConverter; + +public class DataKey implements Comparable, Serializable, Cloneable +{ + static final long serialVersionUID = 8421127539579065705L; + + Long key; + + public DataKey() + { + key = new Long( 0 ); + } + + /** + * Converts string representation to new object. + */ + public DataKey( String aString ) + { + this(); + setKeyString( aString ); + } + + public int hashCode() + { + return key.intValue(); + } + + public void increment() + { + key = new Long( key.longValue() + 1 ); + } + + public Object clone() + { + return new DataKey( this.toString() ); + } + + public String toString() + { + return key.toString(); + } + + public String getKeyString() + { + return key.toString(); + } + + public void setKeyString( String aString ) + { + Long parsed = ValueConverter.getLong( aString ); + if ( parsed != null ) key = parsed; + } + + public boolean equals( Object anObject ) + { + if ( anObject instanceof String ) + { + if ( toString().equals( anObject ) ) + { + return true; + } + } + if ( ! ( anObject instanceof DataKey ) ) return false; + return key.equals( ((DataKey)anObject).key ); + } + + public int compareTo( Object anObject ) + { + if ( anObject instanceof String ) + { + if ( toString().equals( anObject ) ) + { + return 0; + } + } + if ( ! ( anObject instanceof DataKey ) ) + { + Long converted = (Long) ValueConverter.getLong( anObject ); + if ( converted != null ) + { + return (int) ( key.longValue() - converted.longValue() ); + } + return 0; + }; + return (int) ( key.longValue() - ((DataKey)anObject).key.longValue() ); + } +} + +/* + * $Log$ + * Revision 1.2 2006/02/19 16:26:19 cgruber + * Move non-unit-test code to tests project + * Fix up code to work with proper imports + * Fix maven dependencies. + * + * Revision 1.1 2006/02/16 13:18:56 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.4 2003/08/14 19:29:38 chochos + * minor cleanup (imports, static method calls, etc) + * + * Revision 1.3 2001/02/23 23:44:44 mpowers + * Fixes for hashcode to ensure proper key comparison. + * + * Revision 1.2 2001/02/15 21:12:41 mpowers + * Added accessors for key throughout the api. This breaks compatibility. + * insertObject now returns the permanent key for the newly created object. + * The old way returned a copy of the object which was an additional read + * that was often ignored. Now you can read it only if you need it. + * Furthermore, there was not other way of getting the permanent key. + * + * Revision 1.1.1.1 2000/12/21 15:47:04 mpowers + * Contributing wotonomy. + * + * Revision 1.2 2000/12/20 16:25:36 michael + * Added log to all files. + * + * + */ + diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataSoup.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataSoup.java new file mode 100644 index 0000000..3c37d43 --- /dev/null +++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataSoup.java @@ -0,0 +1,257 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2000 Michael Powers + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, see http://www.gnu.org +*/ + +package net.wotonomy.datastore; + +import java.util.Collection; + +public interface DataSoup +{ + /** + * Adds the specified object to the soup and returns the key + * for the new object by which it may be subsequently retrieved. + * Null indicates an error, probably due to serialization. + * @param anObject Object to be added to soup. + * @return The unique identifier used for the new object. + */ + public DataKey addObject( Object anObject ); + + /** + * Removes the specified object from the soup and returns + * the removed object as read from the soup (which is the + * original copy of the object). Null indicates object not found. + * @param aKey A key for an object to be removed. + * @return The object that was removed, or null if not found or error. + */ + public Object removeObject( DataKey aKey ); + + /** + * Updates the specified object and returns the object + * as updated. Null indicates an error writing the object. + * @param aKey A key for an object to be updated. + * @param aKey The new object for that key. + * @return A copy of the updated object, possibly updated, + * or null if not found or error. + */ + public Object updateObject( DataKey aKey, Object updatedObject ); + + /** + * Gets object from data store whose identifier is equal + * to the specified object. + * @param aKey A key for an object to be retrieved. + * @return The corresponding object from the soup. + */ + public Object getObjectByKey( DataKey aKey ); + + /** + * Registers an object that may or may not be created + * later, returning a temporary but uniquely identifiable + * key. The key will be replaced with a permanent key when + * the object is created with addObject(). + * @param anObject An object to be registered. + * @return A temporary key for this object. + */ + public DataKey registerTemporaryObject( Object anObject ); + + // index management + + /** + * Adds an index to the soup. + * @param aName The string identifier for this index. + * @param aProperty The property on which this index will be based. + */ + public void addIndex( String aName, String aProperty ); + + /** + * Deletes the specified index from the soup. + * @param aName The string identifier for the index to be removed. + */ + public void removeIndex( String aName ); + + /** + * Gets a collection of all indices in this soup. + * @return A collection of all indices in this soup. + */ + public Collection getAllIndices(); + + // relationship management + + /** + * Adds a relation to entries in another soup. + * @param aProperty The property on which this relation will be based. + * @param aSoup The name of the soup to be related in this store. + */ +// public void addRelation( String aProperty, String aSoup ); + + /** + * Deletes the specified relation to entries in another soup. + * @param aProperty The property on which this relation will be based. + * @param aSoup The name of the soup to be related in this store. + */ +// public void removeRelation( String aProperty, String aSoup ); + + /** + * Gets a collection of all relations in this soup. + * @return A collection of all relation in this soup. + */ +// public Collection getAllRelations(); + + // queries + + /** + * Returns an empty data view, suitable for creating + * new entries in the soup. + * @return A DataView containing no entries. + */ + public DataView createView(); + + /** + * Queries by the specified pre-generated index, if it exists. + * Will return objects whose values for the indexed property + * fall between the two values inclusive. + * Otherwise, falls through to queryByProperty. + * @param anIndexName The index to be queried. + * @param beginValue The beginning value, or null for all values + * up to an including the end key. + * @param endValue The ending value, or null for all values + * since and including the begin key. + * @return A DataView containing the query results, or null + * for invalid query parameters. + */ + public DataView queryByIndex( + String anIndexName, Object beginKey, Object endKey ); + + /** + * Generates an index based on the specified property + * and then executes the query. + * Will return objects whose values for the specified property + * fall between the two values inclusive. + * @param aPropertyName The property to be queried. If null, + * will query the objects directly with queryObjects(). + * @param beginValue The beginning value, or null for all values + * up to an including the end key. + * @param endValue The ending value, or null for all values + * since and including the begin key. + * @return A DataView containing the query results, or null + * for invalid query parameters. + */ + public DataView queryByProperty( + String aPropertyName, Object beginKey, Object endKey ); + + /** + * Generates an index based on the values of the objects themselves + * and then executes the query. + * Will return objects whose values fall between the two values inclusive. + * @param beginValue The beginning value, or null for all values + * up to and including the end key. + * @param endValue The ending value, or null for all values + * since and including the begin key. + * @return A DataView containing the query results, or null + * for invalid query parameters. + */ + public DataView queryObjects( Object beginKey, Object endKey ); + + /** + * Returns a view containing the objects for the specified keys. + * @param aKeyList A collection of keys to be placed in the view. + * @return A DataView containing the objects for the corresponding + * keys, in the order in which the keys are returned from the collection. + */ + public DataView queryByKeys( Collection aKeyList ); + + /** + * As queryByIndex, but with objects returned in reverse order. + * @param anIndexName The index to be queried. + * @param beginValue The beginning value, or null for all values + * up to and including the end key. + * @param endValue The ending value, or null for all values + * since and including the begin key. + * @return A DataView containing the query results, or null + * for invalid query parameters. + */ + public DataView reverseQueryByIndex( + String anIndexName, Object beginKey, Object endKey ); + + /** + * As queryByProperty, but with objects returned in reverse order. + * @param aPropertyName The property to be queried. If null, + * will query the objects directly with queryObjects(). + * @param beginValue The beginning value, or null for all values + * up to and including the end key. + * @param endValue The ending value, or null for all values + * since and including the begin key. + * @return A DataView containing the query results, or null + * for invalid query parameters. + */ + public DataView reverseQueryByProperty( + String aPropertyName, Object beginKey, Object endKey ); + + /** + * As queryObjects, but with objects returned in reverse order. + * @param beginValue The beginning value, or null for all values + * up to and including the end key. + * @param endValue The ending value, or null for all values + * since and including the begin key. + * @return A DataView containing the query results, or null + * for invalid query parameters. + */ + public DataView reverseQueryObjects( Object beginKey, Object endKey ); + +// public void addIndex( String aName, DataIndex anIndex ) {} +// public void removeIndex( String aName ) {} +// public void addTaggedObject( String aKey, Serializable anObject ) +// public Object getTaggedObject( String aKey ); +// public void removeTaggedObject( String aKey ); +// public void setMetaData( +// String aMetaProperty, Serializable aValue, Serializable anObject ); + +} + +/* + * $Log$ + * Revision 1.2 2006/02/19 16:26:19 cgruber + * Move non-unit-test code to tests project + * Fix up code to work with proper imports + * Fix maven dependencies. + * + * Revision 1.1 2006/02/16 13:18:56 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.4 2003/08/14 19:29:38 chochos + * minor cleanup (imports, static method calls, etc) + * + * Revision 1.3 2001/03/05 22:12:11 mpowers + * Created the control package for a datastore-specific implementation + * of EOObjectStore. + * + * Revision 1.2 2001/02/15 21:12:41 mpowers + * Added accessors for key throughout the api. This breaks compatibility. + * insertObject now returns the permanent key for the newly created object. + * The old way returned a copy of the object which was an additional read + * that was often ignored. Now you can read it only if you need it. + * Furthermore, there was not other way of getting the permanent key. + * + * Revision 1.1.1.1 2000/12/21 15:47:05 mpowers + * Contributing wotonomy. + * + * Revision 1.2 2000/12/20 16:25:36 michael + * Added log to all files. + * + * + */ + diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataStore.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataStore.java new file mode 100644 index 0000000..28fbc90 --- /dev/null +++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataStore.java @@ -0,0 +1,94 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2000 Michael Powers + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, see http://www.gnu.org +*/ + +package net.wotonomy.datastore; + +import java.io.File; +import java.io.Serializable; +import java.util.Iterator; + +public class DataStore implements Serializable +{ + protected File homeDirectory; + + public DataStore( String aPath ) + { + homeDirectory = new File( aPath ); + + // if specified directory does not exist + if ( ! homeDirectory.exists() ) + { + homeDirectory.mkdirs(); + } + + // if existing path is a file, exit with error + if ( homeDirectory.isDirectory() ) + { + new RuntimeException( "DataStore: Specified directory is a file." ); + } + } + + public File getHomeDirectory() + { + return homeDirectory; + } + + + public DataSoup getSoupForName( String aName ) + { + return null; + } + public void removeSoup( DataSoup aSoup ) + { + // FIXME + } + public Iterator getAllSoups() + { + return null; + } + + public static void main( String[] argv ) + { + new DataStore( "/Local/Users/michael/Projects/test/data" ); + } + +} + +/* + * $Log$ + * Revision 1.2 2006/02/19 16:26:19 cgruber + * Move non-unit-test code to tests project + * Fix up code to work with proper imports + * Fix maven dependencies. + * + * Revision 1.1 2006/02/16 13:18:56 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.2 2001/03/05 22:12:11 mpowers + * Created the control package for a datastore-specific implementation + * of EOObjectStore. + * + * Revision 1.1.1.1 2000/12/21 15:47:05 mpowers + * Contributing wotonomy. + * + * Revision 1.2 2000/12/20 16:25:36 michael + * Added log to all files. + * + * + */ + diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataView.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataView.java new file mode 100644 index 0000000..fec9cfc --- /dev/null +++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataView.java @@ -0,0 +1,111 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2000 Michael Powers + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, see http://www.gnu.org +*/ + +package net.wotonomy.datastore; + +import java.util.List; +import java.util.Observer; + +public interface DataView extends List +{ +// public void newQuery( String aProperty, Object beginKey, Object endKey ); +// public void addQuery( String aProperty, Object beginKey, Object endKey ); +// public void removeQuery( String aProperty, Object beginKey, Object endKey ); +// public void retainQuery( String aProperty, Object beginKey, Object endKey ); + + /** + * This method is called to notify the DataView + * that one of its objects has been modified and + * should be updated when the view is committed. + */ + public void update(Object o); + + /** + * This method is called commit all changes to + * the DataView to its data store. The list + * elements may be refreshed from the datastore, + * although the list itself should remain unchanged. + * @return True if the commit was successful, + * otherwise false. + */ + public boolean commit(); + + /** + * Called to add the specified observer to the + * list of observers that should receive notifications + * when the view if modified. DataViews notify + * when objects are added, updated, or deleted, + * passing the affected object as the parameter + * to the Observer's notify method. + * @param o The observer to add. + */ + public void addObserver(Observer o); + + /** + * Called to remove the specified observer from the + * list of observers that should receive notifications + * when the view if modified. + * @param o The observer to delete. + */ + public void deleteObserver(Observer o); + + /** + * Called to clear the list of observers that should + * receive notifications when the view if modified. + */ + public void deleteObservers(); + + /** + * Returns the key for the specified object. + * If the object is not in the view, returns null. + */ + public DataKey getKeyForObject( Object anObject ); + + /** + * Returns the object for the specified key. + * If the key is not in the view, returns null. + */ + public Object getObjectForKey( DataKey aKey ); +} + +/* + * $Log$ + * Revision 1.2 2006/02/19 16:26:19 cgruber + * Move non-unit-test code to tests project + * Fix up code to work with proper imports + * Fix maven dependencies. + * + * Revision 1.1 2006/02/16 13:18:56 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.2 2001/02/15 21:12:41 mpowers + * Added accessors for key throughout the api. This breaks compatibility. + * insertObject now returns the permanent key for the newly created object. + * The old way returned a copy of the object which was an additional read + * that was often ignored. Now you can read it only if you need it. + * Furthermore, there was not other way of getting the permanent key. + * + * Revision 1.1.1.1 2000/12/21 15:47:05 mpowers + * Contributing wotonomy. + * + * Revision 1.2 2000/12/20 16:25:36 michael + * Added log to all files. + * + * + */ + diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultComparator.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultComparator.java new file mode 100644 index 0000000..b97b8a1 --- /dev/null +++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultComparator.java @@ -0,0 +1,145 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2000 Michael Powers + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, see http://www.gnu.org +*/ + +package net.wotonomy.datastore; + +import java.io.Serializable; +import java.util.Comparator; + +import net.wotonomy.foundation.internal.ValueConverter; + +/** +* DefaultComparator exists to compare basic java +* primitive wrappers, since these classes don't +* implement Comparable in jdk 1.1.x. Also uses +* ValueConverter to try to match types for comparison. +*/ +public class DefaultComparator implements Comparator, Serializable +{ + public int compare(Object o1, Object o2) + { +// System.out.println( "compare: " + o1 + " : " + o1.getClass() + " : " + o2 + " : " + o2.getClass() ); +/* + if ( ( o1 instanceof Comparable ) && ( o2 instanceof Comparable ) ) + { + return ((Comparable)o1).compareTo( o2 ); + } +*/ + if ( ( o1 instanceof Number ) && ( o2 instanceof Number ) ) + { + // TODO: special case for each type would be faster + return (int) + ( ((Number)o1).doubleValue() - ((Number)o2).doubleValue() ); + } + + if ( o1 instanceof StringBuffer ) + { + o1 = o1.toString(); + } + if ( o2 instanceof StringBuffer ) + { + o2 = o2.toString(); + } + + if ( ( o1 instanceof String ) && ( o2 instanceof String ) ) + { + return ((String)o1).compareTo( ((String)o2) ); + } + + if ( ( o1 instanceof Character ) && ( o2 instanceof Character ) ) + { + return (int) + ((Character)o1).charValue() - ((Character)o2).charValue(); + } + + if ( ( o1 instanceof Byte ) && ( o2 instanceof Byte ) ) + { + return (int) + ((Byte)o1).byteValue() - ((Byte)o2).byteValue(); + } + + if ( ( o1 instanceof Boolean ) && ( o2 instanceof Boolean ) ) + { + if ( o1.equals( o2 ) ) return 0; + + // presumably TRUE is greater than FALSE + if ( o1.equals( Boolean.TRUE ) ) return 1; + return -1; + } + + // handle all NULL cases: NULL is less than anything else. + if ( ( o1 == null ) && ( o2 == null ) ) return 0; + if ( ( o1 == null ) && ( o2 != null ) ) return -1; + if ( ( o2 == null ) && ( o1 != null ) ) return 1; + + if ( o1.getClass() != o2.getClass() ) + { + Object convertedValue; + + if ( ! ( o2 instanceof String ) ) + // (string should be lowest common demoninator, if possible) + { + // convert first to second's type + convertedValue = + ValueConverter.convertObjectToClass( o1, o2.getClass() ); + if ( convertedValue != null ) + { + return compare( convertedValue, o2 ); + } + } + + // convert second to first's type + convertedValue = + ValueConverter.convertObjectToClass( o2, o1.getClass() ); + if ( convertedValue != null ) + { + return -1 * compare( convertedValue, o1 ); // reverse result + } + } + + // we tried really hard, but these values are incomparable: + // we'll consider them equal. + return 0; + } + + public boolean equals(Object obj) + { + return (obj == this); + } +} + +/* + * $Log$ + * Revision 1.2 2006/02/19 16:26:19 cgruber + * Move non-unit-test code to tests project + * Fix up code to work with proper imports + * Fix maven dependencies. + * + * Revision 1.1 2006/02/16 13:18:56 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.1.1.1 2000/12/21 15:47:08 mpowers + * Contributing wotonomy. + * + * Revision 1.3 2000/12/20 16:25:36 michael + * Added log to all files. + * + * + */ + + diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataIndex.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataIndex.java new file mode 100644 index 0000000..a8ede78 --- /dev/null +++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataIndex.java @@ -0,0 +1,239 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2000 Michael Powers + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, see http://www.gnu.org +*/ + +package net.wotonomy.datastore; + +import java.util.Comparator; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.TreeMap; + +/** +* This implementation of DataIndex wraps a TreeMap and +* adds the ability to contain objects with duplicate keys. +*/ +public class DefaultDataIndex implements DataIndex +{ + static final long serialVersionUID = -3759982714240822885L; + + protected String name; + protected String property; + private TreeMap treeMap; + private Comparator comparator; + + public DefaultDataIndex() + { + comparator = new DefaultComparator(); + setTreeMap( new TreeMap( new DefaultComparator() ) ); + } + + public DefaultDataIndex( String aName, String aProperty ) + { + this(); + setName( aName ); + setProperty( aProperty ); + } + + // included for xml serialization + public Comparator getComparator() { return comparator; } + public void setComparator( Comparator aComparator ) + { + comparator = aComparator; + // set comparator and copy contents + TreeMap map = getTreeMap(); + setTreeMap( new TreeMap( comparator ) ); + getTreeMap().putAll( map ); + + } + + public String getName() { return name; }; + public void setName( String aName ) { name = aName; } + public String getProperty() { return property; }; + public void setProperty( String aProperty ) { property = aProperty; } + public TreeMap getTreeMap() { return treeMap; } + public void setTreeMap( TreeMap aMap ) { treeMap = aMap; } + + public List query( Object beginValue, Object endValue ) + { +//System.out.println( "DefaultDataIndex.query: " + beginValue + " : " + endValue ); + List result = new LinkedList(); + if ( endValue == null ) + { + if ( beginValue == null ) + { + // begin and end are null, return entire set + populateListFromIterator( result, treeMap.values().iterator() ); + return result; + } + + // only end is null, return all starting from beginValue + populateListFromIterator( result, + treeMap.tailMap( beginValue ).values().iterator() ); + return result; + } + else + if ( beginValue == null ) + { + // only begin is null, return all ending with endValue + populateListFromIterator( result, + treeMap.headMap( endValue ).values().iterator() ); + } + else + { + // begin and end are specified, return all inclusive + populateListFromIterator( result, + treeMap.subMap( beginValue, endValue ).values().iterator() ); + } + + // append endValue results, so it's inclusive + Object o = treeMap.get( endValue ); + if ( o != null ) + { + if ( o instanceof DuplicateList ) + { + populateListFromIterator( result, + ((DuplicateList)o).iterator() ); + } + else + { + result.add( o ); + } + } + + // return complete result + return result; + } + + protected void populateListFromIterator( List aList, Iterator it ) + { + Object o; + while ( it.hasNext() ) + { + o = it.next(); + if ( o instanceof DuplicateList ) + { + populateListFromIterator( + aList, ((DuplicateList)o).iterator() ); + } + else + { + aList.add( o ); + } + } + } + + public Object addObject( Object anObject, Object newValue ) + { + Object o = treeMap.get( newValue ); + if ( o != null ) + { + if ( o instanceof DuplicateList ) + { + ((DuplicateList)o).add( anObject ); + return anObject; + } + + DuplicateList list = new DuplicateList(); + list.add( o ); + list.add( anObject ); + anObject = list; + + } +if ( anObject == null ) new RuntimeException().printStackTrace(); + + treeMap.put( newValue, anObject ); + return anObject; + } + + public Object updateObject( Object anObject, + Object oldValue, Object newValue ) + { + removeObject( anObject, oldValue ); + return addObject( anObject, newValue ); + } + + public Object removeObject( Object anObject, Object oldValue ) + { + Object o = treeMap.get( oldValue ); + if ( o != null ) + { + if ( o instanceof DuplicateList ) + { + // remove this item from the list + DuplicateList list = (DuplicateList) o; + list.remove( anObject ); + + // if there are still duplicates, return + if ( list.size() > 1 ) + return anObject; + + // else, list size must be one + if ( list.size() == 0 ) + { + System.out.println( "DefaultDataIndex.deleteObject: " + oldValue + + " : list size is 1 : this should never happen." ); + return null; + } + + // replace existing list with remaining item from list + treeMap.remove( oldValue ); + treeMap.put( oldValue, list.getFirst() ); + return anObject; + } + + // otherwise, proceed normally + treeMap.remove( oldValue ); + } + return anObject; + } + + public void clear() + { + treeMap.clear(); + } + + public String toString() + { + return "DefaultDataIndex: " + name + " : " + property + " : " + treeMap.toString(); + } + +} + +/* + * $Log$ + * Revision 1.2 2006/02/19 16:26:19 cgruber + * Move non-unit-test code to tests project + * Fix up code to work with proper imports + * Fix maven dependencies. + * + * Revision 1.1 2006/02/16 13:18:56 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.2 2003/08/14 19:29:38 chochos + * minor cleanup (imports, static method calls, etc) + * + * Revision 1.1.1.1 2000/12/21 15:47:11 mpowers + * Contributing wotonomy. + * + * Revision 1.3 2000/12/20 16:25:36 michael + * Added log to all files. + * + * + */ + diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataView.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataView.java new file mode 100644 index 0000000..ca76252 --- /dev/null +++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DefaultDataView.java @@ -0,0 +1,557 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2000 Michael Powers + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, see http://www.gnu.org +*/ + +package net.wotonomy.datastore; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Observable; + +public class DefaultDataView extends Observable + implements DataView +{ + protected DataSoup backingSoup; + protected List objectList; + protected List keyList; + protected List addedObjectList; + protected List removedObjectList; + protected List addedKeyList; + protected List removedKeyList; + protected Collection updatedObjects; + protected boolean fullyLoaded; + + DefaultDataView( DataSoup aSoup, Collection aKeyList ) + { + backingSoup = aSoup; + objectList = new ArrayList(); + keyList = new ArrayList(); + addedObjectList = new ArrayList(); + removedObjectList = new ArrayList(); + addedKeyList = new ArrayList(); + removedKeyList = new ArrayList(); + updatedObjects = new LinkedList(); + fullyLoaded = false; + + setKeyList( aKeyList ); + } + + void setKeyList( Collection aCollection ) + { + fullyLoaded = false; + addedObjectList.clear(); + removedObjectList.clear(); + addedKeyList.clear(); + removedKeyList.clear(); + updatedObjects.clear(); + keyList.clear(); + objectList.clear(); + if ( ( aCollection == null ) || ( aCollection.size() == 0 ) ) + { + return; + } + keyList.addAll( aCollection ); + for ( int i = 0; i < keyList.size(); i++ ) + { + objectList.add( null ); + } + } + + public Object get( int i ) + { + if ( i > keyList.size() ) return null; + + Object o = objectList.get( i ); + if ( o == null ) + { + Object key = keyList.get( i ); + if ( key == null ) return null; // FIXME!! + + //NOTE: this is the gateway for getting object from the soup + o = backingSoup.getObjectByKey( (DataKey) key ); + + objectList.set( i, o ); + } + return o; + } + + public int indexOf( Object o ) + { + if ( o == null ) return -1; + for ( int i = 0; i < size(); i++ ) + { + if ( o.equals( get( i ) ) ) + { + return i; + } + } + return -1; + } + + private int indexOfIdenticalObject( Object o ) + { + if ( o == null ) return -1; + for ( int i = 0; i < size(); i++ ) + { + if ( o == get( i ) ) + { + return i; + } + } + return -1; + } + + public int lastIndexOf( Object o ) + { + if ( o == null ) return -1; + int lastIndex = -1; + for ( int i = 0; i < size(); i++ ) + { + if ( o.equals( get( i ) ) ) + { + lastIndex = i; + } + } + return lastIndex; + } + + protected void loadAllObjects() + { + if ( fullyLoaded ) return; + for ( int i = 0; i < keyList.size(); i++ ) + { + get( i ); + } + fullyLoaded = true; + } + + // convenience to return the first object, or null. + public Object getObject() + { + return get( 0 ); + } + + // marked object as updated + public void update( Object anObject ) + { + if ( contains( anObject ) ) + { + if ( ! addedObjectList.contains( anObject ) ) + { + updatedObjects.add( anObject ); + } + } + + // notification + setChanged(); + notifyObservers( anObject ); + } + + // DefaultDataViews know their parent soup to perform the query + // and take the subset + public DataView query( + String aProperty, Object beginKey, Object endKey ) { return this; } + + public boolean commit() + { + int index; + Object o; + DataKey key; + for ( int i = 0; i < addedObjectList.size(); i++ ) + { + o = addedObjectList.get(i); + key = backingSoup.addObject( o ); + index = indexOfIdenticalObject( o ); + keyList.set( index, key ); + } + addedObjectList.clear(); + addedKeyList.clear(); + for ( int i = 0; i < removedObjectList.size(); i++ ) + { + backingSoup.removeObject( (DataKey) removedKeyList.get(i) ); + } + removedObjectList.clear(); + removedKeyList.clear(); + + int i; + Iterator it = updatedObjects.iterator(); + while ( it.hasNext() ) + { + i = objectList.indexOf( it.next() ); + backingSoup.updateObject( + (DataKey) keyList.get(i), objectList.get(i) ); + } + updatedObjects.clear(); + + // notification + setChanged(); + notifyObservers( this ); + + return true; + } + + public DataKey getKeyForObject( Object anObject ) + { + int index = indexOfIdenticalObject( anObject ); + if ( index == -1 ) return null; + return (DataKey) keyList.get( index ); + } + + public Object getObjectForKey( DataKey aKey ) + { + int index = keyList.indexOf( aKey ); + if ( index == -1 ) return null; + return get( index ); + } + + // interface Collection + + public int size () { return keyList.size(); } + public boolean isEmpty () { return keyList.isEmpty(); } + public void clear () { setKeyList( null ); }; + public int hashCode() { return keyList.hashCode(); }; + + public boolean equals (Object o) + { + if ( ! ( o instanceof DefaultDataView ) ) return false; + return keyList.equals( ((DefaultDataView)o).keyList ); + } + + public boolean contains (Object o) + { + loadAllObjects(); + return objectList.contains(o); + } + + public boolean containsAll (Collection c) + { + loadAllObjects(); + return objectList.containsAll( c ); + } + + public boolean add (Object o) + { + // if previously removed, restore to list + if ( removedObjectList.contains( o ) ) + { + int index = removedObjectList.indexOf( o ); + removedObjectList.remove( index ); + Object key = removedKeyList.remove( index ); + objectList.add( o ); + keyList.add( key ); + + // notification + setChanged(); + notifyObservers( o ); + return true; + } + + // register and add to lists + Object key = backingSoup.registerTemporaryObject( o ); + addedObjectList.add( o ); + addedKeyList.add( key ); + objectList.add( o ); + keyList.add( key ); + + // notification + setChanged(); + notifyObservers( o ); + return true; + } + + public Object remove( int index ) + { + Object result = get( index ); + if ( remove( result ) ) + { + return result; + } + return null; + } + + public boolean remove (Object o) + { + loadAllObjects(); + + int index = objectList.indexOf( o ); + if ( index == -1 ) return false; + + objectList.remove( index ); + Object key = keyList.remove( index ); + + if ( updatedObjects.contains( o ) ) + { + updatedObjects.remove( o ); + } + + // if not previously added, track removal + if ( ! ( removedObjectList.contains( o ) ) ) + { + removedObjectList.add( o ); + removedKeyList.add( key ); + } + + // notification + setChanged(); + notifyObservers( o ); + + return true; + } + + /** + * Set completely replaces the object at the specified + * index with the specified object. The new object is not + * marked as inserted, and the old object is not marked + * as deleted: the new object will be stored in the soup + * with the same key. The old object is returned. + */ + public Object set( int index, Object element ) + { + Object result = objectList.set( index, element ); + update( element ); + return result; + } + + public void add( int index, Object o ) + { + // if previously removed, restore to list + if ( removedObjectList.contains( o ) ) + { + int i = removedObjectList.indexOf( o ); + removedObjectList.remove( i ); + Object key = removedKeyList.remove( i ); + objectList.add( index, o ); + keyList.add( index, key ); + + // notification + setChanged(); + notifyObservers( o ); + return; + } + + // register and add to lists + Object key = backingSoup.registerTemporaryObject( o ); + addedObjectList.add( o ); + addedKeyList.add( key ); + objectList.add( index, o ); + keyList.add( index, key ); + + // notification + setChanged(); + notifyObservers( o ); + } + + public boolean addAll (Collection c) + { + boolean result = true; + Iterator it = c.iterator(); + while ( it.hasNext() ) + { + result = result && add( it.next() ); + } + return result; + } + + public boolean addAll (int index, Collection c) + { + int originalSize = size(); + boolean result = true; + Iterator it = c.iterator(); + while ( it.hasNext() ) + { + add( index, it.next() ); + } + return ( originalSize + c.size() == size() ); + } + + public boolean removeAll (Collection c) + { + boolean result = true; + Iterator it = c.iterator(); + while ( it.hasNext() ) + { + result = result && remove( it.next() ); + } + return result; + } + + public boolean retainAll (Collection c) + { + removeAll( new ArrayList( objectList ) ); + return addAll( c ); + } + + public List subList( int fromIndex, int toIndex ) + { + List result = new LinkedList(); + for ( int i = fromIndex; i < toIndex; i++ ) + { + result.add( get( i ) ); + } + return result; + } + + public Iterator iterator() + { + loadAllObjects(); + return objectList.iterator(); + +/* // uncomment to enable on-demand loading + return new Iterator() + { + int index = 0; + public boolean hasNext() { return ( index + 1 < keyList.size() ); } + public Object next() { + return get( index++ ); } + public void remove() + { + Object o = get( index ); + if ( o != null ) DefaultDataView.this.remove( o ); + } + }; +*/ + } + + public ListIterator listIterator() + { + return new DataViewIterator( this ); + } + + public ListIterator listIterator( int index ) + { + return new DataViewIterator( this, index ); + } + + public Object[] toArray () + { + loadAllObjects(); + return objectList.toArray(); + } + public java.lang.Object[] toArray (Object[] array) + { + loadAllObjects(); + return objectList.toArray( array ); + } + + protected class DataViewIterator implements ListIterator + { + DataView theView; + int currentIndex; + + //TODO: should track current object in addition to index + // to track external changes to the view. (or should be listener) + Object currentObject; + + public DataViewIterator( DataView aView ) + { + this( aView, 0 ); + } + + public DataViewIterator( DataView aView, int index ) + { + theView = aView; + if ( theView.size() > index ) + { + currentIndex = index; + currentObject = theView.get( currentIndex ); + } + else + { + index = -1; + currentObject = null; + } + } + + public void add( Object o ) + { + currentIndex++; + theView.add( currentIndex, o ); + } + + public boolean hasNext() + { + return ( theView.size() > currentIndex + 1 ); + } + + public boolean hasPrevious() + { + return ( currentIndex > -1 ); + } + + public Object next() + { + return theView.get( ++currentIndex ); + } + + public int nextIndex() + { + return currentIndex + 1; + } + + public Object previous() + { + return theView.get( currentIndex-- ); + } + + public int previousIndex() + { + return currentIndex; + } + + public void remove() + { + theView.remove( currentIndex-- ); + } + + public void set( Object o ) + { + theView.set( currentIndex, o ); + } + + } +} + +/* + * $Log$ + * Revision 1.2 2006/02/19 16:26:19 cgruber + * Move non-unit-test code to tests project + * Fix up code to work with proper imports + * Fix maven dependencies. + * + * Revision 1.1 2006/02/16 13:18:56 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.2 2001/02/15 21:12:41 mpowers + * Added accessors for key throughout the api. This breaks compatibility. + * insertObject now returns the permanent key for the newly created object. + * The old way returned a copy of the object which was an additional read + * that was often ignored. Now you can read it only if you need it. + * Furthermore, there was not other way of getting the permanent key. + * + * Revision 1.1.1.1 2000/12/21 15:47:14 mpowers + * Contributing wotonomy. + * + * Revision 1.2 2000/12/20 16:25:36 michael + * Added log to all files. + * + * + */ + diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DuplicateList.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DuplicateList.java new file mode 100644 index 0000000..ed47b24 --- /dev/null +++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DuplicateList.java @@ -0,0 +1,49 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2000 Michael Powers + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, see http://www.gnu.org +*/ + +package net.wotonomy.datastore; + +import java.util.LinkedList; + +/** +* DuplicateList is a marker class used to store values +* with duplicate keys in the DataIndex TreeMap. +*/ +public class DuplicateList extends LinkedList +{ +} + +/* + * $Log$ + * Revision 1.2 2006/02/19 16:26:19 cgruber + * Move non-unit-test code to tests project + * Fix up code to work with proper imports + * Fix maven dependencies. + * + * Revision 1.1 2006/02/16 13:18:56 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.1.1.1 2000/12/21 15:47:14 mpowers + * Contributing wotonomy. + * + * Revision 1.2 2000/12/20 16:25:36 michael + * Added log to all files. + * + * + */ + diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/FileSoup.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/FileSoup.java new file mode 100644 index 0000000..45cc9d8 --- /dev/null +++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/FileSoup.java @@ -0,0 +1,468 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2000 Michael Powers + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, see http://www.gnu.org +*/ + +package net.wotonomy.datastore; + +import java.io.File; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import net.wotonomy.foundation.internal.Introspector; + +abstract public class FileSoup implements DataSoup +{ + public static final String INDEX_SUFFIX = ".idx"; + public static final String MAP_SUFFIX = ".map"; + private static final String ID_ID = "id"; + private static final String IDENTITY_PROPERTY = "__SELF__"; + + protected DataKey nextUniqueIdentifier; + protected File homeDirectory; + protected Map indices; + + public FileSoup( String aPath ) + { + homeDirectory = new File( aPath ); + + // if specified directory does not exist + if ( ! homeDirectory.exists() ) + { + homeDirectory.mkdirs(); + } + + // if existing path is a file, exit with error + if ( homeDirectory.isDirectory() ) + { + new RuntimeException( "DataStore: Specified directory is a file." ); + } + + // read indices + DataIndex index; + indices = new HashMap(); + String[] files = getHomeDirectory().list(); + for ( int i = 0; i < files.length; i++ ) + { + if ( files[i].endsWith( INDEX_SUFFIX ) ) + { + index = (DataIndex) readFile( files[i] ); + if ( index != null ) + { + indices.put( index.getName(), index ); + } + } + } + + // read unique identifier + nextUniqueIdentifier = (DataKey) readFile( ID_ID ); + if ( nextUniqueIdentifier == null ) + nextUniqueIdentifier = new DataKey( "1" ); + + } + + public File getHomeDirectory() + { + return homeDirectory; + } + + // index management + + public void addIndex( String aName, String aProperty ) + { + DataIndex index = new DefaultDataIndex( aName, aProperty ); + indices.put( index.getName(), index ); + buildIndex( index ); + writeIndices(); + } + + public void removeIndex( String aName ) + { + indices.remove( aName ); + writeIndices(); + } + + public Collection getAllIndices() + { + return indices.values(); + } + +// public void addIndex( String aName, Index anIndex ) {} +// public void removeIndex( String aName ) {} +// public void addTaggedObject( String aKey, Serializable anObject ) +// public Object getTaggedObject( String aKey ); +// public void removeTaggedObject( String aKey ); +// public void setMetaData( +// String aMetaProperty, Serializable aValue, Serializable anObject ); + + protected void buildIndex( DataIndex anIndex ) + { +//System.out.print( "FileSoup.buildIndex: " + anIndex.getName() + " : " ); +long millis = System.currentTimeMillis(); + + anIndex.clear(); + + int count = 0; + DataKey key; + Object o; + Object value; + String property = anIndex.getProperty(); + + String[] files = getHomeDirectory().list(); + for ( int i = 0; i < files.length; i++ ) + { + if ( ( ! files[i].equals( ID_ID.toString() ) + && ( ! files[i].endsWith( INDEX_SUFFIX ) ) ) ) + { + key = new DataKey( files[i] ); + o = getObjectByKey( key ); + value = getValueFromObject( o, property ); + anIndex.addObject( key, value ); + count++; + } + } + +//System.out.print( count + " objects: " ); +//System.out.println( System.currentTimeMillis() - millis + " milliseconds" ); + } + protected void writeIndices() + { + DataIndex index; + Iterator it = getAllIndices().iterator(); + while ( it.hasNext() ) + { + index = (DataIndex) it.next(); + writeFile( index.getName() + INDEX_SUFFIX, index ); + } + } + + // object management + + // this implementation currently uses up a valid key increment + public DataKey registerTemporaryObject( Object anObject ) + { + DataKey id = getNextKey(); + + if ( anObject instanceof UniquelyIdentifiable ) + { + ((UniquelyIdentifiable)anObject).setUniqueIdentifier( id ); + } + + return id; + } + + /** + * Adds the specified object to the soup and returns the key + * for the new object by which it may be subsequently retrieved. + * Null indicates an error, probably due to serialization. + */ + public DataKey addObject( Object anObject ) + { + DataKey id = getNextKey(); + + if ( anObject instanceof UniquelyIdentifiable ) + { // set id if necessary + ((UniquelyIdentifiable)anObject).setUniqueIdentifier( id ); + } + + writeFile( id.toString(), anObject ); + + // update indices + DataIndex index; + Iterator it = indices.values().iterator(); + while ( it.hasNext() ) + { + index = (DataIndex)it.next(); + index.addObject( id, + getValueFromObject( anObject, index.getProperty() ) ); + } + + writeIndices(); + + return id; + } + + /** + * Removes the specified object from the soup and returns + * the removed object as read from the soup (which is the + * original copy of the object). Null indicates object not found. + */ + public Object removeObject( DataKey aKey ) + { + Object existing = getObjectByKey( aKey ); + if ( existing != null ) + { + if ( ! deleteFile( aKey.toString() ) ) + { + existing = null; // return error + } + else + { + // update indices + DataIndex index; + Iterator it = indices.values().iterator(); + while ( it.hasNext() ) + { + index = (DataIndex)it.next(); + index.removeObject( aKey, + getValueFromObject( existing, index.getProperty() ) ); + } + + writeIndices(); + } + } + + return existing; + } + + /** + * Updates the specified object and returns the object + * as updated. Null indicates an error writing the object. + */ + public Object updateObject( DataKey aKey, Object updatedObject ) + { + Object existing = getObjectByKey( aKey ); + if ( existing == null ) + { + System.err.println( "FileSoup.updateObject: " + + "existing object could not be found with id: " + aKey ); + return null; + } + + Object result = null; + if ( updatedObject instanceof UniquelyIdentifiable ) + { + // update key if changed + ((UniquelyIdentifiable)updatedObject).setUniqueIdentifier( aKey ); + } + + if ( writeFile( aKey.toString(), updatedObject ) ) + { + result = updatedObject; + + // update indices + DataIndex index; + Iterator it = indices.values().iterator(); + while ( it.hasNext() ) + { + index = (DataIndex)it.next(); + index.updateObject( aKey, + getValueFromObject( existing, index.getProperty() ), + getValueFromObject( updatedObject, index.getProperty() ) ); + } + + writeIndices(); + } + +//System.out.println( "FileSoup.updateObject: " + updatedObject + " -> " + result ); + return getObjectByKey( aKey ); + } + + protected DataKey getNextKey() + { + DataKey id = (DataKey) nextUniqueIdentifier.clone(); + // while ( id isn't yet in use by the soup ) increment(); + nextUniqueIdentifier.increment(); + writeFile( ID_ID.toString(), nextUniqueIdentifier ); + return id; + } + + protected DataKey getNextTempKey() + { + return getNextKey(); + } + + /** + * Gets object from data store whose identifier is equal + * to the specified object. + */ + public Object getObjectByKey( DataKey aKey ) + { + return readFile( aKey.toString() ); + } + + // queries + + /** + * Returns an empty data view, suitable for creating + * new entries in the soup. + * @return A DataView containing no entries. + */ + public DataView createView() + { + return new DefaultDataView( this, new LinkedList() ); + } + + /** + * Queries by the specified pre-generated index, if it exists. + * Otherwise, falls through to queryByProperty. + */ + public DataView queryByIndex( + String anIndexName, Object beginKey, Object endKey ) + { + DataIndex index = (DataIndex) indices.get( anIndexName ); + + if ( index == null ) + { + return queryByProperty( anIndexName, beginKey, endKey ); + } + + return queryByKeys( index.query( beginKey, endKey ) ); + } + + /** + * Generates an index based on the specified property + * and then executes the query. + */ + public DataView queryByProperty( + String aPropertyName, Object beginKey, Object endKey ) + { + if ( aPropertyName == null ) aPropertyName = IDENTITY_PROPERTY; + DataIndex index = new DefaultDataIndex( "temporary", aPropertyName ); + buildIndex( index ); + return queryByKeys( index.query( beginKey, endKey ) ); + } + + /** + * Generates an index based on the specified property + * and then executes the query. + */ + public DataView queryObjects( Object beginKey, Object endKey ) + { + return queryByProperty( IDENTITY_PROPERTY, beginKey, endKey ); + } + + /** + * Returns a view containing the objects for the specified keys. + */ + public DataView queryByKeys( Collection aKeyList ) + { + return new DefaultDataView( this, aKeyList ); + } + + /** + * As queryByIndex, but with objects returned in reverse order. + * @param anIndexName The index to be queried. + * @param beginValue The beginning value, or null for all values + * up to an including the end key. + * @param endValue The ending value, or null for all values + * since and including the begin key. + * @return A DataView containing the query results, or null + * for invalid query parameters. + */ + public DataView reverseQueryByIndex( + String anIndexName, Object beginKey, Object endKey ) + { + DataIndex index = (DataIndex) indices.get( anIndexName ); + + if ( index == null ) + { + return reverseQueryByProperty( anIndexName, beginKey, endKey ); + } + + List items = index.query( endKey, beginKey ); + Collections.reverse( items ); + return queryByKeys( items ); + } + + /** + * As queryByProperty, but with objects returned in reverse order. + * @param aPropertyName The property to be queried. If null, + * will query the objects directly with queryObjects(). + * @param beginValue The beginning value, or null for all values + * up to an including the end key. + * @param endValue The ending value, or null for all values + * since and including the begin key. + * @return A DataView containing the query results, or null + * for invalid query parameters. + */ + public DataView reverseQueryByProperty( + String aPropertyName, Object beginKey, Object endKey ) + { + if ( aPropertyName == null ) aPropertyName = IDENTITY_PROPERTY; + DataIndex index = new DefaultDataIndex( "temporary", aPropertyName ); + buildIndex( index ); + List items = index.query( endKey, beginKey ); + Collections.reverse( items ); + return queryByKeys( items ); + } + + /** + * As queryObjects, but with objects returned in reverse order. + * @param beginValue The beginning value, or null for all values + * up to an including the end key. + * @param endValue The ending value, or null for all values + * since and including the begin key. + * @return A DataView containing the query results, or null + * for invalid query parameters. + */ + public DataView reverseQueryObjects( Object beginKey, Object endKey ) + { + return queryByProperty( IDENTITY_PROPERTY, beginKey, endKey ); + } + + public Object getValueFromObject( Object anObject, String aProperty ) + { + if ( IDENTITY_PROPERTY.equals( aProperty ) ) return anObject; + return Introspector.getValueForObject( anObject, aProperty ); + } + + // file access methods + + abstract protected boolean writeFile( String name, Object anObject ); + abstract protected Object readFile( String name ); + abstract protected boolean deleteFile( String name ); + +} + +/* + * $Log$ + * Revision 1.2 2006/02/19 16:26:19 cgruber + * Move non-unit-test code to tests project + * Fix up code to work with proper imports + * Fix maven dependencies. + * + * Revision 1.1 2006/02/16 13:18:56 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.4 2003/08/14 19:29:38 chochos + * minor cleanup (imports, static method calls, etc) + * + * Revision 1.3 2001/03/05 22:12:11 mpowers + * Created the control package for a datastore-specific implementation + * of EOObjectStore. + * + * Revision 1.2 2001/02/15 21:12:41 mpowers + * Added accessors for key throughout the api. This breaks compatibility. + * insertObject now returns the permanent key for the newly created object. + * The old way returned a copy of the object which was an additional read + * that was often ignored. Now you can read it only if you need it. + * Furthermore, there was not other way of getting the permanent key. + * + * Revision 1.1.1.1 2000/12/21 15:47:20 mpowers + * Contributing wotonomy. + * + * Revision 1.3 2000/12/20 16:25:36 michael + * Added log to all files. + * + * + */ + diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/SerializedFileSoup.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/SerializedFileSoup.java new file mode 100644 index 0000000..e466c78 --- /dev/null +++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/SerializedFileSoup.java @@ -0,0 +1,120 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2000 Michael Powers + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, see http://www.gnu.org +*/ + +package net.wotonomy.datastore; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +public class SerializedFileSoup extends FileSoup +{ + public SerializedFileSoup( String aPath ) + { + super( aPath ); + } + + // file access methods + + protected boolean writeFile( String name, Object anObject ) + { + try + { + File f = new File( getHomeDirectory(), name ); + ObjectOutputStream oos = new ObjectOutputStream( + new FileOutputStream( f ) ); + oos.writeObject( anObject ); + oos.flush(); + oos.close(); + return true; + } + catch ( Exception exc ) + { + System.err.println( "SerializedFileSoup.writeFile: " + exc ); + } + + return false; + } + + protected Object readFile( String name ) + { + Object result = null; + + try + { + File f = new File( getHomeDirectory(), name ); + ObjectInputStream ois = new ObjectInputStream( + new FileInputStream( f ) ); + result = ois.readObject(); + ois.close(); + } + catch ( FileNotFoundException exc ) + { + result = null; + } + catch ( Exception exc ) + { + System.err.println( "SerializedFileSoup.readFile: " + exc ); + exc.printStackTrace(); + } + return result; + } + + protected boolean deleteFile( String name ) + { + try + { + File f = new File( getHomeDirectory(), name ); + if ( f.exists() ) + { + f.delete(); + return true; + } + } + catch ( Exception exc ) + { + System.err.println( "SerializedFileSoup.deleteFile: " + exc ); + } + + return false; + } + +} + +/* + * $Log$ + * Revision 1.2 2006/02/19 16:26:19 cgruber + * Move non-unit-test code to tests project + * Fix up code to work with proper imports + * Fix maven dependencies. + * + * Revision 1.1 2006/02/16 13:18:56 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.1.1.1 2000/12/21 15:47:20 mpowers + * Contributing wotonomy. + * + * Revision 1.2 2000/12/20 16:25:37 michael + * Added log to all files. + * + * + */ + diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/UniquelyIdentifiable.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/UniquelyIdentifiable.java new file mode 100644 index 0000000..104932e --- /dev/null +++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/UniquelyIdentifiable.java @@ -0,0 +1,40 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2000 Michael Powers + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, see http://www.gnu.org +*/ + +package net.wotonomy.datastore; + +public interface UniquelyIdentifiable +{ + Object getUniqueIdentifier(); + void setUniqueIdentifier( Object id ); +} + +/* + * $Log$ + * Revision 1.1 2006/02/16 13:18:56 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.1.1.1 2000/12/21 15:47:20 mpowers + * Contributing wotonomy. + * + * Revision 1.2 2000/12/20 16:25:37 michael + * Added log to all files. + * + * + */ + diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/XMLFileSoup.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/XMLFileSoup.java new file mode 100644 index 0000000..94d85fb --- /dev/null +++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/XMLFileSoup.java @@ -0,0 +1,130 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2000 Michael Powers + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, see http://www.gnu.org +*/ + +package net.wotonomy.datastore; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.MalformedURLException; + +import net.wotonomy.web.xml.XMLRPCDecoder; +import net.wotonomy.web.xml.XMLRPCEncoder; + +public class XMLFileSoup extends FileSoup +{ + public XMLFileSoup( String aPath ) + { + super( aPath ); + } + + // file access methods + + protected boolean writeFile( String name, Object anObject ) + { +//System.out.print( "writeFile: " + name + "..." ); + try + { + File f = new File( getHomeDirectory(), name ); + FileOutputStream fos = new FileOutputStream( f ); + XMLRPCEncoder encoder = new XMLRPCEncoder(); + encoder.encode( anObject, fos ); + fos.flush(); + fos.close(); + } + catch ( Exception exc ) + { + System.err.println( "XMLFileSoup.writeFile: " + exc ); + return false; + } +//System.out.println( "done." ); + return true; + } + + protected Object readFile( String name ) + { +//System.out.print( "readFile: " + name + "..." ); + Object result = null; + + try + { + File f = new File( getHomeDirectory(), name ); + FileInputStream fis = new FileInputStream( f ); + XMLRPCDecoder decoder = new XMLRPCDecoder(); + result = decoder.decode( fis, f.getAbsolutePath(), f.toURL() ); + fis.close(); + } + catch ( MalformedURLException exc ) + { + result = null; + } + catch ( IOException exc ) + { + result = null; + } +//System.out.println( "done." ); + return result; + } + + protected boolean deleteFile( String name ) + { + try + { + File f = new File( getHomeDirectory(), name ); + if ( f.exists() ) + { + f.delete(); + return true; + } + } + catch ( Exception exc ) + { + System.err.println( "XMLFileSoup.deleteFile: " + exc ); + } + + return false; + } + +} + +/* + * $Log$ + * Revision 1.2 2006/02/19 16:26:19 cgruber + * Move non-unit-test code to tests project + * Fix up code to work with proper imports + * Fix maven dependencies. + * + * Revision 1.1 2006/02/16 13:18:56 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.3 2003/08/14 19:29:38 chochos + * minor cleanup (imports, static method calls, etc) + * + * Revision 1.2 2001/02/07 19:26:28 mpowers + * XML classes are in new package. + * + * Revision 1.1.1.1 2000/12/21 15:47:23 mpowers + * Contributing wotonomy. + * + * Revision 1.6 2000/12/20 16:25:37 michael + * Added log to all files. + * + * + */ + diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/package.html b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/package.html new file mode 100644 index 0000000..7ca944c --- /dev/null +++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/package.html @@ -0,0 +1,19 @@ +<body> +<p> +A "low technology" object database, suitable +for simple application persistence. The design +goal is to simply store, retrieve, and query +arbitrary java objects that need no knowledge of +how they are to be persisted. +</p> +<p> +DataSoup is the primary interface, with +SerializedFileSoup and XMLFileSoup being the +primary implementations. Both implementations +persist arbitrary java objects to the file system, +with some limitations. +</p> +<p> +This package has dependencies on the util package. +</p> +</body> |
