diff options
| author | Benjamin Culkin <scorpress@gmail.com> | 2024-05-20 17:58:16 -0400 |
|---|---|---|
| committer | Benjamin Culkin <scorpress@gmail.com> | 2024-05-20 17:58:16 -0400 |
| commit | 40a9d99496e098562f090fb7ffce9e749011b131 (patch) | |
| tree | 437df24d65470582e943e494a52db8ed65a881ae /projects/net.wotonomy.foundation/src/main/java/net | |
| parent | ff072dfe782f6f22123cd4ba050828d35c0d0fbd (diff) | |
Formatting pass
Diffstat (limited to 'projects/net.wotonomy.foundation/src/main/java/net')
49 files changed, 8598 insertions, 10032 deletions
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java index 491722c..e79c206 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java @@ -29,633 +29,639 @@ import java.util.List; import java.util.ListIterator; /** -* NSArray is an unmodifiable List. -* Calling the mutator methods of the List interface (add, addAll, -* set, etc.) on an instance of NSArray will throw an Unsupported -* Operation exception: use a NSMutableArray instead. This is to -* simulate Objective-C's pattern of exposing mutator methods only -* on mutable subinterface, which is wonderful for communicating -* via interface the contract on returned collections (whether you -* may modify return values) as well as implementing array faults. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 929 $ -*/ -public class NSArray implements List, Serializable -{ - /** - * Actual list that backs this instance. - */ - List list; - - /** - * Return value when array index is not found. - */ - public static final int NotFound = -1; + * NSArray is an unmodifiable List. Calling the mutator methods of the List + * interface (add, addAll, set, etc.) on an instance of NSArray will throw an + * Unsupported Operation exception: use a NSMutableArray instead. This is to + * simulate Objective-C's pattern of exposing mutator methods only on mutable + * subinterface, which is wonderful for communicating via interface the contract + * on returned collections (whether you may modify return values) as well as + * implementing array faults. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 929 $ + */ +public class NSArray implements List, Serializable { + /** + * Actual list that backs this instance. + */ + List list; /** - * A constant representing an empty array. - */ - public static final NSArray EmptyArray = new NSArray(); - - /** - * Returns an NSArray backed by the specified List. - * This is useful to "protect" an internal representation - * that is returned by a method of return type NSArray. - */ - public static NSArray arrayBackedByList( List aList ) - { - return new NSArray( aList, null ); - } - - /** - * A constructor that uses the provided list as the backing - * list object. This is unlike ArrayList and other - * java.util.Collection types insofar as that API requires - * that the provided Collection be copied into the newly constructed - * Collection. - * - * TODO: See if this signature can be reasonably changed, as having a no-op parameter is a little counter-intuitive. - * @param aList A list that the caller wishes to become the backing list for the NSArray. - * @param ignored This parameter is entirely ignored, and is only there to distinguish the API. - */ - NSArray( List aList, Object ignored ) // differentiates - { - list = aList; - } - - /** - * Constructor with a size hint, used by NSMutableArray. - */ - NSArray( int aSize ) - { - list = new ArrayList( aSize ); - } - - /** - * Default constructor returns an empty array. - */ - public NSArray () - { - list = new ArrayList(); - } + * Return value when array index is not found. + */ + public static final int NotFound = -1; /** - * Produces an array containing only the specified object. - */ - public NSArray (Object anObject) - { - this(); - list.add( anObject ); - } + * A constant representing an empty array. + */ + public static final NSArray EmptyArray = new NSArray(); /** - * Produces an array containing the specified objects. - */ - public NSArray (Object[] anArray) - { - this(); - for ( int i = 0; i < anArray.length; i++ ) - { - list.add( anArray[i] ); - } - } + * Returns an NSArray backed by the specified List. This is useful to "protect" + * an internal representation that is returned by a method of return type + * NSArray. + */ + public static NSArray arrayBackedByList(List aList) { + return new NSArray(aList, null); + } /** - * Produces an array containing the objects in the specified collection. - */ - public NSArray (Collection aCollection) - { - this(); - Iterator i = aCollection.iterator(); - while ( i.hasNext() ) list.add( i.next() ); - } + * A constructor that uses the provided list as the backing list object. This is + * unlike ArrayList and other java.util.Collection types insofar as that API + * requires that the provided Collection be copied into the newly constructed + * Collection. + * + * TODO: See if this signature can be reasonably changed, as having a no-op + * parameter is a little counter-intuitive. + * + * @param aList A list that the caller wishes to become the backing list for + * the NSArray. + * @param ignored This parameter is entirely ignored, and is only there to + * distinguish the API. + */ + NSArray(List aList, Object ignored) // differentiates + { + list = aList; + } /** - * Returns the number of items in this array. - */ - public int count () - { - return list.size(); - } + * Constructor with a size hint, used by NSMutableArray. + */ + NSArray(int aSize) { + list = new ArrayList(aSize); + } /** - * Returns an array containing all objects in this array - * plus the specified object. - */ - public NSArray arrayByAddingObject (Object anObject) - { - NSArray result = new NSArray( this ); - result.protectedAdd( anObject ); - return result; - } + * Default constructor returns an empty array. + */ + public NSArray() { + list = new ArrayList(); + } /** - * Returns an array containing all objects in this array - * plus all objects in the specified list. - */ - public NSArray arrayByAddingObjectsFromArray (Collection aCollection) - { - NSArray result = new NSArray( this ); - result.protectedAddAll( aCollection ); - return result; - } + * Produces an array containing only the specified object. + */ + public NSArray(Object anObject) { + this(); + list.add(anObject); + } /** - * Returns a string containing the string representations of - * each element in this array, with each element separated from - * each neighboring element by the specified string. - */ - public String componentsJoinedByString (String separator) - { - StringBuffer buf = new StringBuffer(); - Iterator it = list.iterator(); - if ( it.hasNext() ) - { - buf.append( it.next().toString() ); - } - while ( it.hasNext() ) - { - buf.append( separator ); - buf.append( String.valueOf(it.next()) ); - } - return buf.toString(); - } - - /** - * Returns whether an equivalent object is contained in this array. - */ - public boolean containsObject (Object anObject) - { - return list.contains( anObject ); - } + * Produces an array containing the specified objects. + */ + public NSArray(Object[] anArray) { + this(); + for (int i = 0; i < anArray.length; i++) { + list.add(anArray[i]); + } + } /** - * Returns the first object in this array that is equivalent to - * an object in the specified list, or null if no objects are - * in common. - */ - public Object firstObjectCommonWithArray (Collection aCollection) - { - if ( aCollection == null ) return null; - - Object o; - Iterator it = list.iterator(); - while ( it.hasNext() ) - { - o = it.next(); - if ( aCollection.contains( o ) ) return o; - } - return null; - } - - /** - * Returns whether the specified list contains elements equivalent - * to those in this array in the same order. - */ - public boolean isEqualToArray (List aList) - { - return list.equals( aList ); - } + * Produces an array containing the objects in the specified collection. + */ + public NSArray(Collection aCollection) { + this(); + Iterator i = aCollection.iterator(); + while (i.hasNext()) + list.add(i.next()); + } /** - * Returns the last object in this array, or null if the array is empty. - */ - public Object lastObject () - { - int i; - if ( (i = list.size()) == 0 ) return null; - return list.get( i - 1 ); - } + * Returns the number of items in this array. + */ + public int count() { + return list.size(); + } + + /** + * Returns an array containing all objects in this array plus the specified + * object. + */ + public NSArray arrayByAddingObject(Object anObject) { + NSArray result = new NSArray(this); + result.protectedAdd(anObject); + return result; + } + + /** + * Returns an array containing all objects in this array plus all objects in the + * specified list. + */ + public NSArray arrayByAddingObjectsFromArray(Collection aCollection) { + NSArray result = new NSArray(this); + result.protectedAddAll(aCollection); + return result; + } + + /** + * Returns a string containing the string representations of each element in + * this array, with each element separated from each neighboring element by the + * specified string. + */ + public String componentsJoinedByString(String separator) { + StringBuffer buf = new StringBuffer(); + Iterator it = list.iterator(); + if (it.hasNext()) { + buf.append(it.next().toString()); + } + while (it.hasNext()) { + buf.append(separator); + buf.append(String.valueOf(it.next())); + } + return buf.toString(); + } + + /** + * Returns whether an equivalent object is contained in this array. + */ + public boolean containsObject(Object anObject) { + return list.contains(anObject); + } + + /** + * Returns the first object in this array that is equivalent to an object in the + * specified list, or null if no objects are in common. + */ + public Object firstObjectCommonWithArray(Collection aCollection) { + if (aCollection == null) + return null; + + Object o; + Iterator it = list.iterator(); + while (it.hasNext()) { + o = it.next(); + if (aCollection.contains(o)) + return o; + } + return null; + } + + /** + * Returns whether the specified list contains elements equivalent to those in + * this array in the same order. + */ + public boolean isEqualToArray(List aList) { + return list.equals(aList); + } + + /** + * Returns the last object in this array, or null if the array is empty. + */ + public Object lastObject() { + int i; + if ((i = list.size()) == 0) + return null; + return list.get(i - 1); + } /** * */ -/* - public NSArray sortedArrayUsingSelector (NSSelector); -*/ + /* + * public NSArray sortedArrayUsingSelector (NSSelector); + */ /** - * Returns an array comprised of only those elements whose - * indices fall within the specified range. - */ - public NSArray subarrayWithRange (NSRange aRange) - { - //TODO: Test this logic. - NSArray result = new NSArray(); - if ( aRange == null ) return result; - - int loc = aRange.location(); - int max = aRange.maxRange(); - int count = count(); - for ( int i = loc; i <= max && i < count; i++ ) - { - result.protectedAdd( list.get( i ) ); - } - return result; - } - - /** - * Returns an enumeration over the the elements of the array. - */ - public Enumeration objectEnumerator () - { - //TODO: Test this logic. - return new Enumeration() - { - Iterator it = NSArray.this.iterator(); - public boolean hasMoreElements() - { + * Returns an array comprised of only those elements whose indices fall within + * the specified range. + */ + public NSArray subarrayWithRange(NSRange aRange) { + // TODO: Test this logic. + NSArray result = new NSArray(); + if (aRange == null) + return result; + + int loc = aRange.location(); + int max = aRange.maxRange(); + int count = count(); + for (int i = loc; i <= max && i < count; i++) { + result.protectedAdd(list.get(i)); + } + return result; + } + + /** + * Returns an enumeration over the the elements of the array. + */ + public Enumeration objectEnumerator() { + // TODO: Test this logic. + return new Enumeration() { + Iterator it = NSArray.this.iterator(); + + public boolean hasMoreElements() { return it.hasNext(); - } - public Object nextElement() - { - return it.next(); - } - }; + } + + public Object nextElement() { + return it.next(); + } + }; } /** - * Returns an enumeration over the elements of the array in reverse order. - */ - public java.util.Enumeration reverseObjectEnumerator () - { - return new java.util.Enumeration() - { - ListIterator it = null; - public ListIterator getIterator() - { - if ( it == null ) - { - it = NSArray.this.listIterator(); - // zoom to end - while ( it.hasNext() ) it.next(); + * Returns an enumeration over the elements of the array in reverse order. + */ + public java.util.Enumeration reverseObjectEnumerator() { + return new java.util.Enumeration() { + ListIterator it = null; + + public ListIterator getIterator() { + if (it == null) { + it = NSArray.this.listIterator(); + // zoom to end + while (it.hasNext()) + it.next(); } return it; - } - public boolean hasMoreElements() - { + } + + public boolean hasMoreElements() { return getIterator().hasPrevious(); - } - public Object nextElement() - { - return getIterator().previous(); - } - }; + } + + public Object nextElement() { + return getIterator().previous(); + } + }; } /** - * Copies the elements of this array into the specified object array - * as the array's capacity permits. - */ - public void getObjects (Object[] anArray) - { - getObjects(anArray,null); - } - - /** - * Copies the elements of this array that fall within the specified range - * into the specified object array as the array's capacity permits. This - * method must not overflow, even in the face of a null range, an over or - * under-sized array, or a bad range. It may underflow and fail to - * entirely populate the array, if the array is larger than the data to - * be copied. - * - * TODO: Check whether in WebObjects the range supposed to be measured against the parameter or the NSArray itself??? -ceg - * - * @param anArray An object array to be filled by this method. - * @param range An NSRange object representing the range of data in the NSArray to be copied. - */ - public void getObjects (Object[] array, NSRange range) - { - if ( array == null ) return; - if ( range == null) range = new NSRange(0,array.length); - int limit = Math.min(Math.min(array.length,range.length()),(count()-range.location())); - for ( int i = 0; i < limit ; i++ ) { - //anArray[ i-aRange.location() ] = objectAtIndex( i ); - array[ i ] = objectAtIndex( range.location() + i ); - } - } - - /** - * Returns the index of the first object in the array equivalent - * to the specified object. Returns NotFound if the item is not found. - */ - public int indexOfObject (Object anObject) - { - int result = list.indexOf( anObject ); - if ( result == -1 ) return NotFound; // in case this changes - return result; - } + * Copies the elements of this array into the specified object array as the + * array's capacity permits. + */ + public void getObjects(Object[] anArray) { + getObjects(anArray, null); + } /** - * Returns the index of the first object in the array - * within the specified range equivalent to the specified object. - * Returns NotFound if the item is not found. - */ - public int indexOfObject (Object anObject, NSRange aRange) - { - if ( ( anObject == null ) || ( aRange == null ) ) return NotFound; - - int loc = aRange.location(); - int max = aRange.maxRange(); - for ( int i = loc; i < max; i++ ) - { - if ( anObject.equals( list.get(i) ) ) - { - return i; - } - } - return NotFound; - } - - /** - * Returns the index of the specified object if it exists - * in the array, comparing by reference. - * Returns NotFound if the item is not found. - */ - public int indexOfIdenticalObject (Object anObject) - { - int size = list.size(); - for ( int i = 0; i < size; i++ ) - { - if ( anObject == list.get(i) ) - { - return i; - } - } - return NotFound; - } - - /** - * Returns the index of the first object in the array - * within the specified range equivalent to the specified object. - */ - public int indexOfIdenticalObject (Object anObject, NSRange aRange) - { - if ( aRange == null ) return NotFound; - - int loc = aRange.location(); - int max = aRange.maxRange(); - for ( int i = loc; i < max; i++ ) - { - if ( anObject == list.get(i) ) - { - return i; - } - } - return NotFound; - } - - /** - * Returns the object at the specified index. Throws an - * IndexOutOfRange exception if the index is out of range. - */ - public Object objectAtIndex (int anIndex) - { - return list.get( anIndex ); - } + * Copies the elements of this array that fall within the specified range into + * the specified object array as the array's capacity permits. This method must + * not overflow, even in the face of a null range, an over or under-sized array, + * or a bad range. It may underflow and fail to entirely populate the array, if + * the array is larger than the data to be copied. + * + * TODO: Check whether in WebObjects the range supposed to be measured against + * the parameter or the NSArray itself??? -ceg + * + * @param anArray An object array to be filled by this method. + * @param range An NSRange object representing the range of data in the + * NSArray to be copied. + */ + public void getObjects(Object[] array, NSRange range) { + if (array == null) + return; + if (range == null) + range = new NSRange(0, array.length); + int limit = Math.min(Math.min(array.length, range.length()), (count() - range.location())); + for (int i = 0; i < limit; i++) { + // anArray[ i-aRange.location() ] = objectAtIndex( i ); + array[i] = objectAtIndex(range.location() + i); + } + } /** - * Returns an array consisting of strings within the specified string - * as delimited by the specified separator characters. - */ - public static NSArray componentsSeparatedByString - (String aString, String aSeparator) - { - NSArray result = new NSArray(); - if ( aString == null ) return result; - if ( aSeparator == null ) return new NSArray( aString ); - - //FIXME: The spec probably considers the whole - // string as a separator, unlike string tokenizer. - java.util.StringTokenizer tokens = - new java.util.StringTokenizer( aString, aSeparator ); - while ( tokens.hasMoreTokens() ) - { - result.protectedAdd( tokens.nextToken() ); - } - - return result; - } - - public Object clone() - { - return new NSArray( list ); - } - - public NSArray immutableClone() - { - return this; - } - - public NSMutableArray mutableClone() - { - return new NSMutableArray( this ); - } - - public String toString() { - StringBuffer buf = new StringBuffer(); - buf.append(NSPropertyListSerialization.TOKEN_BEGIN[NSPropertyListSerialization.PLIST_ARRAY]); - for (int i = 0; i < count(); i++) { - Object x = objectAtIndex(i); - buf.append(NSPropertyListSerialization.stringForPropertyList(x)); - if (i < count() - 1) - buf.append(", "); - } - buf.append(NSPropertyListSerialization.TOKEN_END[NSPropertyListSerialization.PLIST_ARRAY]); - return buf.toString(); - } - - // interface List: accessors - - public boolean contains(Object o) { return list.contains(o); } - public boolean containsAll(Collection c) { return list.containsAll(c); } - public boolean equals(Object o) { return list.equals(o); } - public Object get(int index) { return list.get(index); } - public int hashCode() { - int code = 19; - code *= getClass().hashCode(); - code *= list.hashCode(); - return code; - } - public int indexOf(Object o) { return list.indexOf(o); } - public boolean isEmpty() { return list.isEmpty(); } - public int lastIndexOf(Object o) { return list.lastIndexOf(o); } - public int size() { return list.size(); } - public Object[] toArray() { return list.toArray(); } - public Object[] toArray(Object[] a) { return list.toArray(a); } - - // interface List: mutators - - - public void add(int index, Object element) - { - this.list.add(index,element); - } - - public boolean add(Object o) - { + * Returns the index of the first object in the array equivalent to the + * specified object. Returns NotFound if the item is not found. + */ + public int indexOfObject(Object anObject) { + int result = list.indexOf(anObject); + if (result == -1) + return NotFound; // in case this changes + return result; + } + + /** + * Returns the index of the first object in the array within the specified range + * equivalent to the specified object. Returns NotFound if the item is not + * found. + */ + public int indexOfObject(Object anObject, NSRange aRange) { + if ((anObject == null) || (aRange == null)) + return NotFound; + + int loc = aRange.location(); + int max = aRange.maxRange(); + for (int i = loc; i < max; i++) { + if (anObject.equals(list.get(i))) { + return i; + } + } + return NotFound; + } + + /** + * Returns the index of the specified object if it exists in the array, + * comparing by reference. Returns NotFound if the item is not found. + */ + public int indexOfIdenticalObject(Object anObject) { + int size = list.size(); + for (int i = 0; i < size; i++) { + if (anObject == list.get(i)) { + return i; + } + } + return NotFound; + } + + /** + * Returns the index of the first object in the array within the specified range + * equivalent to the specified object. + */ + public int indexOfIdenticalObject(Object anObject, NSRange aRange) { + if (aRange == null) + return NotFound; + + int loc = aRange.location(); + int max = aRange.maxRange(); + for (int i = loc; i < max; i++) { + if (anObject == list.get(i)) { + return i; + } + } + return NotFound; + } + + /** + * Returns the object at the specified index. Throws an IndexOutOfRange + * exception if the index is out of range. + */ + public Object objectAtIndex(int anIndex) { + return list.get(anIndex); + } + + /** + * Returns an array consisting of strings within the specified string as + * delimited by the specified separator characters. + */ + public static NSArray componentsSeparatedByString(String aString, String aSeparator) { + NSArray result = new NSArray(); + if (aString == null) + return result; + if (aSeparator == null) + return new NSArray(aString); + + // FIXME: The spec probably considers the whole + // string as a separator, unlike string tokenizer. + java.util.StringTokenizer tokens = new java.util.StringTokenizer(aString, aSeparator); + while (tokens.hasMoreTokens()) { + result.protectedAdd(tokens.nextToken()); + } + + return result; + } + + public Object clone() { + return new NSArray(list); + } + + public NSArray immutableClone() { + return this; + } + + public NSMutableArray mutableClone() { + return new NSMutableArray(this); + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append(NSPropertyListSerialization.TOKEN_BEGIN[NSPropertyListSerialization.PLIST_ARRAY]); + for (int i = 0; i < count(); i++) { + Object x = objectAtIndex(i); + buf.append(NSPropertyListSerialization.stringForPropertyList(x)); + if (i < count() - 1) + buf.append(", "); + } + buf.append(NSPropertyListSerialization.TOKEN_END[NSPropertyListSerialization.PLIST_ARRAY]); + return buf.toString(); + } + + // interface List: accessors + + public boolean contains(Object o) { + return list.contains(o); + } + + public boolean containsAll(Collection c) { + return list.containsAll(c); + } + + public boolean equals(Object o) { + return list.equals(o); + } + + public Object get(int index) { + return list.get(index); + } + + public int hashCode() { + int code = 19; + code *= getClass().hashCode(); + code *= list.hashCode(); + return code; + } + + public int indexOf(Object o) { + return list.indexOf(o); + } + + public boolean isEmpty() { + return list.isEmpty(); + } + + public int lastIndexOf(Object o) { + return list.lastIndexOf(o); + } + + public int size() { + return list.size(); + } + + public Object[] toArray() { + return list.toArray(); + } + + public Object[] toArray(Object[] a) { + return list.toArray(a); + } + + // interface List: mutators + + public void add(int index, Object element) { + this.list.add(index, element); + } + + public boolean add(Object o) { return this.list.add(o); - } - - public boolean addAll(Collection coll) - { - return this.list.addAll(coll); - } - - public boolean addAll(int index, Collection c) - { - return this.list.addAll(index,c); - } - - public void clear() - { + } + + public boolean addAll(Collection coll) { + return this.list.addAll(coll); + } + + public boolean addAll(int index, Collection c) { + return this.list.addAll(index, c); + } + + public void clear() { this.list.clear(); - } - - public Iterator iterator() - { - // make a copy to avoid ConcurrentModificationExceptions - final Iterator i = new LinkedList( list ).iterator(); - return new Iterator() - { - public boolean hasNext() {return i.hasNext();} - public Object next() {return i.next();} - public void remove() { throw new UnsupportedOperationException(); } - }; - } - - public ListIterator listIterator() { return listIterator(0); } - - public ListIterator listIterator(final int index) - { - // make a copy to avoid ConcurrentModificationExceptions - final ListIterator i = new LinkedList( list ).listIterator(index); - return new ListIterator() - { - public boolean hasNext() {return i.hasNext();} - public Object next() {return i.next();} - public boolean hasPrevious() {return i.hasPrevious();} - public Object previous() {return i.previous();} - public int nextIndex() {return i.nextIndex();} - public int previousIndex() {return i.previousIndex();} - public void remove() { throw new UnsupportedOperationException(); } - public void set(Object o) { throw new UnsupportedOperationException(); } - public void add(Object o) { throw new UnsupportedOperationException(); } - }; - } - - public Object remove(int index) - { + } + + public Iterator iterator() { + // make a copy to avoid ConcurrentModificationExceptions + final Iterator i = new LinkedList(list).iterator(); + return new Iterator() { + public boolean hasNext() { + return i.hasNext(); + } + + public Object next() { + return i.next(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + public ListIterator listIterator() { + return listIterator(0); + } + + public ListIterator listIterator(final int index) { + // make a copy to avoid ConcurrentModificationExceptions + final ListIterator i = new LinkedList(list).listIterator(index); + return new ListIterator() { + public boolean hasNext() { + return i.hasNext(); + } + + public Object next() { + return i.next(); + } + + public boolean hasPrevious() { + return i.hasPrevious(); + } + + public Object previous() { + return i.previous(); + } + + public int nextIndex() { + return i.nextIndex(); + } + + public int previousIndex() { + return i.previousIndex(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + public void set(Object o) { + throw new UnsupportedOperationException(); + } + + public void add(Object o) { + throw new UnsupportedOperationException(); + } + }; + } + + public Object remove(int index) { return this.list.remove(index); - } - - public boolean remove(Object o) - { + } + + public boolean remove(Object o) { return this.list.remove(o); - } + } - public boolean removeAll(Collection coll) - { + public boolean removeAll(Collection coll) { return this.list.removeAll(coll); - } + } - public boolean retainAll(Collection coll) - { + public boolean retainAll(Collection coll) { return this.list.retainAll(coll); - } - - public Object set(int index, Object element) - { - return this.list.set(index,element); - } - - public List subList(int fromIndex, int toIndex) - { - return Collections.unmodifiableList(list.subList(fromIndex, toIndex)); - } - - /** - * Provided for the use of subclasses like ArrayFault. - */ - protected boolean protectedAdd( Object o ) - { - return list.add( o ); - } - - /** - * Provided for the use of subclasses like ArrayFault. - */ - protected boolean protectedAddAll( Collection coll ) - { - return list.addAll( coll ); - } + } + + public Object set(int index, Object element) { + return this.list.set(index, element); + } + + public List subList(int fromIndex, int toIndex) { + return Collections.unmodifiableList(list.subList(fromIndex, toIndex)); + } + + /** + * Provided for the use of subclasses like ArrayFault. + */ + protected boolean protectedAdd(Object o) { + return list.add(o); + } + + /** + * Provided for the use of subclasses like ArrayFault. + */ + protected boolean protectedAddAll(Collection coll) { + return list.addAll(coll); + } } /* - * $Log$ - * Revision 1.2 2006/03/10 00:52:27 cgruber - * Add tests for NSArray and fix some problems that became obvious as a result. + * $Log$ Revision 1.2 2006/03/10 00:52:27 cgruber Add tests for NSArray and fix + * some problems that became obvious as a result. * - * Revision 1.1 2006/02/16 12:47:16 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.16 2005/07/13 14:12:44 cgruber - * Add mutableClone() and immutableClone() per. WebObjects 5.3 conformance. + * Revision 1.16 2005/07/13 14:12:44 cgruber Add mutableClone() and + * immutableClone() per. WebObjects 5.3 conformance. * - * Revision 1.15 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.15 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.14 2003/08/05 00:48:56 chochos - * use NSPropertyListSerialization to get the opening and closing tokens for the string representation + * Revision 1.14 2003/08/05 00:48:56 chochos use NSPropertyListSerialization to + * get the opening and closing tokens for the string representation * - * Revision 1.13 2003/08/04 20:26:10 chochos - * use NSPropertyListSerialization inside toString() + * Revision 1.13 2003/08/04 20:26:10 chochos use NSPropertyListSerialization + * inside toString() * - * Revision 1.12 2003/08/04 18:18:43 chochos - * toString() yields strings in the same format as Apple's NSArray + * Revision 1.12 2003/08/04 18:18:43 chochos toString() yields strings in the + * same format as Apple's NSArray * - * Revision 1.11 2003/01/28 19:44:20 mpowers - * Fixed reverse enumerator. + * Revision 1.11 2003/01/28 19:44:20 mpowers Fixed reverse enumerator. * - * Revision 1.10 2003/01/18 23:49:55 mpowers - * Added mutableClone(). + * Revision 1.10 2003/01/18 23:49:55 mpowers Added mutableClone(). * - * Revision 1.9 2003/01/18 23:30:42 mpowers - * WODisplayGroup now compiles. + * Revision 1.9 2003/01/18 23:30:42 mpowers WODisplayGroup now compiles. * - * Revision 1.8 2003/01/16 22:47:30 mpowers - * Compatibility changes to support compiling woextensions source. - * (34 out of 56 classes compile!) + * Revision 1.8 2003/01/16 22:47:30 mpowers Compatibility changes to support + * compiling woextensions source. (34 out of 56 classes compile!) * - * Revision 1.7 2003/01/10 19:16:40 mpowers - * Implemented support for page caching. + * Revision 1.7 2003/01/10 19:16:40 mpowers Implemented support for page + * caching. * - * Revision 1.6 2002/10/24 21:15:36 mpowers - * New implementations of NSArray and subclasses. + * Revision 1.6 2002/10/24 21:15:36 mpowers New implementations of NSArray and + * subclasses. * - * Revision 1.5 2002/10/24 18:16:30 mpowers - * Now enforcing NSArray's immutable nature. + * Revision 1.5 2002/10/24 18:16:30 mpowers Now enforcing NSArray's immutable + * nature. * - * Revision 1.4 2002/03/08 19:02:54 mpowers - * Long-overdue speed optimization of indexOfIdenticalObject. + * Revision 1.4 2002/03/08 19:02:54 mpowers Long-overdue speed optimization of + * indexOfIdenticalObject. * - * Revision 1.3 2002/02/13 22:02:56 mpowers - * Fixed: bug in componentsSeparatedByString when separator is null - * (thanks to Cedrik LIME). + * Revision 1.3 2002/02/13 22:02:56 mpowers Fixed: bug in + * componentsSeparatedByString when separator is null (thanks to Cedrik LIME). * - * Revision 1.2 2001/01/11 20:34:26 mpowers - * Implemented EOSortOrdering and added support in framework. - * Added header-click to sort table columns. + * Revision 1.2 2001/01/11 20:34:26 mpowers Implemented EOSortOrdering and added + * support in framework. Added header-click to sort table columns. * - * Revision 1.1.1.1 2000/12/21 15:47:26 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:47:26 mpowers Contributing wotonomy. * - * Revision 1.3 2000/12/20 16:25:37 michael - * Added log to all files. + * Revision 1.3 2000/12/20 16:25:37 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSBundle.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSBundle.java index b735404..49dda88 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSBundle.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSBundle.java @@ -67,7 +67,7 @@ public class NSBundle { private static NSMutableDictionary _languageCodes = new NSMutableDictionary(); private static NSBundle _mainBundle = null; - + protected static NetworkClassLoader _classLoader = new NetworkClassLoader(ClassLoader.getSystemClassLoader()); /* Instance variables */ @@ -94,8 +94,8 @@ public class NSBundle { /** * The default constructor, which is only public to support other framework - * functionality, and to be API compatible with Apple's WebObjects. - * Generally, framework users should use bundleForXXXX() methods. + * functionality, and to be API compatible with Apple's WebObjects. Generally, + * framework users should use bundleForXXXX() methods. */ public NSBundle() { } @@ -118,11 +118,10 @@ public class NSBundle { } /** - * Returns the bundle that contains the provided class, if any. Otherwise, - * it returns null. Because NSBundles have a specialized class-loader, if - * any two bundles contain duiplicates of the same class, the second will - * fail to load. TODO: Determine if class-load scoping of duplicate classes - * is appropriate. + * Returns the bundle that contains the provided class, if any. Otherwise, it + * returns null. Because NSBundles have a specialized class-loader, if any two + * bundles contain duiplicates of the same class, the second will fail to load. + * TODO: Determine if class-load scoping of duplicate classes is appropriate. * * @param class1 * @return NSBundle @@ -133,8 +132,7 @@ public class NSBundle { } /** - * @deprecated Apple's WebObjects says you should not load from arbitrary - * path. + * @deprecated Apple's WebObjects says you should not load from arbitrary path. * @param path * @return */ @@ -150,9 +148,9 @@ public class NSBundle { /** * <strong>Note:</strong>This method is only in Wotonomy. * - * This method returns a bundle at a given URL, registering that bundle as - * well. If the bundle has already been loaded/registered, it is simply - * returned from the cache. + * This method returns a bundle at a given URL, registering that bundle as well. + * If the bundle has already been loaded/registered, it is simply returned from + * the cache. * * @param url * @return @@ -170,14 +168,11 @@ public class NSBundle { StringBuffer filename = new StringBuffer(f.getName()); int extensionIndex = filename.lastIndexOf("."); if (extensionIndex == -1) { - NSLog.err - .appendln("Named URL does not point to a bundle with an extension: " - + url); + NSLog.err.appendln("Named URL does not point to a bundle with an extension: " + url); return null; } String basename = filename.substring(0, extensionIndex); - String extension = filename.substring(extensionIndex + 1, filename - .length()); + String extension = filename.substring(extensionIndex + 1, filename.length()); System.out.println("basename: " + basename); System.out.println("extension: " + extension); result = new NSBundle(); @@ -185,16 +180,15 @@ public class NSBundle { result.isFramework = extension.equals("framework"); if (f.isDirectory()) { try { - File javadir = new File(f.getCanonicalPath() + sep + "Contents" - + sep + "Resources" + sep + "Java"); + File javadir = new File(f.getCanonicalPath() + sep + "Contents" + sep + "Resources" + sep + "Java"); System.out.println(javadir); System.out.println(javadir.exists()); File[] jars = javadir.listFiles(); - - } catch (IOException e) { } + + } catch (IOException e) { + } } else { - throw new RuntimeException( - "Compressed bundle files not currently supported."); + throw new RuntimeException("Compressed bundle files not currently supported."); } throw new RuntimeException("Method not finished."); } else { @@ -205,10 +199,8 @@ public class NSBundle { JarFile f; throw new RuntimeException("Method not finished."); } catch (IOException e) { - NSLog.err - .appendln("IOException loading framework jar from URL " - + url + " - message: " - + e.getLocalizedMessage()); + NSLog.err.appendln( + "IOException loading framework jar from URL " + url + " - message: " + e.getLocalizedMessage()); StringWriter stacktrace = new StringWriter(); e.printStackTrace(new PrintWriter(stacktrace)); NSLog.err.appendln(stacktrace); @@ -218,10 +210,9 @@ public class NSBundle { } /** - * This method returns a bundle, either from cache, or if it doesn't exist - * yet, it attempts to look it up - first from the classpath, then from the - * resource path. TODO: Determine if the lookup order is the desired - * semantic. + * This method returns a bundle, either from cache, or if it doesn't exist yet, + * it attempts to look it up - first from the classpath, then from the resource + * path. TODO: Determine if the lookup order is the desired semantic. * * @param name * @return @@ -237,9 +228,9 @@ public class NSBundle { /** * Used to set the "Main" application bundle, in which primary resources are - * loaded for GUI applications. This is mostly only relevant for - * XXApplication objects. This should therefore not be generally used by - * consumers of the framework. + * loaded for GUI applications. This is mostly only relevant for XXApplication + * objects. This should therefore not be generally used by consumers of the + * framework. * * @param aBundle */ @@ -252,14 +243,13 @@ public class NSBundle { } /** - * Get the default prefix for locale. TODO: This really needs to be made - * dynamic somehow. + * Get the default prefix for locale. TODO: This really needs to be made dynamic + * somehow. * * @return */ protected static String defaultLocalePrefix() { - String language = (String) _languageCodes.objectForKey(Locale - .getDefault().getLanguage()); + String language = (String) _languageCodes.objectForKey(Locale.getDefault().getLanguage()); return language + ".lproj"; } @@ -283,8 +273,8 @@ public class NSBundle { } /** - * Returns a byte array for the given resource path. TODO: Lookup semantics - * in WebObjects javadocs. + * Returns a byte array for the given resource path. TODO: Lookup semantics in + * WebObjects javadocs. * * @param path * @return @@ -303,8 +293,8 @@ public class NSBundle { } /** - * Returns an input stream for a given resource path. TODO: Lookup semantics - * in WebObjects javadocs. + * Returns an input stream for a given resource path. TODO: Lookup semantics in + * WebObjects javadocs. * * @param path * @return @@ -339,14 +329,12 @@ public class NSBundle { * @deprecated Don't use this method, use * resourcePathForLocalizedResourceNamed() instead. */ - public String pathForResource(String aName, String anExtension, - String subDir) { + public String pathForResource(String aName, String anExtension, String subDir) { return this.resourcePathForLocalizedResourceNamed(aName, subDir); } /** - * @deprecated Don't use this method, use resourcePathsForResources() - * instead. + * @deprecated Don't use this method, use resourcePathsForResources() instead. */ public NSArray pathsForResources(String aName, String anExtension) { throw new UnsupportedOperationException("Method not yet implemented."); @@ -362,27 +350,24 @@ public class NSBundle { } /** - * @deprecated Resources are now accessed using the bytesForResourcePath() - * and inputStreamForResourcePath() methods. + * @deprecated Resources are now accessed using the bytesForResourcePath() and + * inputStreamForResourcePath() methods. */ public String resourcePath() { throw new UnsupportedOperationException("Method not yet implemented."); // TODO: Implement. } - public String resourcePathForLocalizedResourceNamed(String aName, - String subDir) { + public String resourcePathForLocalizedResourceNamed(String aName, String subDir) { throw new UnsupportedOperationException("Method not yet implemented."); // TODO: Implement. } - public NSArray resourcePathsForDirectories(String extension, - String subdirPath) { + public NSArray resourcePathsForDirectories(String extension, String subdirPath) { throw new UnsupportedOperationException("Method not yet implemented."); } - public NSArray resourcePathsForLocalizedResources(String extension, - String subdirPath) { + public NSArray resourcePathsForLocalizedResources(String extension, String subdirPath) { throw new UnsupportedOperationException("Method not yet implemented."); } @@ -395,8 +380,8 @@ public class NSBundle { int i = 0; if (classNames != null) i = classNames.count(); - return "<" + getClass().getName() + " name:'" + name + "' bundlePath:'" - + path + "' packages:'" + packages + "' " + i + " classes >"; + return "<" + getClass().getName() + " name:'" + name + "' bundlePath:'" + path + "' packages:'" + packages + + "' " + i + " classes >"; } /* Static initialization code */ @@ -412,7 +397,7 @@ public class NSBundle { static { NSBundle._initLanguages(); - + } } diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoder.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoder.java index ca32dd5..8a1721a 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoder.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoder.java @@ -25,89 +25,87 @@ import java.io.InputStream; import java.io.OutputStream; /** -* A class that defines a simple encode/decode paradigm. Subclasses -* would handle the target format. -* -* @author cgruber@israfil.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ + * A class that defines a simple encode/decode paradigm. Subclasses would handle + * the target format. + * + * @author cgruber@israfil.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ public abstract class NSCoder { - public NSCoder() { - } + public NSCoder() { + } - public abstract void encodeBoolean(boolean flag); + public abstract void encodeBoolean(boolean flag); - public abstract void encodeByte(byte byte0); + public abstract void encodeByte(byte byte0); - public abstract void encodeBytes(byte abyte0[]); + public abstract void encodeBytes(byte abyte0[]); - public abstract void encodeChar(char c); + public abstract void encodeChar(char c); - public abstract void encodeShort(short word0); + public abstract void encodeShort(short word0); - public abstract void encodeInt(int i); + public abstract void encodeInt(int i); - public abstract void encodeLong(long l); + public abstract void encodeLong(long l); - public abstract void encodeFloat(float f); + public abstract void encodeFloat(float f); - public abstract void encodeDouble(double d); + public abstract void encodeDouble(double d); - public abstract void encodeObject(Object obj); + public abstract void encodeObject(Object obj); - public abstract void encodeClass(Class class1); + public abstract void encodeClass(Class class1); - public abstract void encodeObjects(Object aobj[]); + public abstract void encodeObjects(Object aobj[]); - public abstract boolean decodeBoolean(); + public abstract boolean decodeBoolean(); - public abstract byte decodeByte(); + public abstract byte decodeByte(); - public abstract byte[] decodeBytes(); + public abstract byte[] decodeBytes(); - public abstract char decodeChar(); + public abstract char decodeChar(); - public abstract short decodeShort(); + public abstract short decodeShort(); - public abstract int decodeInt(); + public abstract int decodeInt(); - public abstract long decodeLong(); + public abstract long decodeLong(); - public abstract float decodeFloat(); + public abstract float decodeFloat(); - public abstract double decodeDouble(); + public abstract double decodeDouble(); - public abstract Object decodeObject(); + public abstract Object decodeObject(); - public abstract Class decodeClass(); + public abstract Class decodeClass(); - public abstract Object[] decodeObjects(); + public abstract Object[] decodeObjects(); - public void prepareForWriting(OutputStream outputstream) { - } + public void prepareForWriting(OutputStream outputstream) { + } - public void prepareForReading(InputStream inputstream) { - } + public void prepareForReading(InputStream inputstream) { + } - public void finishCoding() { - } + public void finishCoding() { + } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.1 2002/07/14 21:56:16 mpowers - * Contributions from cgruber. + * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber. * - * Revision 1.2 2002/06/25 19:03:02 cgruber - * Internal documentation fixes. + * Revision 1.2 2002/06/25 19:03:02 cgruber Internal documentation fixes. * - * Revision 1.1 2002/06/25 07:52:57 cgruber - * Add quite a few abstract classes, interfaces, and classes. All API consistent with WebObjects, but with no implementation, nor any private or package access members from the original. + * Revision 1.1 2002/06/25 07:52:57 cgruber Add quite a few abstract classes, + * interfaces, and classes. All API consistent with WebObjects, but with no + * implementation, nor any private or package access members from the original. * */ diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoding.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoding.java index 56e4124..c578dbc 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoding.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSCoding.java @@ -24,15 +24,14 @@ package net.wotonomy.foundation; import java.math.BigInteger; /** -* A helper interface supporting the NSCoder APIs. At present it -* very confusing to me how this even works from a structural -* perspective, but to be consistent with WebObjects APIs, this will -* have to be properly implemented. -* -* @author cgruber@israfil.net -* @author $Author: cgruber $ -* @version $Revision: 892 $ -*/ + * A helper interface supporting the NSCoder APIs. At present it very confusing + * to me how this even works from a structural perspective, but to be consistent + * with WebObjects APIs, this will have to be properly implemented. + * + * @author cgruber@israfil.net + * @author $Author: cgruber $ + * @version $Revision: 892 $ + */ public interface NSCoding { @@ -69,9 +68,7 @@ public interface NSCoding { } /** Not yet implemented */ - protected static void _encodeBigInteger( - NSCoder nscoder, - BigInteger biginteger) { + protected static void _encodeBigInteger(NSCoder nscoder, BigInteger biginteger) { throw new UnsupportedOperationException("Not Yet Implemented"); } @@ -273,8 +270,7 @@ public interface NSCoding { /** Helper class for NSCoding. */ public static abstract class Support { - private static NSMutableDictionary classSupportMap = - new NSMutableDictionary(16); + private static NSMutableDictionary classSupportMap = new NSMutableDictionary(16); public static Support supportForClass(Class aClass) { Support support = null; @@ -294,9 +290,9 @@ public interface NSCoding { classSupportMap.setObjectForKey(support, class1); } - /** Return the class of a given object. It boggles the mind - * as to why this is not a static, but in the original, it's - * not. <sigh> + /** + * Return the class of a given object. It boggles the mind as to why this is not + * a static, but in the original, it's not. <sigh> */ public Class classForCoder(Object obj) { return obj.getClass(); @@ -324,48 +320,40 @@ public interface NSCoding { setSupportForClass(new _LongSupport(), java.lang.Long.class); setSupportForClass(new _FloatSupport(), java.lang.Float.class); setSupportForClass(new _DoubleSupport(), java.lang.Double.class); - setSupportForClass( - new _BigIntegerSupport(), - java.math.BigInteger.class); - setSupportForClass( - new _BigDecimalSupport(), - java.math.BigDecimal.class); + setSupportForClass(new _BigIntegerSupport(), java.math.BigInteger.class); + setSupportForClass(new _BigDecimalSupport(), java.math.BigDecimal.class); setSupportForClass(new _DateSupport(), java.util.Date.class); - setSupportForClass( - new _CharacterSupport(), - java.lang.Character.class); + setSupportForClass(new _CharacterSupport(), java.lang.Character.class); } public Support() { } } - //CEG: I'm not sure why these are here, since NSCoding is an interface. - // It doesn't seem to even be used anywhere. - //CEG: I'm not even sure why this compiles!! - //public abstract Class classForCoder(); + // CEG: I'm not sure why these are here, since NSCoding is an interface. + // It doesn't seem to even be used anywhere. + // CEG: I'm not even sure why this compiles!! + // public abstract Class classForCoder(); - //CEG: I'm not sure why these are here, since NSCoding is an interface. - // It doesn't seem to even be used anywhere. - //CEG: I'm not even sure why this compiles!! - //public abstract void encodeWithCoder(NSCoder nscoder); + // CEG: I'm not sure why these are here, since NSCoding is an interface. + // It doesn't seem to even be used anywhere. + // CEG: I'm not even sure why this compiles!! + // public abstract void encodeWithCoder(NSCoder nscoder); } /* - * $Log$ - * Revision 1.1 2006/02/16 12:47:16 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.2 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.1 2002/07/14 21:56:16 mpowers - * Contributions from cgruber. + * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber. * - * Revision 1.2 2002/06/25 19:03:02 cgruber - * Internal documentation fixes. + * Revision 1.2 2002/06/25 19:03:02 cgruber Internal documentation fixes. * - * Revision 1.1 2002/06/25 07:52:56 cgruber - * Add quite a few abstract classes, interfaces, and classes. All API consistent with WebObjects, but with no implementation, nor any private or package access members from the original. + * Revision 1.1 2002/06/25 07:52:56 cgruber Add quite a few abstract classes, + * interfaces, and classes. All API consistent with WebObjects, but with no + * implementation, nor any private or package access members from the original. * */ diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSComparator.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSComparator.java index 287a59b..6c88d19 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSComparator.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSComparator.java @@ -23,82 +23,79 @@ package net.wotonomy.foundation; import java.util.Comparator; - /** -* An object that compares two other objects. As a convenience, it -* also implements java.util.Comparator. -* -* @author cgruber@israfil.net -* @author $Author: cgruber $ -* @version $Revision: 913 $ -*/ + * An object that compares two other objects. As a convenience, it also + * implements java.util.Comparator. + * + * @author cgruber@israfil.net + * @author $Author: cgruber $ + * @version $Revision: 913 $ + */ public abstract class NSComparator implements Comparator { - protected static class _NSSelectorComparator extends NSComparator { + protected static class _NSSelectorComparator extends NSComparator { - public int compare(Object obj, Object obj1) throws ComparisonException { + public int compare(Object obj, Object obj1) throws ComparisonException { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public _NSSelectorComparator(NSSelector nsselector) { + public _NSSelectorComparator(NSSelector nsselector) { throw new UnsupportedOperationException("Not Yet Implemented"); - } - } - - private static class StandInComparator extends NSComparator { + } + } - public StandInComparator() { - throw new UnsupportedOperationException("Not Yet Implemented"); - } + private static class StandInComparator extends NSComparator { - public int compare(Object obj, Object obj1) throws ComparisonException { + public StandInComparator() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - } + public int compare(Object obj, Object obj1) throws ComparisonException { + throw new UnsupportedOperationException("Not Yet Implemented"); + } - public static class ComparisonException extends ClassCastException { + } - public ComparisonException(String s) { - super(s); - } - } + public static class ComparisonException extends ClassCastException { + public ComparisonException(String s) { + super(s); + } + } - public static final NSComparator AscendingStringComparator = new StandInComparator(); - public static final NSComparator DescendingStringComparator = new StandInComparator(); - public static final NSComparator AscendingCaseInsensitiveStringComparator = new StandInComparator(); - public static final NSComparator DescendingCaseInsensitiveStringComparator = new StandInComparator(); - public static final NSComparator AscendingNumberComparator = new StandInComparator(); - public static final NSComparator DescendingNumberComparator = new StandInComparator(); - public static final NSComparator AscendingTimestampComparator = new StandInComparator(); - public static final NSComparator DescendingTimestampComparator = new StandInComparator(); - public static final int OrderedAscending = -1; - public static final int OrderedSame = 0; - public static final int OrderedDescending = 1; + public static final NSComparator AscendingStringComparator = new StandInComparator(); + public static final NSComparator DescendingStringComparator = new StandInComparator(); + public static final NSComparator AscendingCaseInsensitiveStringComparator = new StandInComparator(); + public static final NSComparator DescendingCaseInsensitiveStringComparator = new StandInComparator(); + public static final NSComparator AscendingNumberComparator = new StandInComparator(); + public static final NSComparator DescendingNumberComparator = new StandInComparator(); + public static final NSComparator AscendingTimestampComparator = new StandInComparator(); + public static final NSComparator DescendingTimestampComparator = new StandInComparator(); + public static final int OrderedAscending = -1; + public static final int OrderedSame = 0; + public static final int OrderedDescending = 1; - public NSComparator() { - } + public NSComparator() { + } - public abstract int compare(Object obj, Object obj1) throws ClassCastException; + public abstract int compare(Object obj, Object obj1) throws ClassCastException; - public static int _compareObjects(Comparable comparable, Comparable comparable1) { + public static int _compareObjects(Comparable comparable, Comparable comparable1) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } } /* - * $Log$ - * Revision 1.2 2006/03/10 00:52:27 cgruber - * Add tests for NSArray and fix some problems that became obvious as a result. + * $Log$ Revision 1.2 2006/03/10 00:52:27 cgruber Add tests for NSArray and fix + * some problems that became obvious as a result. * - * Revision 1.1 2006/02/16 12:47:16 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.1 2002/07/14 21:56:16 mpowers - * Contributions from cgruber. + * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber. * - * Revision 1.1 2002/06/25 07:52:56 cgruber - * Add quite a few abstract classes, interfaces, and classes. All API consistent with WebObjects, but with no implementation, nor any private or package access members from the original. + * Revision 1.1 2002/06/25 07:52:56 cgruber Add quite a few abstract classes, + * interfaces, and classes. All API consistent with WebObjects, but with no + * implementation, nor any private or package access members from the original. * */ diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSData.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSData.java index 36c527c..67f1d59 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSData.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSData.java @@ -24,96 +24,85 @@ import java.io.IOException; import java.io.InputStream; /** -* A pure java implementation of NSData, which -* is basically a wrapper on a byte array. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public class NSData -{ - public static final NSData EmptyData = new NSData(); + * A pure java implementation of NSData, which is basically a wrapper on a byte + * array. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public class NSData { + public static final NSData EmptyData = new NSData(); - protected byte[] bytes; + protected byte[] bytes; - /** - * Default constructor creates a zero-data object. - */ - public NSData () - { - bytes = new byte[0]; - } + /** + * Default constructor creates a zero-data object. + */ + public NSData() { + bytes = new byte[0]; + } - /** - * Creates an object containing a copy of the specified bytes. - */ - public NSData (byte[] data) - { - this( data, 0, data.length ); - } + /** + * Creates an object containing a copy of the specified bytes. + */ + public NSData(byte[] data) { + this(data, 0, data.length); + } - /** - * Creates an object containing a copy of the bytes from the specified - * array within the specified range. - */ - public NSData (byte[] data, int start, int length) - { - bytes = new byte[ length ]; - for ( int i = 0; i < length; i++ ) - { - bytes[i] = data[ start+i ]; - } - } + /** + * Creates an object containing a copy of the bytes from the specified array + * within the specified range. + */ + public NSData(byte[] data, int start, int length) { + bytes = new byte[length]; + for (int i = 0; i < length; i++) { + bytes[i] = data[start + i]; + } + } - /** - * Creates an object containing the bytes of the specified string. - */ - public NSData (String aString) - { - this( aString.getBytes() ); - } + /** + * Creates an object containing the bytes of the specified string. + */ + public NSData(String aString) { + this(aString.getBytes()); + } - /** - * Creates an object containing the contents of the specified file. - * Errors reading the file will produce an empty or partially blank array. - */ - public NSData (File aFile) - { - int len = (int) aFile.length(); - byte[] data = new byte[ len ]; - try - { - new java.io.FileInputStream( aFile ).read( data ); - } - catch ( Exception exc ) - { - // produce an empty or partially blank array - } + /** + * Creates an object containing the contents of the specified file. Errors + * reading the file will produce an empty or partially blank array. + */ + public NSData(File aFile) { + int len = (int) aFile.length(); + byte[] data = new byte[len]; + try { + new java.io.FileInputStream(aFile).read(data); + } catch (Exception exc) { + // produce an empty or partially blank array + } bytes = data; - } + } - /** - * Creates an object containing the contents of the specified URL. - */ - public NSData (java.net.URL aURL) - { - throw new RuntimeException( "Not Implemented" ); - } + /** + * Creates an object containing the contents of the specified URL. + */ + public NSData(java.net.URL aURL) { + throw new RuntimeException("Not Implemented"); + } - /** - * Creates an object containing a copy of the contents of the - * specified NSData object. - */ - public NSData (NSData aData) - { - this( aData.bytes() ); - } + /** + * Creates an object containing a copy of the contents of the specified NSData + * object. + */ + public NSData(NSData aData) { + this(aData.bytes()); + } /** - * Creates a new NSData object from the bytes in the input stream. - * The input stream is read fully and is not closed. - * @param stream The stream to read from. + * Creates a new NSData object from the bytes in the input stream. The input + * stream is read fully and is not closed. + * + * @param stream The stream to read from. * @param chunkSize The buffer size used to read from the stream. * @throws IOException if the stream cannot be read from. */ @@ -130,134 +119,119 @@ public class NSData bytes = bout.toByteArray(); } - /** - * Returns the length of the contained data. - */ - public int length () - { - return bytes.length; - } + /** + * Returns the length of the contained data. + */ + public int length() { + return bytes.length; + } - /** - * Returns whether the specified data is equivalent to these data. - */ - public boolean isEqualToData (NSData aData) - { - if (length() != aData.length()) - return false; - byte[] a = bytes(); - byte[] b = aData.bytes(); - - for ( int i = 0; i < a.length; i++ ) { - if ( a[i] != b[i] ) + /** + * Returns whether the specified data is equivalent to these data. + */ + public boolean isEqualToData(NSData aData) { + if (length() != aData.length()) + return false; + byte[] a = bytes(); + byte[] b = aData.bytes(); + + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) return false; } return true; - } + } - /** - * Return the bytes within the data that fall within the specified range. - */ - public NSData subdataWithRange (NSRange aRange) - { - int loc = aRange.location(); - byte[] src = bytes(); - byte[] data = new byte[ aRange.length() ]; - System.arraycopy(src, loc, data, 0, data.length); - return new NSData( data ); - } + /** + * Return the bytes within the data that fall within the specified range. + */ + public NSData subdataWithRange(NSRange aRange) { + int loc = aRange.location(); + byte[] src = bytes(); + byte[] data = new byte[aRange.length()]; + System.arraycopy(src, loc, data, 0, data.length); + return new NSData(data); + } + + /** + * Writes the contents of this data to the specified URL. If atomically is true, + * then the data is written to a temporary file and then renamed to the name + * specified by the URL when the data transfer is complete. + */ + public boolean writeToURL(java.net.URL aURL, boolean atomically) { + throw new RuntimeException("Not Implemented"); + } - /** - * Writes the contents of this data to the specified URL. - * If atomically is true, then the data is written to a temporary - * file and then renamed to the name specified by the URL when - * the data transfer is complete. - */ - public boolean writeToURL (java.net.URL aURL, boolean atomically) - { - throw new RuntimeException( "Not Implemented" ); - } + /** + * Convenience to return the contents of the specified file. + */ + public static NSData dataWithContentsOfMappedFile(java.io.File aFile) { + return new NSData(aFile); + } - /** - * Convenience to return the contents of the specified file. - */ - public static NSData dataWithContentsOfMappedFile (java.io.File aFile) - { - return new NSData( aFile ); - } + /** + * Returns a copy of the bytes starting at the specified location and ranging + * for the specified length. + */ + public byte[] bytes(int location, int length) { + byte[] data = new byte[length]; + for (int i = 0; i < length; i++) { + data[i] = bytes[location + i]; + } + return data; + } - /** - * Returns a copy of the bytes starting at the specified location - * and ranging for the specified length. - */ - public byte[] bytes (int location, int length) - { - byte[] data = new byte[ length ]; - for ( int i = 0; i < length; i++ ) - { - data[i] = bytes[ location + i ]; - } - return data; - } - - /** - * Returns a copy of the bytes backing this data object. - * NOTE: This method is not in the NSData spec and is - * included for convenience only. - */ - public byte[] bytes() - { - return bytes( 0, length() ); - } + /** + * Returns a copy of the bytes backing this data object. NOTE: This method is + * not in the NSData spec and is included for convenience only. + */ + public byte[] bytes() { + return bytes(0, length()); + } - public String toString() { - String hex = "0123456789ABCDEF"; - StringBuffer buf = new StringBuffer(); - buf.append(NSPropertyListSerialization.TOKEN_BEGIN[NSPropertyListSerialization.PLIST_DATA]); - for (int i = 0; i < bytes.length; i++) { - byte b = bytes[i]; - buf.append(hex.charAt((b & 0xf0) >> 4)); - buf.append(hex.charAt(b & 0x0f)); - if (i % 5 == 4) - buf.append(' '); - } - buf.append(NSPropertyListSerialization.TOKEN_END[NSPropertyListSerialization.PLIST_DATA]); - return buf.toString(); - } + public String toString() { + String hex = "0123456789ABCDEF"; + StringBuffer buf = new StringBuffer(); + buf.append(NSPropertyListSerialization.TOKEN_BEGIN[NSPropertyListSerialization.PLIST_DATA]); + for (int i = 0; i < bytes.length; i++) { + byte b = bytes[i]; + buf.append(hex.charAt((b & 0xf0) >> 4)); + buf.append(hex.charAt(b & 0x0f)); + if (i % 5 == 4) + buf.append(' '); + } + buf.append(NSPropertyListSerialization.TOKEN_END[NSPropertyListSerialization.PLIST_DATA]); + return buf.toString(); + } public boolean isEqual(Object obj) { if (obj == this) return true; if (obj instanceof NSData) - return isEqualToData((NSData)obj); + return isEqualToData((NSData) obj); return false; } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.5 2003/08/19 01:53:52 chochos - * added constructor with an InputStream + * Revision 1.5 2003/08/19 01:53:52 chochos added constructor with an + * InputStream * - * Revision 1.4 2003/08/05 00:51:31 chochos - * get the enclosing tokens from NSPropertyListSerialization + * Revision 1.4 2003/08/05 00:51:31 chochos get the enclosing tokens from + * NSPropertyListSerialization * - * Revision 1.3 2003/08/04 22:45:47 chochos - * toString() prints out the bytes in hex (in property list format) + * Revision 1.3 2003/08/04 22:45:47 chochos toString() prints out the bytes in + * hex (in property list format) * - * Revision 1.2 2003/08/02 01:52:00 chochos - * added EmptyData + * Revision 1.2 2003/08/02 01:52:00 chochos added EmptyData * - * Revision 1.1.1.1 2000/12/21 15:47:26 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:47:26 mpowers Contributing wotonomy. * - * Revision 1.3 2000/12/20 16:25:38 michael - * Added log to all files. + * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDate.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDate.java index d5b6f61..a2121fd 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDate.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDate.java @@ -23,17 +23,16 @@ import java.util.GregorianCalendar; import java.util.TimeZone; /** -* A pure java implementation of NSDate that extends -* java.util.Date for greater java compatibility. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 892 $ -*/ -public class NSDate extends Date -{ + * A pure java implementation of NSDate that extends java.util.Date for greater + * java compatibility. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 892 $ + */ +public class NSDate extends Date { // NSComparisonResult compatibility - + public static final int NSOrderedAscending = -1; public static final int NSOrderedSame = 0; public static final int NSOrderedDescending = 1; @@ -41,158 +40,142 @@ public class NSDate extends Date // public static final double TimeIntervalSince1970; // public static final NSDate DateFor1970; - /** - * Default constructor represents the current date. - */ - public NSDate () - { - super(); - } - - /** - * Represents the specified number of seconds from the current date. - */ - public NSDate (double seconds) - { - super( (long) new NSDate().getTime() + - timeIntervalToMilliseconds(seconds) ); - } - - /** - * Represents the specified number of seconds from the specified date. - */ - public NSDate (double seconds, Date sinceDate) - { - super( (long) sinceDate.getTime() + - timeIntervalToMilliseconds(seconds) ); - } - - /** - * Returns the interval between this date and 1 January 2001 GMT. - */ - public double timeIntervalSinceReferenceDate () - { - GregorianCalendar referenceDate = - new GregorianCalendar( TimeZone.getTimeZone( "GMT" ) ); - referenceDate.set( 2001, 0, 0, 0, 0, 0 ); - return timeIntervalSinceDate( referenceDate.getTime() ); - } - - /** - * Returns the interval between this date and the specified date - * in seconds. - */ - public double timeIntervalSinceDate (Date aDate) - { - return millisecondsToTimeInterval( - this.getTime() - aDate.getTime() ); - } - - /** - * Returns the interval between this date and the current date - * in seconds. - */ - public double timeIntervalSinceNow () - { - return timeIntervalSinceDate( new NSDate() ); - } - - /** - * Compares this date to the specified date and returns the - * earlier date. Unspecified which is returned if both are equal. - */ - public NSDate earlierDate (NSDate aDate) - { - if ( aDate == null ) return this; - if ( after( aDate ) ) return aDate; - return this; - } - - /** - * Compares this date to the specified date and returns the - * later date. Unspecified which is returned if both are equal. - */ - public NSDate laterDate (NSDate aDate) - { - if ( aDate == null ) return this; - if ( before( aDate ) ) return aDate; - return this; - } - - /** - * Returns a negative value if the specified date is later than - * this date, a positive value if the specified date is earlier - * than this date, or zero if the dates are equal. The return - * values are compatible with type NSComparisonResult. - */ - public int compare (Date aDate) - { - if ( before( aDate ) ) return NSOrderedAscending; - if ( after( aDate ) ) return NSOrderedDescending; - return NSOrderedSame; - } - - /** - * Returns whether the this date is equal to the specified date, - * per the result of equals(). - */ - public boolean isEqualToDate (Date aDate) - { - return equals( aDate ); - } - - /** - * Returns a date that differs from this date by the specified - * number of seconds. - */ - public NSDate dateByAddingTimeInterval (double seconds) - { - return new NSDate( seconds, this ); - } - - /** - * Returns the number of seconds between now and the reference date. - */ - public static double currentTimeIntervalSinceReferenceDate () - { - return new NSDate().timeIntervalSinceReferenceDate(); - } - - /** - * Converts seconds to milliseconds. Included for compatibility. - */ - public static long timeIntervalToMilliseconds (double seconds) - { - return (long) seconds*1000; - } - - /** - * Converts milliseconds to seconds. Included for compatibility. - */ - public static double millisecondsToTimeInterval (long millis) - { - return millis/1000.0; - } - - /** - * Returns a date that is greater than all representable dates. - */ - public static NSDate distantFuture () - { - NSDate result = new NSDate(); - result.setTime( Long.MAX_VALUE ); - return result; - } - - /** - * Returns a date that is less than all representable dates. - */ - public static NSDate distantPast () - { - NSDate result = new NSDate(); - result.setTime( Long.MIN_VALUE ); - return result; - } + /** + * Default constructor represents the current date. + */ + public NSDate() { + super(); + } + + /** + * Represents the specified number of seconds from the current date. + */ + public NSDate(double seconds) { + super((long) new NSDate().getTime() + timeIntervalToMilliseconds(seconds)); + } + + /** + * Represents the specified number of seconds from the specified date. + */ + public NSDate(double seconds, Date sinceDate) { + super((long) sinceDate.getTime() + timeIntervalToMilliseconds(seconds)); + } + + /** + * Returns the interval between this date and 1 January 2001 GMT. + */ + public double timeIntervalSinceReferenceDate() { + GregorianCalendar referenceDate = new GregorianCalendar(TimeZone.getTimeZone("GMT")); + referenceDate.set(2001, 0, 0, 0, 0, 0); + return timeIntervalSinceDate(referenceDate.getTime()); + } + + /** + * Returns the interval between this date and the specified date in seconds. + */ + public double timeIntervalSinceDate(Date aDate) { + return millisecondsToTimeInterval(this.getTime() - aDate.getTime()); + } + + /** + * Returns the interval between this date and the current date in seconds. + */ + public double timeIntervalSinceNow() { + return timeIntervalSinceDate(new NSDate()); + } + + /** + * Compares this date to the specified date and returns the earlier date. + * Unspecified which is returned if both are equal. + */ + public NSDate earlierDate(NSDate aDate) { + if (aDate == null) + return this; + if (after(aDate)) + return aDate; + return this; + } + + /** + * Compares this date to the specified date and returns the later date. + * Unspecified which is returned if both are equal. + */ + public NSDate laterDate(NSDate aDate) { + if (aDate == null) + return this; + if (before(aDate)) + return aDate; + return this; + } + + /** + * Returns a negative value if the specified date is later than this date, a + * positive value if the specified date is earlier than this date, or zero if + * the dates are equal. The return values are compatible with type + * NSComparisonResult. + */ + public int compare(Date aDate) { + if (before(aDate)) + return NSOrderedAscending; + if (after(aDate)) + return NSOrderedDescending; + return NSOrderedSame; + } + + /** + * Returns whether the this date is equal to the specified date, per the result + * of equals(). + */ + public boolean isEqualToDate(Date aDate) { + return equals(aDate); + } + + /** + * Returns a date that differs from this date by the specified number of + * seconds. + */ + public NSDate dateByAddingTimeInterval(double seconds) { + return new NSDate(seconds, this); + } + + /** + * Returns the number of seconds between now and the reference date. + */ + public static double currentTimeIntervalSinceReferenceDate() { + return new NSDate().timeIntervalSinceReferenceDate(); + } + + /** + * Converts seconds to milliseconds. Included for compatibility. + */ + public static long timeIntervalToMilliseconds(double seconds) { + return (long) seconds * 1000; + } + + /** + * Converts milliseconds to seconds. Included for compatibility. + */ + public static double millisecondsToTimeInterval(long millis) { + return millis / 1000.0; + } + + /** + * Returns a date that is greater than all representable dates. + */ + public static NSDate distantFuture() { + NSDate result = new NSDate(); + result.setTime(Long.MAX_VALUE); + return result; + } + + /** + * Returns a date that is less than all representable dates. + */ + public static NSDate distantPast() { + NSDate result = new NSDate(); + result.setTime(Long.MIN_VALUE); + return result; + } // inherited from java.util.Date // public java.lang.String toString (); @@ -202,16 +185,12 @@ public class NSDate extends Date } /* - * $Log$ - * Revision 1.1 2006/02/16 12:47:16 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.1.1.1 2000/12/21 15:47:28 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:47:28 mpowers Contributing wotonomy. * - * Revision 1.3 2000/12/20 16:25:38 michael - * Added log to all files. + * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDictionary.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDictionary.java index 235a7bb..a4e9cd5 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDictionary.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDictionary.java @@ -24,309 +24,268 @@ import java.util.Iterator; import java.util.Map; /** -* A pure java implementation of NSDictionary that -* implements Map for greater java interoperability. -* -* @author michael@mpowers.net -* @author cgruber@israfil.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public class NSDictionary extends HashMap implements NSKeyValueCoding -{ - public static final NSDictionary EmptyDictionary = new NSDictionary(); - - /** - * Default constructor produces an empty dictionary. - */ - public NSDictionary () - { - super(); - } - - /** - * Constructor produces an empty dictionary with an initial capacity. - */ - public NSDictionary (int initialCapacity) - { - super(initialCapacity); - } - - /** - * Produces a dictionary that contains one key referencing one value. - */ - public NSDictionary (Object key, Object value) - { - super(); - put( key, value ); - } - - /** - * Produces a dictionary containing the specified keys and values. - * An IllegalArgumentException is thrown if the arrays are not - * of the same length. - */ - public NSDictionary (Object[] objects, Object[] keys) - { - super(); - if ( keys.length != objects.length ) - { - throw new IllegalArgumentException( "Array lengths do not match." ); - } - - for ( int i = 0; i < keys.length; i++ ) - { - put( keys[i], objects[i] ); - } - } - - /** - * Produces a dictionary that is a copy of the specified map (or dictionary). - */ - public NSDictionary (Map aMap) - { - super( aMap ); - } - - /** - * Returns a count of the key-value pairs in this dictionary. - */ - public int count () - { - return size(); - } - - /** - * Returns an NSArray containing all keys in this dictionary. - */ - public NSArray allKeys () - { - return new NSArray( keySet() ); - - } - - /** - * Returns an NSArray containing all keys that reference the - * specified value. - */ - public NSArray allKeysForObject (Object value) - { - NSMutableArray result = new NSMutableArray(); - Map.Entry entry; + * A pure java implementation of NSDictionary that implements Map for greater + * java interoperability. + * + * @author michael@mpowers.net + * @author cgruber@israfil.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public class NSDictionary extends HashMap implements NSKeyValueCoding { + public static final NSDictionary EmptyDictionary = new NSDictionary(); + + /** + * Default constructor produces an empty dictionary. + */ + public NSDictionary() { + super(); + } + + /** + * Constructor produces an empty dictionary with an initial capacity. + */ + public NSDictionary(int initialCapacity) { + super(initialCapacity); + } + + /** + * Produces a dictionary that contains one key referencing one value. + */ + public NSDictionary(Object key, Object value) { + super(); + put(key, value); + } + + /** + * Produces a dictionary containing the specified keys and values. An + * IllegalArgumentException is thrown if the arrays are not of the same length. + */ + public NSDictionary(Object[] objects, Object[] keys) { + super(); + if (keys.length != objects.length) { + throw new IllegalArgumentException("Array lengths do not match."); + } + + for (int i = 0; i < keys.length; i++) { + put(keys[i], objects[i]); + } + } + + /** + * Produces a dictionary that is a copy of the specified map (or dictionary). + */ + public NSDictionary(Map aMap) { + super(aMap); + } + + /** + * Returns a count of the key-value pairs in this dictionary. + */ + public int count() { + return size(); + } + + /** + * Returns an NSArray containing all keys in this dictionary. + */ + public NSArray allKeys() { + return new NSArray(keySet()); + + } + + /** + * Returns an NSArray containing all keys that reference the specified value. + */ + public NSArray allKeysForObject(Object value) { + NSMutableArray result = new NSMutableArray(); + Map.Entry entry; Iterator it = entrySet().iterator(); - while ( it.hasNext() ) - { + while (it.hasNext()) { entry = (Map.Entry) it.next(); // handle null values - if ( ( value == null ) && ( entry.getValue() == null ) - || ( value.equals( entry.getValue() ) ) ) - { + if ((value == null) && (entry.getValue() == null) || (value.equals(entry.getValue()))) { // if match, add to result set - result.addObject( entry.getKey() ); + result.addObject(entry.getKey()); } } - + return result; - } - - /** - * Returns an NSArray containing all values in this dictionary. - */ - public NSArray allValues () - { - return new NSArray( values() ); - } - - /** - * Returns whether the specified dictionary has the same or - * equivalent key-value pairs as this dictionary. - */ - public boolean isEqualToDictionary (NSDictionary aDictionary) - { - return equals( aDictionary ); - } - - /** - * Returns an array of objects for the specified array of keys. - * If a key isn't found, the marker parameter will be placed - * in the corresponding index(es) in the returned array. - */ - public NSArray objectsForKeys (NSArray anArray, Object aMarker) - { - NSMutableArray result = new NSMutableArray(); - if ( anArray == null ) return result; - - Object value; - Enumeration enumeration = anArray.objectEnumerator(); - while ( enumeration.hasMoreElements() ) - { - value = objectForKey( enumeration.nextElement() ); - if ( value == null ) - { - value = aMarker; - } - result.addObject( value ); - } - return result; - } - - /** - * Returns an enumeration over the keys in this dictionary. - */ - public java.util.Enumeration keyEnumerator () - { - return new java.util.Enumeration() - { - Iterator it = NSDictionary.this.keySet().iterator(); - public boolean hasMoreElements() - { + } + + /** + * Returns an NSArray containing all values in this dictionary. + */ + public NSArray allValues() { + return new NSArray(values()); + } + + /** + * Returns whether the specified dictionary has the same or equivalent key-value + * pairs as this dictionary. + */ + public boolean isEqualToDictionary(NSDictionary aDictionary) { + return equals(aDictionary); + } + + /** + * Returns an array of objects for the specified array of keys. If a key isn't + * found, the marker parameter will be placed in the corresponding index(es) in + * the returned array. + */ + public NSArray objectsForKeys(NSArray anArray, Object aMarker) { + NSMutableArray result = new NSMutableArray(); + if (anArray == null) + return result; + + Object value; + Enumeration enumeration = anArray.objectEnumerator(); + while (enumeration.hasMoreElements()) { + value = objectForKey(enumeration.nextElement()); + if (value == null) { + value = aMarker; + } + result.addObject(value); + } + return result; + } + + /** + * Returns an enumeration over the keys in this dictionary. + */ + public java.util.Enumeration keyEnumerator() { + return new java.util.Enumeration() { + Iterator it = NSDictionary.this.keySet().iterator(); + + public boolean hasMoreElements() { return it.hasNext(); - } - public Object nextElement() - { - return it.next(); - } - }; - } - - /** - * Returns an enumeration over the values in this dictionary. - */ - public java.util.Enumeration objectEnumerator () - { - return new java.util.Enumeration() - { - Iterator it = NSDictionary.this.values().iterator(); - public boolean hasMoreElements() - { + } + + public Object nextElement() { + return it.next(); + } + }; + } + + /** + * Returns an enumeration over the values in this dictionary. + */ + public java.util.Enumeration objectEnumerator() { + return new java.util.Enumeration() { + Iterator it = NSDictionary.this.values().iterator(); + + public boolean hasMoreElements() { return it.hasNext(); - } - public Object nextElement() - { - return it.next(); - } - }; + } + + public Object nextElement() { + return it.next(); + } + }; + } + + /** + * Returns the value for the specified key, or null if the key is not found. + */ + public Object objectForKey(Object aKey) { + return get(aKey); + } + + // interface NSKeyValueCoding + + public Object valueForKey(String aKey) { // System.out.println( "valueForKey: " + aKey + "->" + this ); + Object result = objectForKey(aKey); + if (result == null) + result = NSKeyValueCodingSupport.valueForKey(this, aKey); + return result; + } + + public void takeValueForKey(Object aValue, String aKey) { // System.out.println( "takeValueForKey: " + aKey + " : " + // + aValue + "->" + this ); + put(aKey, aValue); // FIXME: technically cheating since this is a read-only class + } + + public Object storedValueForKey(String aKey) { + Object result = objectForKey(aKey); + if (result == null) + result = NSKeyValueCodingSupport.storedValueForKey(this, aKey); + return result; + } + + public void takeStoredValueForKey(Object aValue, String aKey) { + put(aKey, aValue); // FIXME: technically cheating since this is a read-only class + } + + public Object handleQueryWithUnboundKey(String aKey) { + return NSKeyValueCodingSupport.handleQueryWithUnboundKey(this, aKey); + } + + public void handleTakeValueForUnboundKey(Object aValue, String aKey) { + NSKeyValueCodingSupport.handleTakeValueForUnboundKey(this, aValue, aKey); + } + + public void unableToSetNullForKey(String aKey) { + NSKeyValueCodingSupport.unableToSetNullForKey(this, aKey); + } + + public Object validateTakeValueForKeyPath(Object aValue, String aKey) { + throw new RuntimeException("Not implemented yet."); + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + Enumeration enumeration = keyEnumerator(); + boolean quote = false; + buf.append(NSPropertyListSerialization.TOKEN_BEGIN[NSPropertyListSerialization.PLIST_DICTIONARY]); + while (enumeration.hasMoreElements()) { + if (buf.length() == 1) + buf.append(' '); + Object k = enumeration.nextElement(); + buf.append(NSPropertyListSerialization.stringForPropertyList(k)); + buf.append(" = "); + k = objectForKey(k); + buf.append(NSPropertyListSerialization.stringForPropertyList(k)); + buf.append("; "); + } + buf.append(NSPropertyListSerialization.TOKEN_END[NSPropertyListSerialization.PLIST_DICTIONARY]); + return buf.toString(); } - - /** - * Returns the value for the specified key, or null - * if the key is not found. - */ - public Object objectForKey (Object aKey) - { - return get( aKey ); - } - - // interface NSKeyValueCoding - - public Object valueForKey (String aKey) - { // System.out.println( "valueForKey: " + aKey + "->" + this ); - Object result = objectForKey( aKey ); - if ( result == null ) - result = NSKeyValueCodingSupport.valueForKey( this, aKey ); - return result; - } - - public void takeValueForKey (Object aValue, String aKey) - { // System.out.println( "takeValueForKey: " + aKey + " : " + aValue + "->" + this ); - put( aKey, aValue ); //FIXME: technically cheating since this is a read-only class - } - - public Object storedValueForKey (String aKey) - { - Object result = objectForKey( aKey ); - if ( result == null ) - result = NSKeyValueCodingSupport.storedValueForKey( this, aKey ); - return result; - } - - public void takeStoredValueForKey (Object aValue, String aKey) - { - put( aKey, aValue ); //FIXME: technically cheating since this is a read-only class - } - - public Object handleQueryWithUnboundKey (String aKey) - { - return NSKeyValueCodingSupport.handleQueryWithUnboundKey( this, aKey ); - } - - public void handleTakeValueForUnboundKey (Object aValue, String aKey) - { - NSKeyValueCodingSupport.handleTakeValueForUnboundKey( this, aValue, aKey ); - } - - public void unableToSetNullForKey (String aKey) - { - NSKeyValueCodingSupport.unableToSetNullForKey( this, aKey ); - } - - public Object validateTakeValueForKeyPath (Object aValue, String aKey) - { - throw new RuntimeException( "Not implemented yet." ); - } - - public String toString() { - StringBuffer buf = new StringBuffer(); - Enumeration enumeration = keyEnumerator(); - boolean quote = false; - buf.append(NSPropertyListSerialization.TOKEN_BEGIN[NSPropertyListSerialization.PLIST_DICTIONARY]); - while (enumeration.hasMoreElements()) { - if (buf.length() == 1) - buf.append(' '); - Object k = enumeration.nextElement(); - buf.append(NSPropertyListSerialization.stringForPropertyList(k)); - buf.append(" = "); - k = objectForKey(k); - buf.append(NSPropertyListSerialization.stringForPropertyList(k)); - buf.append("; "); - } - buf.append(NSPropertyListSerialization.TOKEN_END[NSPropertyListSerialization.PLIST_DICTIONARY]); - return buf.toString(); - } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.9 2005/05/11 15:21:53 cgruber - * Change enum to enumeration, since enum is now a keyword as of Java 5.0 + * Revision 1.9 2005/05/11 15:21:53 cgruber Change enum to enumeration, since + * enum is now a keyword as of Java 5.0 * * A few other comments in the code. * - * Revision 1.8 2003/08/05 00:50:14 chochos - * use NSPropertyListSerialization to get the tokens to enclose the string description + * Revision 1.8 2003/08/05 00:50:14 chochos use NSPropertyListSerialization to + * get the tokens to enclose the string description * - * Revision 1.7 2003/08/04 20:26:10 chochos - * use NSPropertyListSerialization inside toString() + * Revision 1.7 2003/08/04 20:26:10 chochos use NSPropertyListSerialization + * inside toString() * - * Revision 1.6 2003/08/04 18:49:38 chochos - * NSDictionary(Object[], Object[]) was taking the parameters in the wrong order; for compatibility with Apple's NSDictionary, objects comes first, then keys. + * Revision 1.6 2003/08/04 18:49:38 chochos NSDictionary(Object[], Object[]) was + * taking the parameters in the wrong order; for compatibility with Apple's + * NSDictionary, objects comes first, then keys. * - * Revision 1.5 2003/08/04 18:26:19 chochos - * fixed opening '{' + * Revision 1.5 2003/08/04 18:26:19 chochos fixed opening '{' * - * Revision 1.4 2003/01/28 22:11:30 mpowers - * Now implements NSKeyValueCoding. + * Revision 1.4 2003/01/28 22:11:30 mpowers Now implements NSKeyValueCoding. * - * Revision 1.3 2002/06/30 17:58:06 mpowers - * Add a capacity constructor and static empty dictionary: thanks cgruber. + * Revision 1.3 2002/06/30 17:58:06 mpowers Add a capacity constructor and + * static empty dictionary: thanks cgruber. * - * Revision 1.2 2001/02/23 23:43:41 mpowers - * Removed ill-advised this. + * Revision 1.2 2001/02/23 23:43:41 mpowers Removed ill-advised this. * - * Revision 1.1.1.1 2000/12/21 15:47:31 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:47:31 mpowers Contributing wotonomy. * - * Revision 1.3 2000/12/20 16:25:38 michael - * Added log to all files. + * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files. * * */ - - - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDisposable.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDisposable.java index 46df7d2..49b84a2 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDisposable.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDisposable.java @@ -22,14 +22,14 @@ $Id: NSDisposable.java 893 2006-02-16 13:22:23Z cgruber $ package net.wotonomy.foundation; /** -* Interface for objects that respond to dispose(); -* -* @author cgruber@israfil.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ + * Interface for objects that respond to dispose(); + * + * @author cgruber@israfil.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ public interface NSDisposable { - public abstract void dispose(); + public abstract void dispose(); } diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSForwardException.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSForwardException.java index 1db0ad2..10f54af 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSForwardException.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSForwardException.java @@ -23,135 +23,115 @@ import java.io.PrintWriter; import java.io.StringWriter; /** -* Serves to wrap an exception inside of a RuntimeException, -* which is not required to be declared in a throws statement. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ + * Serves to wrap an exception inside of a RuntimeException, which is not + * required to be declared in a throws statement. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ -public class NSForwardException extends RuntimeException -{ +public class NSForwardException extends RuntimeException { protected String message; protected Throwable wrappedThrowable; - + /** - * Default constructor. - */ - public NSForwardException() - { + * Default constructor. + */ + public NSForwardException() { super(); message = null; - wrappedThrowable = null; + wrappedThrowable = null; } - + /** - * Standard constructor with message. - */ - public NSForwardException( String aMessage ) - { - super( aMessage ); + * Standard constructor with message. + */ + public NSForwardException(String aMessage) { + super(aMessage); message = aMessage; wrappedThrowable = null; } - + /** - * Specifies a throwable to wrap. - */ - public NSForwardException( Throwable aThrowable ) - { + * Specifies a throwable to wrap. + */ + public NSForwardException(Throwable aThrowable) { super(); message = null; wrappedThrowable = aThrowable; } - + /** - * Specifies a message and a throwable to wrap. - */ - public NSForwardException( Throwable aThrowable, String aMessage ) - { - super( aMessage ); + * Specifies a message and a throwable to wrap. + */ + public NSForwardException(Throwable aThrowable, String aMessage) { + super(aMessage); message = aMessage; wrappedThrowable = aThrowable; } - - /** - * Returns the wrapped throwable. - */ - public Throwable originalException() - { - return wrappedThrowable; - } - - public void printStackTrace(PrintWriter s) - { - if ( message != null ) - { - s.println( toString() ); + + /** + * Returns the wrapped throwable. + */ + public Throwable originalException() { + return wrappedThrowable; + } + + public void printStackTrace(PrintWriter s) { + if (message != null) { + s.println(toString()); } - if ( wrappedThrowable != null ) - { - wrappedThrowable.printStackTrace( s ); + if (wrappedThrowable != null) { + wrappedThrowable.printStackTrace(s); return; } - super.printStackTrace( s ); + super.printStackTrace(s); } - - public void printStackTrace(PrintStream s) - { - if ( message != null ) - { - s.println( toString() ); + + public void printStackTrace(PrintStream s) { + if (message != null) { + s.println(toString()); } - if ( wrappedThrowable != null ) - { - wrappedThrowable.printStackTrace( s ); + if (wrappedThrowable != null) { + wrappedThrowable.printStackTrace(s); return; } - super.printStackTrace( s ); + super.printStackTrace(s); } - - public void printStackTrace() - { - if ( message != null ) - { - System.err.println( toString() ); + + public void printStackTrace() { + if (message != null) { + System.err.println(toString()); } - if ( wrappedThrowable != null ) - { - wrappedThrowable.printStackTrace(); + if (wrappedThrowable != null) { + wrappedThrowable.printStackTrace(); return; } super.printStackTrace(); } - - public String stackTrace() - { - StringWriter writer = new StringWriter(); - PrintWriter printWriter = new PrintWriter( writer ); - if ( wrappedThrowable != null ) - { - wrappedThrowable.printStackTrace( printWriter ); + + public String stackTrace() { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + if (wrappedThrowable != null) { + wrappedThrowable.printStackTrace(printWriter); + } else { + super.printStackTrace(printWriter); } - else - { - super.printStackTrace( printWriter ); - } - printWriter.flush(); - printWriter.close(); - return writer.toString(); - } - - public String toString() - { - String result = message; - if ( result == null ) result = ""; - if ( wrappedThrowable != null ) - { - result = wrappedThrowable.toString() + " : " + result; + printWriter.flush(); + printWriter.close(); + return writer.toString(); + } + + public String toString() { + String result = message; + if (result == null) + result = ""; + if (wrappedThrowable != null) { + result = wrappedThrowable.toString() + " : " + result; } - return result; - } - + return result; + } + } diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCoding.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCoding.java index 5792303..9eece7e 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCoding.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCoding.java @@ -25,374 +25,293 @@ import net.wotonomy.foundation.internal.NullPrimitiveException; import net.wotonomy.foundation.internal.WotonomyException; /** -* NSKeyValueCoding defines an interface for classes that -* need to have more control over the wotonomy's property -* introspection facilities. <br><br> -* -* On an object that implements this interface, wotonomy -* will call these methods, and otherwise use the static -* methods on NSKeyValueCodingSupport. <br><br> -* -* NSKeyValueCodingSupport implements the default behaviors -* for each of these methods, so classes implementing this -* interface can call those methods to acheive the same -* behavior. <br><br> -* -* valueForKey and takeValueForKey are called in response -* to user actions, like viewing an object or updating its -* value in a user interface. These should call the public -* getter and setter methods on the object itself and the -* operations should be subject to validation. <br><br> -* -* storedValueForKey and takeStoredValueForKey are called -* in response to wotonomy actions, like snapshotting, -* faulting, commits, and reverts. These operations should -* bypass the public methods and directly modify the internal -* state of the object without validation. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public interface NSKeyValueCoding -{ + * NSKeyValueCoding defines an interface for classes that need to have more + * control over the wotonomy's property introspection facilities. <br> + * <br> + * + * On an object that implements this interface, wotonomy will call these + * methods, and otherwise use the static methods on NSKeyValueCodingSupport. + * <br> + * <br> + * + * NSKeyValueCodingSupport implements the default behaviors for each of these + * methods, so classes implementing this interface can call those methods to + * acheive the same behavior. <br> + * <br> + * + * valueForKey and takeValueForKey are called in response to user actions, like + * viewing an object or updating its value in a user interface. These should + * call the public getter and setter methods on the object itself and the + * operations should be subject to validation. <br> + * <br> + * + * storedValueForKey and takeStoredValueForKey are called in response to + * wotonomy actions, like snapshotting, faulting, commits, and reverts. These + * operations should bypass the public methods and directly modify the internal + * state of the object without validation. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public interface NSKeyValueCoding { public static final Null NullValue = new Null(); - /** - * Returns the value for the specified property. - * If the property does not exist, this method should - * call handleQueryWithUnboundKey. - */ - Object valueForKey( String aKey ); - - /** - * Sets the property to the specified value. - * If the property does not exist, this method should - * call handleTakeValueForUnboundKey. - * If the property is of a type that cannot allow - * null (e.g. primitive types) and aValue is null, - * this method should call unableToSetNullForKey. - */ - void takeValueForKey( Object aValue, String aKey ); - - /** - * Returns the value for the private field that - * corresponds to the specified property. - */ - Object storedValueForKey( String aKey ); - - /** - * Sets the the private field that corresponds to the - * specified property to the specified value. - */ - void takeStoredValueForKey( Object aValue, String aKey ); - - /** - * Called by valueForKey when the specified key is - * not found on this object. Implementing classes - * should handle the specified value or otherwise - * throw an exception. - */ - Object handleQueryWithUnboundKey( String aKey ); - - /** - * Called by takeValueForKey when the specified key - * is not found on this object. Implementing classes - * should handle the specified value or otherwise - * throw an exception. - */ - void handleTakeValueForUnboundKey( Object aValue, String aKey ); - - /** - * Called by takeValueForKey when the type of the - * specified key is not allowed to be null, as is - * the case with primitive types. Implementing - * classes should handle this case appropriately - * or otherwise throw an exception. - */ - void unableToSetNullForKey( String aKey ); - - /** - * Static utility methods that - * call the appropriate method if the object implements - * NSKeyValueCoding, otherwise calls the method - * on DefaultImplementation. - */ - public class Utility - { - /** - * Calls the appropriate method if the object implements - * NSKeyValueCoding, otherwise calls the method - * on DefaultImplementation. - */ - static public Object valueForKey( - Object anObject, String aKey ) - { - if ( anObject instanceof NSKeyValueCoding ) - { - return ((NSKeyValueCoding)anObject).valueForKey( aKey ); - } - return DefaultImplementation.valueForKey( anObject, aKey ); - } - - /** - * Calls the appropriate method if the object implements - * NSKeyValueCoding, otherwise calls the method - * on DefaultImplementation. - */ - static public void takeValueForKey( - Object anObject, Object aValue, String aKey ) - { - if ( anObject instanceof NSKeyValueCoding ) - { - ((NSKeyValueCoding)anObject).takeValueForKey( aValue, aKey ); - } - DefaultImplementation.takeValueForKey( anObject, aValue, aKey ); - } - - /** - * Calls the appropriate method if the object implements - * NSKeyValueCoding, otherwise calls the method - * on DefaultImplementation. - */ - static public Object storedValueForKey( - Object anObject, String aKey ) - { - if ( anObject instanceof NSKeyValueCoding ) - { - return ((NSKeyValueCoding)anObject).storedValueForKey( aKey ); - } - return DefaultImplementation.storedValueForKey( anObject, aKey ); - } - - /** - * Calls the appropriate method if the object implements - * NSKeyValueCoding, otherwise calls the method - * on DefaultImplementation. - */ - static public void takeStoredValueForKey( - Object anObject, Object aValue, String aKey ) - { - if ( anObject instanceof NSKeyValueCoding ) - { - ((NSKeyValueCoding)anObject).takeStoredValueForKey( aValue, aKey ); - } - DefaultImplementation.takeStoredValueForKey( anObject, aValue, aKey ); - } - - /** - * Calls the appropriate method if the object implements - * NSKeyValueCoding, otherwise calls the method - * on DefaultImplementation. - */ - static public Object handleQueryWithUnboundKey( - Object anObject, String aKey ) - { - if ( anObject instanceof NSKeyValueCoding ) - { - return ((NSKeyValueCoding)anObject).handleQueryWithUnboundKey( aKey ); - } - return DefaultImplementation.handleQueryWithUnboundKey( anObject, aKey ); - } - - /** - * Calls the appropriate method if the object implements - * NSKeyValueCoding, otherwise calls the method - * on DefaultImplementation. - */ - static public void handleTakeValueForUnboundKey( - Object anObject, Object aValue, String aKey ) - { - if ( anObject instanceof NSKeyValueCoding ) - { - ((NSKeyValueCoding)anObject).handleTakeValueForUnboundKey( aValue, aKey ); - } - DefaultImplementation.handleTakeValueForUnboundKey( anObject, aValue, aKey ); - } - - /** - * Calls the appropriate method if the object implements - * NSKeyValueCoding, otherwise calls the method - * on DefaultImplementation. - */ - static public void unableToSetNullForKey( - Object anObject, String aKey ) - { - if ( anObject instanceof NSKeyValueCoding ) - { - ((NSKeyValueCoding)anObject).unableToSetNullForKey( aKey ); - } - DefaultImplementation.unableToSetNullForKey( anObject, aKey ); - } - } - - public class DefaultImplementation - { - /** - * Returns the value for the specified property key - * on the specified object. <br><br> - * - * If the property does not exist, this method calls - * handleQueryWithUnboundKey on the object if it - * implements NSKeyValueCoding, otherwise calls - * handleQueryWithUnboundKey on this class. <br><br> - */ - static public Object valueForKey( - Object anObject, String aKey ) - { - if ( anObject == null ) return null; - //TODO: may need to handle "." nesting here so - // that handleQueryWithUnboundKey gets called for - // for the nested object, not the parent object - - //Correction: need to handle key paths in - // KeyValueCodingAdditionsSupport. - - try - { - return Introspector.get( anObject, aKey ); - } - catch ( IntrospectorException exc ) - { - if ( anObject instanceof NSKeyValueCoding ) - { - return ((NSKeyValueCoding)anObject).handleQueryWithUnboundKey( aKey ); - } - return handleQueryWithUnboundKey( anObject, aKey ); - } - } - - /** - * Sets the property to the specified value on - * the specified object. - * - * If the property does not exist, this method calls - * handleTakeValueForUnboundKey on the object if it - * implements NSKeyValueCoding, otherwise calls - * handleTakeValueForUnboundKey on this class. - * - * If the property is of a type that cannot allow - * null (e.g. primitive types) and aValue is null, - * this method should call unableToSetNullForKey - * on the object if it implements NSKeyValueCoding, - * otherwise calls unableToSetNullForKey on this class. - */ - static public void takeValueForKey( - Object anObject, Object aValue, String aKey ) - { - if ( anObject == null ) return; - //TODO: may need to handle "." nesting here so - // that handleTakeValueForUnboundKey gets called for - // for the nested object, not the parent object - try - { - Introspector.set( anObject, aKey, aValue ); - } - catch ( NullPrimitiveException exc ) - { - if ( anObject instanceof NSKeyValueCoding ) - { - ((NSKeyValueCoding)anObject).unableToSetNullForKey( aKey ); - } - else - { - unableToSetNullForKey( anObject, aKey ); - } - } - catch ( MissingPropertyException exc ) - { - if ( anObject instanceof NSKeyValueCoding ) - { - ((NSKeyValueCoding)anObject).handleTakeValueForUnboundKey( - aValue, aKey ); - } - else - { - handleTakeValueForUnboundKey( anObject, aValue, aKey ); - } - } - - } - - /** - * Returns the value for the private field that - * corresponds to the specified property on - * the specified object. - * - * This implementation currently calls valueForKey, - * because java security currently prevents us from - * accessing the fields of another object. - */ - static public Object storedValueForKey( - Object anObject, String aKey ) - { - //TODO: this currently just calls valueForKey - return valueForKey( anObject, aKey ); - } - - /** - * Sets the the private field that corresponds to the - * specified property to the specified value on the - * specified object. - * - * This implementation currently calls takeValueForKey, - * because java security currently prevents us from - * accessing the fields of another object. - */ - static public void takeStoredValueForKey( - Object anObject, Object aValue, String aKey ) - { - //TODO: this currently just calls takeValueForKey - takeValueForKey( anObject, aValue, aKey ); - } - - /** - * Called by valueForKey when the specified key is - * not found on the specified object, if that object - * does not implement NSKeyValueCoding. - * - * This implementation throws a WotonomyException. - */ - static public Object handleQueryWithUnboundKey( - Object anObject, String aKey ) - { - throw new WotonomyException( - "Key not found for object: " - + aKey + " : " + anObject ); - } - - /** - * Called by takeValueForKey when the specified key - * is not found on the specified object, if that object - * does not implement NSKeyValueCoding. - * - * This implementation throws a WotonomyException. - */ - static public void handleTakeValueForUnboundKey( - Object anObject, Object aValue, String aKey ) - { - throw new WotonomyException( - "Key not found for object while setting value: " - + aKey + " : " + anObject + " : " + aValue ); - } - - /** - * Called by takeValueForKey when the type of the - * specified key is not allowed to be null, as is - * the case with primitive types, if the specified - * object does not implement NSKeyValueCoding. - * - * This implementation throws a WotonomyException. - */ - static public void unableToSetNullForKey( - Object anObject, String aKey ) - { - throw new WotonomyException( - "Tried to key on object to null: " - + aKey + " : " + anObject ); - } - } + /** + * Returns the value for the specified property. If the property does not exist, + * this method should call handleQueryWithUnboundKey. + */ + Object valueForKey(String aKey); + + /** + * Sets the property to the specified value. If the property does not exist, + * this method should call handleTakeValueForUnboundKey. If the property is of a + * type that cannot allow null (e.g. primitive types) and aValue is null, this + * method should call unableToSetNullForKey. + */ + void takeValueForKey(Object aValue, String aKey); + + /** + * Returns the value for the private field that corresponds to the specified + * property. + */ + Object storedValueForKey(String aKey); + + /** + * Sets the the private field that corresponds to the specified property to the + * specified value. + */ + void takeStoredValueForKey(Object aValue, String aKey); + + /** + * Called by valueForKey when the specified key is not found on this object. + * Implementing classes should handle the specified value or otherwise throw an + * exception. + */ + Object handleQueryWithUnboundKey(String aKey); + + /** + * Called by takeValueForKey when the specified key is not found on this object. + * Implementing classes should handle the specified value or otherwise throw an + * exception. + */ + void handleTakeValueForUnboundKey(Object aValue, String aKey); + + /** + * Called by takeValueForKey when the type of the specified key is not allowed + * to be null, as is the case with primitive types. Implementing classes should + * handle this case appropriately or otherwise throw an exception. + */ + void unableToSetNullForKey(String aKey); + + /** + * Static utility methods that call the appropriate method if the object + * implements NSKeyValueCoding, otherwise calls the method on + * DefaultImplementation. + */ + public class Utility { + /** + * Calls the appropriate method if the object implements NSKeyValueCoding, + * otherwise calls the method on DefaultImplementation. + */ + static public Object valueForKey(Object anObject, String aKey) { + if (anObject instanceof NSKeyValueCoding) { + return ((NSKeyValueCoding) anObject).valueForKey(aKey); + } + return DefaultImplementation.valueForKey(anObject, aKey); + } + + /** + * Calls the appropriate method if the object implements NSKeyValueCoding, + * otherwise calls the method on DefaultImplementation. + */ + static public void takeValueForKey(Object anObject, Object aValue, String aKey) { + if (anObject instanceof NSKeyValueCoding) { + ((NSKeyValueCoding) anObject).takeValueForKey(aValue, aKey); + } + DefaultImplementation.takeValueForKey(anObject, aValue, aKey); + } + + /** + * Calls the appropriate method if the object implements NSKeyValueCoding, + * otherwise calls the method on DefaultImplementation. + */ + static public Object storedValueForKey(Object anObject, String aKey) { + if (anObject instanceof NSKeyValueCoding) { + return ((NSKeyValueCoding) anObject).storedValueForKey(aKey); + } + return DefaultImplementation.storedValueForKey(anObject, aKey); + } + + /** + * Calls the appropriate method if the object implements NSKeyValueCoding, + * otherwise calls the method on DefaultImplementation. + */ + static public void takeStoredValueForKey(Object anObject, Object aValue, String aKey) { + if (anObject instanceof NSKeyValueCoding) { + ((NSKeyValueCoding) anObject).takeStoredValueForKey(aValue, aKey); + } + DefaultImplementation.takeStoredValueForKey(anObject, aValue, aKey); + } + + /** + * Calls the appropriate method if the object implements NSKeyValueCoding, + * otherwise calls the method on DefaultImplementation. + */ + static public Object handleQueryWithUnboundKey(Object anObject, String aKey) { + if (anObject instanceof NSKeyValueCoding) { + return ((NSKeyValueCoding) anObject).handleQueryWithUnboundKey(aKey); + } + return DefaultImplementation.handleQueryWithUnboundKey(anObject, aKey); + } + + /** + * Calls the appropriate method if the object implements NSKeyValueCoding, + * otherwise calls the method on DefaultImplementation. + */ + static public void handleTakeValueForUnboundKey(Object anObject, Object aValue, String aKey) { + if (anObject instanceof NSKeyValueCoding) { + ((NSKeyValueCoding) anObject).handleTakeValueForUnboundKey(aValue, aKey); + } + DefaultImplementation.handleTakeValueForUnboundKey(anObject, aValue, aKey); + } + + /** + * Calls the appropriate method if the object implements NSKeyValueCoding, + * otherwise calls the method on DefaultImplementation. + */ + static public void unableToSetNullForKey(Object anObject, String aKey) { + if (anObject instanceof NSKeyValueCoding) { + ((NSKeyValueCoding) anObject).unableToSetNullForKey(aKey); + } + DefaultImplementation.unableToSetNullForKey(anObject, aKey); + } + } + + public class DefaultImplementation { + /** + * Returns the value for the specified property key on the specified object. + * <br> + * <br> + * + * If the property does not exist, this method calls handleQueryWithUnboundKey + * on the object if it implements NSKeyValueCoding, otherwise calls + * handleQueryWithUnboundKey on this class. <br> + * <br> + */ + static public Object valueForKey(Object anObject, String aKey) { + if (anObject == null) + return null; + // TODO: may need to handle "." nesting here so + // that handleQueryWithUnboundKey gets called for + // for the nested object, not the parent object + + // Correction: need to handle key paths in + // KeyValueCodingAdditionsSupport. + + try { + return Introspector.get(anObject, aKey); + } catch (IntrospectorException exc) { + if (anObject instanceof NSKeyValueCoding) { + return ((NSKeyValueCoding) anObject).handleQueryWithUnboundKey(aKey); + } + return handleQueryWithUnboundKey(anObject, aKey); + } + } + + /** + * Sets the property to the specified value on the specified object. + * + * If the property does not exist, this method calls + * handleTakeValueForUnboundKey on the object if it implements NSKeyValueCoding, + * otherwise calls handleTakeValueForUnboundKey on this class. + * + * If the property is of a type that cannot allow null (e.g. primitive types) + * and aValue is null, this method should call unableToSetNullForKey on the + * object if it implements NSKeyValueCoding, otherwise calls + * unableToSetNullForKey on this class. + */ + static public void takeValueForKey(Object anObject, Object aValue, String aKey) { + if (anObject == null) + return; + // TODO: may need to handle "." nesting here so + // that handleTakeValueForUnboundKey gets called for + // for the nested object, not the parent object + try { + Introspector.set(anObject, aKey, aValue); + } catch (NullPrimitiveException exc) { + if (anObject instanceof NSKeyValueCoding) { + ((NSKeyValueCoding) anObject).unableToSetNullForKey(aKey); + } else { + unableToSetNullForKey(anObject, aKey); + } + } catch (MissingPropertyException exc) { + if (anObject instanceof NSKeyValueCoding) { + ((NSKeyValueCoding) anObject).handleTakeValueForUnboundKey(aValue, aKey); + } else { + handleTakeValueForUnboundKey(anObject, aValue, aKey); + } + } + + } + + /** + * Returns the value for the private field that corresponds to the specified + * property on the specified object. + * + * This implementation currently calls valueForKey, because java security + * currently prevents us from accessing the fields of another object. + */ + static public Object storedValueForKey(Object anObject, String aKey) { + // TODO: this currently just calls valueForKey + return valueForKey(anObject, aKey); + } + + /** + * Sets the the private field that corresponds to the specified property to the + * specified value on the specified object. + * + * This implementation currently calls takeValueForKey, because java security + * currently prevents us from accessing the fields of another object. + */ + static public void takeStoredValueForKey(Object anObject, Object aValue, String aKey) { + // TODO: this currently just calls takeValueForKey + takeValueForKey(anObject, aValue, aKey); + } + + /** + * Called by valueForKey when the specified key is not found on the specified + * object, if that object does not implement NSKeyValueCoding. + * + * This implementation throws a WotonomyException. + */ + static public Object handleQueryWithUnboundKey(Object anObject, String aKey) { + throw new WotonomyException("Key not found for object: " + aKey + " : " + anObject); + } + + /** + * Called by takeValueForKey when the specified key is not found on the + * specified object, if that object does not implement NSKeyValueCoding. + * + * This implementation throws a WotonomyException. + */ + static public void handleTakeValueForUnboundKey(Object anObject, Object aValue, String aKey) { + throw new WotonomyException( + "Key not found for object while setting value: " + aKey + " : " + anObject + " : " + aValue); + } + + /** + * Called by takeValueForKey when the type of the specified key is not allowed + * to be null, as is the case with primitive types, if the specified object does + * not implement NSKeyValueCoding. + * + * This implementation throws a WotonomyException. + */ + static public void unableToSetNullForKey(Object anObject, String aKey) { + throw new WotonomyException("Tried to key on object to null: " + aKey + " : " + anObject); + } + } public class Null { public Null() { @@ -406,26 +325,19 @@ public interface NSKeyValueCoding } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.3 2003/08/07 02:43:56 chochos - * added NullValue, which points to a Null instance. + * Revision 1.3 2003/08/07 02:43:56 chochos added NullValue, which points to a + * Null instance. * - * Revision 1.2 2003/01/18 23:30:42 mpowers - * WODisplayGroup now compiles. + * Revision 1.2 2003/01/18 23:30:42 mpowers WODisplayGroup now compiles. * - * Revision 1.1 2003/01/17 14:40:49 mpowers - * Adding files to fix build. + * Revision 1.1 2003/01/17 14:40:49 mpowers Adding files to fix build. * - * Revision 1.2 2001/03/28 16:12:30 mpowers - * Documented interface. + * Revision 1.2 2001/03/28 16:12:30 mpowers Documented interface. * - * Revision 1.1 2001/03/27 23:25:05 mpowers - * Contributing interface, no docs yet. + * Revision 1.1 2001/03/27 23:25:05 mpowers Contributing interface, no docs yet. * * */ - - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingAdditions.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingAdditions.java index 785facd..39428ad 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingAdditions.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingAdditions.java @@ -22,192 +22,161 @@ import java.util.List; import java.util.Map; /** -* NSKeyValueCodingAdditions defines an interface for classes -* that need to have more control over the wotonomy's bulk -* property copying and cloning facilities. <br><br> -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public interface NSKeyValueCodingAdditions extends NSKeyValueCoding -{ - /** - * Returns the value for the specified key path, which is - * a series of keys delimited by ".", for example: - * "createTime.year.length". - */ - Object valueForKeyPath( String aKeyPath ); - - /** - * Sets the value for the specified key path, which is - * a series of keys delimited by ".", for example: - * "createTime.year.length". - * The value is set for the last object referenced by - * the key path. - */ - void takeValueForKeyPath( Object aValue, String aKeyPath ); - - /** - * Returns a Map of the specified keys to their values, - * each of which might be obtained by calling valueForKey. - */ - NSDictionary valuesForKeys( List aKeyList ); - - /** - * Takes the keys from the specified map as properties - * and applies the corresponding values, each of which - * might be set by calling takeValueForKey. - */ - void takeValuesFromDictionary( Map aMap ); - - - /** - * Static utility methods that - * call the appropriate method if the object implements - * NSKeyValueCodingAdditions, otherwise calls the method - * on DefaultImplementation. - */ - public class Utility - { - /** - * Calls the appropriate method if the object implements - * NSKeyValueCodingAdditions, otherwise calls the method - * on DefaultImplementation. - */ - public static void takeValuesFromDictionary( - Object object, Map dictionary) - { - if (object instanceof NSKeyValueCodingAdditions) { - ((NSKeyValueCodingAdditions)object).takeValuesFromDictionary(dictionary); - } else { - DefaultImplementation.takeValuesFromDictionary(object, dictionary); - } - } - - /** - * Calls the appropriate method if the object implements - * NSKeyValueCodingAdditions, otherwise calls the method - * on DefaultImplementation. - */ - public static void takeValueForKeyPath( - Object object, Object aValue, String aKeyPath) - { - if (object instanceof NSKeyValueCodingAdditions) { - ((NSKeyValueCodingAdditions)object).takeValueForKeyPath(aValue, aKeyPath); - } else { - DefaultImplementation.takeValueForKeyPath(object, aValue, aKeyPath); - } - } - - /** - * Calls the appropriate method if the object implements - * NSKeyValueCodingAdditions, otherwise calls the method - * on DefaultImplementation. - */ - public static NSDictionary valuesForKeys( - Object object, List keys) - { - if (object instanceof NSKeyValueCodingAdditions) { - return ((NSKeyValueCodingAdditions)object).valuesForKeys(keys); - } else { - return DefaultImplementation.valuesForKeys(object, keys); - } - } - - /** - * Calls the appropriate method if the object implements - * NSKeyValueCodingAdditions, otherwise calls the method - * on DefaultImplementation. - */ - public static Object valueForKeyPath( - Object object, String aKeyPath) - { - if (object instanceof NSKeyValueCodingAdditions) { - return ((NSKeyValueCodingAdditions)object).valueForKeyPath(aKeyPath); - } else { - return DefaultImplementation.valueForKeyPath(object, aKeyPath); - } - } - } - - /** - * Provides a reflection-based implementation for classes that - * don't implement NSKeyValueCodingAdditions. - */ - public class DefaultImplementation - { - /** - * Provides a reflection-based implementation for classes that - * don't implement NSKeyValueCodingAdditions. - */ - public static void takeValuesFromDictionary( - Object object, Map dictionary) - { - throw new RuntimeException( "Not implemented yet." ); - } - - /** - * Provides a reflection-based implementation for classes that - * don't implement NSKeyValueCodingAdditions. - */ - public static void takeValueForKeyPath( - Object object, Object aValue, String aKeyPath) - { - // currently, NSKeyValueCoding.takeValueForKey accepts paths - NSKeyValueCoding.DefaultImplementation.takeValueForKey( object, aValue, aKeyPath ); - } - - /** - * Provides a reflection-based implementation for classes that - * don't implement NSKeyValueCodingAdditions. - */ - public static NSDictionary valuesForKeys( - Object object, List keys) - { - throw new RuntimeException( "Not implemented yet." ); - } - - /** - * Provides a reflection-based implementation for classes that - * don't implement NSKeyValueCodingAdditions. - */ - public static Object valueForKeyPath( - Object object, String aKeyPath) - { - // currently, NSKeyValueCoding.valueForKey accepts paths - return NSKeyValueCoding.DefaultImplementation.valueForKey( object, aKeyPath ); - } - } + * NSKeyValueCodingAdditions defines an interface for classes that need to have + * more control over the wotonomy's bulk property copying and cloning + * facilities. <br> + * <br> + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public interface NSKeyValueCodingAdditions extends NSKeyValueCoding { + /** + * Returns the value for the specified key path, which is a series of keys + * delimited by ".", for example: "createTime.year.length". + */ + Object valueForKeyPath(String aKeyPath); + + /** + * Sets the value for the specified key path, which is a series of keys + * delimited by ".", for example: "createTime.year.length". The value is set for + * the last object referenced by the key path. + */ + void takeValueForKeyPath(Object aValue, String aKeyPath); + + /** + * Returns a Map of the specified keys to their values, each of which might be + * obtained by calling valueForKey. + */ + NSDictionary valuesForKeys(List aKeyList); + + /** + * Takes the keys from the specified map as properties and applies the + * corresponding values, each of which might be set by calling takeValueForKey. + */ + void takeValuesFromDictionary(Map aMap); + + /** + * Static utility methods that call the appropriate method if the object + * implements NSKeyValueCodingAdditions, otherwise calls the method on + * DefaultImplementation. + */ + public class Utility { + /** + * Calls the appropriate method if the object implements + * NSKeyValueCodingAdditions, otherwise calls the method on + * DefaultImplementation. + */ + public static void takeValuesFromDictionary(Object object, Map dictionary) { + if (object instanceof NSKeyValueCodingAdditions) { + ((NSKeyValueCodingAdditions) object).takeValuesFromDictionary(dictionary); + } else { + DefaultImplementation.takeValuesFromDictionary(object, dictionary); + } + } + + /** + * Calls the appropriate method if the object implements + * NSKeyValueCodingAdditions, otherwise calls the method on + * DefaultImplementation. + */ + public static void takeValueForKeyPath(Object object, Object aValue, String aKeyPath) { + if (object instanceof NSKeyValueCodingAdditions) { + ((NSKeyValueCodingAdditions) object).takeValueForKeyPath(aValue, aKeyPath); + } else { + DefaultImplementation.takeValueForKeyPath(object, aValue, aKeyPath); + } + } + + /** + * Calls the appropriate method if the object implements + * NSKeyValueCodingAdditions, otherwise calls the method on + * DefaultImplementation. + */ + public static NSDictionary valuesForKeys(Object object, List keys) { + if (object instanceof NSKeyValueCodingAdditions) { + return ((NSKeyValueCodingAdditions) object).valuesForKeys(keys); + } else { + return DefaultImplementation.valuesForKeys(object, keys); + } + } + + /** + * Calls the appropriate method if the object implements + * NSKeyValueCodingAdditions, otherwise calls the method on + * DefaultImplementation. + */ + public static Object valueForKeyPath(Object object, String aKeyPath) { + if (object instanceof NSKeyValueCodingAdditions) { + return ((NSKeyValueCodingAdditions) object).valueForKeyPath(aKeyPath); + } else { + return DefaultImplementation.valueForKeyPath(object, aKeyPath); + } + } + } + + /** + * Provides a reflection-based implementation for classes that don't implement + * NSKeyValueCodingAdditions. + */ + public class DefaultImplementation { + /** + * Provides a reflection-based implementation for classes that don't implement + * NSKeyValueCodingAdditions. + */ + public static void takeValuesFromDictionary(Object object, Map dictionary) { + throw new RuntimeException("Not implemented yet."); + } + + /** + * Provides a reflection-based implementation for classes that don't implement + * NSKeyValueCodingAdditions. + */ + public static void takeValueForKeyPath(Object object, Object aValue, String aKeyPath) { + // currently, NSKeyValueCoding.takeValueForKey accepts paths + NSKeyValueCoding.DefaultImplementation.takeValueForKey(object, aValue, aKeyPath); + } + + /** + * Provides a reflection-based implementation for classes that don't implement + * NSKeyValueCodingAdditions. + */ + public static NSDictionary valuesForKeys(Object object, List keys) { + throw new RuntimeException("Not implemented yet."); + } + + /** + * Provides a reflection-based implementation for classes that don't implement + * NSKeyValueCodingAdditions. + */ + public static Object valueForKeyPath(Object object, String aKeyPath) { + // currently, NSKeyValueCoding.valueForKey accepts paths + return NSKeyValueCoding.DefaultImplementation.valueForKey(object, aKeyPath); + } + } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.2 2003/01/18 23:30:42 mpowers - * WODisplayGroup now compiles. + * Revision 1.2 2003/01/18 23:30:42 mpowers WODisplayGroup now compiles. * - * Revision 1.1 2003/01/17 14:40:49 mpowers - * Adding files to fix build. + * Revision 1.1 2003/01/17 14:40:49 mpowers Adding files to fix build. * - * Revision 1.3 2001/12/10 15:25:11 mpowers - * Now properly extending NSKeyValueCoding. + * Revision 1.3 2001/12/10 15:25:11 mpowers Now properly extending + * NSKeyValueCoding. * - * Revision 1.2 2001/04/28 14:12:23 mpowers - * Refactored cloning/copying into KeyValueCodingUtilities. + * Revision 1.2 2001/04/28 14:12:23 mpowers Refactored cloning/copying into + * KeyValueCodingUtilities. * - * Revision 1.1 2001/03/29 03:29:49 mpowers - * Now using KeyValueCoding and Support instead of Introspector. + * Revision 1.1 2001/03/29 03:29:49 mpowers Now using KeyValueCoding and Support + * instead of Introspector. * - * Revision 1.2 2001/03/28 16:12:30 mpowers - * Documented interface. + * Revision 1.2 2001/03/28 16:12:30 mpowers Documented interface. * - * Revision 1.1 2001/03/27 23:25:05 mpowers - * Contributing interface, no docs yet. + * Revision 1.1 2001/03/27 23:25:05 mpowers Contributing interface, no docs yet. * * */ - - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingSupport.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingSupport.java index a947896..8fa4646 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingSupport.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSKeyValueCodingSupport.java @@ -25,204 +25,154 @@ import net.wotonomy.foundation.internal.NullPrimitiveException; import net.wotonomy.foundation.internal.WotonomyException; /** -* NSKeyValueCodingSupport defines default behavior for -* classes implementing NSKeyValueSupport. <br><br> -* -* On an object that does not implement NSKeyValueCoding, -* wotonomy will call the methods on this class directly. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 892 $ -*/ -public class NSKeyValueCodingSupport -{ - /** - * Returns the value for the specified property key - * on the specified object. <br><br> - * - * If the property does not exist, this method calls - * handleQueryWithUnboundKey on the object if it - * implements NSKeyValueCoding, otherwise calls - * handleQueryWithUnboundKey on this class. <br><br> - */ - static public Object valueForKey( - Object anObject, String aKey ) - { - //TODO: may need to handle "." nesting here so - // that handleQueryWithUnboundKey gets called for - // for the nested object, not the parent object - - //Correction: need to handle key paths in - // KeyValueCodingAdditionsSupport. - - try - { - return Introspector.get( anObject, aKey ); - } - catch ( IntrospectorException exc ) - { - if ( anObject instanceof NSKeyValueCoding ) - { - return ((NSKeyValueCoding)anObject).handleQueryWithUnboundKey( aKey ); - } - return handleQueryWithUnboundKey( anObject, aKey ); - } - } - - /** - * Sets the property to the specified value on - * the specified object. - * - * If the property does not exist, this method calls - * handleTakeValueForUnboundKey on the object if it - * implements NSKeyValueCoding, otherwise calls - * handleTakeValueForUnboundKey on this class. - * - * If the property is of a type that cannot allow - * null (e.g. primitive types) and aValue is null, - * this method should call unableToSetNullForKey - * on the object if it implements NSKeyValueCoding, - * otherwise calls unableToSetNullForKey on this class. - */ - static public void takeValueForKey( - Object anObject, Object aValue, String aKey ) - { - //TODO: may need to handle "." nesting here so - // that handleTakeValueForUnboundKey gets called for - // for the nested object, not the parent object - - try - { - Introspector.set( anObject, aKey, aValue ); - } - catch ( NullPrimitiveException exc ) - { - if ( anObject instanceof NSKeyValueCoding ) - { - ((NSKeyValueCoding)anObject).unableToSetNullForKey( aKey ); - } - else - { - unableToSetNullForKey( anObject, aKey ); - } - } - catch ( MissingPropertyException exc ) - { - if ( anObject instanceof NSKeyValueCoding ) - { - ((NSKeyValueCoding)anObject).handleTakeValueForUnboundKey( - aValue, aKey ); - } - else - { - handleTakeValueForUnboundKey( anObject, aValue, aKey ); - } - } - - } - - /** - * Returns the value for the private field that - * corresponds to the specified property on - * the specified object. - * - * This implementation currently calls valueForKey, - * because java security currently prevents us from - * accessing the fields of another object. - */ - static public Object storedValueForKey( - Object anObject, String aKey ) - { - //TODO: this currently just calls valueForKey - return valueForKey( anObject, aKey ); - } - - /** - * Sets the the private field that corresponds to the - * specified property to the specified value on the - * specified object. - * - * This implementation currently calls takeValueForKey, - * because java security currently prevents us from - * accessing the fields of another object. - */ - static public void takeStoredValueForKey( - Object anObject, Object aValue, String aKey ) - { - //TODO: this currently just calls takeValueForKey - takeValueForKey( anObject, aValue, aKey ); - } - - /** - * Called by valueForKey when the specified key is - * not found on the specified object, if that object - * does not implement NSKeyValueCoding. - * - * This implementation throws a WotonomyException. - */ - static public Object handleQueryWithUnboundKey( - Object anObject, String aKey ) - { - throw new WotonomyException( - "Key not found for object: " - + aKey + " : " + anObject ); - } - - /** - * Called by takeValueForKey when the specified key - * is not found on the specified object, if that object - * does not implement NSKeyValueCoding. - * - * This implementation throws a WotonomyException. - */ - static public void handleTakeValueForUnboundKey( - Object anObject, Object aValue, String aKey ) - { - throw new WotonomyException( - "Key not found for object while setting value: " - + aKey + " : " + anObject + " : " + aValue ); - } - - /** - * Called by takeValueForKey when the type of the - * specified key is not allowed to be null, as is - * the case with primitive types, if the specified - * object does not implement NSKeyValueCoding. - * - * This implementation throws a WotonomyException. - */ - static public void unableToSetNullForKey( - Object anObject, String aKey ) - { - throw new WotonomyException( - "Tried to key on object to null: " - + aKey + " : " + anObject ); - } + * NSKeyValueCodingSupport defines default behavior for classes implementing + * NSKeyValueSupport. <br> + * <br> + * + * On an object that does not implement NSKeyValueCoding, wotonomy will call the + * methods on this class directly. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 892 $ + */ +public class NSKeyValueCodingSupport { + /** + * Returns the value for the specified property key on the specified object. + * <br> + * <br> + * + * If the property does not exist, this method calls handleQueryWithUnboundKey + * on the object if it implements NSKeyValueCoding, otherwise calls + * handleQueryWithUnboundKey on this class. <br> + * <br> + */ + static public Object valueForKey(Object anObject, String aKey) { + // TODO: may need to handle "." nesting here so + // that handleQueryWithUnboundKey gets called for + // for the nested object, not the parent object + + // Correction: need to handle key paths in + // KeyValueCodingAdditionsSupport. + + try { + return Introspector.get(anObject, aKey); + } catch (IntrospectorException exc) { + if (anObject instanceof NSKeyValueCoding) { + return ((NSKeyValueCoding) anObject).handleQueryWithUnboundKey(aKey); + } + return handleQueryWithUnboundKey(anObject, aKey); + } + } + + /** + * Sets the property to the specified value on the specified object. + * + * If the property does not exist, this method calls + * handleTakeValueForUnboundKey on the object if it implements NSKeyValueCoding, + * otherwise calls handleTakeValueForUnboundKey on this class. + * + * If the property is of a type that cannot allow null (e.g. primitive types) + * and aValue is null, this method should call unableToSetNullForKey on the + * object if it implements NSKeyValueCoding, otherwise calls + * unableToSetNullForKey on this class. + */ + static public void takeValueForKey(Object anObject, Object aValue, String aKey) { + // TODO: may need to handle "." nesting here so + // that handleTakeValueForUnboundKey gets called for + // for the nested object, not the parent object + + try { + Introspector.set(anObject, aKey, aValue); + } catch (NullPrimitiveException exc) { + if (anObject instanceof NSKeyValueCoding) { + ((NSKeyValueCoding) anObject).unableToSetNullForKey(aKey); + } else { + unableToSetNullForKey(anObject, aKey); + } + } catch (MissingPropertyException exc) { + if (anObject instanceof NSKeyValueCoding) { + ((NSKeyValueCoding) anObject).handleTakeValueForUnboundKey(aValue, aKey); + } else { + handleTakeValueForUnboundKey(anObject, aValue, aKey); + } + } + + } + + /** + * Returns the value for the private field that corresponds to the specified + * property on the specified object. + * + * This implementation currently calls valueForKey, because java security + * currently prevents us from accessing the fields of another object. + */ + static public Object storedValueForKey(Object anObject, String aKey) { + // TODO: this currently just calls valueForKey + return valueForKey(anObject, aKey); + } + + /** + * Sets the the private field that corresponds to the specified property to the + * specified value on the specified object. + * + * This implementation currently calls takeValueForKey, because java security + * currently prevents us from accessing the fields of another object. + */ + static public void takeStoredValueForKey(Object anObject, Object aValue, String aKey) { + // TODO: this currently just calls takeValueForKey + takeValueForKey(anObject, aValue, aKey); + } + + /** + * Called by valueForKey when the specified key is not found on the specified + * object, if that object does not implement NSKeyValueCoding. + * + * This implementation throws a WotonomyException. + */ + static public Object handleQueryWithUnboundKey(Object anObject, String aKey) { + throw new WotonomyException("Key not found for object: " + aKey + " : " + anObject); + } + + /** + * Called by takeValueForKey when the specified key is not found on the + * specified object, if that object does not implement NSKeyValueCoding. + * + * This implementation throws a WotonomyException. + */ + static public void handleTakeValueForUnboundKey(Object anObject, Object aValue, String aKey) { + throw new WotonomyException( + "Key not found for object while setting value: " + aKey + " : " + anObject + " : " + aValue); + } + + /** + * Called by takeValueForKey when the type of the specified key is not allowed + * to be null, as is the case with primitive types, if the specified object does + * not implement NSKeyValueCoding. + * + * This implementation throws a WotonomyException. + */ + static public void unableToSetNullForKey(Object anObject, String aKey) { + throw new WotonomyException("Tried to key on object to null: " + aKey + " : " + anObject); + } } /* - * $Log$ - * Revision 1.1 2006/02/16 12:47:16 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.1 2003/01/17 14:40:50 mpowers - * Adding files to fix build. + * Revision 1.1 2003/01/17 14:40:50 mpowers Adding files to fix build. * - * Revision 1.4 2001/05/18 21:04:33 mpowers - * Reimplemented EditingContext.initializeObject. + * Revision 1.4 2001/05/18 21:04:33 mpowers Reimplemented + * EditingContext.initializeObject. * - * Revision 1.3 2001/04/27 00:28:29 mpowers - * Fixed a return value. + * Revision 1.3 2001/04/27 00:28:29 mpowers Fixed a return value. * - * Revision 1.2 2001/04/03 20:36:01 mpowers - * Fixed refaulting/reverting/invalidating to be self-consistent. + * Revision 1.2 2001/04/03 20:36:01 mpowers Fixed + * refaulting/reverting/invalidating to be self-consistent. * - * Revision 1.1 2001/03/28 17:49:33 mpowers - * Implemented NSKeyValueCodingSupport. + * Revision 1.1 2001/03/28 17:49:33 mpowers Implemented NSKeyValueCodingSupport. * * */ - - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLock.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLock.java index e6a5147..45afdde 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLock.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLock.java @@ -24,85 +24,78 @@ package net.wotonomy.foundation; import EDU.oswego.cs.dl.util.concurrent.Mutex; /** -* A simple mutually-exclusive lock. Currently an API-compliance -* subclass of an external Mutex class, conforming to the API and -* behavior of com.webobjects.foundation.NSLock. This class implements -* the NSLocking protocol (interface), and is implemented using -* Doug Lea's concurrent programming package. -* -* @author cgruber@israfil.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -* -*/ + * A simple mutually-exclusive lock. Currently an API-compliance subclass of an + * external Mutex class, conforming to the API and behavior of + * com.webobjects.foundation.NSLock. This class implements the NSLocking + * protocol (interface), and is implemented using Doug Lea's concurrent + * programming package. + * + * @author cgruber@israfil.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + * + */ public class NSLock extends Mutex implements NSLocking { - - public NSLock() { - } - - public synchronized void lock() { - try { - acquire(); - } catch (InterruptedException interruptedexception) { - notify(); - } - } - - public synchronized void unlock() { - release(); - } - - public synchronized boolean tryLock() { - return tryLock(0); - } - - public synchronized boolean tryLock(long l) { - try { - return attempt(l); - } catch (InterruptedException interruptedexception) { - notify(); - return false; - } - } - - public boolean tryLock(NSTimestamp nstimestamp) { - return tryLock(nstimestamp.getTime() - System.currentTimeMillis()); - } - - public String toString() { + public NSLock() { + } + + public synchronized void lock() { + try { + acquire(); + } catch (InterruptedException interruptedexception) { + notify(); + } + } + + public synchronized void unlock() { + release(); + } + + public synchronized boolean tryLock() { + return tryLock(0); + } + + public synchronized boolean tryLock(long l) { + try { + return attempt(l); + } catch (InterruptedException interruptedexception) { + notify(); + return false; + } + } + + public boolean tryLock(NSTimestamp nstimestamp) { + return tryLock(nstimestamp.getTime() - System.currentTimeMillis()); + } + + public String toString() { return getClass().getName() + " <" + (inuse_ ? "Locked" : "Unlocked") + ">"; - } + } - public synchronized boolean isLocked() { + public synchronized boolean isLocked() { return inuse_; - } + } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.1 2002/07/14 21:56:16 mpowers - * Contributions from cgruber. + * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber. * - * Revision 1.4 2002/06/25 19:03:02 cgruber - * Internal documentation fixes. + * Revision 1.4 2002/06/25 19:03:02 cgruber Internal documentation fixes. * - * Revision 1.3 2002/06/25 18:52:56 cgruber - * Fix javadocs that resulted from bad cut-and-paste of the - * boilerplate. + * Revision 1.3 2002/06/25 18:52:56 cgruber Fix javadocs that resulted from bad + * cut-and-paste of the boilerplate. * - * Revision 1.2 2002/06/25 17:45:52 cgruber - * Add implementation of NSLock using Doug Lea's concurrent - * programming APIs. + * Revision 1.2 2002/06/25 17:45:52 cgruber Add implementation of NSLock using + * Doug Lea's concurrent programming APIs. * - * Revision 1.1 2002/06/25 07:52:57 cgruber - * Add quite a few abstract classes, interfaces, and classes. All - * API consistent with WebObjects, but with no implementation, nor - * any private or package access members from the original. + * Revision 1.1 2002/06/25 07:52:57 cgruber Add quite a few abstract classes, + * interfaces, and classes. All API consistent with WebObjects, but with no + * implementation, nor any private or package access members from the original. * */ diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLocking.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLocking.java index f8c8ff4..d5925b5 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLocking.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLocking.java @@ -22,38 +22,35 @@ $Id: NSLocking.java 892 2006-02-16 12:47:16Z cgruber $ package net.wotonomy.foundation; /** -* Defines a simple locking protocol. Very course-grain locking. -* -* @author cgruber@israfil.net -* @author $Author: cgruber $ -* @version $Revision: 892 $ -*/ + * Defines a simple locking protocol. Very course-grain locking. + * + * @author cgruber@israfil.net + * @author $Author: cgruber $ + * @version $Revision: 892 $ + */ public interface NSLocking { - public static final long OneSecond = 1000L; - public static final long OneMinute = 60000L; - public static final long OneHour = 0x36ee80L; - public static final long OneDay = 0x5265c00L; - public static final long OneWeek = 0x240c8400L; - public static final long OneYear = 0x758f0dfc0L; - public static final long OneCentury = 0x2debe176700L; + public static final long OneSecond = 1000L; + public static final long OneMinute = 60000L; + public static final long OneHour = 0x36ee80L; + public static final long OneDay = 0x5265c00L; + public static final long OneWeek = 0x240c8400L; + public static final long OneYear = 0x758f0dfc0L; + public static final long OneCentury = 0x2debe176700L; - public abstract void lock(); + public abstract void lock(); - public abstract void unlock(); + public abstract void unlock(); } /* - * $Log$ - * Revision 1.1 2006/02/16 12:47:16 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.1 2002/07/14 21:56:16 mpowers - * Contributions from cgruber. + * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber. * - * Revision 1.2 2002/06/21 22:11:19 cgruber - * Add a log trail + * Revision 1.2 2002/06/21 22:11:19 cgruber Add a log trail * */ diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLog.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLog.java index 52e4090..b447bd3 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLog.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSLog.java @@ -24,466 +24,399 @@ import java.io.PrintStream; import java.util.Date; /** -* NSLog is foundation's built-in logging facility: IMPLEMENTED, BUT NOT TESTED. -* By default, all groups are enabled, and debug level is DebugLevelOff. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public class NSLog -{ - public static long DebugGroupApplicationGeneration = 1L << 3; - public static long DebugGroupArchiving = 1L << 6; - public static long DebugGroupAssociations = 1L << 19; - public static long DebugGroupComponentBindings = 1L << 9; - public static long DebugGroupControllers = 1L << 20; - public static long DebugGroupComponents = 1L << 26; - public static long DebugGroupDatabaseAccess = 1L << 16; - public static long DebugGroupDeployment = 1L << 22; - public static long DebugGroupEnterpriseObjects = 1L << 1; - public static long DebugGroupFormatting = 1L << 10; - public static long DebugGroupIO = 1L << 13; - public static long DebugGroupJSPServlets = 1L << 27; - public static long DebugGroupKeyValueCoding = 1L << 8; - public static long DebugGroupModel = 1L << 15; - public static long DebugGroupMultithreading = 1L << 4; - public static long DebugGroupParsing = 1L << 23; - public static long DebugGroupQualifiers = 1L << 11; - public static long DebugGroupReflection = 1L << 24; - public static long DebugGroupRequestHandling = 1L << 25; - public static long DebugGroupResources = 1L << 5; - public static long DebugGroupRules = 1L << 21; - public static long DebugGroupSQLGeneration = 1L << 17; - public static long DebugGroupTiming = 1L << 14; - public static long DebugGroupUserInterface = 1L << 18; - public static long DebugGroupValidation = 1L << 7; - public static long DebugGroupWebObjects = 1L << 2; - public static long DebugGroupWebServices = 1L << 2; - - public static int DebugLevelOff = 0; - public static int DebugLevelCritical = 1; - public static int DebugLevelInformational = 2; - public static int DebugLevelDetailed = 3; - - /** - * The logger to which debug statements should be - * conditionally written. By default, these messages - * appear on the standard error stream. - */ - public static Logger debug; - - /** - * The logger to which error messages should be written, - * which may not always be user-visible. By default, - * these messages appear on the standard error stream. - */ - public static Logger err; - - /** - * The logger to which user-visible messages should be written. - * By default, these messages appear on the standard output stream. - */ - public static Logger out; - - private static long allowedGroups; - private static int allowedLevel; - - static - { - debug = new PrintStreamLogger( System.err ); - err = new PrintStreamLogger( System.err ); - out = new PrintStreamLogger( System.out ); - - //TODO: need to initialize the debug level and groups based - // on the value of the NSDebugLevel and NSDebugGroup properties - allowedGroups = Long.MAX_VALUE; - allowedLevel = 0; - } - - /** - * Adds the specified group masks to those allowed for logging. - */ - public static void allowDebugLoggingForGroups(long aDebugGroups) - { - allowedGroups = allowedGroups | aDebugGroups; - } - - /** - * Returns the current logging debug level. - */ - public static int allowedDebugLevel() - { - return allowedLevel; - } - - /** - * Returns whether logging is allowed for the specified groups masks. - */ - public static boolean debugLoggingAllowedForGroups(long aDebugGroups) - { - return ( allowedGroups == ( allowedGroups | aDebugGroups ) ); - } - - /** - * Returns whether logging is allowed for the specified level. - */ - public static boolean debugLoggingAllowedForLevel(int aDebugLevel) - { - return ( allowedLevel >= aDebugLevel ); - } - - /** - * Returns whether logging allowed for the specified groups masks - * at the specified level. Convenience method. - */ - public static boolean debugLoggingAllowedForLevelAndGroups(int aDebugLevel, - long aDebugGroups) - { - return ( ( allowedLevel >= aDebugLevel ) - && ( allowedGroups == ( allowedGroups | aDebugGroups ) ) ); - } - - /** - * Convenience to obtain a java PrintStream for the specified file path. - * Returns null if the stream could not be created. - */ - public static PrintStream printStreamForPath(String aPath) - { - try - { - return new PrintStream( new FileOutputStream( aPath ) ); - } - catch ( Throwable t ) - { - } - return null; - } - - /** - * Removes the specified group masks from those allowed for logging. - */ - public static void refuseDebugLoggingForGroups(long aDebugGroups) - { - allowedGroups = ( allowedGroups | aDebugGroups ) ^ aDebugGroups; - } - - /** - * Sets the allowed groups to only those specified by the mask. - */ - public static void setAllowedDebugGroups(long aDebugGroups) - { - allowedGroups = aDebugGroups; - } - - /** - * Sets the current debug level. - */ - public static void setAllowedDebugLevel(int aDebugLevel) - { - allowedLevel = aDebugLevel; - } - - /** - * Sets the current debug logger. - * Does nothing if logger is null. - */ - public static void setDebug(NSLog.Logger logger) - { - if ( logger != null ) - { - debug = logger; - } - } - - /** - * Sets the current error logger. - * Does nothing if logger is null. - */ - public static void setErr(NSLog.Logger logger) - { - if ( logger != null ) - { - err = logger; - } - } - - /** - * Sets the current output logger. - * Does nothing if logger is null. - */ - public static void setOut(NSLog.Logger logger) - { - if ( logger != null ) - { - out = logger; - } - } - - /** - * Convenience to write the throwable's stack trace - * to a string. - */ - public static String throwableAsString(Throwable t) - { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream( os ); - t.printStackTrace( ps ); - return os.toString(); - } - - /** - * The abstract superclass of all Logger implementations. - */ - static abstract public class Logger - { - private boolean enabled; - private boolean verbose; - - /** - * Default constructor sets enabled - * and verbose to true. - */ - public Logger() - { - enabled = true; - verbose = true; - } - - /** - * Convenience to append a Boolean. - */ - public void appendln(boolean aValue) - { - appendln( new Boolean( aValue ) ); - } - - /** - * Convenience to append a Byte. - */ - public void appendln(byte aValue) - { - appendln( new Byte( aValue ) ); - } - - /** - * Convenience to write a String - * comprised of the byte array using - * the default encoding. - */ - public void appendln(byte[] aValue) - { - appendln( new String( aValue ) ); - } - - /** - * Convenience to append a Character. - */ - public void appendln(char aValue) - { - appendln( new Character( aValue ) ); - } - - /** - * Convenience to append a String - * comprised of the character array. - */ - public void appendln(char[] aValue) - { - appendln( new String( aValue ) ); - } - - /** - * Convenience to append a Double. - */ - public void appendln(double aValue) - { - appendln( new Double( aValue ) ); - } - - /** - * Convenience to append a Float. - */ - public void appendln(float aValue) - { - appendln( new Float( aValue ) ); - } - - /** - * Convenience to append a Integer. - */ - public void appendln(int aValue) - { - appendln( new Integer( aValue ) ); - } - - /** - * Convenience to append a Long. - */ - public void appendln(long aValue) - { - appendln( new Long( aValue ) ); - } - - /** - * Convenience to append a Short - */ - public void appendln(short aValue) - { - appendln( new Short( aValue ) ); - } - - /** - * Convenience to append a Throwable. - */ - public void appendln(Throwable aValue) - { - appendln( NSLog.throwableAsString( aValue ) ); - } - - /** - * Writes the object to the log. - */ - public abstract void appendln(Object aValue); - - /** - * Appends a line to the log. - */ - public abstract void appendln(); - - /** - * Flushes any buffered output to the log. - */ - public abstract void flush(); - - /** - * Returns whether the logger is enabled, - * the meaning of which is defined by the - * implementing class. - */ - public boolean isEnabled() - { - return enabled; - } - - /** - * Returns whether the logger is verbose, - * the meaning of which is defined by the - * implementing class. - */ - public boolean isVerbose() - { - return verbose; - } - - /** - * Sets whether the logger is enabled, - * the meaning of which is defined by the - * implementing class. - */ - public void setIsEnabled(boolean aBool) - { - enabled = aBool; - } - - /** - * Sets whether the logger is verbose, - * the meaning of which is defined by the - * implementing class. - */ - public void setIsVerbose(boolean aBool) - { - verbose = aBool; - } - } - - /** - * The default implementation of Logger that writes to a Java - * PrintStream. If not enabled, no output is written. - * If verbose, output is in format: "[time] <thread name> message". - */ - static public class PrintStreamLogger extends Logger - { - private PrintStream thePrintStream; - - /** - * Constructor takes a PrintStream. - */ - public PrintStreamLogger(PrintStream ps) - { - thePrintStream = ps; - } - - /** - * Sends a newline to the print stream. - */ - public void appendln() - { - if ( isEnabled() ) - { - thePrintStream.println(); - } - } - - /** - * Writes the throwable to the print stream. - */ - public void appendln(Throwable aValue) - { - appendln( NSLog.throwableAsString( aValue ) ); - } - - /** - * Writes aValue.toString to the print stream. - */ - public void appendln(Object aValue) - { - if ( isEnabled() ) - { - if ( isVerbose() ) - { - thePrintStream.print( '[' + new Date().toString() + "] <" + - Thread.currentThread().getName() + "> " ); - } - if ( aValue == null ) aValue = "null"; - thePrintStream.println( aValue.toString() ); - } - } - - /** - * Flushes the print stream. - */ - public void flush() - { - thePrintStream.flush(); - } - - /** - * Returns the current print stream. - */ - public PrintStream printStream() - { - return thePrintStream; - } - - /** - * Replaces the current print stream. - */ - public void setPrintStream(PrintStream aStream) - { - thePrintStream = aStream; - } - } + * NSLog is foundation's built-in logging facility: IMPLEMENTED, BUT NOT TESTED. + * By default, all groups are enabled, and debug level is DebugLevelOff. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public class NSLog { + public static long DebugGroupApplicationGeneration = 1L << 3; + public static long DebugGroupArchiving = 1L << 6; + public static long DebugGroupAssociations = 1L << 19; + public static long DebugGroupComponentBindings = 1L << 9; + public static long DebugGroupControllers = 1L << 20; + public static long DebugGroupComponents = 1L << 26; + public static long DebugGroupDatabaseAccess = 1L << 16; + public static long DebugGroupDeployment = 1L << 22; + public static long DebugGroupEnterpriseObjects = 1L << 1; + public static long DebugGroupFormatting = 1L << 10; + public static long DebugGroupIO = 1L << 13; + public static long DebugGroupJSPServlets = 1L << 27; + public static long DebugGroupKeyValueCoding = 1L << 8; + public static long DebugGroupModel = 1L << 15; + public static long DebugGroupMultithreading = 1L << 4; + public static long DebugGroupParsing = 1L << 23; + public static long DebugGroupQualifiers = 1L << 11; + public static long DebugGroupReflection = 1L << 24; + public static long DebugGroupRequestHandling = 1L << 25; + public static long DebugGroupResources = 1L << 5; + public static long DebugGroupRules = 1L << 21; + public static long DebugGroupSQLGeneration = 1L << 17; + public static long DebugGroupTiming = 1L << 14; + public static long DebugGroupUserInterface = 1L << 18; + public static long DebugGroupValidation = 1L << 7; + public static long DebugGroupWebObjects = 1L << 2; + public static long DebugGroupWebServices = 1L << 2; + + public static int DebugLevelOff = 0; + public static int DebugLevelCritical = 1; + public static int DebugLevelInformational = 2; + public static int DebugLevelDetailed = 3; + + /** + * The logger to which debug statements should be conditionally written. By + * default, these messages appear on the standard error stream. + */ + public static Logger debug; + + /** + * The logger to which error messages should be written, which may not always be + * user-visible. By default, these messages appear on the standard error stream. + */ + public static Logger err; + + /** + * The logger to which user-visible messages should be written. By default, + * these messages appear on the standard output stream. + */ + public static Logger out; + + private static long allowedGroups; + private static int allowedLevel; + + static { + debug = new PrintStreamLogger(System.err); + err = new PrintStreamLogger(System.err); + out = new PrintStreamLogger(System.out); + + // TODO: need to initialize the debug level and groups based + // on the value of the NSDebugLevel and NSDebugGroup properties + allowedGroups = Long.MAX_VALUE; + allowedLevel = 0; + } + + /** + * Adds the specified group masks to those allowed for logging. + */ + public static void allowDebugLoggingForGroups(long aDebugGroups) { + allowedGroups = allowedGroups | aDebugGroups; + } + + /** + * Returns the current logging debug level. + */ + public static int allowedDebugLevel() { + return allowedLevel; + } + + /** + * Returns whether logging is allowed for the specified groups masks. + */ + public static boolean debugLoggingAllowedForGroups(long aDebugGroups) { + return (allowedGroups == (allowedGroups | aDebugGroups)); + } + + /** + * Returns whether logging is allowed for the specified level. + */ + public static boolean debugLoggingAllowedForLevel(int aDebugLevel) { + return (allowedLevel >= aDebugLevel); + } + + /** + * Returns whether logging allowed for the specified groups masks at the + * specified level. Convenience method. + */ + public static boolean debugLoggingAllowedForLevelAndGroups(int aDebugLevel, long aDebugGroups) { + return ((allowedLevel >= aDebugLevel) && (allowedGroups == (allowedGroups | aDebugGroups))); + } + + /** + * Convenience to obtain a java PrintStream for the specified file path. Returns + * null if the stream could not be created. + */ + public static PrintStream printStreamForPath(String aPath) { + try { + return new PrintStream(new FileOutputStream(aPath)); + } catch (Throwable t) { + } + return null; + } + + /** + * Removes the specified group masks from those allowed for logging. + */ + public static void refuseDebugLoggingForGroups(long aDebugGroups) { + allowedGroups = (allowedGroups | aDebugGroups) ^ aDebugGroups; + } + + /** + * Sets the allowed groups to only those specified by the mask. + */ + public static void setAllowedDebugGroups(long aDebugGroups) { + allowedGroups = aDebugGroups; + } + + /** + * Sets the current debug level. + */ + public static void setAllowedDebugLevel(int aDebugLevel) { + allowedLevel = aDebugLevel; + } + + /** + * Sets the current debug logger. Does nothing if logger is null. + */ + public static void setDebug(NSLog.Logger logger) { + if (logger != null) { + debug = logger; + } + } + + /** + * Sets the current error logger. Does nothing if logger is null. + */ + public static void setErr(NSLog.Logger logger) { + if (logger != null) { + err = logger; + } + } + + /** + * Sets the current output logger. Does nothing if logger is null. + */ + public static void setOut(NSLog.Logger logger) { + if (logger != null) { + out = logger; + } + } + + /** + * Convenience to write the throwable's stack trace to a string. + */ + public static String throwableAsString(Throwable t) { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(os); + t.printStackTrace(ps); + return os.toString(); + } + + /** + * The abstract superclass of all Logger implementations. + */ + static abstract public class Logger { + private boolean enabled; + private boolean verbose; + + /** + * Default constructor sets enabled and verbose to true. + */ + public Logger() { + enabled = true; + verbose = true; + } + + /** + * Convenience to append a Boolean. + */ + public void appendln(boolean aValue) { + appendln(new Boolean(aValue)); + } + + /** + * Convenience to append a Byte. + */ + public void appendln(byte aValue) { + appendln(new Byte(aValue)); + } + + /** + * Convenience to write a String comprised of the byte array using the default + * encoding. + */ + public void appendln(byte[] aValue) { + appendln(new String(aValue)); + } + + /** + * Convenience to append a Character. + */ + public void appendln(char aValue) { + appendln(new Character(aValue)); + } + + /** + * Convenience to append a String comprised of the character array. + */ + public void appendln(char[] aValue) { + appendln(new String(aValue)); + } + + /** + * Convenience to append a Double. + */ + public void appendln(double aValue) { + appendln(new Double(aValue)); + } + + /** + * Convenience to append a Float. + */ + public void appendln(float aValue) { + appendln(new Float(aValue)); + } + + /** + * Convenience to append a Integer. + */ + public void appendln(int aValue) { + appendln(new Integer(aValue)); + } + + /** + * Convenience to append a Long. + */ + public void appendln(long aValue) { + appendln(new Long(aValue)); + } + + /** + * Convenience to append a Short + */ + public void appendln(short aValue) { + appendln(new Short(aValue)); + } + + /** + * Convenience to append a Throwable. + */ + public void appendln(Throwable aValue) { + appendln(NSLog.throwableAsString(aValue)); + } + + /** + * Writes the object to the log. + */ + public abstract void appendln(Object aValue); + + /** + * Appends a line to the log. + */ + public abstract void appendln(); + + /** + * Flushes any buffered output to the log. + */ + public abstract void flush(); + + /** + * Returns whether the logger is enabled, the meaning of which is defined by the + * implementing class. + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Returns whether the logger is verbose, the meaning of which is defined by the + * implementing class. + */ + public boolean isVerbose() { + return verbose; + } + + /** + * Sets whether the logger is enabled, the meaning of which is defined by the + * implementing class. + */ + public void setIsEnabled(boolean aBool) { + enabled = aBool; + } + + /** + * Sets whether the logger is verbose, the meaning of which is defined by the + * implementing class. + */ + public void setIsVerbose(boolean aBool) { + verbose = aBool; + } + } + + /** + * The default implementation of Logger that writes to a Java PrintStream. If + * not enabled, no output is written. If verbose, output is in format: "[time] + * <thread name> message". + */ + static public class PrintStreamLogger extends Logger { + private PrintStream thePrintStream; + + /** + * Constructor takes a PrintStream. + */ + public PrintStreamLogger(PrintStream ps) { + thePrintStream = ps; + } + + /** + * Sends a newline to the print stream. + */ + public void appendln() { + if (isEnabled()) { + thePrintStream.println(); + } + } + + /** + * Writes the throwable to the print stream. + */ + public void appendln(Throwable aValue) { + appendln(NSLog.throwableAsString(aValue)); + } + + /** + * Writes aValue.toString to the print stream. + */ + public void appendln(Object aValue) { + if (isEnabled()) { + if (isVerbose()) { + thePrintStream.print('[' + new Date().toString() + "] <" + Thread.currentThread().getName() + "> "); + } + if (aValue == null) + aValue = "null"; + thePrintStream.println(aValue.toString()); + } + } + + /** + * Flushes the print stream. + */ + public void flush() { + thePrintStream.flush(); + } + + /** + * Returns the current print stream. + */ + public PrintStream printStream() { + return thePrintStream; + } + + /** + * Replaces the current print stream. + */ + public void setPrintStream(PrintStream aStream) { + thePrintStream = aStream; + } + } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.1 2003/01/31 22:33:00 mpowers - * Contributing NSLog. + * Revision 1.1 2003/01/31 22:33:00 mpowers Contributing NSLog. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMultiReaderLock.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMultiReaderLock.java index abed576..3492141 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMultiReaderLock.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMultiReaderLock.java @@ -24,136 +24,134 @@ package net.wotonomy.foundation; import EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock; /** -* A Read-Write lock that allows unlimited number of calling threads to -* acquire read locks, but only one thread to acquire a write lock. It -* is also reentrant, allowing each thread to re-acquire it's lock -* recursively. For that reason it is somewhat slower, as there is a -* hash lookup when attempting to acquire and release reader locks. Of -* course a writer lock is quite a bit slower than a reader lock. A -* write lock is mutally exclusive with read locks, though a thread -* that has obtained a read-lock may be promoted to a write lock and -* vice versa when conditions permit. -* -* @author cgruber@israfil.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ + * A Read-Write lock that allows unlimited number of calling threads to acquire + * read locks, but only one thread to acquire a write lock. It is also + * reentrant, allowing each thread to re-acquire it's lock recursively. For that + * reason it is somewhat slower, as there is a hash lookup when attempting to + * acquire and release reader locks. Of course a writer lock is quite a bit + * slower than a reader lock. A write lock is mutally exclusive with read locks, + * though a thread that has obtained a read-lock may be promoted to a write lock + * and vice versa when conditions permit. + * + * @author cgruber@israfil.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ public class NSMultiReaderLock extends ReentrantWriterPreferenceReadWriteLock implements NSLocking { - NSMutableDictionary _readerSuspended = new NSMutableDictionary(); - - public NSMultiReaderLock() { - } - - public void lockForReading() { - try { - readerLock_.acquire(); - } catch (InterruptedException interruptedexception) { - // Null behavior, as notify() is already called - // by acquire(); - // We may want to log here. - } - } - - public void unlockForReading() { - readerLock_.release(); - } - - public void lock() { - lockForWriting(); - } - - public void lockForWriting() { - try { - writerLock_.acquire(); - } catch (InterruptedException interruptedexception) { - // Null behavior, as notify() is already called - // by acquire(); - // We may want to log here. - } - } - - public void unlock() { - unlockForWriting(); - } - - public void unlockForWriting() { - writerLock_.release(); - } - - /** @see com.webobjects.foundation.NSMultiReaderLock#suspendReaderLock() */ - public void suspendReaderLocks() { - Thread thisThread = Thread.currentThread(); - Integer suspendedReaders = (Integer)_readerSuspended.get(thisThread); - if (suspendedReaders != null && suspendedReaders.intValue() > 0) return; - // logic is to override startRead / endRead and ensure that the suspension - // isn't improperly stopped. + NSMutableDictionary _readerSuspended = new NSMutableDictionary(); + + public NSMultiReaderLock() { + } + + public void lockForReading() { + try { + readerLock_.acquire(); + } catch (InterruptedException interruptedexception) { + // Null behavior, as notify() is already called + // by acquire(); + // We may want to log here. + } + } + + public void unlockForReading() { + readerLock_.release(); + } + + public void lock() { + lockForWriting(); + } + + public void lockForWriting() { + try { + writerLock_.acquire(); + } catch (InterruptedException interruptedexception) { + // Null behavior, as notify() is already called + // by acquire(); + // We may want to log here. + } + } + + public void unlock() { + unlockForWriting(); + } + + public void unlockForWriting() { + writerLock_.release(); + } + + /** @see com.webobjects.foundation.NSMultiReaderLock#suspendReaderLock() */ + public void suspendReaderLocks() { + Thread thisThread = Thread.currentThread(); + Integer suspendedReaders = (Integer) _readerSuspended.get(thisThread); + if (suspendedReaders != null && suspendedReaders.intValue() > 0) + return; + // logic is to override startRead / endRead and ensure that the suspension + // isn't improperly stopped. throw new UnsupportedOperationException("Not Yet Implemented"); - } - - /** @see com.webobjects.foundation.NSMultiReaderLock#retrieveReaderLock() */ - public void retrieveReaderLocks() { - Thread thisThread = Thread.currentThread(); - Integer suspendedReaders = (Integer)_readerSuspended.get(thisThread); - if (suspendedReaders != null && suspendedReaders.intValue() > 0) return; - // logic is to override startRead / endRead and ensure that the suspension - // isn't improperly stopped. - throw new UnsupportedOperationException("Not Yet Implemented"); - } - - public boolean tryLockForWriting() { - try { - return writerLock_.attempt(0); - } catch (InterruptedException interruptedexception) { - // notify() is already called by attempt(); - // We may want to log here. - return false; - } - } - - public boolean tryLockForReading() { - try { - return readerLock_.attempt(0); - } catch (InterruptedException interruptedexception) { - // notify() is already called by attempt(); - // We may want to log here. - return false; - } - } - - public String toString() { + } + + /** @see com.webobjects.foundation.NSMultiReaderLock#retrieveReaderLock() */ + public void retrieveReaderLocks() { + Thread thisThread = Thread.currentThread(); + Integer suspendedReaders = (Integer) _readerSuspended.get(thisThread); + if (suspendedReaders != null && suspendedReaders.intValue() > 0) + return; + // logic is to override startRead / endRead and ensure that the suspension + // isn't improperly stopped. throw new UnsupportedOperationException("Not Yet Implemented"); - } - - protected String _padString(long l, int i) { + } + + public boolean tryLockForWriting() { + try { + return writerLock_.attempt(0); + } catch (InterruptedException interruptedexception) { + // notify() is already called by attempt(); + // We may want to log here. + return false; + } + } + + public boolean tryLockForReading() { + try { + return readerLock_.attempt(0); + } catch (InterruptedException interruptedexception) { + // notify() is already called by attempt(); + // We may want to log here. + return false; + } + } + + public String toString() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - protected String _padString(String s, int i, boolean flag) { + protected String _padString(long l, int i) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } + protected String _padString(String s, int i, boolean flag) { + throw new UnsupportedOperationException("Not Yet Implemented"); + } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.2 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.1 2002/07/14 21:56:16 mpowers - * Contributions from cgruber. + * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber. * - * Revision 1.2 2002/06/26 00:40:22 cgruber - * Add implementation, using ReentrantWriterPreferenceReadWriteLock - * as a base. + * Revision 1.2 2002/06/26 00:40:22 cgruber Add implementation, using + * ReentrantWriterPreferenceReadWriteLock as a base. * - * suspendReaderLocks and retreiveReaderLocks is the one - * that's likeliest to be a pain. + * suspendReaderLocks and retreiveReaderLocks is the one that's likeliest to be + * a pain. * - * Revision 1.1 2002/06/25 07:52:57 cgruber - * Add quite a few abstract classes, interfaces, and classes. All API consistent with WebObjects, but with no implementation, nor any private or package access members from the original. + * Revision 1.1 2002/06/25 07:52:57 cgruber Add quite a few abstract classes, + * interfaces, and classes. All API consistent with WebObjects, but with no + * implementation, nor any private or package access members from the original. * */ diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableArray.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableArray.java index f705000..c75de01 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableArray.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableArray.java @@ -24,406 +24,345 @@ import java.util.List; import java.util.ListIterator; /** -* NSMutableArray extends NSArray to allow modification. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public class NSMutableArray extends NSArray -{ - /** - * Returns an NSArray backed by the specified List. - * This is useful to "protect" an internal representation - * that is returned by a method of return type NSArray. - */ - public static NSMutableArray mutableArrayBackedByList( List aList ) - { - return new NSMutableArray( aList, null ); - } - - NSMutableArray( List aList, Object ignored ) // differentiates - { - super( aList, ignored ); - } - + * NSMutableArray extends NSArray to allow modification. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public class NSMutableArray extends NSArray { + /** + * Returns an NSArray backed by the specified List. This is useful to "protect" + * an internal representation that is returned by a method of return type + * NSArray. + */ + public static NSMutableArray mutableArrayBackedByList(List aList) { + return new NSMutableArray(aList, null); + } + + NSMutableArray(List aList, Object ignored) // differentiates + { + super(aList, ignored); + } + /** - * Default constructor returns an empty array. - */ - public NSMutableArray () - { - super(); + * Default constructor returns an empty array. + */ + public NSMutableArray() { + super(); //System.out.println( "NSMutableArray: " + net.wotonomy.ui.swing.util.StackTraceInspector.getMyCaller() ); - } + } /** - * Constructor with a size hint. - */ - public NSMutableArray ( int aSize ) - { - super(); + * Constructor with a size hint. + */ + public NSMutableArray(int aSize) { + super(); //System.out.println( "NSMutableArray: " + net.wotonomy.ui.swing.util.StackTraceInspector.getMyCaller() ); - } + } /** - * Produces an array containing only the specified object. - */ - public NSMutableArray (Object anObject) - { - super( anObject ); + * Produces an array containing only the specified object. + */ + public NSMutableArray(Object anObject) { + super(anObject); //System.out.println( "NSMutableArray: " + net.wotonomy.ui.swing.util.StackTraceInspector.getMyCaller() ); - } + } /** - * Produces an array containing the specified objects. - */ - public NSMutableArray (Object[] anArray) - { - super( anArray ); + * Produces an array containing the specified objects. + */ + public NSMutableArray(Object[] anArray) { + super(anArray); //System.out.println( "NSMutableArray: " + net.wotonomy.ui.swing.util.StackTraceInspector.getMyCaller() ); - } + } /** - * Produces an array containing the objects in the specified collection. - */ - public NSMutableArray (Collection aCollection) - { - super( aCollection ); + * Produces an array containing the objects in the specified collection. + */ + public NSMutableArray(Collection aCollection) { + super(aCollection); //System.out.println( "NSMutableArray: " + net.wotonomy.ui.swing.util.StackTraceInspector.getMyCaller() ); - } + } /** - * Removes the last object from the array. - */ - public void removeLastObject () - { - list.remove( count() - 1 ); - } + * Removes the last object from the array. + */ + public void removeLastObject() { + list.remove(count() - 1); + } /** - * Removes the object at the specified index. - */ - public void removeObjectAtIndex (int index) - { - list.remove( index ); - } + * Removes the object at the specified index. + */ + public void removeObjectAtIndex(int index) { + list.remove(index); + } /** - * Adds all objects in the specified collection. - */ - public void addObjectsFromArray (Collection aCollection) - { - list.addAll( aCollection ); - } + * Adds all objects in the specified collection. + */ + public void addObjectsFromArray(Collection aCollection) { + list.addAll(aCollection); + } /** - * Removes all objects from the array. - */ - public void removeAllObjects () - { - list.clear(); - } + * Removes all objects from the array. + */ + public void removeAllObjects() { + list.clear(); + } /** - * Removes all objects equivalent to the specified object - * within the range of specified indices. - */ - public void removeObject (Object anObject, NSRange aRange) - { - if ( ( anObject == null ) || ( aRange == null ) ) return; - - int loc = aRange.location(); - int max = aRange.maxRange(); - for ( int i = loc; i < max; i++ ) - { - if ( anObject.equals( list.get( i ) ) ) - { - list.remove( i ); - i = i - 1; - max = max - 1; - } - } - } + * Removes all objects equivalent to the specified object within the range of + * specified indices. + */ + public void removeObject(Object anObject, NSRange aRange) { + if ((anObject == null) || (aRange == null)) + return; + + int loc = aRange.location(); + int max = aRange.maxRange(); + for (int i = loc; i < max; i++) { + if (anObject.equals(list.get(i))) { + list.remove(i); + i = i - 1; + max = max - 1; + } + } + } /** - * Removes all instances of the specified object within the - * range of specified indices, comparing by reference. - */ - public void removeIdenticalObject (Object anObject, NSRange aRange) - { - if ( ( anObject == null ) || ( aRange == null ) ) return; - - int loc = aRange.location(); - int max = aRange.maxRange(); - for ( int i = loc; i < max; i++ ) - { - if ( anObject == list.get( i ) ) - { - list.remove( i ); - i = i - 1; - max = max - 1; - } - } - } + * Removes all instances of the specified object within the range of specified + * indices, comparing by reference. + */ + public void removeIdenticalObject(Object anObject, NSRange aRange) { + if ((anObject == null) || (aRange == null)) + return; + + int loc = aRange.location(); + int max = aRange.maxRange(); + for (int i = loc; i < max; i++) { + if (anObject == list.get(i)) { + list.remove(i); + i = i - 1; + max = max - 1; + } + } + } /** - * Removes all objects in the specified collection from the array. - */ - public void removeObjectsInArray (Collection aCollection) - { - list.removeAll( aCollection ); - } + * Removes all objects in the specified collection from the array. + */ + public void removeObjectsInArray(Collection aCollection) { + list.removeAll(aCollection); + } /** - * Removes all objects in the indices within the specified range - * from the array. - */ - public void removeObjectsInRange (NSRange aRange) - { - if ( aRange == null ) return; - - for ( int i = 0; i < aRange.length(); i++ ) - { - list.remove( aRange.location() ); - } - } + * Removes all objects in the indices within the specified range from the array. + */ + public void removeObjectsInRange(NSRange aRange) { + if (aRange == null) + return; + + for (int i = 0; i < aRange.length(); i++) { + list.remove(aRange.location()); + } + } /** - * Replaces objects in the current range with objects from - * the specified range of the specified array. If currentRange - * is larger than otherRange, the extra objects are removed. - * If otherRange is larger than currentRange, the extra objects - * are added. - */ - public void replaceObjectsInRange (NSRange currentRange, - List otherArray, NSRange otherRange) - { - if ( ( currentRange == null ) || ( otherArray == null ) || - ( otherRange == null ) ) return; - + * Replaces objects in the current range with objects from the specified range + * of the specified array. If currentRange is larger than otherRange, the extra + * objects are removed. If otherRange is larger than currentRange, the extra + * objects are added. + */ + public void replaceObjectsInRange(NSRange currentRange, List otherArray, NSRange otherRange) { + if ((currentRange == null) || (otherArray == null) || (otherRange == null)) + return; + // transform otherRange if out of bounds for array - if ( otherRange.maxRange() > otherArray.size() ) - { + if (otherRange.maxRange() > otherArray.size()) { // TODO: Test this logic. - int loc = Math.min( otherRange.location(), otherArray.size() - 1 ); - otherRange = new NSRange( loc, otherArray.size() - loc ); + int loc = Math.min(otherRange.location(), otherArray.size() - 1); + otherRange = new NSRange(loc, otherArray.size() - loc); } - + Object o; - List subList = list.subList( - currentRange.location(), currentRange.maxRange() ); + List subList = list.subList(currentRange.location(), currentRange.maxRange()); int otherIndex = otherRange.location(); // TODO: Test this logic. - for ( int i = 0; i < subList.size(); i++ ) - { - if ( otherIndex < otherRange.maxRange() ) - { // set object - subList.set( i, otherArray.get( otherIndex ) ); - } - else - { // remove extra elements from currentRange - subList.remove( i ); - i--; + for (int i = 0; i < subList.size(); i++) { + if (otherIndex < otherRange.maxRange()) { // set object + subList.set(i, otherArray.get(otherIndex)); + } else { // remove extra elements from currentRange + subList.remove(i); + i--; } otherIndex++; } // TODO: Test this logic. - for ( int i = otherIndex; i < otherRange.maxRange(); i++ ) - { - list.add( otherArray.get( i ) ); + for (int i = otherIndex; i < otherRange.maxRange(); i++) { + list.add(otherArray.get(i)); } } /** - * Clears the current array and then populates it with the - * contents of the specified collection. - */ - public void setArray (Collection aCollection) - { - list.clear(); - list.addAll( aCollection ); - } + * Clears the current array and then populates it with the contents of the + * specified collection. + */ + public void setArray(Collection aCollection) { + list.clear(); + list.addAll(aCollection); + } /** - * Sorts this array using the values from the specified selector. - */ - public void sortUsingSelector (NSSelector aSelector) - { - //TODO: implement - throw new UnsupportedOperationException( "Not implemented yet." ); - } + * Sorts this array using the values from the specified selector. + */ + public void sortUsingSelector(NSSelector aSelector) { + // TODO: implement + throw new UnsupportedOperationException("Not implemented yet."); + } /** - * Removes all objects equivalent to the specified object. - */ - public void removeObject (Object anObject) - { - list.remove( anObject ); - } + * Removes all objects equivalent to the specified object. + */ + public void removeObject(Object anObject) { + list.remove(anObject); + } /** - * Removes all occurences of the specified object, - * comparing by reference. - */ - public void removeIdenticalObject (Object anObject) - { - Iterator it = list.iterator(); - while ( it.hasNext() ) - { - if ( it.next() == anObject ) - { - it.remove(); - } - } - } + * Removes all occurences of the specified object, comparing by reference. + */ + public void removeIdenticalObject(Object anObject) { + Iterator it = list.iterator(); + while (it.hasNext()) { + if (it.next() == anObject) { + it.remove(); + } + } + } /** - * Inserts the specified object into this array at the - * specified index. - */ - public void insertObjectAtIndex (Object anObject, int anIndex) - { - list.add( anIndex, anObject ); - } - + * Inserts the specified object into this array at the specified index. + */ + public void insertObjectAtIndex(Object anObject, int anIndex) { + list.add(anIndex, anObject); + } + /** - * Replaces the object at the specified index with the - * specified object. - */ - public void replaceObjectAtIndex (int anIndex, Object anObject) - { - list.set( anIndex, anObject ); - } + * Replaces the object at the specified index with the specified object. + */ + public void replaceObjectAtIndex(int anIndex, Object anObject) { + list.set(anIndex, anObject); + } /** - * Adds the specified object to the end of this array. - */ - public void addObject (Object anObject) - { - list.add( anObject ); - } - - public Object clone() - { - return new NSMutableArray( list ); - } - - public NSArray immutableClone() { - return new NSArray(this); - } - - public NSMutableArray mutableClone() { - return new NSMutableArray(this); - } - - // interface List: mutators - - public void add(int index, Object element) - { - list.add( index, element ); - } - - public boolean add(Object o) - { - return list.add(o); - } - - public boolean addAll(Collection coll) - { - return list.addAll(coll); - } - - public boolean addAll(int index, Collection c) - { - return list.addAll( index, c ); - } - - public void clear() - { - list.clear(); - } - - public Iterator iterator() - { - return list.iterator(); - } - - public ListIterator listIterator() - { - return list.listIterator(); - } - - public ListIterator listIterator(int index) - { - return list.listIterator(); - } - - public Object remove(int index) - { - return list.remove( index ); - } - - public boolean remove(Object o) - { - return list.remove(o); - } - - public boolean removeAll(Collection coll) - { - return list.removeAll(coll); - } - - public boolean retainAll(Collection coll) - { - return list.retainAll(coll); - } - - public Object set(int index, Object element) - { - return list.set( index, element ); - } - - public List subList(int fromIndex, int toIndex) - { - return list.subList( fromIndex, toIndex ); - } - + * Adds the specified object to the end of this array. + */ + public void addObject(Object anObject) { + list.add(anObject); + } + + public Object clone() { + return new NSMutableArray(list); + } + + public NSArray immutableClone() { + return new NSArray(this); + } + + public NSMutableArray mutableClone() { + return new NSMutableArray(this); + } + + // interface List: mutators + + public void add(int index, Object element) { + list.add(index, element); + } + + public boolean add(Object o) { + return list.add(o); + } + + public boolean addAll(Collection coll) { + return list.addAll(coll); + } + + public boolean addAll(int index, Collection c) { + return list.addAll(index, c); + } + + public void clear() { + list.clear(); + } + + public Iterator iterator() { + return list.iterator(); + } + + public ListIterator listIterator() { + return list.listIterator(); + } + + public ListIterator listIterator(int index) { + return list.listIterator(); + } + + public Object remove(int index) { + return list.remove(index); + } + + public boolean remove(Object o) { + return list.remove(o); + } + + public boolean removeAll(Collection coll) { + return list.removeAll(coll); + } + + public boolean retainAll(Collection coll) { + return list.retainAll(coll); + } + + public Object set(int index, Object element) { + return list.set(index, element); + } + + public List subList(int fromIndex, int toIndex) { + return list.subList(fromIndex, toIndex); + } + } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.8 2005/07/13 14:12:44 cgruber - * Add mutableClone() and immutableClone() per. WebObjects 5.3 conformance. + * Revision 1.8 2005/07/13 14:12:44 cgruber Add mutableClone() and + * immutableClone() per. WebObjects 5.3 conformance. * - * Revision 1.7 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.7 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.6 2003/01/16 22:47:30 mpowers - * Compatibility changes to support compiling woextensions source. - * (34 out of 56 classes compile!) + * Revision 1.6 2003/01/16 22:47:30 mpowers Compatibility changes to support + * compiling woextensions source. (34 out of 56 classes compile!) * - * Revision 1.5 2003/01/10 19:16:40 mpowers - * Implemented support for page caching. + * Revision 1.5 2003/01/10 19:16:40 mpowers Implemented support for page + * caching. * - * Revision 1.4 2002/10/24 21:15:36 mpowers - * New implementations of NSArray and subclasses. + * Revision 1.4 2002/10/24 21:15:36 mpowers New implementations of NSArray and + * subclasses. * - * Revision 1.3 2002/10/24 18:16:30 mpowers - * Now enforcing NSArray's immutable nature. + * Revision 1.3 2002/10/24 18:16:30 mpowers Now enforcing NSArray's immutable + * nature. * - * Revision 1.2 2001/01/11 20:34:26 mpowers - * Implemented EOSortOrdering and added support in framework. - * Added header-click to sort table columns. + * Revision 1.2 2001/01/11 20:34:26 mpowers Implemented EOSortOrdering and added + * support in framework. Added header-click to sort table columns. * - * Revision 1.1.1.1 2000/12/21 15:47:31 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:47:31 mpowers Contributing wotonomy. * - * Revision 1.3 2000/12/20 16:25:38 michael - * Added log to all files. + * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableData.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableData.java index c677ea7..c24e04d 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableData.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableData.java @@ -19,95 +19,82 @@ License along with this library; if not, see http://www.gnu.org package net.wotonomy.foundation; /** -* A pure java implementation of NSMutableData, which -* is basically an editable wrapper for a byte array. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 892 $ -*/ -public class NSMutableData - extends NSData -{ - /** - * Default constructor creates a zero-data object. - */ - public NSMutableData () - { - super(); - } - - /** - * Creates an object containing the contents of the specified URL. - */ - public NSMutableData (java.net.URL aURL) - { - super( aURL ); - } - - /** - * Creates an object containing a copy of the contents of the - * specified NSData object. - */ - public NSMutableData (NSData aData) - { - super( aData ); - } - - /** - * Creates an object containing the specified number of bytes - * initialized to all zeroes. - */ - public NSMutableData (int size) - { - super( new byte[size] ); // inits to zeroes - } + * A pure java implementation of NSMutableData, which is basically an editable + * wrapper for a byte array. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 892 $ + */ +public class NSMutableData extends NSData { + /** + * Default constructor creates a zero-data object. + */ + public NSMutableData() { + super(); + } + /** + * Creates an object containing the contents of the specified URL. + */ + public NSMutableData(java.net.URL aURL) { + super(aURL); + } /** - * Sets the length of the data to the specified length. - * If shorter, the data is truncated. If longer, the extra - * bytes are initialized to zeroes. - */ - public void setLength (int length) - { - byte[] data = new byte[ length ]; // inits to zeroes - int limit = length; - if (limit > bytes.length) - limit = bytes.length; - for ( int i = 0; i < limit; i++ ) - { - data[i] = this.bytes[ i ]; - } - this.bytes = data; - } + * Creates an object containing a copy of the contents of the specified NSData + * object. + */ + public NSMutableData(NSData aData) { + super(aData); + } /** - * Appends the specified data to the end of this data. - */ - public void appendData (NSData aData) - { - int len = aData.length(); - byte[] data = new byte[ bytes.length + len ]; - - int i; - for ( i = 0; i < bytes.length; i++ ) - { - data[i] = bytes[i]; - } - - byte[] src = aData.bytes( 0, len ); - for ( int j = 0; j < len; j++ ) - { - data[i+j] = src[j]; - } - - bytes = data; - } + * Creates an object containing the specified number of bytes initialized to all + * zeroes. + */ + public NSMutableData(int size) { + super(new byte[size]); // inits to zeroes + } + + /** + * Sets the length of the data to the specified length. If shorter, the data is + * truncated. If longer, the extra bytes are initialized to zeroes. + */ + public void setLength(int length) { + byte[] data = new byte[length]; // inits to zeroes + int limit = length; + if (limit > bytes.length) + limit = bytes.length; + for (int i = 0; i < limit; i++) { + data[i] = this.bytes[i]; + } + this.bytes = data; + } + + /** + * Appends the specified data to the end of this data. + */ + public void appendData(NSData aData) { + int len = aData.length(); + byte[] data = new byte[bytes.length + len]; + + int i; + for (i = 0; i < bytes.length; i++) { + data[i] = bytes[i]; + } + + byte[] src = aData.bytes(0, len); + for (int j = 0; j < len; j++) { + data[i + j] = src[j]; + } + + bytes = data; + } public void appendByte(byte b) { setLength(bytes.length + 1); - bytes[bytes.length-1] = b; + bytes[bytes.length - 1] = b; } public void appendBytes(byte[] b) { @@ -118,50 +105,41 @@ public class NSMutableData } /** - * Increases the size of the byte array by the specified amount. - */ - public void increaseLengthBy (int increment) - { - setLength( length() + increment ); - } + * Increases the size of the byte array by the specified amount. + */ + public void increaseLengthBy(int increment) { + setLength(length() + increment); + } /** - * Sets the bytes in the array within the specified range to zero. - */ - public void resetBytesInRange (NSRange aRange) - { - int loc = aRange.location(); - int max = aRange.maxRange(); - for ( int i = loc; i < max; i++ ) - { - bytes[i] = 0; - } - } + * Sets the bytes in the array within the specified range to zero. + */ + public void resetBytesInRange(NSRange aRange) { + int loc = aRange.location(); + int max = aRange.maxRange(); + for (int i = loc; i < max; i++) { + bytes[i] = 0; + } + } /** - * Copies the data in the specified object to this object, - * completely replacing the previous contents. - */ - public void setData (NSData aData) - { - bytes = aData.bytes( 0, aData.length() ); - } + * Copies the data in the specified object to this object, completely replacing + * the previous contents. + */ + public void setData(NSData aData) { + bytes = aData.bytes(0, aData.length()); + } } /* - * $Log$ - * Revision 1.1 2006/02/16 12:47:16 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.2 2003/08/06 23:57:13 chochos - * appendByte(), appendBytes() + * Revision 1.2 2003/08/06 23:57:13 chochos appendByte(), appendBytes() * - * Revision 1.1.1.1 2000/12/21 15:47:34 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:47:34 mpowers Contributing wotonomy. * - * Revision 1.3 2000/12/20 16:25:38 michael - * Added log to all files. + * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableDictionary.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableDictionary.java index 0b291a7..ba58189 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableDictionary.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableDictionary.java @@ -22,145 +22,122 @@ import java.util.Enumeration; import java.util.Map; /** -* A pure java implementation of NSMutableDictionary that -* implements Map for greater java interoperability. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public class NSMutableDictionary - extends NSDictionary -{ - /** - * Default constructor produces an empty dictionary. - */ - public NSMutableDictionary () - { - super(); - } - - /** - * Default constructor produces an empty dictionary. - */ - public NSMutableDictionary (int initialSize) - { - super(initialSize); - } - - /** - * Produces a dictionary that contains one key referencing one value. - */ - public NSMutableDictionary (Object key, Object value) - { - super( key, value ); - } - - /** - * Produces a dictionary containing the specified keys and values. - * An IllegalArgumentException is thrown if the arrays are not - * of the same length. - */ - public NSMutableDictionary (Object[] keys, Object[] values) - { - super( keys, values ); + * A pure java implementation of NSMutableDictionary that implements Map for + * greater java interoperability. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public class NSMutableDictionary extends NSDictionary { + /** + * Default constructor produces an empty dictionary. + */ + public NSMutableDictionary() { + super(); + } + + /** + * Default constructor produces an empty dictionary. + */ + public NSMutableDictionary(int initialSize) { + super(initialSize); + } + + /** + * Produces a dictionary that contains one key referencing one value. + */ + public NSMutableDictionary(Object key, Object value) { + super(key, value); + } + + /** + * Produces a dictionary containing the specified keys and values. An + * IllegalArgumentException is thrown if the arrays are not of the same length. + */ + public NSMutableDictionary(Object[] keys, Object[] values) { + super(keys, values); } - /** - * Produces a dictionary that is a copy of the specified map (or dictionary). - */ - public NSMutableDictionary (Map aMap) - { - super( aMap ); - } - - /** - * Removes the key-value pair for the specified key. - */ - public void removeObjectForKey (Object aKey) - { - remove( aKey ); - } - - /** - * Copies all mappings from the specified dictionary to this dictionary, - * replacing any mappings this map had for any keys in the specified map. - */ - public void addEntriesFromDictionary (Map aMap) - { - putAll( aMap ); - } - - /** - * Removes all mappings from this dictionary. - */ - public void removeAllObjects () - { - clear(); - } - - /** - * Removes all keys in the specified array from this dictionary. - */ - public void removeObjectsForKeys (NSArray anArray) - { - Enumeration enumeration = anArray.objectEnumerator(); - while ( enumeration.hasMoreElements() ) - { - removeObjectForKey( enumeration.nextElement() ); - } - } - - /** - * Clears all mappings in this dictionary and then adds all entries - * in the specified dictionary. - */ - public void setDictionary (Map aMap) - { - removeAllObjects(); - addEntriesFromDictionary( aMap ); - } - - /** - * Sets the value for the specified key. If the key currently - * exists to the dictionary, the old value is replaced with the - * specified value. An IllegalArgumentException is thrown if - * either the key or value is null. - */ - public void setObjectForKey (Object aValue, Object aKey) - { - if ( ( aKey == null ) || ( aValue == null ) ) - { - throw new IllegalArgumentException( - "Cannot use null objects with an NSMutableDictionary." ); - } - put( aKey, aValue ); - } + /** + * Produces a dictionary that is a copy of the specified map (or dictionary). + */ + public NSMutableDictionary(Map aMap) { + super(aMap); + } + + /** + * Removes the key-value pair for the specified key. + */ + public void removeObjectForKey(Object aKey) { + remove(aKey); + } + + /** + * Copies all mappings from the specified dictionary to this dictionary, + * replacing any mappings this map had for any keys in the specified map. + */ + public void addEntriesFromDictionary(Map aMap) { + putAll(aMap); + } + + /** + * Removes all mappings from this dictionary. + */ + public void removeAllObjects() { + clear(); + } + + /** + * Removes all keys in the specified array from this dictionary. + */ + public void removeObjectsForKeys(NSArray anArray) { + Enumeration enumeration = anArray.objectEnumerator(); + while (enumeration.hasMoreElements()) { + removeObjectForKey(enumeration.nextElement()); + } + } + + /** + * Clears all mappings in this dictionary and then adds all entries in the + * specified dictionary. + */ + public void setDictionary(Map aMap) { + removeAllObjects(); + addEntriesFromDictionary(aMap); + } + + /** + * Sets the value for the specified key. If the key currently exists to the + * dictionary, the old value is replaced with the specified value. An + * IllegalArgumentException is thrown if either the key or value is null. + */ + public void setObjectForKey(Object aValue, Object aKey) { + if ((aKey == null) || (aValue == null)) { + throw new IllegalArgumentException("Cannot use null objects with an NSMutableDictionary."); + } + put(aKey, aValue); + } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.4 2005/05/11 15:21:53 cgruber - * Change enum to enumeration, since enum is now a keyword as of Java 5.0 + * Revision 1.4 2005/05/11 15:21:53 cgruber Change enum to enumeration, since + * enum is now a keyword as of Java 5.0 * * A few other comments in the code. * - * Revision 1.3 2002/06/30 17:16:26 mpowers - * Added new constructor taking an int: thanks cgruber. + * Revision 1.3 2002/06/30 17:16:26 mpowers Added new constructor taking an int: + * thanks cgruber. * * - * Revision 1.2 2001/02/23 23:43:41 mpowers - * Removed ill-advised this. + * Revision 1.2 2001/02/23 23:43:41 mpowers Removed ill-advised this. * - * Revision 1.1.1.1 2000/12/21 15:47:34 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:47:34 mpowers Contributing wotonomy. * - * Revision 1.3 2000/12/20 16:25:38 michael - * Added log to all files. + * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableRange.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableRange.java index a0bcda1..2bfb692 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableRange.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSMutableRange.java @@ -19,98 +19,84 @@ License along with this library; if not, see http://www.gnu.org package net.wotonomy.foundation; /** -* A pure java implementation of NSMutableRange. -* An NSMutableRange is a modifiable NSRange. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public class NSMutableRange extends NSRange -{ - /** - * Default constructor produces an empty range. - */ - public NSMutableRange () - { - super(); - } + * A pure java implementation of NSMutableRange. An NSMutableRange is a + * modifiable NSRange. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public class NSMutableRange extends NSRange { + /** + * Default constructor produces an empty range. + */ + public NSMutableRange() { + super(); + } - /** - * Produces a range that has the same location and length as - * the specified range. - */ - public NSMutableRange (NSRange aRange) - { - super( aRange ); - } + /** + * Produces a range that has the same location and length as the specified + * range. + */ + public NSMutableRange(NSRange aRange) { + super(aRange); + } - /** - * Produces a range with the specified location and length. - */ - public NSMutableRange (int location, int length) - { - super( location, length ); - } + /** + * Produces a range with the specified location and length. + */ + public NSMutableRange(int location, int length) { + super(location, length); + } - /** - * Sets the location of this range. - */ - public void setLocation (int location) - { - loc = location; - } + /** + * Sets the location of this range. + */ + public void setLocation(int location) { + loc = location; + } - /** - * Sets the length of this range. - */ - public void setLength (int length) - { - len = length; - } - - /** - * Modifies this range to be the union of this - * range and the specified range. - */ - public void unionRange (NSRange aRange) - { - NSRange range = rangeByUnioningRange( aRange ); - setLocation( range.location() ); - setLength( range.length() ); - } + /** + * Sets the length of this range. + */ + public void setLength(int length) { + len = length; + } - /** - * Modifies this range to be the intersection of this - * range and the specified range. - */ - public void intersectRange (NSRange aRange) - { - NSRange range = rangeByIntersectingRange( aRange ); - setLocation( range.location() ); - setLength( range.length() ); - } + /** + * Modifies this range to be the union of this range and the specified range. + */ + public void unionRange(NSRange aRange) { + NSRange range = rangeByUnioningRange(aRange); + setLocation(range.location()); + setLength(range.length()); + } - /** - * Returns a copy of this range. - */ - public Object clone () - { - return new NSMutableRange( location(), length() ); - } + /** + * Modifies this range to be the intersection of this range and the specified + * range. + */ + public void intersectRange(NSRange aRange) { + NSRange range = rangeByIntersectingRange(aRange); + setLocation(range.location()); + setLength(range.length()); + } + + /** + * Returns a copy of this range. + */ + public Object clone() { + return new NSMutableRange(location(), length()); + } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.1.1.1 2000/12/21 15:47:36 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:47:36 mpowers Contributing wotonomy. * - * Revision 1.3 2000/12/20 16:25:38 michael - * Added log to all files. + * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotification.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotification.java index f288d3f..6b091e2 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotification.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotification.java @@ -21,144 +21,125 @@ package net.wotonomy.foundation; import java.util.Map; /** -* An NSNotification is a generic message that can be -* dispatched by the NSNotificationCenter. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public class NSNotification -{ - public static boolean showStack = false; - - protected String name; - protected Object object; - protected Map userInfo; - - // for debugging only - private Throwable stackTrace; - - /** - * Default constructor creates a new notification - * with no name, object, or info dictionary. - */ - public NSNotification () - { - this( null, null, null ); - } - - /** - * Constructor specifying name and object. - */ - public NSNotification ( String aName, Object anObject ) - { - this( aName, anObject, null ); - } - - /** - * Constructor specifying name, object, and a Map - * containing application specific information. - */ - public NSNotification ( - String aName, Object anObject, Map aUserInfo ) - { - name = aName; - object = anObject; - if ( showStack ) stackTrace = new RuntimeException(); - userInfo = aUserInfo; - } - - /** - * Returns the name of this notification. - */ - public String name () - { - return name; - } - - /** - * Returns the object of this notification. - */ - public Object object () - { - return object; - } - - /** - * Returns an NSDictionary that is a copy of - * the map containing application specific - * information relating to this notification, - * or null if no such data exists. - */ - public NSDictionary userInfo () - { - if ( userInfo == null ) return null; - return new NSDictionary( userInfo ); - } - - /** - * Returns a Map containing application specific - * information relating to this notification, - * or null if no such data exists. - * Note: this method is not in the spec. - */ - public Map userInfoMap () - { - return userInfo; - } - - /** - * Returns the stack trace when this notification was generated, - * or null if showStack is false, which is the default. - * NOTE: This method is not part of the specification. - */ - public Throwable stackTrace() - { - return stackTrace; - } - - /** - * Returns a human-readable string representation. - */ - public String toString() - { - return "[ " + name() + " : " + object() + " : " + userInfo() + " ]"; - } + * An NSNotification is a generic message that can be dispatched by the + * NSNotificationCenter. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public class NSNotification { + public static boolean showStack = false; + + protected String name; + protected Object object; + protected Map userInfo; + + // for debugging only + private Throwable stackTrace; + + /** + * Default constructor creates a new notification with no name, object, or info + * dictionary. + */ + public NSNotification() { + this(null, null, null); + } + + /** + * Constructor specifying name and object. + */ + public NSNotification(String aName, Object anObject) { + this(aName, anObject, null); + } + + /** + * Constructor specifying name, object, and a Map containing application + * specific information. + */ + public NSNotification(String aName, Object anObject, Map aUserInfo) { + name = aName; + object = anObject; + if (showStack) + stackTrace = new RuntimeException(); + userInfo = aUserInfo; + } + + /** + * Returns the name of this notification. + */ + public String name() { + return name; + } + + /** + * Returns the object of this notification. + */ + public Object object() { + return object; + } + + /** + * Returns an NSDictionary that is a copy of the map containing application + * specific information relating to this notification, or null if no such data + * exists. + */ + public NSDictionary userInfo() { + if (userInfo == null) + return null; + return new NSDictionary(userInfo); + } + + /** + * Returns a Map containing application specific information relating to this + * notification, or null if no such data exists. Note: this method is not in the + * spec. + */ + public Map userInfoMap() { + return userInfo; + } + + /** + * Returns the stack trace when this notification was generated, or null if + * showStack is false, which is the default. NOTE: This method is not part of + * the specification. + */ + public Throwable stackTrace() { + return stackTrace; + } + + /** + * Returns a human-readable string representation. + */ + public String toString() { + return "[ " + name() + " : " + object() + " : " + userInfo() + " ]"; + } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.7 2002/10/24 18:16:04 mpowers - * No longer generating stack trace by default. + * Revision 1.7 2002/10/24 18:16:04 mpowers No longer generating stack trace by + * default. * - * Revision 1.6 2002/06/21 22:02:47 mpowers - * Oops: Fixed NPE. + * Revision 1.6 2002/06/21 22:02:47 mpowers Oops: Fixed NPE. * - * Revision 1.5 2002/06/21 21:50:41 mpowers - * Added a method to get the map directly from the notification. - * Changed the internal representation to a map not a dictionary. - * We had been creating a new dictionary with each creation. + * Revision 1.5 2002/06/21 21:50:41 mpowers Added a method to get the map + * directly from the notification. Changed the internal representation to a map + * not a dictionary. We had been creating a new dictionary with each creation. * This also allows people to modify the contents of the userInfo. * - * Revision 1.4 2001/04/09 21:41:49 mpowers - * Better debugging. + * Revision 1.4 2001/04/09 21:41:49 mpowers Better debugging. * - * Revision 1.3 2001/02/21 18:31:07 mpowers - * Finished and tested implementation of NSNotificationCenter. + * Revision 1.3 2001/02/21 18:31:07 mpowers Finished and tested implementation + * of NSNotificationCenter. * - * Revision 1.2 2001/02/20 23:57:03 mpowers - * Implemented NSNotificationCenter. + * Revision 1.2 2001/02/20 23:57:03 mpowers Implemented NSNotificationCenter. * - * Revision 1.1.1.1 2000/12/21 15:47:36 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:47:36 mpowers Contributing wotonomy. * - * Revision 1.3 2000/12/20 16:25:38 michael - * Added log to all files. + * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationCenter.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationCenter.java index aaf8261..cf0af53 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationCenter.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationCenter.java @@ -30,642 +30,502 @@ import java.util.Vector; import net.wotonomy.foundation.internal.WotonomyException; /** -* NSNotificationCenter broadcasts NSNotifications to -* registered observers. Observers can register for all -* notifications of a specific type, or all notifications -* about a specific object, or both. Observers specify -* the method that will be called when they are notified. -* A global notification center can be accessed with -* defaultCenter(), but other centers can be created and -* used independently of the default center. <br><br> -* -* This implementation uses weak references for observers -* and observables. The advantage to this approach is -* that you do not need to explicitly unregister observers -* or observables; they will be unregistered when they are -* garbage-collected. Note that you will need to retain -* a reference to any objects you register or they may -* become unregistered if no other object references them. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public class NSNotificationCenter -{ - /** - * Null marker class simplifies equals() logic - * for CompoundKey class below. - */ - public static final Object NullMarker = new Object(); - - private static NSNotificationCenter defaultCenter = null; - - /** - * A Map of (name,object) pairs to a List - * of (observer,selector) pairs. - */ - private Hashtable observers; // thread-safe - - /** - * Default constructor creates a new notification center. - */ - public NSNotificationCenter() - { - observers = new Hashtable(); - } - - /** - * Returns the system default center, creating one - * if it has not yet been created. - */ - static public NSNotificationCenter defaultCenter() - { - if ( defaultCenter == null ) - { - defaultCenter = new NSNotificationCenter(); - } - return defaultCenter; - } - + * NSNotificationCenter broadcasts NSNotifications to registered observers. + * Observers can register for all notifications of a specific type, or all + * notifications about a specific object, or both. Observers specify the method + * that will be called when they are notified. A global notification center can + * be accessed with defaultCenter(), but other centers can be created and used + * independently of the default center. <br> + * <br> + * + * This implementation uses weak references for observers and observables. The + * advantage to this approach is that you do not need to explicitly unregister + * observers or observables; they will be unregistered when they are + * garbage-collected. Note that you will need to retain a reference to any + * objects you register or they may become unregistered if no other object + * references them. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public class NSNotificationCenter { + /** + * Null marker class simplifies equals() logic for CompoundKey class below. + */ + public static final Object NullMarker = new Object(); + + private static NSNotificationCenter defaultCenter = null; + /** - * Addes the specified observer to the notification queue for - * notifications with the specified name or the specified - * object or both. - * @param anObserver The observer that wishes to be notified. - * @param aSelector The selector that will be invoked. - * Must have exactly one argument, to which a notification - * will be passed. - * @param notificationName The name of the notifications for - * which the observer will be notified. If null, will notify - * only based on matching anObject. - * @param anObject The object of the notifications for which - * the observer will be notified. If null, will notify - * only based on matching notificationName. - */ - public void addObserver( - Object anObserver, NSSelector aSelector, - String notificationName, Object anObject ) - { - // remove freed objects - processKeyQueue(); - - Object name = notificationName; - if ( name == null ) - { - name = NullMarker; - } - if ( anObject == null ) - { - anObject = NullMarker; - } - Object key = new CompoundKey( name, anObject ); - Object value = new CompoundValue( anObserver, aSelector ); - List list = (List) observers.get( key ); - if ( list == null ) - { - // create new list with value and put it in map - list = new Vector(); // thread-safe - list.add( value ); - observers.put( new CompoundKey( - name, anObject, keyQueue ), list ); - } - else - { - // add only if not already in list - if ( ! list.contains( value ) ) - { - list.add( value ); - } - } - } - + * A Map of (name,object) pairs to a List of (observer,selector) pairs. + */ + private Hashtable observers; // thread-safe + + /** + * Default constructor creates a new notification center. + */ + public NSNotificationCenter() { + observers = new Hashtable(); + } + + /** + * Returns the system default center, creating one if it has not yet been + * created. + */ + static public NSNotificationCenter defaultCenter() { + if (defaultCenter == null) { + defaultCenter = new NSNotificationCenter(); + } + return defaultCenter; + } + + /** + * Addes the specified observer to the notification queue for notifications with + * the specified name or the specified object or both. + * + * @param anObserver The observer that wishes to be notified. + * @param aSelector The selector that will be invoked. Must have exactly + * one argument, to which a notification will be passed. + * @param notificationName The name of the notifications for which the observer + * will be notified. If null, will notify only based on + * matching anObject. + * @param anObject The object of the notifications for which the + * observer will be notified. If null, will notify only + * based on matching notificationName. + */ + public void addObserver(Object anObserver, NSSelector aSelector, String notificationName, Object anObject) { + // remove freed objects + processKeyQueue(); + + Object name = notificationName; + if (name == null) { + name = NullMarker; + } + if (anObject == null) { + anObject = NullMarker; + } + Object key = new CompoundKey(name, anObject); + Object value = new CompoundValue(anObserver, aSelector); + List list = (List) observers.get(key); + if (list == null) { + // create new list with value and put it in map + list = new Vector(); // thread-safe + list.add(value); + observers.put(new CompoundKey(name, anObject, keyQueue), list); + } else { + // add only if not already in list + if (!list.contains(value)) { + list.add(value); + } + } + } + /** - * Posts the specified notification. Notifies all registered - * observers that match either the notification name or - * the notification object, or both. - * @param aNotification The notification that will be passed - * to the observers selector. - */ - public void postNotification( - NSNotification aNotification ) - { - List mergedList = new LinkedList(); - Object key, observerList; - - Object name = aNotification.name(); - Object object = aNotification.object(); - - if ( name != null ) - { - if ( object != null ) - { // both are specified - observerList = observers.get( new CompoundKey( name, object ) ); - if ( observerList != null ) - { - mergedList.addAll( (List) observerList ); - } - observerList = observers.get( new CompoundKey( name, NullMarker ) ); - if ( observerList != null ) - { - mergedList.addAll( (List) observerList ); - } - observerList = observers.get( new CompoundKey( NullMarker, object ) ); - if ( observerList != null ) - { - mergedList.addAll( (List) observerList ); - } - } - else - { // object is null - observerList = observers.get( new CompoundKey( name, NullMarker ) ); - if ( observerList != null ) - { - mergedList.addAll( (List) observerList ); - } - } - } - else - if ( object != null ) - { // name is null - observerList = observers.get( new CompoundKey( NullMarker, object ) ); - if ( observerList != null ) - { - mergedList.addAll( (List) observerList ); - } - } - - key = new CompoundKey( - NullMarker, NullMarker ); - observerList = observers.get( key ); - if ( observerList != null ) - { - mergedList.addAll( (List) observerList ); - } - - CompoundValue value; - Iterator it = mergedList.iterator(); - while ( it.hasNext() ) - { - value = (CompoundValue) it.next(); - if ( value.get() == null ) - { - it.remove(); - } - else - { - try - { - value.selector().invoke( - value.get(), - new Object[] { aNotification } ); - } - catch ( Exception exc ) - { - WotonomyException w = new WotonomyException( - "Error notifying object: " + value.get() + " : " + aNotification, exc ); + * Posts the specified notification. Notifies all registered observers that + * match either the notification name or the notification object, or both. + * + * @param aNotification The notification that will be passed to the observers + * selector. + */ + public void postNotification(NSNotification aNotification) { + List mergedList = new LinkedList(); + Object key, observerList; + + Object name = aNotification.name(); + Object object = aNotification.object(); + + if (name != null) { + if (object != null) { // both are specified + observerList = observers.get(new CompoundKey(name, object)); + if (observerList != null) { + mergedList.addAll((List) observerList); + } + observerList = observers.get(new CompoundKey(name, NullMarker)); + if (observerList != null) { + mergedList.addAll((List) observerList); + } + observerList = observers.get(new CompoundKey(NullMarker, object)); + if (observerList != null) { + mergedList.addAll((List) observerList); + } + } else { // object is null + observerList = observers.get(new CompoundKey(name, NullMarker)); + if (observerList != null) { + mergedList.addAll((List) observerList); + } + } + } else if (object != null) { // name is null + observerList = observers.get(new CompoundKey(NullMarker, object)); + if (observerList != null) { + mergedList.addAll((List) observerList); + } + } + + key = new CompoundKey(NullMarker, NullMarker); + observerList = observers.get(key); + if (observerList != null) { + mergedList.addAll((List) observerList); + } + + CompoundValue value; + Iterator it = mergedList.iterator(); + while (it.hasNext()) { + value = (CompoundValue) it.next(); + if (value.get() == null) { + it.remove(); + } else { + try { + value.selector().invoke(value.get(), new Object[] { aNotification }); + } catch (Exception exc) { + WotonomyException w = new WotonomyException( + "Error notifying object: " + value.get() + " : " + aNotification, exc); // throw w; - w.printStackTrace(); -postNotification( "Error notifying object", this, new NSDictionary( "exception", w ) ); - } - } - } - - } - + w.printStackTrace(); + postNotification("Error notifying object", this, new NSDictionary("exception", w)); + } + } + } + + } + /** - * Posts a notification created from the specified name - * and object. Calls postNotification( NSNotification ). - * @param notificationName a String key to distinguish - * this notification. - * @param anObject any object, by convention this is - * the originator of the notification. - */ - public void postNotification( - String notificationName, Object anObject ) - { - postNotification( new NSNotification( - notificationName, anObject ) ); - } - + * Posts a notification created from the specified name and object. Calls + * postNotification( NSNotification ). + * + * @param notificationName a String key to distinguish this notification. + * @param anObject any object, by convention this is the originator of + * the notification. + */ + public void postNotification(String notificationName, Object anObject) { + postNotification(new NSNotification(notificationName, anObject)); + } + /** - * Posts a notification created from the specified name, - * object, and info. Calls postNotification( NSNotification ). - * @param notificationName a String key to distinguish - * this notification. - * @param anObject any object, by convention this is - * the originator of the notification. - * @param userInfo a Map containing information specific - * to the originator of the notification and that may - * be of interest to a knowledgable observer. - */ - public void postNotification( - String notificationName, Object anObject, Map userInfo ) - { - postNotification( new NSNotification( - notificationName, anObject, userInfo ) ); - } - + * Posts a notification created from the specified name, object, and info. Calls + * postNotification( NSNotification ). + * + * @param notificationName a String key to distinguish this notification. + * @param anObject any object, by convention this is the originator of + * the notification. + * @param userInfo a Map containing information specific to the + * originator of the notification and that may be of + * interest to a knowledgable observer. + */ + public void postNotification(String notificationName, Object anObject, Map userInfo) { + postNotification(new NSNotification(notificationName, anObject, userInfo)); + } + /** - * Unregisters the specified observer from all notification - * queues for which it is registered. - * @param anObserver The observer to be unregistered. - */ - public void removeObserver( - Object anObserver ) - { - // remove freed objects - processKeyQueue(); - - Iterator it = new LinkedList( observers.keySet() ).iterator(); - while ( it.hasNext() ) - { - removeObserver( anObserver, it.next() ); - } - } - + * Unregisters the specified observer from all notification queues for which it + * is registered. + * + * @param anObserver The observer to be unregistered. + */ + public void removeObserver(Object anObserver) { + // remove freed objects + processKeyQueue(); + + Iterator it = new LinkedList(observers.keySet()).iterator(); + while (it.hasNext()) { + removeObserver(anObserver, it.next()); + } + } + /** - * Unregisters the specified observer from all notifications - * queues associated with the specified name or object or both. - * @param anObserver The observer to be unregistered, if null - * will unregister all observers for the specified notification - * name and object. - * @param notificationName The name of the notification for which - * the observer will be unregistered, if null will unregister - * the specified observer for all notifications with the - * specified object. - * @param anObject The object for the notification for which - * the observer will be unregistered, if null will unregister - * the specified observer for all objects with the specified - * notification. - */ - public void removeObserver( - Object anObserver, String notificationName, Object anObject ) - { - // remove freed objects - processKeyQueue(); - - // get key matches - List keys = matchingKeys( notificationName, anObject ); - - // remove specified observer from each matching key - Iterator it = keys.iterator(); - while ( it.hasNext() ) - { - removeObserver( anObserver, it.next() ); - } - } - - /** - * Returns all keys that match the specified name and object, - * but in this case null parameters are considered wildcards. - * Pass NullMarkers if you want to explicitly match nulls. - */ - private List matchingKeys( String name, Object object ) - { - List result = new LinkedList(); - - boolean willAdd; - CompoundKey key; - Iterator it = observers.keySet().iterator(); - while ( it.hasNext() ) - { - key = (CompoundKey) it.next(); - willAdd = false; - if ( ( name == null ) || ( name == key.name() ) ) - { - if ( ( object == null ) || ( object == key.get() ) ) - { - willAdd = true; - } - } - if ( willAdd ) - { - result.add( key ); - } - } - return result; - } - - /** - * Removes the specified observer from the list referenced - * by the specified key in the observer map. - */ - private void removeObserver( - Object anObserver, Object key ) - { - // if observer null, remove all observers for key - if ( anObserver == null ) - { - observers.remove( key ); - return; - } - - List list = (List) observers.get( key ); - if ( list == null ) return; - - // remove specified observer from list - Object observer; - Iterator it = list.iterator(); - while ( it.hasNext() ) - { - observer = ((CompoundValue)it.next()).get(); - if ( ( observer == null ) || ( anObserver == observer ) ) - { - // remove if match or freed object - it.remove(); - - // do not return; process entire list - } - } - if ( list.size() == 0 ) - { - observers.remove( key ); - } - } - - /* Reference queues for cleared WeakKeys */ - private ReferenceQueue keyQueue = new ReferenceQueue(); - - /** - * Removes any keys whose object has been garbage collected. - * (Garbage collected values are removed as they are encountered.) - */ - private void processKeyQueue() - { - CompoundKey ck; - while ((ck = (CompoundKey)keyQueue.poll()) != null) - { - //System.out.println( "EOObserverCenter.processQueue: removing object" ); - observers.remove(ck); - } - } - - /** - * Key combining a name with an object. - * The object is weakly referenced, and keys - * are deallocated by reference queue. - * equals() compares by reference. - */ - private static class CompoundKey extends WeakReference - { - private Object name; - private int hashCode; - - /** - * Creates compound key. - * Neither name nor object may be null. - * Use NullMarker to represent null - * in either name or object. - */ - public CompoundKey ( - Object aName, Object anObject ) - { - super( anObject ); - name = aName; - hashCode = aName.hashCode() + anObject.hashCode(); - } - - /** - * Creates compound key with queue. - * Neither name nor object may be null. - * Use NullMarker to represent null - * in either name or object. - */ - public CompoundKey ( - Object aName, Object anObject, ReferenceQueue aQueue ) - { - super( anObject, aQueue ); - name = aName; - hashCode = aName.hashCode() + anObject.hashCode(); - } - - public Object name() - { - return name; - } - - public int hashCode() - { - return hashCode; - } - - public boolean equals( Object anObject ) - { - if ( this == anObject ) return true; - // assumes only used with other compound keys - CompoundKey key = (CompoundKey) anObject; - if ( name == key.name || ( name != null && name.equals( key.name ) ) ) - { - Object object = get(); - if ( object != null ) - { - // compares by reference - if ( object == ( key.get() ) ) - { - return true; - } - } - } - return false; - } - - public String toString() - { - return "[CompoundKey:"+name()+":"+get()+"]"; - } - } - - /** - * Value combining an object with a selector. - * The object is weakly referenced, and null - * values are not allowed. - */ - private static class CompoundValue extends WeakReference - { - private NSSelector selector; - private int hashCode; - - public CompoundValue( Object anObject, NSSelector aSelector ) - { - super( anObject ); - hashCode = anObject.hashCode(); - selector = aSelector; - } - - public NSSelector selector() - { - return selector; - } - - public int hashCode() - { - return hashCode; - } - - public boolean equals( Object anObject ) - { - if ( this == anObject ) return true; - // assumes only used with other compound values - CompoundValue value = (CompoundValue) anObject; - if ( selector == value.selector || - ( selector != null && selector.equals( value.selector ) ) ) - { - Object object = get(); - if ( object != null ) - { - if ( object == value.get() ) - { - return true; - } - } - } - return false; - } - - public String toString() - { - return "[CompoundValue:"+get()+":"+selector().name()+"]"; - } - } -/* - public static void main( String[] argv ) - { - Object aSource = "aSource"; - Object bSource = "bSource"; - - Object oneTest = new OneTest(); - Object twoTest = new TwoTest(); - NSSelector notifyMeOnce = - new NSSelector( "notifyMeOnce", - new Class[] { NSNotification.class } ); - NSSelector notifyMeTwice = - new NSSelector( "notifyMeTwice", - new Class[] { NSNotification.class } ); - - NSNotificationCenter.defaultCenter().addObserver( - oneTest, notifyMeOnce, "aMessage", null ); - - NSNotificationCenter.defaultCenter().addObserver( - oneTest, notifyMeOnce, null, aSource ); - - NSNotificationCenter.defaultCenter().addObserver( - twoTest, notifyMeOnce, "aMessage", aSource ); - - NSNotificationCenter.defaultCenter().addObserver( - twoTest, notifyMeTwice, null, null ); - - NSNotificationCenter.defaultCenter().postNotification( - "aMessage", aSource ); - System.out.println(); - NSNotificationCenter.defaultCenter().postNotification( - "aMessage", bSource ); - System.out.println(); - NSNotificationCenter.defaultCenter().postNotification( - "bMessage", aSource ); - System.out.println(); - NSNotificationCenter.defaultCenter().postNotification( - "bMessage", bSource ); - System.out.println( "---" ); - - NSNotificationCenter.defaultCenter().removeObserver( - oneTest, null, aSource ); - - NSNotificationCenter.defaultCenter().postNotification( - "aMessage", aSource ); - System.out.println(); - NSNotificationCenter.defaultCenter().postNotification( - "aMessage", bSource ); - System.out.println(); - NSNotificationCenter.defaultCenter().postNotification( - "bMessage", aSource ); - System.out.println(); - NSNotificationCenter.defaultCenter().postNotification( - "bMessage", bSource ); - System.out.println( "---" ); - - NSNotificationCenter.defaultCenter().removeObserver( - null ); - - NSNotificationCenter.defaultCenter().postNotification( - "aMessage", aSource ); - System.out.println(); - NSNotificationCenter.defaultCenter().postNotification( - "aMessage", bSource ); - System.out.println(); - NSNotificationCenter.defaultCenter().postNotification( - "bMessage", aSource ); - System.out.println(); - NSNotificationCenter.defaultCenter().postNotification( - "bMessage", bSource ); - System.out.println( "---" ); - } - - static private class OneTest - { - public void notifyMeOnce( NSNotification aNotification ) - { - System.out.println( "OneTest.notifyMeOnce: " + aNotification ); - } - } - - static private class TwoTest - { - public void notifyMeOnce( NSNotification aNotification ) - { - System.out.println( "TwoTest.notifyMeOnce: " + aNotification ); - } - public void notifyMeTwice( NSNotification aNotification ) - { - System.out.println( "TwoTest.notifyMeTwice: " + aNotification ); - } - } -*/ -} + * Unregisters the specified observer from all notifications queues associated + * with the specified name or object or both. + * + * @param anObserver The observer to be unregistered, if null will + * unregister all observers for the specified + * notification name and object. + * @param notificationName The name of the notification for which the observer + * will be unregistered, if null will unregister the + * specified observer for all notifications with the + * specified object. + * @param anObject The object for the notification for which the + * observer will be unregistered, if null will + * unregister the specified observer for all objects + * with the specified notification. + */ + public void removeObserver(Object anObserver, String notificationName, Object anObject) { + // remove freed objects + processKeyQueue(); + // get key matches + List keys = matchingKeys(notificationName, anObject); + // remove specified observer from each matching key + Iterator it = keys.iterator(); + while (it.hasNext()) { + removeObserver(anObserver, it.next()); + } + } + + /** + * Returns all keys that match the specified name and object, but in this case + * null parameters are considered wildcards. Pass NullMarkers if you want to + * explicitly match nulls. + */ + private List matchingKeys(String name, Object object) { + List result = new LinkedList(); + + boolean willAdd; + CompoundKey key; + Iterator it = observers.keySet().iterator(); + while (it.hasNext()) { + key = (CompoundKey) it.next(); + willAdd = false; + if ((name == null) || (name == key.name())) { + if ((object == null) || (object == key.get())) { + willAdd = true; + } + } + if (willAdd) { + result.add(key); + } + } + return result; + } + + /** + * Removes the specified observer from the list referenced by the specified key + * in the observer map. + */ + private void removeObserver(Object anObserver, Object key) { + // if observer null, remove all observers for key + if (anObserver == null) { + observers.remove(key); + return; + } + + List list = (List) observers.get(key); + if (list == null) + return; + + // remove specified observer from list + Object observer; + Iterator it = list.iterator(); + while (it.hasNext()) { + observer = ((CompoundValue) it.next()).get(); + if ((observer == null) || (anObserver == observer)) { + // remove if match or freed object + it.remove(); + + // do not return; process entire list + } + } + if (list.size() == 0) { + observers.remove(key); + } + } + + /* Reference queues for cleared WeakKeys */ + private ReferenceQueue keyQueue = new ReferenceQueue(); + + /** + * Removes any keys whose object has been garbage collected. (Garbage collected + * values are removed as they are encountered.) + */ + private void processKeyQueue() { + CompoundKey ck; + while ((ck = (CompoundKey) keyQueue.poll()) != null) { + // System.out.println( "EOObserverCenter.processQueue: removing object" ); + observers.remove(ck); + } + } + + /** + * Key combining a name with an object. The object is weakly referenced, and + * keys are deallocated by reference queue. equals() compares by reference. + */ + private static class CompoundKey extends WeakReference { + private Object name; + private int hashCode; + + /** + * Creates compound key. Neither name nor object may be null. Use NullMarker to + * represent null in either name or object. + */ + public CompoundKey(Object aName, Object anObject) { + super(anObject); + name = aName; + hashCode = aName.hashCode() + anObject.hashCode(); + } + + /** + * Creates compound key with queue. Neither name nor object may be null. Use + * NullMarker to represent null in either name or object. + */ + public CompoundKey(Object aName, Object anObject, ReferenceQueue aQueue) { + super(anObject, aQueue); + name = aName; + hashCode = aName.hashCode() + anObject.hashCode(); + } + + public Object name() { + return name; + } + + public int hashCode() { + return hashCode; + } + + public boolean equals(Object anObject) { + if (this == anObject) + return true; + // assumes only used with other compound keys + CompoundKey key = (CompoundKey) anObject; + if (name == key.name || (name != null && name.equals(key.name))) { + Object object = get(); + if (object != null) { + // compares by reference + if (object == (key.get())) { + return true; + } + } + } + return false; + } + + public String toString() { + return "[CompoundKey:" + name() + ":" + get() + "]"; + } + } + + /** + * Value combining an object with a selector. The object is weakly referenced, + * and null values are not allowed. + */ + private static class CompoundValue extends WeakReference { + private NSSelector selector; + private int hashCode; + + public CompoundValue(Object anObject, NSSelector aSelector) { + super(anObject); + hashCode = anObject.hashCode(); + selector = aSelector; + } + + public NSSelector selector() { + return selector; + } + + public int hashCode() { + return hashCode; + } + + public boolean equals(Object anObject) { + if (this == anObject) + return true; + // assumes only used with other compound values + CompoundValue value = (CompoundValue) anObject; + if (selector == value.selector || (selector != null && selector.equals(value.selector))) { + Object object = get(); + if (object != null) { + if (object == value.get()) { + return true; + } + } + } + return false; + } + + public String toString() { + return "[CompoundValue:" + get() + ":" + selector().name() + "]"; + } + } + /* + * public static void main( String[] argv ) { Object aSource = "aSource"; Object + * bSource = "bSource"; + * + * Object oneTest = new OneTest(); Object twoTest = new TwoTest(); NSSelector + * notifyMeOnce = new NSSelector( "notifyMeOnce", new Class[] { + * NSNotification.class } ); NSSelector notifyMeTwice = new NSSelector( + * "notifyMeTwice", new Class[] { NSNotification.class } ); + * + * NSNotificationCenter.defaultCenter().addObserver( oneTest, notifyMeOnce, + * "aMessage", null ); + * + * NSNotificationCenter.defaultCenter().addObserver( oneTest, notifyMeOnce, + * null, aSource ); + * + * NSNotificationCenter.defaultCenter().addObserver( twoTest, notifyMeOnce, + * "aMessage", aSource ); + * + * NSNotificationCenter.defaultCenter().addObserver( twoTest, notifyMeTwice, + * null, null ); + * + * NSNotificationCenter.defaultCenter().postNotification( "aMessage", aSource ); + * System.out.println(); NSNotificationCenter.defaultCenter().postNotification( + * "aMessage", bSource ); System.out.println(); + * NSNotificationCenter.defaultCenter().postNotification( "bMessage", aSource ); + * System.out.println(); NSNotificationCenter.defaultCenter().postNotification( + * "bMessage", bSource ); System.out.println( "---" ); + * + * NSNotificationCenter.defaultCenter().removeObserver( oneTest, null, aSource + * ); + * + * NSNotificationCenter.defaultCenter().postNotification( "aMessage", aSource ); + * System.out.println(); NSNotificationCenter.defaultCenter().postNotification( + * "aMessage", bSource ); System.out.println(); + * NSNotificationCenter.defaultCenter().postNotification( "bMessage", aSource ); + * System.out.println(); NSNotificationCenter.defaultCenter().postNotification( + * "bMessage", bSource ); System.out.println( "---" ); + * + * NSNotificationCenter.defaultCenter().removeObserver( null ); + * + * NSNotificationCenter.defaultCenter().postNotification( "aMessage", aSource ); + * System.out.println(); NSNotificationCenter.defaultCenter().postNotification( + * "aMessage", bSource ); System.out.println(); + * NSNotificationCenter.defaultCenter().postNotification( "bMessage", aSource ); + * System.out.println(); NSNotificationCenter.defaultCenter().postNotification( + * "bMessage", bSource ); System.out.println( "---" ); } + * + * static private class OneTest { public void notifyMeOnce( NSNotification + * aNotification ) { System.out.println( "OneTest.notifyMeOnce: " + + * aNotification ); } } + * + * static private class TwoTest { public void notifyMeOnce( NSNotification + * aNotification ) { System.out.println( "TwoTest.notifyMeOnce: " + + * aNotification ); } public void notifyMeTwice( NSNotification aNotification ) + * { System.out.println( "TwoTest.notifyMeTwice: " + aNotification ); } } + */ +} /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.11 2003/06/03 14:51:15 mpowers - * Added commented-out println for debugging. + * Revision 1.11 2003/06/03 14:51:15 mpowers Added commented-out println for + * debugging. * - * Revision 1.10 2003/03/27 21:46:00 mpowers - * Better handling for null parameters on subscribe. - * Better handling for null parameters on post. + * Revision 1.10 2003/03/27 21:46:00 mpowers Better handling for null parameters + * on subscribe. Better handling for null parameters on post. * - * Revision 1.9 2003/01/28 19:44:38 mpowers - * Now comparing strings by value not reference. + * Revision 1.9 2003/01/28 19:44:38 mpowers Now comparing strings by value not + * reference. * - * Revision 1.8 2001/06/29 16:14:23 mpowers - * Fixed a javac compiler error that jikes allowed: shoe's on the other foot! + * Revision 1.8 2001/06/29 16:14:23 mpowers Fixed a javac compiler error that + * jikes allowed: shoe's on the other foot! * - * Revision 1.7 2001/06/07 22:09:03 mpowers - * Exceptions during a notification are no longer being thrown - * so we can assure that all notifications get handled. + * Revision 1.7 2001/06/07 22:09:03 mpowers Exceptions during a notification are + * no longer being thrown so we can assure that all notifications get handled. * Instead, we're printing stack traces... * - * Revision 1.6 2001/04/09 21:41:50 mpowers - * Better debugging. + * Revision 1.6 2001/04/09 21:41:50 mpowers Better debugging. * - * Revision 1.5 2001/03/15 21:09:06 mpowers - * Fixed notifications with null objects. + * Revision 1.5 2001/03/15 21:09:06 mpowers Fixed notifications with null + * objects. * - * Revision 1.4 2001/02/21 21:18:34 mpowers - * Clarified need to retain references. + * Revision 1.4 2001/02/21 21:18:34 mpowers Clarified need to retain references. * - * Revision 1.3 2001/02/21 18:31:07 mpowers - * Finished and tested implementation of NSNotificationCenter. + * Revision 1.3 2001/02/21 18:31:07 mpowers Finished and tested implementation + * of NSNotificationCenter. * - * Revision 1.1.1.1 2000/12/21 15:47:39 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:47:39 mpowers Contributing wotonomy. * - * Revision 1.3 2000/12/20 16:25:38 michael - * Added log to all files. + * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java index 7350a39..81dc6e8 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java @@ -23,323 +23,264 @@ import java.util.LinkedList; import java.util.List; /** -* NSNotificationQueue coalesces notifications to be -* posted to the NSNotificationCenter and can post them -* asynchronously. While calling postNotification on -* the notification center does not return until all -* receivers have been notified, calling enqueueNotification -* can return immediately. Use this class when you want -* to coalesce notifications or notify asynchronously, or -* both, which is the typical case. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public class NSNotificationQueue -{ - private static NSNotificationQueue defaultQueue = null; - - /** - * Posting style specifying that the notification should - * be posted on the next available event loop. - */ - public static final int PostASAP = 4; - - /** - * Posting style specifying that the notification should - * be posted on the next available idle loop. - */ - public static final int PostWhenIdle = 8; - - /** - * Posting style specifying that the notification should - * be posted immediately. The enqueue method will not - * return until all receivers have been notified. - */ - public static final int PostNow = 16; - - /** - * Used to indicate that this notification should not - * be coalesced with other notifications. - * Ignored if combined with other coalesce flags. - */ - public static final int NotificationNoCoalescing = 0; - - /** - * Used to indicate that this notification should - * be coalesced with other notifications with the - * same name. - * May be combined with NotificationCoalescingOnSender. - */ - public static final int NotificationCoalescingOnName = 1; - - /** - * Used to indicate that this notification should - * be coalesced with other notifications with the - * same object argument (which is typically the sender). - * May be combined with NotificationCoalescingOnName. - */ - public static final int NotificationCoalescingOnSender = 2; - - /** - * The ASAP queue, which should probably use a LinkedList. - */ - private List queue; - - /** - * The idle queue, which should probably use a LinkedList. - */ - private List idleQueue; - - /** - * The notification center we will be using. - */ - private NSNotificationCenter center; - - /** - * Our private ASAP notifier. - */ - private Notifier notifier; - - /** - * Our private idle notifier. - */ - private Notifier idleNotifier; - - /** - * Default constructor creates a new notification queue - * that uses the default notification center. - */ - public NSNotificationQueue() - { - this( NSNotificationCenter.defaultCenter() ); - } - - /** - * Creates a new notification queue that uses the - * specified notification center. - */ - public NSNotificationQueue( - NSNotificationCenter aCenter ) - { - queue = new LinkedList(); - idleQueue = new LinkedList(); - center = aCenter; - notifier = new Notifier( this, queue ); - idleNotifier = new Notifier( this, idleQueue ); - } - - /** - * Returns the system default queue, creating one - * if it has not yet been created. The system default - * queue uses the system default notification center. - */ - static public NSNotificationQueue defaultQueue() - { - if ( defaultQueue == null ) - { - defaultQueue = new NSNotificationQueue(); - } - return defaultQueue; - } - - /** - * Removes notifications from the queue that match - * the specified notification, considering the - * specified coalesce mask. - */ - public void dequeueMatchingNotifications( - NSNotification aNotification, - int aCoalesceMask) - { - if ( aCoalesceMask == NotificationNoCoalescing ) return; - dequeueFromQueue( aNotification, aCoalesceMask, queue ); - dequeueFromQueue( aNotification, aCoalesceMask, idleQueue ); - } - - private void dequeueFromQueue( - NSNotification aNotification, - int aCoalesceMask, - List aQueue ) - { - synchronized ( aQueue ) - { - int flag; - NSNotification notification; - Object name = aNotification.name(); - Object object = aNotification.object(); - Iterator it = aQueue.iterator(); - while ( it.hasNext() ) - { - flag = 0; - notification = (NSNotification) it.next(); - // if NotificationCoalescingOnName - if ( ( aCoalesceMask == 1 ) || ( aCoalesceMask == 3 ) ) - { - if ( name == null ) - { - if ( notification.name() != null ) - { - flag += NotificationCoalescingOnName; - } - } - else - { - // compare by value - if ( name.equals( notification.name() ) ) - { - flag += NotificationCoalescingOnName; - } - } - } - // if NotificationCoalescingOnSender - if ( aCoalesceMask >= 2 ) - { - // compare by reference - if ( object == notification.object() ) - { - flag += NotificationCoalescingOnSender; - } - } - - if ( flag == aCoalesceMask ) - { - it.remove(); - } - } - } - } - - /** - * Adds the notification to the queue to be run at - * the time specified by the posting style. The - * notification will be coalesced with other notifications - * that match the same name and object (sender) argument. - */ - public void enqueueNotification( - NSNotification aNotification, - int aPostingStyle) - { - enqueueNotificationWithCoalesceMaskForModes( - aNotification, aPostingStyle, - NotificationCoalescingOnName + NotificationCoalescingOnSender, - null ); - } - - /** - * Adds the notification to the queue to be run at - * the time specified by the posting style and coelesced - * as the specified mask indicates. - * aModeList is currently ignored and may be null. - */ - public void enqueueNotificationWithCoalesceMaskForModes( - NSNotification aNotification, - int aPostingStyle, - int aCoalesceMask, - List aModeList) - { - dequeueMatchingNotifications( aNotification, aCoalesceMask ); - - if ( aPostingStyle == PostNow ) - { - center.postNotification( aNotification ); - return; - } - - if ( aPostingStyle == PostASAP ) - { - synchronized ( queue ) - { - queue.add( aNotification ); - if ( ! notifier.willRun ) - { - // asap runs at the very first run loop ordering, plus one just in case - NSRunLoop.invokeLaterWithOrder( notifier, 1 ); - notifier.willRun = true; - } - } - return; - } - - if ( aPostingStyle == PostWhenIdle ) - { - synchronized ( idleQueue ) - { - idleQueue.add( aNotification ); - if ( ! idleNotifier.willRun ) - { - // when idle runs at the very last run loop ordering, minus one just in case - NSRunLoop.invokeLaterWithOrder( idleNotifier, Integer.MAX_VALUE - 1 ); - idleNotifier.willRun = true; - } - } - return; - } - - } - - private class Notifier implements Runnable - { - public boolean willRun; - - NSNotificationQueue parent; - List queue; - - public Notifier( - NSNotificationQueue aParent, List aQueue ) - { - willRun = false; - parent = aParent; - queue = aQueue; - } - - public void run() - { - Iterator it = new LinkedList( queue ).iterator(); - synchronized ( queue ) - { - queue.clear(); - } - willRun = false; - - // queue must already be cleared and willRun reset - // because this loop might queue more notifications - while ( it.hasNext() ) - { - parent.center.postNotification( - (NSNotification) it.next() ); - } - } - } + * NSNotificationQueue coalesces notifications to be posted to the + * NSNotificationCenter and can post them asynchronously. While calling + * postNotification on the notification center does not return until all + * receivers have been notified, calling enqueueNotification can return + * immediately. Use this class when you want to coalesce notifications or notify + * asynchronously, or both, which is the typical case. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public class NSNotificationQueue { + private static NSNotificationQueue defaultQueue = null; + + /** + * Posting style specifying that the notification should be posted on the next + * available event loop. + */ + public static final int PostASAP = 4; + + /** + * Posting style specifying that the notification should be posted on the next + * available idle loop. + */ + public static final int PostWhenIdle = 8; + + /** + * Posting style specifying that the notification should be posted immediately. + * The enqueue method will not return until all receivers have been notified. + */ + public static final int PostNow = 16; + + /** + * Used to indicate that this notification should not be coalesced with other + * notifications. Ignored if combined with other coalesce flags. + */ + public static final int NotificationNoCoalescing = 0; + + /** + * Used to indicate that this notification should be coalesced with other + * notifications with the same name. May be combined with + * NotificationCoalescingOnSender. + */ + public static final int NotificationCoalescingOnName = 1; + + /** + * Used to indicate that this notification should be coalesced with other + * notifications with the same object argument (which is typically the sender). + * May be combined with NotificationCoalescingOnName. + */ + public static final int NotificationCoalescingOnSender = 2; + + /** + * The ASAP queue, which should probably use a LinkedList. + */ + private List queue; + + /** + * The idle queue, which should probably use a LinkedList. + */ + private List idleQueue; + + /** + * The notification center we will be using. + */ + private NSNotificationCenter center; + + /** + * Our private ASAP notifier. + */ + private Notifier notifier; + + /** + * Our private idle notifier. + */ + private Notifier idleNotifier; + + /** + * Default constructor creates a new notification queue that uses the default + * notification center. + */ + public NSNotificationQueue() { + this(NSNotificationCenter.defaultCenter()); + } + + /** + * Creates a new notification queue that uses the specified notification center. + */ + public NSNotificationQueue(NSNotificationCenter aCenter) { + queue = new LinkedList(); + idleQueue = new LinkedList(); + center = aCenter; + notifier = new Notifier(this, queue); + idleNotifier = new Notifier(this, idleQueue); + } + + /** + * Returns the system default queue, creating one if it has not yet been + * created. The system default queue uses the system default notification + * center. + */ + static public NSNotificationQueue defaultQueue() { + if (defaultQueue == null) { + defaultQueue = new NSNotificationQueue(); + } + return defaultQueue; + } + + /** + * Removes notifications from the queue that match the specified notification, + * considering the specified coalesce mask. + */ + public void dequeueMatchingNotifications(NSNotification aNotification, int aCoalesceMask) { + if (aCoalesceMask == NotificationNoCoalescing) + return; + dequeueFromQueue(aNotification, aCoalesceMask, queue); + dequeueFromQueue(aNotification, aCoalesceMask, idleQueue); + } + + private void dequeueFromQueue(NSNotification aNotification, int aCoalesceMask, List aQueue) { + synchronized (aQueue) { + int flag; + NSNotification notification; + Object name = aNotification.name(); + Object object = aNotification.object(); + Iterator it = aQueue.iterator(); + while (it.hasNext()) { + flag = 0; + notification = (NSNotification) it.next(); + // if NotificationCoalescingOnName + if ((aCoalesceMask == 1) || (aCoalesceMask == 3)) { + if (name == null) { + if (notification.name() != null) { + flag += NotificationCoalescingOnName; + } + } else { + // compare by value + if (name.equals(notification.name())) { + flag += NotificationCoalescingOnName; + } + } + } + // if NotificationCoalescingOnSender + if (aCoalesceMask >= 2) { + // compare by reference + if (object == notification.object()) { + flag += NotificationCoalescingOnSender; + } + } + + if (flag == aCoalesceMask) { + it.remove(); + } + } + } + } + + /** + * Adds the notification to the queue to be run at the time specified by the + * posting style. The notification will be coalesced with other notifications + * that match the same name and object (sender) argument. + */ + public void enqueueNotification(NSNotification aNotification, int aPostingStyle) { + enqueueNotificationWithCoalesceMaskForModes(aNotification, aPostingStyle, + NotificationCoalescingOnName + NotificationCoalescingOnSender, null); + } + + /** + * Adds the notification to the queue to be run at the time specified by the + * posting style and coelesced as the specified mask indicates. aModeList is + * currently ignored and may be null. + */ + public void enqueueNotificationWithCoalesceMaskForModes(NSNotification aNotification, int aPostingStyle, + int aCoalesceMask, List aModeList) { + dequeueMatchingNotifications(aNotification, aCoalesceMask); + + if (aPostingStyle == PostNow) { + center.postNotification(aNotification); + return; + } + + if (aPostingStyle == PostASAP) { + synchronized (queue) { + queue.add(aNotification); + if (!notifier.willRun) { + // asap runs at the very first run loop ordering, plus one just in case + NSRunLoop.invokeLaterWithOrder(notifier, 1); + notifier.willRun = true; + } + } + return; + } + + if (aPostingStyle == PostWhenIdle) { + synchronized (idleQueue) { + idleQueue.add(aNotification); + if (!idleNotifier.willRun) { + // when idle runs at the very last run loop ordering, minus one just in case + NSRunLoop.invokeLaterWithOrder(idleNotifier, Integer.MAX_VALUE - 1); + idleNotifier.willRun = true; + } + } + return; + } + + } + + private class Notifier implements Runnable { + public boolean willRun; + + NSNotificationQueue parent; + List queue; + + public Notifier(NSNotificationQueue aParent, List aQueue) { + willRun = false; + parent = aParent; + queue = aQueue; + } + + public void run() { + Iterator it = new LinkedList(queue).iterator(); + synchronized (queue) { + queue.clear(); + } + willRun = false; + + // queue must already be cleared and willRun reset + // because this loop might queue more notifications + while (it.hasNext()) { + parent.center.postNotification((NSNotification) it.next()); + } + } + } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.6 2003/08/11 18:18:08 chochos - * improved encoding of strings, removed warnings + * Revision 1.6 2003/08/11 18:18:08 chochos improved encoding of strings, + * removed warnings * - * Revision 1.5 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.5 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.4 2001/11/01 15:49:26 mpowers - * With NSRunLoop, we can now correctly implement PostASAP and PostWhenIdle. + * Revision 1.4 2001/11/01 15:49:26 mpowers With NSRunLoop, we can now correctly + * implement PostASAP and PostWhenIdle. * - * Revision 1.3 2001/06/25 14:47:24 mpowers - * Fixed serious error where some notifications were not being posted at all. - * A simple change to Notifier class fixed the problem. Thanks to glista. + * Revision 1.3 2001/06/25 14:47:24 mpowers Fixed serious error where some + * notifications were not being posted at all. A simple change to Notifier class + * fixed the problem. Thanks to glista. * - * Revision 1.2 2001/02/26 15:53:22 mpowers - * Fine-tuning notification firing. + * Revision 1.2 2001/02/26 15:53:22 mpowers Fine-tuning notification firing. * Child display groups now update properly after parent save or invalidate. * - * Revision 1.1 2001/02/24 17:03:22 mpowers - * Implemented the notification queue, and changed editing context to use it. + * Revision 1.1 2001/02/24 17:03:22 mpowers Implemented the notification queue, + * and changed editing context to use it. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNull.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNull.java index db1f216..861f576 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNull.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNull.java @@ -21,84 +21,72 @@ package net.wotonomy.foundation; import java.io.Serializable; /** -* NSNull is used to represent null in Collections classes -* because List and Map do not specify whether null values -* are allowed and because NSArray and NSDictionary explicitly -* do not allow null values. <br><br> -* -* Use of the static singleton method nullValue() is required -* by this implementation because Java cannot return a singleton -* instance from a constructor. Even then, more than one instance -* may exist in the application due to object serialization. -* Be sure to compare with equals(). -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 892 $ -*/ -public class NSNull implements Serializable -{ - private static final NSNull instance = new NSNull(); - - /** - * Create a new instance of NSNull. - */ - private NSNull () - { - } + * NSNull is used to represent null in Collections classes because List and Map + * do not specify whether null values are allowed and because NSArray and + * NSDictionary explicitly do not allow null values. <br> + * <br> + * + * Use of the static singleton method nullValue() is required by this + * implementation because Java cannot return a singleton instance from a + * constructor. Even then, more than one instance may exist in the application + * due to object serialization. Be sure to compare with equals(). + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 892 $ + */ +public class NSNull implements Serializable { + private static final NSNull instance = new NSNull(); - /** - * Returns the static instance of nullValue. - * Note that serialization may mean that more than - * one instance of NSNull exists, so be sure to - * compare with equals(). - */ - public static NSNull nullValue () - { - return instance; - } + /** + * Create a new instance of NSNull. + */ + private NSNull() { + } - /** - * Returns a human-readable string representation. - */ - public String toString() - { - return "[null]"; - } - - /** - * Hashcode of all instances is zero. - */ - public int hashCode() - { - return 0; - } - - /** - * Implemented to return true for any instance of NSNull. - */ - public boolean equals( Object anObject ) - { - return ( anObject instanceof NSNull ); - } + /** + * Returns the static instance of nullValue. Note that serialization may mean + * that more than one instance of NSNull exists, so be sure to compare with + * equals(). + */ + public static NSNull nullValue() { + return instance; + } + + /** + * Returns a human-readable string representation. + */ + public String toString() { + return "[null]"; + } + + /** + * Hashcode of all instances is zero. + */ + public int hashCode() { + return 0; + } + + /** + * Implemented to return true for any instance of NSNull. + */ + public boolean equals(Object anObject) { + return (anObject instanceof NSNull); + } } /* - * $Log$ - * Revision 1.1 2006/02/16 12:47:16 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.3 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.3 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.2 2001/03/01 20:36:09 mpowers - * Implemented equals, hashcode, and serializable. + * Revision 1.2 2001/03/01 20:36:09 mpowers Implemented equals, hashcode, and + * serializable. * - * Revision 1.1 2001/02/26 22:41:51 mpowers - * Implemented null placeholder classes. - * Duplicator now uses NSNull. - * No longer catching base exception class. + * Revision 1.1 2001/02/26 22:41:51 mpowers Implemented null placeholder + * classes. Duplicator now uses NSNull. No longer catching base exception class. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNumberFormatter.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNumberFormatter.java index 064ee3c..7e6386d 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNumberFormatter.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNumberFormatter.java @@ -24,34 +24,29 @@ package net.wotonomy.foundation; import java.text.DecimalFormat; /** -* A Format that accepts C-style number formatting syntax. -* Not currently implemented, included for compile compatibility. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ + * A Format that accepts C-style number formatting syntax. Not currently + * implemented, included for compile compatibility. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ + +public class NSNumberFormatter extends DecimalFormat { + public NSNumberFormatter() { + super(); + } -public class NSNumberFormatter extends DecimalFormat -{ - public NSNumberFormatter() - { - super(); - } - - public NSNumberFormatter(String aPattern) - { - super( aPattern ); - } + public NSNumberFormatter(String aPattern) { + super(aPattern); + } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.1 2003/01/17 14:40:50 mpowers - * Adding files to fix build. + * Revision 1.1 2003/01/17 14:40:50 mpowers Adding files to fix build. * * */ diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyListSerialization.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyListSerialization.java index 7f8bcc9..b52dc2d 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyListSerialization.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyListSerialization.java @@ -3,273 +3,287 @@ package net.wotonomy.foundation; public class NSPropertyListSerialization { - public static final int PLIST_ARRAY = 0; - public static final int PLIST_DICTIONARY = 1; - public static final int PLIST_DATA = 2; - public static final int PLIST_STRING = 3; + public static final int PLIST_ARRAY = 0; + public static final int PLIST_DICTIONARY = 1; + public static final int PLIST_DATA = 2; + public static final int PLIST_STRING = 3; - public static final char[] TOKEN_BEGIN = new char[]{ - '(', '{', '<', '"' - }; - public static final char[] TOKEN_END = new char[]{ - ')', '}', '>', '"' - }; - public static final char[] QUOTING_CHARS = new char[]{ - ':', '/', '-', '.', '\\' - }; + public static final char[] TOKEN_BEGIN = new char[] { '(', '{', '<', '"' }; + public static final char[] TOKEN_END = new char[] { ')', '}', '>', '"' }; + public static final char[] QUOTING_CHARS = new char[] { ':', '/', '-', '.', '\\' }; - private NSPropertyListSerialization() { - super(); - } + private NSPropertyListSerialization() { + super(); + } - /** Creates a NSArray object from a string representation. - @s The string representation of a NSArray object. */ - public static NSArray arrayForString(String s) { - s = s.trim(); - if (!(s.charAt(0) == TOKEN_BEGIN[PLIST_ARRAY] && s.charAt(s.length()-1) == TOKEN_END[PLIST_ARRAY])) - return null; - NSMutableArray arr = new NSMutableArray(); - int pos = 1; - int valbegin = -1; - while (pos < s.length()) { - char c = s.charAt(pos); - int tokenCount = 0; - int what = 0; - for (int i = 0 ; i < TOKEN_BEGIN.length; i++) { - if (c == TOKEN_BEGIN[i]) { - tokenCount = 1; - what = i; - break; - } - } - if (tokenCount > 0) { - //mark it - int quote = pos; - //find the closing token - do { - pos++; + /** + * Creates a NSArray object from a string representation. + * + * @s The string representation of a NSArray object. + */ + public static NSArray arrayForString(String s) { + s = s.trim(); + if (!(s.charAt(0) == TOKEN_BEGIN[PLIST_ARRAY] && s.charAt(s.length() - 1) == TOKEN_END[PLIST_ARRAY])) + return null; + NSMutableArray arr = new NSMutableArray(); + int pos = 1; + int valbegin = -1; + while (pos < s.length()) { + char c = s.charAt(pos); + int tokenCount = 0; + int what = 0; + for (int i = 0; i < TOKEN_BEGIN.length; i++) { + if (c == TOKEN_BEGIN[i]) { + tokenCount = 1; + what = i; + break; + } + } + if (tokenCount > 0) { + // mark it + int quote = pos; + // find the closing token + do { + pos++; try { c = s.charAt(pos); } catch (StringIndexOutOfBoundsException ex) { - throw new IllegalArgumentException("Could not parse property list; unclosed token '" + TOKEN_BEGIN[what] + "'"); + throw new IllegalArgumentException( + "Could not parse property list; unclosed token '" + TOKEN_BEGIN[what] + "'"); } if (c == '"' && what == PLIST_STRING) { - if (pos > 0 && s.charAt(pos-1) != '\\') { + if (pos > 0 && s.charAt(pos - 1) != '\\') { tokenCount--; } } else if (c == TOKEN_BEGIN[what]) - tokenCount++; - else if (c == TOKEN_END[what]) - tokenCount--; - } while (tokenCount > 0); - arr.addObject(propertyListFromString(s.substring(quote, pos+1))); - valbegin = -1; - //advance to the next position - do { - pos++; - c = s.charAt(pos); - } while (Character.isWhitespace(c)); - } - if (c == ',' || c ==')') { - if (valbegin > 0) { - arr.addObject(s.substring(valbegin, pos).trim()); - valbegin = -1; - } - } else if (!Character.isWhitespace(c)) { - if (valbegin < 0) { - valbegin = pos; - } - } - pos++; - } - return arr; - } + tokenCount++; + else if (c == TOKEN_END[what]) + tokenCount--; + } while (tokenCount > 0); + arr.addObject(propertyListFromString(s.substring(quote, pos + 1))); + valbegin = -1; + // advance to the next position + do { + pos++; + c = s.charAt(pos); + } while (Character.isWhitespace(c)); + } + if (c == ',' || c == ')') { + if (valbegin > 0) { + arr.addObject(s.substring(valbegin, pos).trim()); + valbegin = -1; + } + } else if (!Character.isWhitespace(c)) { + if (valbegin < 0) { + valbegin = pos; + } + } + pos++; + } + return arr; + } - /** Creates a NSDictionary instance from a string representation. - @s The string representation of a NSDictionary. */ - public static NSDictionary dictionaryForString(String s) { - s = s.trim(); - if (!(s.charAt(0) == TOKEN_BEGIN[PLIST_DICTIONARY] && s.charAt(s.length()-1) == TOKEN_END[PLIST_DICTIONARY])) - return null; - NSMutableDictionary d = new NSMutableDictionary(); - int pos = 1; - boolean parsing = true; - Object key = null; - int valbegin = -1; - while (pos < s.length()) { - //look for an opening token - char c = s.charAt(pos); - int tokenCount = 0; - int what = 0; - for (int i = 0 ; i < TOKEN_BEGIN.length; i++) { - if (c == TOKEN_BEGIN[i]) { - tokenCount = 1; - what = i; - break; - } - } - if (tokenCount > 0) { - //mark it - int quote = pos; - //find the closing token - do { - pos++; - try { + /** + * Creates a NSDictionary instance from a string representation. + * + * @s The string representation of a NSDictionary. + */ + public static NSDictionary dictionaryForString(String s) { + s = s.trim(); + if (!(s.charAt(0) == TOKEN_BEGIN[PLIST_DICTIONARY] && s.charAt(s.length() - 1) == TOKEN_END[PLIST_DICTIONARY])) + return null; + NSMutableDictionary d = new NSMutableDictionary(); + int pos = 1; + boolean parsing = true; + Object key = null; + int valbegin = -1; + while (pos < s.length()) { + // look for an opening token + char c = s.charAt(pos); + int tokenCount = 0; + int what = 0; + for (int i = 0; i < TOKEN_BEGIN.length; i++) { + if (c == TOKEN_BEGIN[i]) { + tokenCount = 1; + what = i; + break; + } + } + if (tokenCount > 0) { + // mark it + int quote = pos; + // find the closing token + do { + pos++; + try { c = s.charAt(pos); - } catch (StringIndexOutOfBoundsException ex) { - throw new IllegalArgumentException("Could not parse property list; unclosed token '" + TOKEN_BEGIN[what] + "'"); - } - if (c == '"' && what == PLIST_STRING) { - if (pos > 0 && s.charAt(pos-1) != '\\') { - tokenCount--; - } - } else if (c == TOKEN_BEGIN[what]) - tokenCount++; - else if (c == TOKEN_END[what]) - tokenCount--; - } while (tokenCount > 0); - if (key == null) { - key = propertyListFromString(s.substring(quote, pos+1)); - } else { - d.setObjectForKey(propertyListFromString(s.substring(quote, pos+1)), key); - key = null; - } - valbegin = -1; - //advance to the next position - do { - pos++; - c = s.charAt(pos); - } while (Character.isWhitespace(c)); - } - if (c == ';' || c == '=' || c == '}') { - if (valbegin > 0) { - if (key == null) { - key = s.substring(valbegin, pos).trim(); - } else { - d.setObjectForKey(s.substring(valbegin, pos).trim(), key); - key = null; - } - valbegin = -1; - } - } else if (!Character.isWhitespace(c)) { - if (valbegin < 0) { - valbegin = pos; - } - } - pos++; - } - return d; - } + } catch (StringIndexOutOfBoundsException ex) { + throw new IllegalArgumentException( + "Could not parse property list; unclosed token '" + TOKEN_BEGIN[what] + "'"); + } + if (c == '"' && what == PLIST_STRING) { + if (pos > 0 && s.charAt(pos - 1) != '\\') { + tokenCount--; + } + } else if (c == TOKEN_BEGIN[what]) + tokenCount++; + else if (c == TOKEN_END[what]) + tokenCount--; + } while (tokenCount > 0); + if (key == null) { + key = propertyListFromString(s.substring(quote, pos + 1)); + } else { + d.setObjectForKey(propertyListFromString(s.substring(quote, pos + 1)), key); + key = null; + } + valbegin = -1; + // advance to the next position + do { + pos++; + c = s.charAt(pos); + } while (Character.isWhitespace(c)); + } + if (c == ';' || c == '=' || c == '}') { + if (valbegin > 0) { + if (key == null) { + key = s.substring(valbegin, pos).trim(); + } else { + d.setObjectForKey(s.substring(valbegin, pos).trim(), key); + key = null; + } + valbegin = -1; + } + } else if (!Character.isWhitespace(c)) { + if (valbegin < 0) { + valbegin = pos; + } + } + pos++; + } + return d; + } - public static boolean booleanForString(String s) { - return s.trim().toLowerCase().equals("true"); - } + public static boolean booleanForString(String s) { + return s.trim().toLowerCase().equals("true"); + } - /** Creates a NSData instance from a string representation. - @s The string representation of a NSData object. */ - public static NSData dataFromPropertyList(String s) { - String hex = "0123456789ABCDEF"; - s = s.trim(); - if (!(s.charAt(0) == TOKEN_BEGIN[PLIST_DATA] && s.charAt(s.length()-1) == TOKEN_END[PLIST_DATA])) - return null; - int pos = 1; - java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream(); - while (pos < s.length()-1) { - char c1 = s.charAt(pos); - while (c1 == ' ') { - pos++; - if (pos == s.length()-1) - return new NSData(bout.toByteArray()); - c1 = s.charAt(pos); - } - if (hex.indexOf(c1) < 0) - throw new IllegalArgumentException("The string does not represent a NSData object (" + s + ", pos " + pos + ")"); - pos++; - char c2 = s.charAt(pos); - if (hex.indexOf(c2) < 0) - throw new IllegalArgumentException("The string does not represent a NSData object (" + s + ")"); - int x = (hex.indexOf(c1) << 4) | hex.indexOf(c2); - bout.write(x); - pos++; - } - return new NSData(bout.toByteArray()); - } + /** + * Creates a NSData instance from a string representation. + * + * @s The string representation of a NSData object. + */ + public static NSData dataFromPropertyList(String s) { + String hex = "0123456789ABCDEF"; + s = s.trim(); + if (!(s.charAt(0) == TOKEN_BEGIN[PLIST_DATA] && s.charAt(s.length() - 1) == TOKEN_END[PLIST_DATA])) + return null; + int pos = 1; + java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream(); + while (pos < s.length() - 1) { + char c1 = s.charAt(pos); + while (c1 == ' ') { + pos++; + if (pos == s.length() - 1) + return new NSData(bout.toByteArray()); + c1 = s.charAt(pos); + } + if (hex.indexOf(c1) < 0) + throw new IllegalArgumentException( + "The string does not represent a NSData object (" + s + ", pos " + pos + ")"); + pos++; + char c2 = s.charAt(pos); + if (hex.indexOf(c2) < 0) + throw new IllegalArgumentException("The string does not represent a NSData object (" + s + ")"); + int x = (hex.indexOf(c1) << 4) | hex.indexOf(c2); + bout.write(x); + pos++; + } + return new NSData(bout.toByteArray()); + } - public static int intForString(String s) { - return Integer.parseInt(s); - } + public static int intForString(String s) { + return Integer.parseInt(s); + } - /** Returns the string representation of a property list. - @plist The property list. It can be a String, NSData, NSArray, NSDictionary. */ - public static String stringForPropertyList(Object plist) { - if (plist == null) - return ""; - if (plist instanceof NSArray || plist instanceof NSDictionary || plist instanceof NSData) - return plist.toString(); - String x = plist.toString(); - boolean quote = false; - for (int i = 0; i < x.length(); i++) { - char c = x.charAt(i); - for (int z = 0; z < TOKEN_BEGIN.length; z++) { - if (c == TOKEN_BEGIN[z] || c == TOKEN_END[z]) - quote = true; - } - if (!quote) { - for (int z = 0; z < QUOTING_CHARS.length; z++) { - if (c == QUOTING_CHARS[z]) - quote = true; - } - } - if (!quote && Character.isWhitespace(c)) { - quote = true; - i = x.length(); - } - } - if (quote) - return "\"" + x + "\""; - return x; - } + /** + * Returns the string representation of a property list. + * + * @plist The property list. It can be a String, NSData, NSArray, NSDictionary. + */ + public static String stringForPropertyList(Object plist) { + if (plist == null) + return ""; + if (plist instanceof NSArray || plist instanceof NSDictionary || plist instanceof NSData) + return plist.toString(); + String x = plist.toString(); + boolean quote = false; + for (int i = 0; i < x.length(); i++) { + char c = x.charAt(i); + for (int z = 0; z < TOKEN_BEGIN.length; z++) { + if (c == TOKEN_BEGIN[z] || c == TOKEN_END[z]) + quote = true; + } + if (!quote) { + for (int z = 0; z < QUOTING_CHARS.length; z++) { + if (c == QUOTING_CHARS[z]) + quote = true; + } + } + if (!quote && Character.isWhitespace(c)) { + quote = true; + i = x.length(); + } + } + if (quote) + return "\"" + x + "\""; + return x; + } - /** Returns an property list created from a string representation. - @s The string with a representation of a property list. - @returns A property list object; either a NSData, NSArray, NSDictionary, or a String. */ - public static Object propertyListFromString(String s) { - s = s.trim(); - int type = -1; - for (int i = 0; i < TOKEN_BEGIN.length; i++) { - if (TOKEN_BEGIN[i] == s.charAt(0)) { - if (TOKEN_END[i] == s.charAt(s.length()-1)) - type = i; - } - } - switch (type) { - case PLIST_DATA: - return dataFromPropertyList(s); - case PLIST_ARRAY: - return arrayForString(s); - case PLIST_DICTIONARY: - return dictionaryForString(s); - case PLIST_STRING: - if (s.equals("\"\"")) - return ""; - return s.substring(1, s.length()-1); - } - return s; - } + /** + * Returns an property list created from a string representation. + * + * @s The string with a representation of a property list. + * @returns A property list object; either a NSData, NSArray, NSDictionary, or a + * String. + */ + public static Object propertyListFromString(String s) { + s = s.trim(); + int type = -1; + for (int i = 0; i < TOKEN_BEGIN.length; i++) { + if (TOKEN_BEGIN[i] == s.charAt(0)) { + if (TOKEN_END[i] == s.charAt(s.length() - 1)) + type = i; + } + } + switch (type) { + case PLIST_DATA: + return dataFromPropertyList(s); + case PLIST_ARRAY: + return arrayForString(s); + case PLIST_DICTIONARY: + return dictionaryForString(s); + case PLIST_STRING: + if (s.equals("\"\"")) + return ""; + return s.substring(1, s.length() - 1); + } + return s; + } - /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. - * - * Revision 1.5 2003/08/11 18:18:08 chochos - * improved encoding of strings, removed warnings - * - * Revision 1.4 2003/08/11 17:33:45 chochos - * Implemented detection of escaped quotes (\"). improved quoting strings when converting property lists to strings. - * - * Revision 1.3 2003/08/04 23:50:55 chochos - * propertyListForString() now works. dictionaryForString and arrayForString can parse complex structures with nested arrays and dictionaries. - * - */ + /* + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. + * + * Revision 1.5 2003/08/11 18:18:08 chochos improved encoding of strings, + * removed warnings + * + * Revision 1.4 2003/08/11 17:33:45 chochos Implemented detection of escaped + * quotes (\"). improved quoting strings when converting property lists to + * strings. + * + * Revision 1.3 2003/08/04 23:50:55 chochos propertyListForString() now works. + * dictionaryForString and arrayForString can parse complex structures with + * nested arrays and dictionaries. + * + */ }
\ No newline at end of file diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRange.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRange.java index 2de52f5..13dca2f 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRange.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRange.java @@ -19,333 +19,280 @@ License along with this library; if not, see http://www.gnu.org package net.wotonomy.foundation; /** -* A pure java implementation of NSRange. -* An NSRange represents a range of numbers -* having a starting location and spanning a -* length. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 920 $ -*/ -public class NSRange implements Cloneable -{ - /** - * An empty range. - */ - public static final NSRange ZeroRange = new NSRange(); - - protected int loc; - protected int len; - - /** - * Default constructor produces an empty range. - */ - public NSRange () - { - this( 0, 0 ); - } - - /** - * Produces a range with the specified location and length. - */ - public NSRange (int location, int length) - { - loc = location; - len = length; - } - - /** - * Produces a range that has the same location and length as - * the specified range. - */ - public NSRange (NSRange aRange) - { - this( aRange.location(), aRange.length() ); - } - - /** - * Returns the location of this range. - */ - public int location () - { - return loc; - } - - /** - * Returns the length of this range. - */ - public int length () - { - return len; - } - - /** - * Returns the maximum extent of the range. This number is - * one more than the last position in the range. - */ - public int maxRange () - { - return location() + length() -1; - } - - /** - * Returns whether this is an empty range, therefore - * whether the length is zero. - */ - public boolean isEmpty () - { - return ( length() == 0 ); - } - - /** - * Returns whether the specified location is contained - * within this range. - */ - public boolean locationInRange (int location) - { - if ( location < location() ) return false; - if ( location >= maxRange() ) return false; - return true; - } - - /** - * Returns whether the specified range is equal to this range. - */ - public boolean isEqualToRange (NSRange aRange) - { - if ( aRange == null ) return false; - return ( ( aRange.location() == location() ) - && ( aRange.length() == length() ) ); - } - - /** - * Returns whether the specified object is equal to this range. - */ - public boolean equals (Object anObject) - { - if ( anObject instanceof NSRange ) - return isEqualToRange( (NSRange) anObject ); + * A pure java implementation of NSRange. An NSRange represents a range of + * numbers having a starting location and spanning a length. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 920 $ + */ +public class NSRange implements Cloneable { + /** + * An empty range. + */ + public static final NSRange ZeroRange = new NSRange(); + + protected int loc; + protected int len; + + /** + * Default constructor produces an empty range. + */ + public NSRange() { + this(0, 0); + } + + /** + * Produces a range with the specified location and length. + */ + public NSRange(int location, int length) { + loc = location; + len = length; + } + + /** + * Produces a range that has the same location and length as the specified + * range. + */ + public NSRange(NSRange aRange) { + this(aRange.location(), aRange.length()); + } + + /** + * Returns the location of this range. + */ + public int location() { + return loc; + } + + /** + * Returns the length of this range. + */ + public int length() { + return len; + } + + /** + * Returns the maximum extent of the range. This number is one more than the + * last position in the range. + */ + public int maxRange() { + return location() + length() - 1; + } + + /** + * Returns whether this is an empty range, therefore whether the length is zero. + */ + public boolean isEmpty() { + return (length() == 0); + } + + /** + * Returns whether the specified location is contained within this range. + */ + public boolean locationInRange(int location) { + if (location < location()) + return false; + if (location >= maxRange()) + return false; + return true; + } + + /** + * Returns whether the specified range is equal to this range. + */ + public boolean isEqualToRange(NSRange aRange) { + if (aRange == null) + return false; + return ((aRange.location() == location()) && (aRange.length() == length())); + } + + /** + * Returns whether the specified object is equal to this range. + */ + public boolean equals(Object anObject) { + if (anObject instanceof NSRange) + return isEqualToRange((NSRange) anObject); return false; - } - - /** - * Returns a hashCode. - */ - public int hashCode () - { - // TODO: Test this logic. - return ( location() << 2 ) & length(); // bitwise ops never my forte - } - - /** - * Returns a string representation of this range. - */ - public String toString () - { - return "[NSRange: location = " + location() - + "; length = " + length() + "]"; - } - - /** - * Returns the union of this range and the specified range, if any. - * Gaps are filled, so the result is the smallest starting position - * and the largest ending position. - */ - public NSRange rangeByUnioningRange (NSRange aRange) - { - if ( aRange == null ) return this; - - // TODO: Test this logic. - int resultLoc = Math.min( this.location(), aRange.location() ); - int resultLen = Math.max( this.location() + this.length(), - aRange.location() + aRange.length() ) - resultLoc; - return new NSRange( resultLoc, resultLen ); - } - - /** - * Returns the intersection of this range and the specified range, - * if any. If no intersection, returns an empty range. - */ - public NSRange rangeByIntersectingRange (NSRange aRange) - { - // TODO: Test this logic. - if ( ! intersectsRange( aRange ) ) return ZeroRange; - int start = Math.max( this.location(), aRange.location() ); - int end = Math.min( this.location() + this.length(), - aRange.location() + aRange.length() ); - return new NSRange( start, end - start ); - } - - /** - * Returns whether the specified range overlaps - * at any point with this range. - */ - public boolean intersectsRange (NSRange aRange) - { - // TODO: Test this logic. - if ( aRange == null ) return false; - if ( ( this.location() >= aRange.location() ) - && ( this.location() < aRange.location() + aRange.length() ) ) + } + + /** + * Returns a hashCode. + */ + public int hashCode() { + // TODO: Test this logic. + return (location() << 2) & length(); // bitwise ops never my forte + } + + /** + * Returns a string representation of this range. + */ + public String toString() { + return "[NSRange: location = " + location() + "; length = " + length() + "]"; + } + + /** + * Returns the union of this range and the specified range, if any. Gaps are + * filled, so the result is the smallest starting position and the largest + * ending position. + */ + public NSRange rangeByUnioningRange(NSRange aRange) { + if (aRange == null) + return this; + + // TODO: Test this logic. + int resultLoc = Math.min(this.location(), aRange.location()); + int resultLen = Math.max(this.location() + this.length(), aRange.location() + aRange.length()) - resultLoc; + return new NSRange(resultLoc, resultLen); + } + + /** + * Returns the intersection of this range and the specified range, if any. If no + * intersection, returns an empty range. + */ + public NSRange rangeByIntersectingRange(NSRange aRange) { + // TODO: Test this logic. + if (!intersectsRange(aRange)) + return ZeroRange; + int start = Math.max(this.location(), aRange.location()); + int end = Math.min(this.location() + this.length(), aRange.location() + aRange.length()); + return new NSRange(start, end - start); + } + + /** + * Returns whether the specified range overlaps at any point with this range. + */ + public boolean intersectsRange(NSRange aRange) { + // TODO: Test this logic. + if (aRange == null) + return false; + if ((this.location() >= aRange.location()) && (this.location() < aRange.location() + aRange.length())) return true; - if ( ( aRange.location() >= this.location() ) - && ( aRange.location() < this.location() + this.length() ) ) + if ((aRange.location() >= this.location()) && (aRange.location() < this.location() + this.length())) return true; return false; - } - - /** - * Returns whether this range is completely - * contained within the specified range. - */ - public boolean isSubrangeOfRange (NSRange aRange) - { - // TODO: Test this logic. - if ( aRange == null ) return false; - if ( ( this.location() >= aRange.location() ) - && ( this.maxRange() <= aRange.maxRange() ) ) - return true; + } + + /** + * Returns whether this range is completely contained within the specified + * range. + */ + public boolean isSubrangeOfRange(NSRange aRange) { + // TODO: Test this logic. + if (aRange == null) + return false; + if ((this.location() >= aRange.location()) && (this.maxRange() <= aRange.maxRange())) + return true; return false; - } - - /** - * Eliminates any intersections between this range and the specified - * range. This produces two ranges, either of which may be empty. - * These two ranges are returned by modifying the supplied second - * and third parameters. - */ - public void subtractRange (NSRange aRange, - NSMutableRange firstResult, NSMutableRange secondResult) - { - if ( aRange == null ) return; - - // TODO: Test this logic. - // no intersection: return this and aRange without calculation - if ( ! intersectsRange( aRange ) ) - { - if ( firstResult != null ) - { - firstResult.setLocation( this.location() ); - firstResult.setLength( this.length() ); - } - if ( secondResult != null ) - { - secondResult.setLocation( aRange.location() ); - secondResult.setLength( aRange.location() ); - } - return; - } - - // TODO: Test this logic. - // this range is completely contained by other range - if ( isSubrangeOfRange( aRange ) ) - { - if ( firstResult != null ) - { - firstResult.setLocation( aRange.location() ); - firstResult.setLength( this.location() - aRange.location() ); - } - if ( secondResult != null ) - { - secondResult.setLocation( this.maxRange() ); - secondResult.setLength( - aRange.maxRange() - this.maxRange() - 1 ); // test this - } - return; - } - - // TODO: Test this logic. - // other range is completely contained by this range - if ( aRange.isSubrangeOfRange( this ) ) - { - if ( firstResult != null ) - { - firstResult.setLocation( this.location() ); - firstResult.setLength( aRange.location() - this.location() ); - } - if ( secondResult != null ) - { - secondResult.setLocation( aRange.maxRange() ); - secondResult.setLength( - this.maxRange() - aRange.maxRange() - 1 ); // test this - } - return; - } - - // TODO: Test this logic. - // ranges intersect: remove only the intersection - - NSRange firstRange, secondRange; - if ( this.location() <= aRange.location() ) - { - firstRange = this; - secondRange = aRange; - } - else - { - firstRange = aRange; - secondRange = this; - } - - if ( firstResult != null ) - { - firstResult.setLocation( firstRange.location() ); - firstResult.setLength( - secondRange.location() - firstRange.location() ); - } - if ( secondResult != null ) - { - secondResult.setLocation( firstRange.maxRange() ); - secondResult.setLength( - secondRange.maxRange() - aRange.maxRange() - 1 ); // test this - } - return; - - } - - /** - * Returns a copy of this range. - */ - public Object clone () - { - return new NSRange( location(), length() ); - } - - /** - * Parses a range from a string of the form "{x,y}" where - * x is the location and y is the length. If not parsable, - * an IllegalArgumentException is thrown. - */ - public static NSRange fromString (String aString) - { - // TODO: Test this logic. - try - { - java.util.StringTokenizer tokens = - new java.util.StringTokenizer( aString, "{,}" ); - int loc = Integer.parseInt( tokens.nextToken() ); - int len = Integer.parseInt( tokens.nextToken() ); - return new NSRange( loc, len ); - } - catch ( Exception exc ) - { - throw new IllegalArgumentException( exc.toString() ); - } - } - + } + + /** + * Eliminates any intersections between this range and the specified range. This + * produces two ranges, either of which may be empty. These two ranges are + * returned by modifying the supplied second and third parameters. + */ + public void subtractRange(NSRange aRange, NSMutableRange firstResult, NSMutableRange secondResult) { + if (aRange == null) + return; + + // TODO: Test this logic. + // no intersection: return this and aRange without calculation + if (!intersectsRange(aRange)) { + if (firstResult != null) { + firstResult.setLocation(this.location()); + firstResult.setLength(this.length()); + } + if (secondResult != null) { + secondResult.setLocation(aRange.location()); + secondResult.setLength(aRange.location()); + } + return; + } + + // TODO: Test this logic. + // this range is completely contained by other range + if (isSubrangeOfRange(aRange)) { + if (firstResult != null) { + firstResult.setLocation(aRange.location()); + firstResult.setLength(this.location() - aRange.location()); + } + if (secondResult != null) { + secondResult.setLocation(this.maxRange()); + secondResult.setLength(aRange.maxRange() - this.maxRange() - 1); // test this + } + return; + } + + // TODO: Test this logic. + // other range is completely contained by this range + if (aRange.isSubrangeOfRange(this)) { + if (firstResult != null) { + firstResult.setLocation(this.location()); + firstResult.setLength(aRange.location() - this.location()); + } + if (secondResult != null) { + secondResult.setLocation(aRange.maxRange()); + secondResult.setLength(this.maxRange() - aRange.maxRange() - 1); // test this + } + return; + } + + // TODO: Test this logic. + // ranges intersect: remove only the intersection + + NSRange firstRange, secondRange; + if (this.location() <= aRange.location()) { + firstRange = this; + secondRange = aRange; + } else { + firstRange = aRange; + secondRange = this; + } + + if (firstResult != null) { + firstResult.setLocation(firstRange.location()); + firstResult.setLength(secondRange.location() - firstRange.location()); + } + if (secondResult != null) { + secondResult.setLocation(firstRange.maxRange()); + secondResult.setLength(secondRange.maxRange() - aRange.maxRange() - 1); // test this + } + return; + + } + + /** + * Returns a copy of this range. + */ + public Object clone() { + return new NSRange(location(), length()); + } + + /** + * Parses a range from a string of the form "{x,y}" where x is the location and + * y is the length. If not parsable, an IllegalArgumentException is thrown. + */ + public static NSRange fromString(String aString) { + // TODO: Test this logic. + try { + java.util.StringTokenizer tokens = new java.util.StringTokenizer(aString, "{,}"); + int loc = Integer.parseInt(tokens.nextToken()); + int len = Integer.parseInt(tokens.nextToken()); + return new NSRange(loc, len); + } catch (Exception exc) { + throw new IllegalArgumentException(exc.toString()); + } + } + } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.1.1.1 2000/12/21 15:47:42 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:47:42 mpowers Contributing wotonomy. * - * Revision 1.3 2000/12/20 16:25:38 michael - * Added log to all files. + * Revision 1.3 2000/12/20 16:25:38 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRecursiveLock.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRecursiveLock.java index 65f58db..999af6c 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRecursiveLock.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRecursiveLock.java @@ -24,125 +24,129 @@ package net.wotonomy.foundation; import EDU.oswego.cs.dl.util.concurrent.ReentrantLock; /** -* A lock class that allows a thread to re-acquire it's lock -* recursively. Currently an API-compliance wrapper around Doug Lea's -* ReentrantLock, conforming to the API and behavior of -* com.webobjects.foundation.NSRecursiveLock. -* -* @author cgruber@israfil.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ + * A lock class that allows a thread to re-acquire it's lock recursively. + * Currently an API-compliance wrapper around Doug Lea's ReentrantLock, + * conforming to the API and behavior of + * com.webobjects.foundation.NSRecursiveLock. + * + * @author cgruber@israfil.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ public class NSRecursiveLock extends ReentrantLock implements NSLocking { - public NSRecursiveLock() { - } - /** Acquire the lock, catching the thrown exception to mirror the - * behavior of com.webobjects.foundation.NSRecursiveLock. Note that - * ReentrantLock.acquire() performs a notify() when it's interrupted. - * - * @see edu.oswego.cs.dl.util.concurrent.ReentrantLock#acquire() - */ - public void lock() { - try { - acquire(); - } catch (InterruptedException interruptedexception) { - // Null behavior, as notify() is already called - // by acquire(); - // We may want to log here. - } - } - - /** Pass the buck to tryLock(long), passing zero time as the parameter. - * - * @see #tryLock(long) - */ - public boolean tryLock() { - return tryLock(1); - } - - /** Attempt to acquire the lock, catching the thrown exception to mirror - * the behavior of com.webobjects.foundation.NSRecursiveLock. Note that - * ReentrantLock.attempt(*) performs a notify() when it's interrupted. - * Fail gracefully after the given milliseconds - * - * @param (long) - * @see edu.oswego.cs.dl.util.concurrent.ReentrantLock#acquire() - */ - public boolean tryLock(long milliseconds) { - try { - return attempt(milliseconds); - } catch (InterruptedException interruptedexception) { - // notify() is already called by attempt(); - // We may want to log here. - return false; - } - } - /** - * Attempt to acquire a lock until the timestamp is reached. Add - * 1 to the recursion count if the calling thread already owns the - * lock. Otherwise block until free or until the given timestamp - * is reached. - * - * @see Timestamp - * @see ReentrantLock.attempt(long); - */ - public boolean tryLock(NSTimestamp nstimestamp) { - return tryLock(nstimestamp.getTime() - System.currentTimeMillis()); - } - - /** Unlock the current lock precisely once. - */ - public synchronized void unlock() { - unlock(1); - } - - /** Unlock the current lock count times. - */ - public synchronized void unlock(long count) { - if (owner_ != null && Thread.currentThread() != owner_) - throw new IllegalStateException("Illegal Lock usage: unlocking thread not owner."); - if (owner_ == null || holds_ == 0L) - throw new IllegalStateException("Illegal Lock usage: unlock() called without a lock()."); + public NSRecursiveLock() { + } + + /** + * Acquire the lock, catching the thrown exception to mirror the behavior of + * com.webobjects.foundation.NSRecursiveLock. Note that ReentrantLock.acquire() + * performs a notify() when it's interrupted. + * + * @see edu.oswego.cs.dl.util.concurrent.ReentrantLock#acquire() + */ + public void lock() { + try { + acquire(); + } catch (InterruptedException interruptedexception) { + // Null behavior, as notify() is already called + // by acquire(); + // We may want to log here. + } + } + + /** + * Pass the buck to tryLock(long), passing zero time as the parameter. + * + * @see #tryLock(long) + */ + public boolean tryLock() { + return tryLock(1); + } + + /** + * Attempt to acquire the lock, catching the thrown exception to mirror the + * behavior of com.webobjects.foundation.NSRecursiveLock. Note that + * ReentrantLock.attempt(*) performs a notify() when it's interrupted. Fail + * gracefully after the given milliseconds + * + * @param (long) + * @see edu.oswego.cs.dl.util.concurrent.ReentrantLock#acquire() + */ + public boolean tryLock(long milliseconds) { + try { + return attempt(milliseconds); + } catch (InterruptedException interruptedexception) { + // notify() is already called by attempt(); + // We may want to log here. + return false; + } + } + + /** + * Attempt to acquire a lock until the timestamp is reached. Add 1 to the + * recursion count if the calling thread already owns the lock. Otherwise block + * until free or until the given timestamp is reached. + * + * @see Timestamp + * @see ReentrantLock.attempt(long); + */ + public boolean tryLock(NSTimestamp nstimestamp) { + return tryLock(nstimestamp.getTime() - System.currentTimeMillis()); + } + + /** + * Unlock the current lock precisely once. + */ + public synchronized void unlock() { + unlock(1); + } + + /** + * Unlock the current lock count times. + */ + public synchronized void unlock(long count) { + if (owner_ != null && Thread.currentThread() != owner_) + throw new IllegalStateException("Illegal Lock usage: unlocking thread not owner."); + if (owner_ == null || holds_ == 0L) + throw new IllegalStateException("Illegal Lock usage: unlock() called without a lock()."); release(count); - } + } - public synchronized long recursionCount() { + public synchronized long recursionCount() { return holds(); - } + } - public String toString() { - long holds = holds(); - boolean oneHold = (holds == 1); - boolean noHolds = (holds < 1 || owner_ == null); - return getClass().getName() + " <" + - ((noHolds) ? "Unlocked" : ( "Locked " + holds + " time" + (oneHold ? "" : "s") + " by " + owner_ ) ) + ">"; - } + public String toString() { + long holds = holds(); + boolean oneHold = (holds == 1); + boolean noHolds = (holds < 1 || owner_ == null); + return getClass().getName() + " <" + + ((noHolds) ? "Unlocked" : ("Locked " + holds + " time" + (oneHold ? "" : "s") + " by " + owner_)) + + ">"; + } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.1 2002/07/14 21:56:16 mpowers - * Contributions from cgruber. + * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber. * - * Revision 1.5 2002/06/25 19:02:19 cgruber - * I'm a dumbass. + * Revision 1.5 2002/06/25 19:02:19 cgruber I'm a dumbass. * - * Revision 1.4 2002/06/25 18:52:56 cgruber - * Fix javadocs that resulted from bad cut-and-paste of the boilerplate. + * Revision 1.4 2002/06/25 18:52:56 cgruber Fix javadocs that resulted from bad + * cut-and-paste of the boilerplate. * - * Revision 1.3 2002/06/25 18:45:27 cgruber - * Add some javadocs. + * Revision 1.3 2002/06/25 18:45:27 cgruber Add some javadocs. * - * Revision 1.2 2002/06/25 18:06:48 cgruber - * Add implementation of NSRecursiveLock using Doug Lea's concurrent programming APIs. - * Specifically inherit from ReentrantLock, which magically does the exact job we want! + * Revision 1.2 2002/06/25 18:06:48 cgruber Add implementation of + * NSRecursiveLock using Doug Lea's concurrent programming APIs. Specifically + * inherit from ReentrantLock, which magically does the exact job we want! * - * Revision 1.1 2002/06/25 07:52:56 cgruber - * Add quite a few abstract classes, interfaces, and classes. All API consistent with WebObjects, but with no implementation, nor any private or package access members from the original. + * Revision 1.1 2002/06/25 07:52:56 cgruber Add quite a few abstract classes, + * interfaces, and classes. All API consistent with WebObjects, but with no + * implementation, nor any private or package access members from the original. * */ diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRunLoop.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRunLoop.java index 2d122aa..c72cd23 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRunLoop.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSRunLoop.java @@ -28,495 +28,421 @@ import java.util.List; import java.util.ListIterator; /** -* NSRunLoop is provided specifically for EODelayedObserverQueue -* and EOEditingContext, which assume the existence of a -* prioritized event queue that Java does not provide. <br><br> -* -* This extends java.awt.EventQueue and does not conform to the -* NSRunLoop specifications. The only supported methods are -* NSRunLoop.currentRunLoop, performSelectorWithOrder, and -* cancelSelectorWithOrder. Note that in Swing there is only -* one AWT thread and one event queue; newly created threads -* will not get their own run loop as in OpenStep.<br><br> -* -* That said, this event queue is servicable as a replacement -* for the default event queue and will provide prioritized -* execution of selectors before and after normal AWT events. -* <br><br> -* -* Each run loop dispatches the lowest order event from -* the queue. When queued events have the same ordering, -* they are dispatched as first-in, first-out (FIFO). Because -* all AWT events have the same ordering (AWTEventsRunLoopOrdering), -* they are processed FIFO, just like the default event queue. <br><br> -* -* Note that because EventQueue is not well-factored for -* subclassing, pushing a new event queue onto the stack -* on top of this one will only copy the existing AWT events -* to the new queue. For this reason, pushing new event -* queues onto the stack is not supported and will throw -* an exception. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public class NSRunLoop extends EventQueue -{ - /** - * This is the ordering at which the conventional AWT event - * queue will be executed. Selectors with this ordering - * or less will be executed before AWT events, and - * selectors with ordering greater than this ordering will be - * be executed after AWT events. - */ - public static final int AWTEventsRunLoopOrdering = 500000; - - /** - * The singleton instance. - */ - protected static NSRunLoop instance; - - private LinkedList earlyQueue; - private LinkedList lateQueue; - - /** - * Needed because JDK1.4 made our lives more difficult. - */ - private static Toolkit toolkit; - - /** - * Because SunToolkit.flushPendingEvents was changed - * to a static method in 1.4, you can't compile the library - * in such a way that it works with both 1.3 and 1.4. - * So we have to rely on dynamic method invocation, - * which is slower, but we try to make it as fast as - * humanly possible. - */ - private static NSSelector flushPendingEvents; - - /** - * Create a new instance of NSRunLoop. - */ - protected NSRunLoop () - { - earlyQueue = new LinkedList(); - lateQueue = new LinkedList(); - } - - /** - * Returns the singleton instance of NSRunLoop. - * This returns the same instance no matter what - * thread calls it, which is different from OpenStep. - * NSRunLoop is limited to a singleton instance - * because there is no way of obtaining the stack - * of event queues from EventQueue because it is - * private state. - */ - public synchronized static NSRunLoop currentRunLoop () - { - if ( instance == null ) - { - // create and initialize - flushPendingEvents = new NSSelector( "flushPendingEvents" ); - toolkit = Toolkit.getDefaultToolkit(); - instance = new NSRunLoop(); - - toolkit.getSystemEventQueue().push( instance ); - } - - return instance; - } - - /** - * Post a 1.1-style event to the EventQueue. If there is an - * existing event on the queue with the same ID and event source, - * the source Component's coalesceEvents method will be called. - * - * @param theEvent an instance of java.awt.AWTEvent, or a - * subclass of it. - */ - public void postEvent(AWTEvent theEvent) - { - if ( theEvent instanceof OrderedInvocationEvent ) - { - OrderedInvocationEvent event = (OrderedInvocationEvent) theEvent; - if ( event.getOrdering() > AWTEventsRunLoopOrdering ) - { - insertEventIntoQueue( event, lateQueue ); - } - else - { - insertEventIntoQueue( event, earlyQueue ); - } - } - else - { - super.postEvent( theEvent ); - } - } - - private synchronized void insertEventIntoQueue( OrderedInvocationEvent e, LinkedList q ) - { - OrderedInvocationEvent o; - int ordering = e.getOrdering(); - ListIterator iterator = - q.listIterator(); - - // iterate forwards until we find a priority - // greater than our priority, - // then insert ourself before that element. - while ( iterator.hasNext() ) - { - o = (OrderedInvocationEvent) iterator.next(); - if ( o.getOrdering() > ordering ) - { - // back up one - iterator.previous(); - break; - } - } - // add after the current element - iterator.add( e ); - } - - /** - * Useful method, but not in the spec. - * Dispatches the next AWT event in the queue. - * Returns whether a selector or an event was executed: - * if the event queue is empty, returns false. - */ - public boolean dispatchNextEvent() - { - // check for empty queue to avoid blocking - if ( peekEvent() == null ) - { - return false; - } - - // queue not empty: dispatch the next event - try - { - dispatchEvent( getNextEvent() ); - } - catch ( InterruptedException exc ) - { - System.out.println( "NSRunLoop: error while dispatching event: " ); - exc.printStackTrace(); - } - return true; - } - - /** - * Useful method, but not in the spec. - * Dispatches all events in the queue before returning. - */ - public void dispatchAllEvents() - { - while ( dispatchNextEvent() ); - } - - /** - * Remove an event from the EventQueue and return it. - * This override will dispatch all selectors up to 5000, - * and then check if there are AWT events on the queue. - * If the queue is empty, all remaining selectors - * are dispatched. Then, this method calls the - * super class' implementation. - * @return the next AWTEvent - * @exception InterruptedException - * if another thread has interrupted this thread. - */ - public AWTEvent getNextEvent() throws InterruptedException - { - //NOTE: it's currently unclear to me whether we should - // be operating as a run loop or as a priority queue. - // I'm opting for priority queue now, but that means that - // selectors that requeue themselves could hang the application. - // In the future, we could fake a run loop by putting a marker - // event on the AWT queue to mark the boundary between loops. - - AWTEvent result; - - while ( true ) - { - //NOTE: as of java 1.4, we have to flush pending events - // using this cheesy undocumented method on suntoolkit. - // Unsurprisingly, java.awt.EventQueue got worse, not better. - // See notes above about our use of an NSSelector. - try - { - flushPendingEvents.invoke( toolkit ); - } - catch ( Throwable t ) - { - System.out.println( "NSRunLoop.getNextEvent: " + Thread.currentThread() ); - System.err.println( "Unexpected error while flushing pending events: " ); - t.printStackTrace(); - }; - - synchronized( this ) - { - result = popNextEarlyEvent(); - if ( result != null ) - { + * NSRunLoop is provided specifically for EODelayedObserverQueue and + * EOEditingContext, which assume the existence of a prioritized event queue + * that Java does not provide. <br> + * <br> + * + * This extends java.awt.EventQueue and does not conform to the NSRunLoop + * specifications. The only supported methods are NSRunLoop.currentRunLoop, + * performSelectorWithOrder, and cancelSelectorWithOrder. Note that in Swing + * there is only one AWT thread and one event queue; newly created threads will + * not get their own run loop as in OpenStep.<br> + * <br> + * + * That said, this event queue is servicable as a replacement for the default + * event queue and will provide prioritized execution of selectors before and + * after normal AWT events. <br> + * <br> + * + * Each run loop dispatches the lowest order event from the queue. When queued + * events have the same ordering, they are dispatched as first-in, first-out + * (FIFO). Because all AWT events have the same ordering + * (AWTEventsRunLoopOrdering), they are processed FIFO, just like the default + * event queue. <br> + * <br> + * + * Note that because EventQueue is not well-factored for subclassing, pushing a + * new event queue onto the stack on top of this one will only copy the existing + * AWT events to the new queue. For this reason, pushing new event queues onto + * the stack is not supported and will throw an exception. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public class NSRunLoop extends EventQueue { + /** + * This is the ordering at which the conventional AWT event queue will be + * executed. Selectors with this ordering or less will be executed before AWT + * events, and selectors with ordering greater than this ordering will be be + * executed after AWT events. + */ + public static final int AWTEventsRunLoopOrdering = 500000; + + /** + * The singleton instance. + */ + protected static NSRunLoop instance; + + private LinkedList earlyQueue; + private LinkedList lateQueue; + + /** + * Needed because JDK1.4 made our lives more difficult. + */ + private static Toolkit toolkit; + + /** + * Because SunToolkit.flushPendingEvents was changed to a static method in 1.4, + * you can't compile the library in such a way that it works with both 1.3 and + * 1.4. So we have to rely on dynamic method invocation, which is slower, but we + * try to make it as fast as humanly possible. + */ + private static NSSelector flushPendingEvents; + + /** + * Create a new instance of NSRunLoop. + */ + protected NSRunLoop() { + earlyQueue = new LinkedList(); + lateQueue = new LinkedList(); + } + + /** + * Returns the singleton instance of NSRunLoop. This returns the same instance + * no matter what thread calls it, which is different from OpenStep. NSRunLoop + * is limited to a singleton instance because there is no way of obtaining the + * stack of event queues from EventQueue because it is private state. + */ + public synchronized static NSRunLoop currentRunLoop() { + if (instance == null) { + // create and initialize + flushPendingEvents = new NSSelector("flushPendingEvents"); + toolkit = Toolkit.getDefaultToolkit(); + instance = new NSRunLoop(); + + toolkit.getSystemEventQueue().push(instance); + } + + return instance; + } + + /** + * Post a 1.1-style event to the EventQueue. If there is an existing event on + * the queue with the same ID and event source, the source Component's + * coalesceEvents method will be called. + * + * @param theEvent an instance of java.awt.AWTEvent, or a subclass of it. + */ + public void postEvent(AWTEvent theEvent) { + if (theEvent instanceof OrderedInvocationEvent) { + OrderedInvocationEvent event = (OrderedInvocationEvent) theEvent; + if (event.getOrdering() > AWTEventsRunLoopOrdering) { + insertEventIntoQueue(event, lateQueue); + } else { + insertEventIntoQueue(event, earlyQueue); + } + } else { + super.postEvent(theEvent); + } + } + + private synchronized void insertEventIntoQueue(OrderedInvocationEvent e, LinkedList q) { + OrderedInvocationEvent o; + int ordering = e.getOrdering(); + ListIterator iterator = q.listIterator(); + + // iterate forwards until we find a priority + // greater than our priority, + // then insert ourself before that element. + while (iterator.hasNext()) { + o = (OrderedInvocationEvent) iterator.next(); + if (o.getOrdering() > ordering) { + // back up one + iterator.previous(); + break; + } + } + // add after the current element + iterator.add(e); + } + + /** + * Useful method, but not in the spec. Dispatches the next AWT event in the + * queue. Returns whether a selector or an event was executed: if the event + * queue is empty, returns false. + */ + public boolean dispatchNextEvent() { + // check for empty queue to avoid blocking + if (peekEvent() == null) { + return false; + } + + // queue not empty: dispatch the next event + try { + dispatchEvent(getNextEvent()); + } catch (InterruptedException exc) { + System.out.println("NSRunLoop: error while dispatching event: "); + exc.printStackTrace(); + } + return true; + } + + /** + * Useful method, but not in the spec. Dispatches all events in the queue before + * returning. + */ + public void dispatchAllEvents() { + while (dispatchNextEvent()) + ; + } + + /** + * Remove an event from the EventQueue and return it. This override will + * dispatch all selectors up to 5000, and then check if there are AWT events on + * the queue. If the queue is empty, all remaining selectors are dispatched. + * Then, this method calls the super class' implementation. + * + * @return the next AWTEvent + * @exception InterruptedException if another thread has interrupted this + * thread. + */ + public AWTEvent getNextEvent() throws InterruptedException { + // NOTE: it's currently unclear to me whether we should + // be operating as a run loop or as a priority queue. + // I'm opting for priority queue now, but that means that + // selectors that requeue themselves could hang the application. + // In the future, we could fake a run loop by putting a marker + // event on the AWT queue to mark the boundary between loops. + + AWTEvent result; + + while (true) { + // NOTE: as of java 1.4, we have to flush pending events + // using this cheesy undocumented method on suntoolkit. + // Unsurprisingly, java.awt.EventQueue got worse, not better. + // See notes above about our use of an NSSelector. + try { + flushPendingEvents.invoke(toolkit); + } catch (Throwable t) { + System.out.println("NSRunLoop.getNextEvent: " + Thread.currentThread()); + System.err.println("Unexpected error while flushing pending events: "); + t.printStackTrace(); + } + ; + + synchronized (this) { + result = popNextEarlyEvent(); + if (result != null) { //System.out.println( "getNextEvent: early : " + result ); - return result; - } - } - - if ( ( result = peekEvent() ) != null ) - { + return result; + } + } + + if ((result = peekEvent()) != null) { //System.out.println( "getNextEvent: AWT : " + result ); - return super.getNextEvent(); - } - - synchronized( this ) - { - result = popNextLateEvent(); - if ( result != null ) - { + return super.getNextEvent(); + } + + synchronized (this) { + result = popNextLateEvent(); + if (result != null) { //System.out.println( "getNextEvent: late : " + result ); - return result; - } - - // yield + return result; + } + + // yield //System.out.println( "getNextEvent: wait" ); - wait(); + wait(); //System.out.println( "getNextEvent: notified" ); - } - } - } - - private AWTEvent popNextEarlyEvent() - { - if ( earlyQueue == null ) return null; // shouldn't be necessary, but is - if ( earlyQueue.isEmpty() ) return null; - return (AWTEvent) earlyQueue.removeFirst(); - } - - private AWTEvent popNextLateEvent() - { - if ( lateQueue == null ) return null; // shouldn't be necessary, but is - if ( lateQueue.isEmpty() ) return null; - return (AWTEvent) lateQueue.removeFirst(); - } - - /** - * This implementation calls super and then throws an - * UnsupportedOperationException. Catch that exception - * and ignore it if you know what you are doing. - */ - public synchronized void push(EventQueue newEventQueue) - { - super.push( newEventQueue ); - throw new UnsupportedOperationException( - "NSRunLoop may not function properly with push()" ); - } - - /** - * This implementation calls super and then throws an - * UnsupportedOperationException. Catch that exception - * and ignore it if you know what you are doing. - */ - protected void pop() throws EmptyStackException - { - super.pop(); - throw new UnsupportedOperationException( - "NSRunLoop may not function properly with pop()" ); - } - - /** - * Schedules the specified selector with the specified target and parameter - * to be invoked on the next event loop with the specified ordering. - * The selector must be able to be invoked on the target and the target method - * must accept the parameter. aModeList is currently ignored. - */ - public void performSelectorWithOrder( - NSSelector aSelector, Object aTarget, Object aParameter, int anOrdering, List aModeList ) - { - postEvent( new OrderedInvocationEvent( aSelector, aTarget, aParameter, anOrdering, aModeList ) ); - } - - /** - * Cancels the next scheduled invocation of the specified selector, target, and parameter. - * If no such invocation is scheduled, does nothing. - */ - public synchronized void cancelPerformSelectorWithOrder( - NSSelector aSelector, Object aTarget, Object aParameter ) - { - ListIterator i; - i = earlyQueue.listIterator(); - while ( i.hasNext() ) - { - if ( ((OrderedInvocationEvent)i.next()).compareTo( - aSelector, aTarget, aParameter ) ) - { - i.remove(); - return; - } - } - i = lateQueue.listIterator(); - while ( i.hasNext() ) - { - if ( ((OrderedInvocationEvent)i.next()).compareTo( - aSelector, aTarget, aParameter ) ) - { - i.remove(); - return; - } - } - } - - /** - * Causes runnable to have its run() method on the next - * event loop with the specified priority ordering. - */ - public static void invokeLaterWithOrder(Runnable aRunnable, int anOrdering) { - currentRunLoop().postEvent( - new OrderedInvocationEvent( Toolkit.getDefaultToolkit(), aRunnable, anOrdering ) ); - } - - /** - * An invocation event that can specify a priority for execution. - * The prioritization only works if the current event queue is an - * NSRunLoop; otherwise, performs as a normal invocation event. - */ - private static class OrderedInvocationEvent extends InvocationEvent - { - int ordering; - NSSelector selector = null; - Object target = null; - Object parameter = null; - - /** - * Constructs an InvocationEvent with the specified source which will - * execute the runnable's run() method when dispatched at the specified ordering. - */ - public OrderedInvocationEvent(Object source, - Runnable runnable, int anOrdering) - { - super( source, runnable ); - ordering = anOrdering; - } - - /** - * Constructs an InvocationEvent with the specified source which will - * execute the runnable's run() method when dispatched at the specified ordering. - * If notifier is non-null, notifyAll() will be called on it immediately after run() returns. - */ - public OrderedInvocationEvent(Object source, - Runnable runnable, - Object notifier, - boolean catchExceptions, int anOrdering) - { - super( source, runnable, notifier, catchExceptions ); - ordering = anOrdering; - } - - OrderedInvocationEvent( - final NSSelector aSelector, - final Object aTarget, - final Object aParameter, - int anOrdering, List aModeList) - { - this( Toolkit.getDefaultToolkit(), new Runnable() - { - public void run() - { - try - { - aSelector.invoke( aTarget, aParameter ); - } - catch ( Exception exc ) - { - System.out.println( "NSRunLoop: error invoking selector: " ); - exc.printStackTrace(); - } - } - }, anOrdering ); - - selector = aSelector; - target = aTarget; - parameter = aParameter; - } - - /** - * Called by cancelPerformSelectorWithOrder. - * Compares against the specified arguments. - */ - boolean compareTo( NSSelector aSelector, Object aTarget, Object aParameter ) - { - return ( - compareByValue( selector, aSelector ) && - compareByValue( target, aTarget ) && - compareByValue( parameter, aParameter ) ); - } - - private boolean compareByValue( Object first, Object second ) - { - if ( first == second ) return true; - if ( first == null ) return second.equals( first ); - return first.equals( second ); - - } - - /** - * Returns the ordering for this event in the run loop. - */ - public int getOrdering() - { - return ordering; - } - - } - + } + } + } + + private AWTEvent popNextEarlyEvent() { + if (earlyQueue == null) + return null; // shouldn't be necessary, but is + if (earlyQueue.isEmpty()) + return null; + return (AWTEvent) earlyQueue.removeFirst(); + } + + private AWTEvent popNextLateEvent() { + if (lateQueue == null) + return null; // shouldn't be necessary, but is + if (lateQueue.isEmpty()) + return null; + return (AWTEvent) lateQueue.removeFirst(); + } + + /** + * This implementation calls super and then throws an + * UnsupportedOperationException. Catch that exception and ignore it if you know + * what you are doing. + */ + public synchronized void push(EventQueue newEventQueue) { + super.push(newEventQueue); + throw new UnsupportedOperationException("NSRunLoop may not function properly with push()"); + } + + /** + * This implementation calls super and then throws an + * UnsupportedOperationException. Catch that exception and ignore it if you know + * what you are doing. + */ + protected void pop() throws EmptyStackException { + super.pop(); + throw new UnsupportedOperationException("NSRunLoop may not function properly with pop()"); + } + + /** + * Schedules the specified selector with the specified target and parameter to + * be invoked on the next event loop with the specified ordering. The selector + * must be able to be invoked on the target and the target method must accept + * the parameter. aModeList is currently ignored. + */ + public void performSelectorWithOrder(NSSelector aSelector, Object aTarget, Object aParameter, int anOrdering, + List aModeList) { + postEvent(new OrderedInvocationEvent(aSelector, aTarget, aParameter, anOrdering, aModeList)); + } + + /** + * Cancels the next scheduled invocation of the specified selector, target, and + * parameter. If no such invocation is scheduled, does nothing. + */ + public synchronized void cancelPerformSelectorWithOrder(NSSelector aSelector, Object aTarget, Object aParameter) { + ListIterator i; + i = earlyQueue.listIterator(); + while (i.hasNext()) { + if (((OrderedInvocationEvent) i.next()).compareTo(aSelector, aTarget, aParameter)) { + i.remove(); + return; + } + } + i = lateQueue.listIterator(); + while (i.hasNext()) { + if (((OrderedInvocationEvent) i.next()).compareTo(aSelector, aTarget, aParameter)) { + i.remove(); + return; + } + } + } + + /** + * Causes runnable to have its run() method on the next event loop with the + * specified priority ordering. + */ + public static void invokeLaterWithOrder(Runnable aRunnable, int anOrdering) { + currentRunLoop().postEvent(new OrderedInvocationEvent(Toolkit.getDefaultToolkit(), aRunnable, anOrdering)); + } + + /** + * An invocation event that can specify a priority for execution. The + * prioritization only works if the current event queue is an NSRunLoop; + * otherwise, performs as a normal invocation event. + */ + private static class OrderedInvocationEvent extends InvocationEvent { + int ordering; + NSSelector selector = null; + Object target = null; + Object parameter = null; + + /** + * Constructs an InvocationEvent with the specified source which will execute + * the runnable's run() method when dispatched at the specified ordering. + */ + public OrderedInvocationEvent(Object source, Runnable runnable, int anOrdering) { + super(source, runnable); + ordering = anOrdering; + } + + /** + * Constructs an InvocationEvent with the specified source which will execute + * the runnable's run() method when dispatched at the specified ordering. If + * notifier is non-null, notifyAll() will be called on it immediately after + * run() returns. + */ + public OrderedInvocationEvent(Object source, Runnable runnable, Object notifier, boolean catchExceptions, + int anOrdering) { + super(source, runnable, notifier, catchExceptions); + ordering = anOrdering; + } + + OrderedInvocationEvent(final NSSelector aSelector, final Object aTarget, final Object aParameter, + int anOrdering, List aModeList) { + this(Toolkit.getDefaultToolkit(), new Runnable() { + public void run() { + try { + aSelector.invoke(aTarget, aParameter); + } catch (Exception exc) { + System.out.println("NSRunLoop: error invoking selector: "); + exc.printStackTrace(); + } + } + }, anOrdering); + + selector = aSelector; + target = aTarget; + parameter = aParameter; + } + + /** + * Called by cancelPerformSelectorWithOrder. Compares against the specified + * arguments. + */ + boolean compareTo(NSSelector aSelector, Object aTarget, Object aParameter) { + return (compareByValue(selector, aSelector) && compareByValue(target, aTarget) + && compareByValue(parameter, aParameter)); + } + + private boolean compareByValue(Object first, Object second) { + if (first == second) + return true; + if (first == null) + return second.equals(first); + return first.equals(second); + + } + + /** + * Returns the ordering for this event in the run loop. + */ + public int getOrdering() { + return ordering; + } + + } + } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.13 2003/06/06 20:48:19 mpowers - * Fixed race condition when run loop is started from main thread. - * That was causing the dispatch thread to call getNextEvent before the - * static fields had been initialized. + * Revision 1.13 2003/06/06 20:48:19 mpowers Fixed race condition when run loop + * is started from main thread. That was causing the dispatch thread to call + * getNextEvent before the static fields had been initialized. * - * Revision 1.12 2003/06/03 14:52:11 mpowers - * Super constructor was calling getNextEvent before selector was created. + * Revision 1.12 2003/06/03 14:52:11 mpowers Super constructor was calling + * getNextEvent before selector was created. * - * Revision 1.10 2002/05/28 21:59:19 mpowers - * We now can compile against 1.3 and 1.4, as well as run against both too. + * Revision 1.10 2002/05/28 21:59:19 mpowers We now can compile against 1.3 and + * 1.4, as well as run against both too. * - * Revision 1.9 2002/04/09 18:10:45 mpowers - * Fixes for 1.4. Commented out until we start building on 1.4. + * Revision 1.9 2002/04/09 18:10:45 mpowers Fixes for 1.4. Commented out until + * we start building on 1.4. * - * Revision 1.8 2002/02/13 21:20:15 mpowers - * Updated comments. + * Revision 1.8 2002/02/13 21:20:15 mpowers Updated comments. * - * Revision 1.7 2001/11/01 15:48:49 mpowers - * Additional debug code. + * Revision 1.7 2001/11/01 15:48:49 mpowers Additional debug code. * - * Revision 1.6 2001/10/30 22:14:35 mpowers - * Constructor is now protected, not private. + * Revision 1.6 2001/10/30 22:14:35 mpowers Constructor is now protected, not + * private. * - * Revision 1.5 2001/10/29 20:41:49 mpowers - * Improved docs, better support for potential subclassing, invokeLater. + * Revision 1.5 2001/10/29 20:41:49 mpowers Improved docs, better support for + * potential subclassing, invokeLater. * - * Revision 1.4 2001/10/26 18:46:30 mpowers - * Now running AWT events with the appropriate ordering. - * Added invokeLaterWithOrder for java compatibility. + * Revision 1.4 2001/10/26 18:46:30 mpowers Now running AWT events with the + * appropriate ordering. Added invokeLaterWithOrder for java compatibility. * - * Revision 1.3 2001/10/26 14:39:46 mpowers - * Completed implementation. + * Revision 1.3 2001/10/26 14:39:46 mpowers Completed implementation. * - * Revision 1.2 2001/10/25 22:20:21 mpowers - * Got to check in an interim version - this will briefly break the build. + * Revision 1.2 2001/10/25 22:20:21 mpowers Got to check in an interim version - + * this will briefly break the build. * - * Revision 1.1 2001/10/24 19:30:38 mpowers - * Initial check-in: incomplete implementation. + * Revision 1.1 2001/10/24 19:30:38 mpowers Initial check-in: incomplete + * implementation. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSelector.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSelector.java index 965606b..8f5969a 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSelector.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSelector.java @@ -26,366 +26,298 @@ import java.util.Comparator; import net.wotonomy.foundation.internal.PropertyComparator; /** -* A pure java implementation of NSSelector. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 892 $ -*/ -public class NSSelector implements Comparator, Serializable -{ + * A pure java implementation of NSSelector. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 892 $ + */ +public class NSSelector implements Comparator, Serializable { protected NSMutableDictionary methodMap; // map of classes to methods protected String methodName; protected Class[] parameterTypes; /** - * A marker to indicate object not found. - */ + * A marker to indicate object not found. + */ protected static final String NOT_FOUND = "NOT_FOUND"; - + /** - * Saves creating a new class array for parameterless method invocation. - */ + * Saves creating a new class array for parameterless method invocation. + */ protected static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; - + /** - * Saves creating a new object array for parameterless method invocation. - */ + * Saves creating a new object array for parameterless method invocation. + */ protected static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; - - /** - * Constructor specifying a method name and an array of parameter types. - */ - public NSSelector (String aMethodName, Class[] aParameterTypeArray) - { - methodName = aMethodName; - parameterTypes = aParameterTypeArray; - methodMap = new NSMutableDictionary(); - } - - /** - * Constructor specifying a method name with no parameters. - */ - public NSSelector (String aMethodName) - { - this( aMethodName, EMPTY_CLASS_ARRAY ); - } - - /** - * Constructor for custom subclasses that implement specific operators - * and that do not use dynamic method invocation. - */ - protected NSSelector() - { - } - - /** - * Returns the name of the method. - */ - public String name () - { - return methodName; - } - - /** - * Returns the array of parameter types. - */ - public Class[] parameterTypes () - { - return parameterTypes; - } - - /** - * A String description of this selector. - */ - public String toString () - { - StringBuffer result = new StringBuffer(); - result.append( "[" + getClass().getName() + ": name = " + name() + ", parameter types = [" ); - if ( parameterTypes != null ) - { - if ( parameterTypes.length > 0 ) - { - result.append( parameterTypes[0].toString() ); - } - for ( int i = 1; i < parameterTypes.length; i++ ) - { - result.append( ", " ); - result.append( parameterTypes[i].toString() ); - } - } - result.append( "] ]" ); - return result.toString(); - } - - /** - * Returns the appropriate method for the specified class. - */ - public Method methodOnClass (Class aClass) - throws NoSuchMethodException - { - Object result = methodMap.objectForKey( aClass ); - - if ( result == null ) - { - result = getMethodForClass( aClass ); - if ( result == null ) - { - result = NOT_FOUND; - } - methodMap.setObjectForKey( result, aClass ); + + /** + * Constructor specifying a method name and an array of parameter types. + */ + public NSSelector(String aMethodName, Class[] aParameterTypeArray) { + methodName = aMethodName; + parameterTypes = aParameterTypeArray; + methodMap = new NSMutableDictionary(); + } + + /** + * Constructor specifying a method name with no parameters. + */ + public NSSelector(String aMethodName) { + this(aMethodName, EMPTY_CLASS_ARRAY); + } + + /** + * Constructor for custom subclasses that implement specific operators and that + * do not use dynamic method invocation. + */ + protected NSSelector() { + } + + /** + * Returns the name of the method. + */ + public String name() { + return methodName; + } + + /** + * Returns the array of parameter types. + */ + public Class[] parameterTypes() { + return parameterTypes; + } + + /** + * A String description of this selector. + */ + public String toString() { + StringBuffer result = new StringBuffer(); + result.append("[" + getClass().getName() + ": name = " + name() + ", parameter types = ["); + if (parameterTypes != null) { + if (parameterTypes.length > 0) { + result.append(parameterTypes[0].toString()); + } + for (int i = 1; i < parameterTypes.length; i++) { + result.append(", "); + result.append(parameterTypes[i].toString()); + } + } + result.append("] ]"); + return result.toString(); + } + + /** + * Returns the appropriate method for the specified class. + */ + public Method methodOnClass(Class aClass) throws NoSuchMethodException { + Object result = methodMap.objectForKey(aClass); + + if (result == null) { + result = getMethodForClass(aClass); + if (result == null) { + result = NOT_FOUND; + } + methodMap.setObjectForKey(result, aClass); } - - if ( result == NOT_FOUND ) - { + + if (result == NOT_FOUND) { throw new NoSuchMethodException(); } return (Method) result; } - - /** - * Returns the appropriate method, or null if not found. - */ - private Method getMethodForClass( Class aClass ) - { + + /** + * Returns the appropriate method, or null if not found. + */ + private Method getMethodForClass(Class aClass) { Method[] methods = aClass.getMethods(); - for ( int i = 0; i < methods.length; i++ ) - { - if ( methods[i].getName().equals( name() ) ) - { + for (int i = 0; i < methods.length; i++) { + if (methods[i].getName().equals(name())) { Class[] params = methods[i].getParameterTypes(); - if ( params.length == parameterTypes.length ) - { + if (params.length == parameterTypes.length) { boolean pass = true; - for ( int j = 0; j < params.length; j++ ) - { - if ( ! params[j].isAssignableFrom( parameterTypes[j] ) ) - { + for (int j = 0; j < params.length; j++) { + if (!params[j].isAssignableFrom(parameterTypes[j])) { pass = false; } - } - if ( pass ) return methods[i]; + } + if (pass) + return methods[i]; } } } return null; } - /** - * Convenience to get a method for an object. - */ - public Method methodOnObject (Object anObject) - throws NoSuchMethodException - { - Method m = methodOnClass( anObject.getClass() ); - if ( m == null ) throw new NoSuchMethodException( name() ); - return m; + /** + * Convenience to get a method for an object. + */ + public Method methodOnObject(Object anObject) throws NoSuchMethodException { + Method m = methodOnClass(anObject.getClass()); + if (m == null) + throw new NoSuchMethodException(name()); + return m; } - /** - * Returns whether the class implements the method for this selector. - */ - public boolean implementedByClass (Class aClass) - { - try - { - methodOnClass( aClass ); + /** + * Returns whether the class implements the method for this selector. + */ + public boolean implementedByClass(Class aClass) { + try { + methodOnClass(aClass); return true; - } - catch ( NoSuchMethodException exc ) - { - } - return false; - } - - /** - * Returns whether the object's class implements the method - * for this selector. - */ - public boolean implementedByObject (Object anObject) - { - try - { - methodOnObject( anObject ); + } catch (NoSuchMethodException exc) { + } + return false; + } + + /** + * Returns whether the object's class implements the method for this selector. + */ + public boolean implementedByObject(Object anObject) { + try { + methodOnObject(anObject); return true; - } - catch ( NoSuchMethodException exc ) - { - } - return false; - } - - /** - * Invokes this selector's method on the specified object - * using the specified parameters. - */ - public Object invoke (Object anObject, Object[] parameters) - throws IllegalAccessException, IllegalArgumentException, - InvocationTargetException, NoSuchMethodException - { - return methodOnObject( anObject ).invoke( anObject, parameters ); + } catch (NoSuchMethodException exc) { + } + return false; + } + + /** + * Invokes this selector's method on the specified object using the specified + * parameters. + */ + public Object invoke(Object anObject, Object[] parameters) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { + return methodOnObject(anObject).invoke(anObject, parameters); + } + + /** + * Invokes this selector's method on the specified object with no parameters. + */ + public Object invoke(Object anObject) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { + return invoke(anObject, EMPTY_OBJECT_ARRAY); + } + + /** + * Invokes this selector's method on the specified object with the specified + * parameter. + */ + public Object invoke(Object anObject, Object aParameter) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { + return invoke(anObject, new Object[] { aParameter }); } - /** - * Invokes this selector's method on the specified object - * with no parameters. - */ - public Object invoke (Object anObject) - throws IllegalAccessException, IllegalArgumentException, - InvocationTargetException, NoSuchMethodException - { - return invoke( anObject, EMPTY_OBJECT_ARRAY ); + /** + * Invokes this selector's method on the specified object using the specified + * two parameters. + */ + public Object invoke(Object anObject, Object p1, Object p2) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { + return invoke(anObject, new Object[] { p1, p2 }); + } + + /** + * Invokes the method with the specified signature on the specified object using + * the specified parameters. + */ + public static Object invoke(String methodName, Class[] parameterTypes, Object anObject, Object[] parameters) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { + return new NSSelector(methodName, parameterTypes).invoke(anObject, parameters); } - /** - * Invokes this selector's method on the specified object - * with the specified parameter. - */ - public Object invoke (Object anObject, Object aParameter) - throws IllegalAccessException, IllegalArgumentException, - InvocationTargetException, NoSuchMethodException - { - return invoke( anObject, new Object[] { aParameter } ); + /** + * Invokes the method with the specified signature on the specified object with + * no parameters. + */ + public static Object invoke(String methodName, Object anObject) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { + return NSSelector.invoke(methodName, EMPTY_CLASS_ARRAY, anObject, EMPTY_OBJECT_ARRAY); } - /** - * Invokes this selector's method on the specified object - * using the specified two parameters. - */ - public Object invoke (Object anObject, Object p1, Object p2) - throws IllegalAccessException, IllegalArgumentException, - InvocationTargetException, NoSuchMethodException - { - return invoke( anObject, new Object[] { p1, p2 } ); + /** + * Invokes the method with the specified signature on the specified object using + * the specified parameter. + */ + public static Object invoke(String methodName, Class[] parameterTypes, Object anObject, Object aParameter) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { + return NSSelector.invoke(methodName, parameterTypes, anObject, new Object[] { aParameter }); } - - /** - * Invokes the method with the specified signature on the specified - * object using the specified parameters. - */ - public static Object invoke - (String methodName, Class[] parameterTypes, Object anObject, Object[] parameters) - throws IllegalAccessException, IllegalArgumentException, - InvocationTargetException, NoSuchMethodException - { - return new NSSelector( methodName, parameterTypes ).invoke( anObject, parameters ); + + /** + * Invokes the method with the specified signature on the specified object using + * the specified two parameters. + */ + public static Object invoke(String methodName, Class[] parameterTypes, Object anObject, Object p1, Object p2) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { + return NSSelector.invoke(methodName, parameterTypes, anObject, new Object[] { p1, p2 }); } - /** - * Invokes the method with the specified signature on the specified object - * with no parameters. - */ - public static Object invoke - (String methodName, Object anObject) - throws IllegalAccessException, IllegalArgumentException, - InvocationTargetException, NoSuchMethodException - { - return NSSelector.invoke( - methodName, EMPTY_CLASS_ARRAY, anObject, EMPTY_OBJECT_ARRAY ); + // interface Comparator + + private Comparator comparator; + + /** + * Constructor specifying a method name and a comparator. This is not in the + * spec. + */ + public NSSelector(String aMethodName, Comparator aComparator) { + this(aMethodName, EMPTY_CLASS_ARRAY); + comparator = aComparator; } - /** - * Invokes the method with the specified signature on the specified - * object using the specified parameter. - */ - public static Object invoke - (String methodName, Class[] parameterTypes, - Object anObject, Object aParameter) - throws IllegalAccessException, IllegalArgumentException, - InvocationTargetException, NoSuchMethodException - { - return NSSelector.invoke( - methodName, parameterTypes, anObject, new Object[] { aParameter } ); + /** + * Returns the Comparator used for this selector. This is not in the spec. + */ + public Comparator comparator() { + if (comparator == null) { + comparator = new PropertyComparator(methodName); + } + return comparator; } - /** - * Invokes the method with the specified signature on the specified - * object using the specified two parameters. - */ - public static Object invoke - (String methodName, Class[] parameterTypes, - Object anObject, Object p1, Object p2) - throws IllegalAccessException, IllegalArgumentException, - InvocationTargetException, NoSuchMethodException - { - return NSSelector.invoke( - methodName, parameterTypes, anObject, new Object[] { p1, p2 } ); + public int compare(Object o1, Object o2) { + if (comparator == null) { + comparator = new PropertyComparator(methodName); + } + return comparator.compare(o1, o2); } - // interface Comparator - - private Comparator comparator; - - /** - * Constructor specifying a method name and a comparator. - * This is not in the spec. - */ - public NSSelector (String aMethodName, Comparator aComparator) - { - this( aMethodName, EMPTY_CLASS_ARRAY ); - comparator = aComparator; - } - - /** - * Returns the Comparator used for this selector. - * This is not in the spec. - */ - public Comparator comparator() - { - if ( comparator == null ) - { - comparator = new PropertyComparator( methodName ); - } - return comparator; - } - - public int compare(Object o1, Object o2) - { - if ( comparator == null ) - { - comparator = new PropertyComparator( methodName ); - } - return comparator.compare( o1, o2 ); - } - - public boolean equals(Object obj) - { - return ( obj == this ); - } + public boolean equals(Object obj) { + return (obj == this); + } } /* - * $Log$ - * Revision 1.1 2006/02/16 12:47:16 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.9 2003/02/12 19:34:35 mpowers - * Added accessor for comparator. + * Revision 1.9 2003/02/12 19:34:35 mpowers Added accessor for comparator. * - * Revision 1.8 2003/02/07 20:23:41 mpowers - * Provided backwards compatibility for comparators. + * Revision 1.8 2003/02/07 20:23:41 mpowers Provided backwards compatibility for + * comparators. * - * Revision 1.7 2003/01/22 23:02:25 mpowers - * Fixed a null pointer error in NSSelector.toString. + * Revision 1.7 2003/01/22 23:02:25 mpowers Fixed a null pointer error in + * NSSelector.toString. * - * Revision 1.6 2003/01/18 23:46:58 mpowers - * EOSortOrdering is now correctly using NSSelectors. + * Revision 1.6 2003/01/18 23:46:58 mpowers EOSortOrdering is now correctly + * using NSSelectors. * - * Revision 1.4 2001/10/31 15:24:45 mpowers - * Implicit constructor is now protected. + * Revision 1.4 2001/10/31 15:24:45 mpowers Implicit constructor is now + * protected. * - * Revision 1.3 2001/02/07 19:25:51 mpowers - * Fixed: method matching uses isAssignableFrom rather than ==. + * Revision 1.3 2001/02/07 19:25:51 mpowers Fixed: method matching uses + * isAssignableFrom rather than ==. * - * Revision 1.2 2001/01/08 23:30:16 mpowers - * Fixed major bug - selectors were not supposed to share a method map. + * Revision 1.2 2001/01/08 23:30:16 mpowers Fixed major bug - selectors were not + * supposed to share a method map. * - * Revision 1.1.1.1 2000/12/21 15:47:45 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:47:45 mpowers Contributing wotonomy. * - * Revision 1.3 2000/12/20 16:25:39 michael - * Added log to all files. + * Revision 1.3 2000/12/20 16:25:39 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSet.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSet.java index 5318fe8..38a7ec6 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSet.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSSet.java @@ -26,187 +26,154 @@ import java.util.Set; import java.util.Vector; /** -* A pure java implementation of NSSet that -* implements Set for greater java interoperability. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public class NSSet extends HashSet -{ - /** - * Default constructor. - */ - public NSSet () - { - super(); - } - - /** - * Constructs a NSSet containing the objects - * in the specified collection. - */ - public NSSet ( Collection aCollection ) - { - super( aCollection ); - } - - /** - * Constructs a NSSet containing only - * the specified object. - */ - public NSSet ( Object anObject ) - { - super(); - add( anObject ); - } - - /** - * Constructs a NSSet containing the objects - * in the specified array. - */ - public NSSet ( Object[] anObjectArray ) - { - super(); - for ( int i = 0; i < anObjectArray.length; i++ ) - { - add( anObjectArray[i] ); - } - } - - /** - * Returns an NSArray containing all objects in the set. - */ - public NSArray allObjects () - { - return new NSArray( this ); - } - - /** - * - */ - public Object anyObject () - { - throw new RuntimeException( "Not implemented yet." ); - } - - /** - * Returns whether this set contains the - * specified object. - */ - public boolean containsObject ( Object anObject ) - { - return contains( anObject ); - } - - /** - * Returns the number of elements in this set. - */ - public int count () - { - return size(); - } - - /** - * Returns whether this set has one or more - * elements in common with the specified set. - */ - public boolean intersectsSet ( Set aSet ) - { - Iterator it = aSet.iterator(); - while ( it.hasNext() ) - { - if ( this.containsObject( it.next() ) ) - { - return true; - } - } - return false; - - } - - /** - * Returns whether this set contains the - * same object as the specified set. - */ - public boolean isEqualToSet ( Set aSet ) - { - return equals( aSet ); - } - - /** - * Returns whether this set is a subset - * of the specified set. - */ - public boolean isSubsetOfSet ( Set aSet ) - { - return aSet.containsAll( this ); - } - - /** - * - */ - public Object member ( Object anObject ) - { - throw new RuntimeException( "Not implemented yet." ); - } - - /** - * Returns an enumerator over the objects - * in this set. - */ - public Enumeration objectEnumerator () - { - return new Vector( this ).elements(); - } - - /** - * Returns a set that is the intersection - * of this set and the specified set. - */ - public NSSet setByIntersectingSet ( Set aSet ) - { - NSSet result = new NSSet( this ); - result.retainAll( aSet ); - return result; - } - - /** - * Returns a set that contains all elements - * in this set that are not in the specified set. - */ - public NSSet setBySubtractingSet ( Set aSet ) - { - NSSet result = new NSSet( this ); - result.removeAll( aSet ); - return result; - } - - /** - * Returns a set that is the union - * of this set and the specified set. - */ - public NSSet setByUnioningSet ( Set aSet ) - { - NSSet result = new NSSet( this ); - result.addAll( aSet ); - return result; - } - + * A pure java implementation of NSSet that implements Set for greater java + * interoperability. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public class NSSet extends HashSet { + /** + * Default constructor. + */ + public NSSet() { + super(); + } + + /** + * Constructs a NSSet containing the objects in the specified collection. + */ + public NSSet(Collection aCollection) { + super(aCollection); + } + + /** + * Constructs a NSSet containing only the specified object. + */ + public NSSet(Object anObject) { + super(); + add(anObject); + } + + /** + * Constructs a NSSet containing the objects in the specified array. + */ + public NSSet(Object[] anObjectArray) { + super(); + for (int i = 0; i < anObjectArray.length; i++) { + add(anObjectArray[i]); + } + } + + /** + * Returns an NSArray containing all objects in the set. + */ + public NSArray allObjects() { + return new NSArray(this); + } + + /** + * + */ + public Object anyObject() { + throw new RuntimeException("Not implemented yet."); + } + + /** + * Returns whether this set contains the specified object. + */ + public boolean containsObject(Object anObject) { + return contains(anObject); + } + + /** + * Returns the number of elements in this set. + */ + public int count() { + return size(); + } + + /** + * Returns whether this set has one or more elements in common with the + * specified set. + */ + public boolean intersectsSet(Set aSet) { + Iterator it = aSet.iterator(); + while (it.hasNext()) { + if (this.containsObject(it.next())) { + return true; + } + } + return false; + + } + + /** + * Returns whether this set contains the same object as the specified set. + */ + public boolean isEqualToSet(Set aSet) { + return equals(aSet); + } + + /** + * Returns whether this set is a subset of the specified set. + */ + public boolean isSubsetOfSet(Set aSet) { + return aSet.containsAll(this); + } + + /** + * + */ + public Object member(Object anObject) { + throw new RuntimeException("Not implemented yet."); + } + + /** + * Returns an enumerator over the objects in this set. + */ + public Enumeration objectEnumerator() { + return new Vector(this).elements(); + } + + /** + * Returns a set that is the intersection of this set and the specified set. + */ + public NSSet setByIntersectingSet(Set aSet) { + NSSet result = new NSSet(this); + result.retainAll(aSet); + return result; + } + + /** + * Returns a set that contains all elements in this set that are not in the + * specified set. + */ + public NSSet setBySubtractingSet(Set aSet) { + NSSet result = new NSSet(this); + result.removeAll(aSet); + return result; + } + + /** + * Returns a set that is the union of this set and the specified set. + */ + public NSSet setByUnioningSet(Set aSet) { + NSSet result = new NSSet(this); + result.addAll(aSet); + return result; + } + } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.1.1.1 2000/12/21 15:47:45 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:47:45 mpowers Contributing wotonomy. * - * Revision 1.3 2000/12/20 16:25:39 michael - * Added log to all files. + * Revision 1.3 2000/12/20 16:25:39 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimeZone.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimeZone.java index 171e756..7c7b4da 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimeZone.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimeZone.java @@ -26,247 +26,245 @@ import java.io.Serializable; import java.util.Date; import java.util.Locale; import java.util.TimeZone; + /** -* A channel to the database, representing a communication -* stream within a context of an adaptor. -* -* @author cgruber@israfil.net -* @author $Author: cgruber $ -* @version $Revision: 892 $ -*/ + * A channel to the database, representing a communication stream within a + * context of an adaptor. + * + * @author cgruber@israfil.net + * @author $Author: cgruber $ + * @version $Revision: 892 $ + */ -public class NSTimeZone extends TimeZone - implements Cloneable, Serializable, NSCoding { - protected static class __NSTZPeriodComparator extends NSComparator { +public class NSTimeZone extends TimeZone implements Cloneable, Serializable, NSCoding { + protected static class __NSTZPeriodComparator extends NSComparator { - protected boolean _ascending = false; + protected boolean _ascending = false; - public int compare(Object obj, Object obj1) throws NSComparator.ComparisonException { + public int compare(Object obj, Object obj1) throws NSComparator.ComparisonException { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public __NSTZPeriodComparator() { + public __NSTZPeriodComparator() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public __NSTZPeriodComparator(boolean flag) { + public __NSTZPeriodComparator(boolean flag) { throw new UnsupportedOperationException("Not Yet Implemented"); - } - } + } + } - protected static class __NSTZPeriod { + protected static class __NSTZPeriod { - protected String _abbreviation = null; - protected int _isdst = 0; - protected int _offset = 0; - protected double _startTime = 0; + protected String _abbreviation = null; + protected int _isdst = 0; + protected int _offset = 0; + protected double _startTime = 0; - protected boolean before(__NSTZPeriod _p_nstzperiod) { + protected boolean before(__NSTZPeriod _p_nstzperiod) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - protected boolean equals(__NSTZPeriod _p_nstzperiod) { + protected boolean equals(__NSTZPeriod _p_nstzperiod) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - protected __NSTZPeriod() { + protected __NSTZPeriod() { throw new UnsupportedOperationException("Not Yet Implemented"); - } - } - + } + } - public static final String SystemTimeZoneDidChangeNotification = "NSSystemTimeZoneDidChangeNotification"; - protected NSData _data = null; - protected transient int _hashCode = 0; - protected transient boolean _initialized = false; - protected transient TimeZone _jdkTimeZone = null; - protected String _name = null; - protected transient int _rawOffset = 0; - protected transient NSMutableArray _timeZonePeriods = null; - protected transient int _timeZonePeriodsCount = 0; - protected transient boolean _useDaylightTime = false; + public static final String SystemTimeZoneDidChangeNotification = "NSSystemTimeZoneDidChangeNotification"; + protected NSData _data = null; + protected transient int _hashCode = 0; + protected transient boolean _initialized = false; + protected transient TimeZone _jdkTimeZone = null; + protected String _name = null; + protected transient int _rawOffset = 0; + protected transient NSMutableArray _timeZonePeriods = null; + protected transient int _timeZonePeriodsCount = 0; + protected transient boolean _useDaylightTime = false; - public NSTimeZone() { + public NSTimeZone() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - protected NSTimeZone(String s, NSData nsdata) { + protected NSTimeZone(String s, NSData nsdata) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public static NSDictionary abbreviationDictionary() { + public static NSDictionary abbreviationDictionary() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public Class classForCoder() { - return getClass(); - } + public Class classForCoder() { + return getClass(); + } - public Object clone() { + public Object clone() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public static Object decodeObject(NSCoder nscoder) { + public static Object decodeObject(NSCoder nscoder) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public void encodeWithCoder(NSCoder nscoder) { + public void encodeWithCoder(NSCoder nscoder) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public static synchronized NSTimeZone defaultTimeZone() { + public static synchronized NSTimeZone defaultTimeZone() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public static String[] getAvailableIDs() { + public static String[] getAvailableIDs() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public static TimeZone getDefault() { + public static TimeZone getDefault() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public static NSArray knownTimeZoneNames() { + public static NSArray knownTimeZoneNames() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public static NSTimeZone localTimeZone() { + public static NSTimeZone localTimeZone() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public static synchronized void resetSystemTimeZone() { + public static synchronized void resetSystemTimeZone() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public static synchronized void setDefault(TimeZone timezone) { + public static synchronized void setDefault(TimeZone timezone) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public static synchronized void setDefaultTimeZone(NSTimeZone nstimezone) { + public static synchronized void setDefaultTimeZone(NSTimeZone nstimezone) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public void setID(String s) { - throw new IllegalStateException(getClass().getName() + " is immutable."); - } + public void setID(String s) { + throw new IllegalStateException(getClass().getName() + " is immutable."); + } - public void setRawOffset(int i) { - throw new IllegalStateException(getClass().getName() + " is immutable."); - } + public void setRawOffset(int i) { + throw new IllegalStateException(getClass().getName() + " is immutable."); + } - public static synchronized NSTimeZone systemTimeZone() { + public static synchronized NSTimeZone systemTimeZone() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public static synchronized NSTimeZone timeZoneForSecondsFromGMT(int i) { + public static synchronized NSTimeZone timeZoneForSecondsFromGMT(int i) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public static synchronized NSTimeZone timeZoneWithName(String s, boolean flag) { + public static synchronized NSTimeZone timeZoneWithName(String s, boolean flag) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public static synchronized NSTimeZone timeZoneWithNameAndData(String s, NSData nsdata) { + public static synchronized NSTimeZone timeZoneWithNameAndData(String s, NSData nsdata) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public static NSTimeZone _nstimeZoneWithTimeZone(TimeZone timezone) { + public static NSTimeZone _nstimeZoneWithTimeZone(TimeZone timezone) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public String abbreviation() { + public String abbreviation() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public String abbreviationForTimestamp(NSTimestamp nstimestamp) { + public String abbreviationForTimestamp(NSTimestamp nstimestamp) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public NSData data() { + public NSData data() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public boolean equals(Object obj) { + public boolean equals(Object obj) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public String getDisplayName(boolean flag, int i, Locale locale) { + public String getDisplayName(boolean flag, int i, Locale locale) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public String getID() { + public String getID() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public int getOffset(int i, int j, int k, int l, int i1, int j1) { + public int getOffset(int i, int j, int k, int l, int i1, int j1) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public int getRawOffset() { + public int getRawOffset() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public synchronized int hashCode() { + public synchronized int hashCode() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public boolean hasSameRules(TimeZone timezone) { + public boolean hasSameRules(TimeZone timezone) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public boolean inDaylightTime(Date date) { + public boolean inDaylightTime(Date date) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public boolean isDaylightSavingTime() { + public boolean isDaylightSavingTime() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public boolean isDaylightSavingTimeForTimestamp(NSTimestamp nstimestamp) { + public boolean isDaylightSavingTimeForTimestamp(NSTimestamp nstimestamp) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public boolean isEqualToTimeZone(NSTimeZone nstimezone) { + public boolean isEqualToTimeZone(NSTimeZone nstimezone) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public String name() { + public String name() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public int secondsFromGMT() { + public int secondsFromGMT() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public int secondsFromGMTForTimestamp(NSTimestamp nstimestamp) { + public int secondsFromGMTForTimestamp(NSTimestamp nstimestamp) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public String toString() { + public String toString() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public boolean useDaylightTime() { + public boolean useDaylightTime() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - protected Object readResolve() throws ObjectStreamException { + protected Object readResolve() throws ObjectStreamException { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } } /* - * $Log$ - * Revision 1.1 2006/02/16 12:47:16 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.2 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.1 2002/07/14 21:56:16 mpowers - * Contributions from cgruber. + * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber. * - * Revision 1.1 2002/06/25 07:52:57 cgruber - * Add quite a few abstract classes, interfaces, and classes. All API consistent with WebObjects, but with no implementation, nor any private or package access members from the original. + * Revision 1.1 2002/06/25 07:52:57 cgruber Add quite a few abstract classes, + * interfaces, and classes. All API consistent with WebObjects, but with no + * implementation, nor any private or package access members from the original. * */ diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestamp.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestamp.java index bd246e0..03590f2 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestamp.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestamp.java @@ -26,260 +26,255 @@ import java.util.Date; import java.util.TimeZone; /** -* A channel to the database, representing a communication -* stream within a context of an adaptor. -* -* @author cgruber@israfil.net -* @author $Author: cgruber $ -* @version $Revision: 892 $ -*/ + * A channel to the database, representing a communication stream within a + * context of an adaptor. + * + * @author cgruber@israfil.net + * @author $Author: cgruber $ + * @version $Revision: 892 $ + */ -public class NSTimestamp extends Timestamp - implements NSCoding { +public class NSTimestamp extends Timestamp implements NSCoding { - public static class IntRef { + public static class IntRef { - public int value = 0; + public int value = 0; - public String toString() { - return getClass().getName() + " < value = " + value + " >"; - } + public String toString() { + return getClass().getName() + " < value = " + value + " >"; + } - public IntRef() { - } - } + public IntRef() { + } + } + public static final NSTimestamp DistantPast = new NSTimestamp(0xffffc77f2e9b6800L); + public static final NSTimestamp DistantFuture = new NSTimestamp(0x7fffffffffffffffL); - public static final NSTimestamp DistantPast = new NSTimestamp(0xffffc77f2e9b6800L); - public static final NSTimestamp DistantFuture = new NSTimestamp(0x7fffffffffffffffL); - public static long currentTimeIntervalSinceReferenceDate() { - return System.currentTimeMillis() / 1000L; - } + public static long currentTimeIntervalSinceReferenceDate() { + return System.currentTimeMillis() / 1000L; + } - public static NSTimestamp distantFuture() { - return DistantFuture; - } + public static NSTimestamp distantFuture() { + return DistantFuture; + } - public static NSTimestamp distantPast() { - return DistantPast; - } + public static NSTimestamp distantPast() { + return DistantPast; + } - public static long millisecondsToTimeInterval(long l) { - return l / 1000L; - } + public static long millisecondsToTimeInterval(long l) { + return l / 1000L; + } - public static long timeIntervalToMilliseconds(long l) { - return l * 1000L; - } + public static long timeIntervalToMilliseconds(long l) { + return l * 1000L; + } - public Class classForCoder() { - return getClass(); - } + public Class classForCoder() { + return getClass(); + } - public static Object decodeObject(NSCoder nscoder) { + public static Object decodeObject(NSCoder nscoder) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public void encodeWithCoder(NSCoder nscoder) { + public void encodeWithCoder(NSCoder nscoder) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public NSTimestamp() { - super(0); + public NSTimestamp() { + super(0); throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public NSTimestamp(long l) { - super(l); + public NSTimestamp(long l) { + super(l); throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public NSTimestamp(long l, int i) { - super(0); + public NSTimestamp(long l, int i) { + super(0); throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public NSTimestamp(long l, NSTimestamp nstimestamp) { - super(0); + public NSTimestamp(long l, NSTimestamp nstimestamp) { + super(0); throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public NSTimestamp(long l, TimeZone timezone) { - super(0); + public NSTimestamp(long l, TimeZone timezone) { + super(0); throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public NSTimestamp(long l, int i, TimeZone timezone) { - super(0); + public NSTimestamp(long l, int i, TimeZone timezone) { + super(0); throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public NSTimestamp(int i, int j, int k, int l, int i1, int j1, TimeZone timezone) { - super(0); + public NSTimestamp(int i, int j, int k, int l, int i1, int j1, TimeZone timezone) { + super(0); throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public NSTimestamp(Date date) { - super(0); + public NSTimestamp(Date date) { + super(0); throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public NSTimestamp(Timestamp timestamp) { - super(0); + public NSTimestamp(Timestamp timestamp) { + super(0); throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public NSTimestamp timestampByAddingGregorianUnits(int i, int j, int k, int l, int i1, int j1) { + public NSTimestamp timestampByAddingGregorianUnits(int i, int j, int k, int l, int i1, int j1) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public NSTimestamp timestampByAddingTimeInterval(long l) { + public NSTimestamp timestampByAddingTimeInterval(long l) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public long dayOfCommonEra() { + public long dayOfCommonEra() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public int dayOfMonth() { + public int dayOfMonth() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public int dayOfWeek() { + public int dayOfWeek() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public int dayOfYear() { + public int dayOfYear() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public int hourOfDay() { + public int hourOfDay() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public int microsecondOfSecond() { + public int microsecondOfSecond() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public int minuteOfHour() { + public int minuteOfHour() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public int monthOfYear() { + public int monthOfYear() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public int secondOfMinute() { + public int secondOfMinute() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public int yearOfCommonEra() { + public int yearOfCommonEra() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public void gregorianUnitsSinceTimestamp(IntRef intref, IntRef intref1, IntRef intref2, IntRef intref3, IntRef intref4, IntRef intref5, NSTimestamp nstimestamp) { + public void gregorianUnitsSinceTimestamp(IntRef intref, IntRef intref1, IntRef intref2, IntRef intref3, + IntRef intref4, IntRef intref5, NSTimestamp nstimestamp) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public long timeIntervalSinceTimestamp(NSTimestamp nstimestamp) { + public long timeIntervalSinceTimestamp(NSTimestamp nstimestamp) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public long timeIntervalSinceNow() { + public long timeIntervalSinceNow() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public long timeIntervalSinceReferenceDate() { + public long timeIntervalSinceReferenceDate() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public int compare(NSTimestamp nstimestamp) { + public int compare(NSTimestamp nstimestamp) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public NSTimestamp earlierTimestamp(NSTimestamp nstimestamp) { + public NSTimestamp earlierTimestamp(NSTimestamp nstimestamp) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public NSTimestamp laterTimestamp(NSTimestamp nstimestamp) { + public NSTimestamp laterTimestamp(NSTimestamp nstimestamp) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public String toString() { + public String toString() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public NSTimeZone timeZone() { + public NSTimeZone timeZone() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public long _getTimeInMillis() { + public long _getTimeInMillis() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public void setNanos(int i) { + public void setNanos(int i) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - /** @deprecated This method deprecated in parent java.util.Date */ - public void setDate(int i) { + /** @deprecated This method deprecated in parent java.util.Date */ + public void setDate(int i) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - /** @deprecated This method deprecated in parent java.util.Date */ - public void setHours(int i) { + /** @deprecated This method deprecated in parent java.util.Date */ + public void setHours(int i) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - /** @deprecated This method deprecated in parent java.util.Date */ - public void setMinutes(int i) { + /** @deprecated This method deprecated in parent java.util.Date */ + public void setMinutes(int i) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - /** @deprecated This method deprecated in parent java.util.Date */ - public void setMonth(int i) { + /** @deprecated This method deprecated in parent java.util.Date */ + public void setMonth(int i) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - /** @deprecated This method deprecated in parent java.util.Date */ - public void setSeconds(int i) { + /** @deprecated This method deprecated in parent java.util.Date */ + public void setSeconds(int i) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public void setTime(long l) { + public void setTime(long l) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - public long getTime() { + public long getTime() { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } - /** @deprecated This method deprecated in parent java.util.Date */ - public void setYear(int i) { + /** @deprecated This method deprecated in parent java.util.Date */ + public void setYear(int i) { throw new UnsupportedOperationException("Not Yet Implemented"); - } + } } /* - * $Log$ - * Revision 1.1 2006/02/16 12:47:16 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.1 2006/02/16 12:47:16 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.2 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.1 2002/07/14 21:56:16 mpowers - * Contributions from cgruber. + * Revision 1.1 2002/07/14 21:56:16 mpowers Contributions from cgruber. * - * Revision 1.3 2002/06/25 19:06:13 cgruber - * Comment fix. + * Revision 1.3 2002/06/25 19:06:13 cgruber Comment fix. * - * Revision 1.2 2002/06/25 19:05:27 cgruber - * Add deprecation statements to remove warnings - * about java.util.Date's deprecated APIs. + * Revision 1.2 2002/06/25 19:05:27 cgruber Add deprecation statements to remove + * warnings about java.util.Date's deprecated APIs. * - * Revision 1.1 2002/06/25 07:52:56 cgruber - * Add quite a few abstract classes, interfaces, and classes. All - * API consistent with WebObjects, but with no implementation, nor - * any private or package access members from the original. + * Revision 1.1 2002/06/25 07:52:56 cgruber Add quite a few abstract classes, + * interfaces, and classes. All API consistent with WebObjects, but with no + * implementation, nor any private or package access members from the original. * */ diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestampFormatter.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestampFormatter.java index ecc67ca..c8fbc44 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestampFormatter.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSTimestampFormatter.java @@ -25,41 +25,34 @@ import java.text.DateFormatSymbols; import java.text.SimpleDateFormat; /** -* A Format that accepts C-style date formatting syntax. -* Not currently implemented, included for compile compatibility. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ + * A Format that accepts C-style date formatting syntax. Not currently + * implemented, included for compile compatibility. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ + +public class NSTimestampFormatter extends SimpleDateFormat { + public NSTimestampFormatter() { + super(); + } + + public NSTimestampFormatter(String aPattern) { + super(aPattern); + } -public class NSTimestampFormatter extends SimpleDateFormat -{ - public NSTimestampFormatter() - { - super(); - } - - public NSTimestampFormatter(String aPattern) - { - super( aPattern ); - } + public NSTimestampFormatter(String aPattern, DateFormatSymbols symbols) { + super(aPattern, symbols); + } - public NSTimestampFormatter(String aPattern, - DateFormatSymbols symbols) - { - super( aPattern, symbols ); - } - } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.1 2003/01/17 14:40:51 mpowers - * Adding files to fix build. + * Revision 1.1 2003/01/17 14:40:51 mpowers Adding files to fix build. * * */ diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Duplicator.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Duplicator.java index ddf347d..16ef393 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Duplicator.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Duplicator.java @@ -26,274 +26,219 @@ import java.io.*; import java.util.*; //collections /** -* Duplicator makes use of Introspector to duplicate objects, -* either by shallow copy, deep copy, or by copying properties -* from one object to apply to another object. You may find this -* class useful because java.lang.Object.clone() only supports -* shallow copying. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 895 $ -*/ + * Duplicator makes use of Introspector to duplicate objects, either by shallow + * copy, deep copy, or by copying properties from one object to apply to another + * object. You may find this class useful because java.lang.Object.clone() only + * supports shallow copying. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 895 $ + */ + +public class Duplicator { + /** + * Used to represent null values for properties in the maps returned by + * readProperties and cloneProperties and in the parameter to writeProperties. + * This actually references the NSNull instance. + */ + public static final Object NULL = NSNull.nullValue(); + private static NSSelector clone = new NSSelector("clone"); + + /** + * Returns a list of properties for the specified class that are both readable + * and writable. + */ + static public List editablePropertiesForObject(Object anObject) { + List readProperties = new ArrayList(); + String[] read = Introspector.getReadPropertiesForObject(anObject); + for (int i = 0; i < read.length; i++) { + readProperties.add(read[i]); + } + + List properties = new ArrayList(); + String[] write = Introspector.getWritePropertiesForObject(anObject); + for (int i = 0; i < write.length; i++) { + properties.add(write[i]); + } + + // only use properties on both lists: read/write + properties.retainAll(readProperties); + + return properties; + } -public class Duplicator -{ - /** - * Used to represent null values for properties in the - * maps returned by readProperties and cloneProperties - * and in the parameter to writeProperties. - * This actually references the NSNull instance. - */ - public static final Object NULL = NSNull.nullValue(); - private static NSSelector clone = new NSSelector( "clone" ); + /** + * Returns a Map containing only the mutable properties for the specified object + * and their values. Any null values for properties will be represented with the + * NULL object. + */ + static public Map readPropertiesForObject(Object anObject) { + NSMutableDictionary result = new NSMutableDictionary(); - /** - * Returns a list of properties for the specified class - * that are both readable and writable. - */ - static public List editablePropertiesForObject( - Object anObject ) - { - List readProperties = new ArrayList(); - String[] read = Introspector.getReadPropertiesForObject( anObject ); - for ( int i = 0; i < read.length; i++ ) - { - readProperties.add( read[i] ); - } + String key; + Object value; + Iterator it = editablePropertiesForObject(anObject).iterator(); + while (it.hasNext()) { + key = it.next().toString(); + value = Introspector.get(anObject, key); + if (value == null) + value = NULL; + result.setObjectForKey(value, key); + } + return result; + } - List properties = new ArrayList(); - String[] write = Introspector.getWritePropertiesForObject( anObject ); - for ( int i = 0; i < write.length; i++ ) - { - properties.add( write[i] ); - } - - // only use properties on both lists: read/write - properties.retainAll( readProperties ); + /** + * Returns a Map containing only the mutable properties for the specified object + * and deep clones of their values. Nulls are represented by the NULL object. + */ + static public Map clonePropertiesForObject(Object anObject) { + Object key, value; + Map result = readPropertiesForObject(anObject); + Iterator it = result.keySet().iterator(); + while (it.hasNext()) { + key = it.next(); + value = result.get(key); + value = deepClone(value); + result.put(key, value); + } + return result; + } - return properties; - } - - /** - * Returns a Map containing only the mutable properties - * for the specified object and their values. - * Any null values for properties will be represented with - * the NULL object. - */ - static public Map readPropertiesForObject( - Object anObject ) - { - NSMutableDictionary result = new NSMutableDictionary(); - - String key; - Object value; - Iterator it = editablePropertiesForObject( anObject ).iterator(); - while ( it.hasNext() ) - { - key = it.next().toString(); - value = Introspector.get( anObject, key ); - if ( value == null ) value = NULL; - result.setObjectForKey( value, key ); - } - return result; - } - - /** - * Returns a Map containing only the mutable properties - * for the specified object and deep clones of their values. - * Nulls are represented by the NULL object. - */ - static public Map clonePropertiesForObject( - Object anObject ) - { - Object key, value; - Map result = readPropertiesForObject( anObject ); - Iterator it = result.keySet().iterator(); - while ( it.hasNext() ) - { - key = it.next(); - value = result.get( key ); - value = deepClone( value ); - result.put( key, value ); - } - return result; - } - - /** - * Applies the map of properties and values to the - * specified object. Null values for properties must - * be represented by the NULL object. - */ - static public void writePropertiesForObject( - Map aMap, Object anObject ) - { - String key; - Object value; - Iterator it = aMap.keySet().iterator(); - while ( it.hasNext() ) - { - key = it.next().toString(); - value = aMap.get( key ); - if ( NULL.equals( value ) ) value = null; - Introspector.set( anObject, key, value ); - } - } - - /** - * Creates a new copy of the specified object. - * This implementation tries to call clone(), - * and failing that, calls newInstance - * and then calls copy() to transfer the values. - * @throws WotonomyException if any operation fails. - */ - static public Object clone( - Object aSource ) - { - Object result = null; - if ( clone.implementedByObject( aSource ) ) - { - try - { - result = clone.invoke( aSource ); - return result; - } - catch ( Exception exc ) - { - // fall back on newInstance() - } - } - - Class c = aSource.getClass(); - try - { - result = c.newInstance(); - } - catch ( Exception exc ) - { - throw new WotonomyException( exc ); - } - return copy( aSource, result ); - } + /** + * Applies the map of properties and values to the specified object. Null values + * for properties must be represented by the NULL object. + */ + static public void writePropertiesForObject(Map aMap, Object anObject) { + String key; + Object value; + Iterator it = aMap.keySet().iterator(); + while (it.hasNext()) { + key = it.next().toString(); + value = aMap.get(key); + if (NULL.equals(value)) + value = null; + Introspector.set(anObject, key, value); + } + } - /** - * Creates a deep copy of the specified object. - * Every object in this objects graph will be - * duplicated with new instances. - * @throws WotonomyException if any operation fails. - */ - static public Object deepClone( - Object aSource ) - { - // the only known way to deep copy in - // java without native code is serialization - - try - { - ByteArrayOutputStream byteOutput = - new ByteArrayOutputStream(); - ObjectOutputStream objectOutput = - new ObjectOutputStream( byteOutput ); - - objectOutput.writeObject( aSource ); - objectOutput.flush(); - objectOutput.close(); - - ByteArrayInputStream byteInput = - new ByteArrayInputStream( byteOutput.toByteArray() ); - ObjectInputStream objectInput = - new ObjectInputStream( byteInput ); - return objectInput.readObject(); - } - catch ( Exception exc ) - { - throw new WotonomyException( "Error cloning object: " + aSource, exc ); - } - } + /** + * Creates a new copy of the specified object. This implementation tries to call + * clone(), and failing that, calls newInstance and then calls copy() to + * transfer the values. + * + * @throws WotonomyException if any operation fails. + */ + static public Object clone(Object aSource) { + Object result = null; + if (clone.implementedByObject(aSource)) { + try { + result = clone.invoke(aSource); + return result; + } catch (Exception exc) { + // fall back on newInstance() + } + } - /** - * Copies values from one object to another. - * Returns the destination object. - * @throws WotonomyException if any operation fails. - */ - static public Object copy( - Object aSource, Object aDestination ) - { - try - { - writePropertiesForObject( - readPropertiesForObject( aSource ), aDestination ); - } - catch ( RuntimeException exc ) - { - throw new WotonomyException( exc ); - } - return aDestination; - } - - /** - * Deeply clones the values from one object and applies them - * to another object. - * Returns the destination object. - * @throws WotonomyException if any operation fails. - */ - static public Object deepCopy( - Object aSource, Object aDestination ) - { - try - { - writePropertiesForObject( - clonePropertiesForObject( aSource ), aDestination ); - } - catch ( RuntimeException exc ) - { - throw new WotonomyException( exc ); - } - return aDestination; - } + Class c = aSource.getClass(); + try { + result = c.newInstance(); + } catch (Exception exc) { + throw new WotonomyException(exc); + } + return copy(aSource, result); + } + + /** + * Creates a deep copy of the specified object. Every object in this objects + * graph will be duplicated with new instances. + * + * @throws WotonomyException if any operation fails. + */ + static public Object deepClone(Object aSource) { + // the only known way to deep copy in + // java without native code is serialization + + try { + ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(); + ObjectOutputStream objectOutput = new ObjectOutputStream(byteOutput); + + objectOutput.writeObject(aSource); + objectOutput.flush(); + objectOutput.close(); + + ByteArrayInputStream byteInput = new ByteArrayInputStream(byteOutput.toByteArray()); + ObjectInputStream objectInput = new ObjectInputStream(byteInput); + return objectInput.readObject(); + } catch (Exception exc) { + throw new WotonomyException("Error cloning object: " + aSource, exc); + } + } + + /** + * Copies values from one object to another. Returns the destination object. + * + * @throws WotonomyException if any operation fails. + */ + static public Object copy(Object aSource, Object aDestination) { + try { + writePropertiesForObject(readPropertiesForObject(aSource), aDestination); + } catch (RuntimeException exc) { + throw new WotonomyException(exc); + } + return aDestination; + } + + /** + * Deeply clones the values from one object and applies them to another object. + * Returns the destination object. + * + * @throws WotonomyException if any operation fails. + */ + static public Object deepCopy(Object aSource, Object aDestination) { + try { + writePropertiesForObject(clonePropertiesForObject(aSource), aDestination); + } catch (RuntimeException exc) { + throw new WotonomyException(exc); + } + return aDestination; + } } /* - * $Log$ - * Revision 1.1 2006/02/16 16:52:12 cgruber - * Add cvsignore crap to find off checking in binary crap. + * $Log$ Revision 1.1 2006/02/16 16:52:12 cgruber Add cvsignore crap to find off + * checking in binary crap. * - * Revision 1.1 2006/02/16 13:22:22 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.11 2001/08/22 19:24:26 mpowers - * Providing a more helpful error message for cloning exceptions. + * Revision 1.11 2001/08/22 19:24:26 mpowers Providing a more helpful error + * message for cloning exceptions. * - * Revision 1.10 2001/03/29 03:30:36 mpowers - * Refactored duplicator a bit. + * Revision 1.10 2001/03/29 03:30:36 mpowers Refactored duplicator a bit. * Disabled MissingPropertyExceptions for now. * - * Revision 1.9 2001/03/28 14:11:23 mpowers - * Removed debugging printlns. + * Revision 1.9 2001/03/28 14:11:23 mpowers Removed debugging printlns. * - * Revision 1.8 2001/03/27 23:25:48 mpowers - * Basically reverting to the previous version. + * Revision 1.8 2001/03/27 23:25:48 mpowers Basically reverting to the previous + * version. * - * Revision 1.7 2001/03/06 23:18:13 mpowers - * Clarified some comments. + * Revision 1.7 2001/03/06 23:18:13 mpowers Clarified some comments. * - * Revision 1.6 2001/03/01 20:36:35 mpowers - * Better error handling and better handling of nulls. + * Revision 1.6 2001/03/01 20:36:35 mpowers Better error handling and better + * handling of nulls. * - * Revision 1.5 2001/02/27 21:43:40 mpowers - * Removed NullMarker class in favor of NSNull. + * Revision 1.5 2001/02/27 21:43:40 mpowers Removed NullMarker class in favor of + * NSNull. * - * Revision 1.4 2001/02/26 22:41:51 mpowers - * Implemented null placeholder classes. - * Duplicator now uses NSNull. - * No longer catching base exception class. + * Revision 1.4 2001/02/26 22:41:51 mpowers Implemented null placeholder + * classes. Duplicator now uses NSNull. No longer catching base exception class. * - * Revision 1.3 2001/02/23 21:07:46 mpowers - * Documented the NULL object. + * Revision 1.3 2001/02/23 21:07:46 mpowers Documented the NULL object. * - * Revision 1.1 2001/02/16 22:51:29 mpowers - * Now deep-cloning objects passed between editing contexts. + * Revision 1.1 2001/02/16 22:51:29 mpowers Now deep-cloning objects passed + * between editing contexts. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Introspector.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Introspector.java index 2b313d0..09687e2 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Introspector.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/Introspector.java @@ -30,912 +30,750 @@ import java.util.Map; import java.util.Set; /** -* This Introspector is a static utility class written to work -* around limitations in PropertyDescriptor and Introspector.<br><br> -* -* Of particular note are the get() and set() methods, which will attempt -* to get and set artibrary values on arbitrary objects to the best of its -* ability, converting values as appropriate. Properties of the form -* "property.nestedproperty.anotherproperty" are supported to get and set -* values on property values directly.<br><br> -* -* Note that for naming getter methods, this class supports "get", "is", -* and also the property name itself, which supports NeXT-style properties. -* Introspector supports Maps by treating the keys a property names, -* supports Lists by treating the indexes as property names. <br><br> -* -* Numeric and boolean types can be inverted by prepending a "!" before -* the name of the property, like "manager.!active" or "task.!lag". -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ + * This Introspector is a static utility class written to work around + * limitations in PropertyDescriptor and Introspector.<br> + * <br> + * + * Of particular note are the get() and set() methods, which will attempt to get + * and set artibrary values on arbitrary objects to the best of its ability, + * converting values as appropriate. Properties of the form + * "property.nestedproperty.anotherproperty" are supported to get and set values + * on property values directly.<br> + * <br> + * + * Note that for naming getter methods, this class supports "get", "is", and + * also the property name itself, which supports NeXT-style properties. + * Introspector supports Maps by treating the keys a property names, supports + * Lists by treating the indexes as property names. <br> + * <br> + * + * Numeric and boolean types can be inverted by prepending a "!" before the name + * of the property, like "manager.!active" or "task.!lag". + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ + +public class Introspector { + // allows "hasProperty" or "property" forms + public static boolean strict = false; -public class Introspector -{ - // allows "hasProperty" or "property" forms - public static boolean strict = false; - // print exception stack traces private static boolean debug = true; - + // path separator public static final String SEPARATOR = "."; - // method cache - use hashtables for thread safety - private static Map getterMethods = new Hashtable(); - private static Map setterMethods = new Hashtable(); - - // wildcard value - using this class to represent a "wildcard" generic class. - // we have to do this when matching methods by parameter types and a - // null value is passed in - can't tell what class the null should be. - public static Class WILD = Introspector.class; - - // empty class array - prevents having to create one every time - private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; - - // use OGNL for property access - private static boolean useOGNL; - - static - { - try - { - useOGNL = ( Class.forName( "ognl.Ognl" ) != null ); - } - catch ( ClassNotFoundException t ) - { - useOGNL = false; - } - } + // method cache - use hashtables for thread safety + private static Map getterMethods = new Hashtable(); + private static Map setterMethods = new Hashtable(); -/** -* Utility method to get the read method for a property belonging to a class. -* Will search for methods in the form of "getProperty" and failing that -* "isProperty" (to handle booleans). -* @param objectClass the class whose property methods will be retrieved. -* @param aProperty The property whose method will be retrieved. -* @param paramTypes An array of class objects representing the types of parameters. -* @return The appropriate method for the class, or null if not found. -*/ - static public Method getPropertyReadMethod( - Class objectClass, String aProperty, Class[] paramTypes ) - { - Method result = null; - - result = getMethodFromClass( objectClass, aProperty, paramTypes, true ); + // wildcard value - using this class to represent a "wildcard" generic class. + // we have to do this when matching methods by parameter types and a + // null value is passed in - can't tell what class the null should be. + public static Class WILD = Introspector.class; - return result; - } + // empty class array - prevents having to create one every time + private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; -/** -* Utility method to get the write method for a property belonging to a class. -* Will search for methods in the form of "setProperty". -* @param objectClass the class whose property methods will be retrieved. -* @param aProperty The property whose method will be retrieved. -* @param paramTypes An array of class objects representing the types of parameters. -* @return The appropriate method for the class, or null if not found. -*/ - static public Method getPropertyWriteMethod( - Class objectClass, String aProperty, Class[] paramTypes ) - { - Method result = null; - - result = getMethodFromClass( objectClass, aProperty, paramTypes, false ); + // use OGNL for property access + private static boolean useOGNL; - return result; - } + static { + try { + useOGNL = (Class.forName("ognl.Ognl") != null); + } catch (ClassNotFoundException t) { + useOGNL = false; + } + } -/** -* Gets a named method from a class. Using this method is preferred because -* the results are cached and should be faster than calling Class.getMethod(). -* Note that if an object has a "get" getter method and an "is" getter method -* with the same signature defined for a given property. The "get" method -* is called. -* @param objectClass the Class whose property methods will be retrieved. -* @param aMethodName A String containing the name of the desired method. -* @param paramTypes An array of class objects representing the types of parameters. -* @return The appropriate Method from the Class, or null if not found. -*/ - static private Method getMethodFromClass( - Class objectClass, String aProperty, Class[] paramTypes, boolean doGetter) - { // System.out.print( "Introspector.getMethodFromClass: " + aMethodName + " : " ); - - Map classesToMethods = (doGetter ? - getterMethods : - setterMethods); - - Map allMethods = (Map) classesToMethods.get( objectClass ); - if (allMethods == null) - { - // need to build maps for this class - mapPropertiesForClass( objectClass ); - // now the map should exist - allMethods = (Map) classesToMethods.get( objectClass ); - } - - Method[] methods = (Method[]) allMethods.get( aProperty ); - if ( methods == null ) - { - return null; // property doesn't exist - } - - methods_loop: // walks through all methods for name - for ( int i = 0; i < methods.length; i++ ) - { - Class[] types = methods[i].getParameterTypes(); - - // if parameter lengths don't match - if ( types.length != paramTypes.length ) - { - // System.out.println( aMethodName + " : " + types.length + " != " + paramTypes.length ); - continue methods_loop; // continue with outer loop - } - - // match up each parameter - for ( int j = 0; j < types.length; j++ ) - { - // convert primitives so they'll match - ugly - // (would have thought isAssignableFrom() would catch this) - if ( types[j].isPrimitive() ) - { - if ( types[j] == Boolean.TYPE ) - { - types[j] = Boolean.class; - } - else - if ( types[j] == Character.TYPE ) - { - types[j] = Character.class; - } - else - if ( types[j] == Byte.TYPE ) - { - types[j] = Byte.class; - } - else - if ( types[j] == Short.TYPE ) - { - types[j] = Short.class; - } - else - if ( types[j] == Integer.TYPE ) - { - types[j] = Integer.class; - } - else - if ( types[j] == Long.TYPE ) - { - types[j] = Long.class; - } - else - if ( types[j] == Float.TYPE ) - { - types[j] = Float.class; - } - else - if ( types[j] == Double.TYPE ) - { - types[j] = Double.class; - } - } - - // if parameters don't match - if ( ( paramTypes[j] != WILD ) && ( ! types[j].isAssignableFrom( paramTypes[j] ) ) ) - { + /** + * Utility method to get the read method for a property belonging to a class. + * Will search for methods in the form of "getProperty" and failing that + * "isProperty" (to handle booleans). + * + * @param objectClass the class whose property methods will be retrieved. + * @param aProperty The property whose method will be retrieved. + * @param paramTypes An array of class objects representing the types of + * parameters. + * @return The appropriate method for the class, or null if not found. + */ + static public Method getPropertyReadMethod(Class objectClass, String aProperty, Class[] paramTypes) { + Method result = null; + + result = getMethodFromClass(objectClass, aProperty, paramTypes, true); + + return result; + } + + /** + * Utility method to get the write method for a property belonging to a class. + * Will search for methods in the form of "setProperty". + * + * @param objectClass the class whose property methods will be retrieved. + * @param aProperty The property whose method will be retrieved. + * @param paramTypes An array of class objects representing the types of + * parameters. + * @return The appropriate method for the class, or null if not found. + */ + static public Method getPropertyWriteMethod(Class objectClass, String aProperty, Class[] paramTypes) { + Method result = null; + + result = getMethodFromClass(objectClass, aProperty, paramTypes, false); + + return result; + } + + /** + * Gets a named method from a class. Using this method is preferred because the + * results are cached and should be faster than calling Class.getMethod(). Note + * that if an object has a "get" getter method and an "is" getter method with + * the same signature defined for a given property. The "get" method is called. + * + * @param objectClass the Class whose property methods will be retrieved. + * @param aMethodName A String containing the name of the desired method. + * @param paramTypes An array of class objects representing the types of + * parameters. + * @return The appropriate Method from the Class, or null if not found. + */ + static private Method getMethodFromClass(Class objectClass, String aProperty, Class[] paramTypes, + boolean doGetter) { // System.out.print( "Introspector.getMethodFromClass: " + aMethodName + " : " + // ); + + Map classesToMethods = (doGetter ? getterMethods : setterMethods); + + Map allMethods = (Map) classesToMethods.get(objectClass); + if (allMethods == null) { + // need to build maps for this class + mapPropertiesForClass(objectClass); + // now the map should exist + allMethods = (Map) classesToMethods.get(objectClass); + } + + Method[] methods = (Method[]) allMethods.get(aProperty); + if (methods == null) { + return null; // property doesn't exist + } + + methods_loop: // walks through all methods for name + for (int i = 0; i < methods.length; i++) { + Class[] types = methods[i].getParameterTypes(); + + // if parameter lengths don't match + if (types.length != paramTypes.length) { + // System.out.println( aMethodName + " : " + types.length + " != " + + // paramTypes.length ); + continue methods_loop; // continue with outer loop + } + + // match up each parameter + for (int j = 0; j < types.length; j++) { + // convert primitives so they'll match - ugly + // (would have thought isAssignableFrom() would catch this) + if (types[j].isPrimitive()) { + if (types[j] == Boolean.TYPE) { + types[j] = Boolean.class; + } else if (types[j] == Character.TYPE) { + types[j] = Character.class; + } else if (types[j] == Byte.TYPE) { + types[j] = Byte.class; + } else if (types[j] == Short.TYPE) { + types[j] = Short.class; + } else if (types[j] == Integer.TYPE) { + types[j] = Integer.class; + } else if (types[j] == Long.TYPE) { + types[j] = Long.class; + } else if (types[j] == Float.TYPE) { + types[j] = Float.class; + } else if (types[j] == Double.TYPE) { + types[j] = Double.class; + } + } + + // if parameters don't match + if ((paramTypes[j] != WILD) && (!types[j].isAssignableFrom(paramTypes[j]))) { // System.out.println( "Introspector.getMethodFromClass: " + // aProperty + " : " + types[j] + " != " + paramTypes[j] ); - continue methods_loop; // continue with outer loop - } - } - - // all params match - return methods[i]; - } - - // no match - return null; - } - - static private final Method[] getAllMethodsForClass( Class aClass ) - { - Method[] local = aClass.getDeclaredMethods(); // only local - Method[] all = aClass.getMethods(); // all public - Method[] result = new Method[ local.length + all.length ]; - System.arraycopy( local, 0, result, 0, local.length ); - System.arraycopy( all, 0, result, local.length, all.length ); - return result; - } - - /** - * Generates a map of properties to both getter or setter methods for the given class. - * Then assigned those maps into the appropriate getterMethods and setterMethods maps - * keyed by the specified class. Even on error, this method will at least place empty - * property maps into each of the methods maps. - */ - static private void mapPropertiesForClass( Class objectClass ) - { - try - { - Map readProperties = new HashMap(); - getterMethods.put( objectClass, readProperties ); - Map writeProperties = new HashMap(); - setterMethods.put( objectClass, writeProperties ); - - String name, property; - Method[] methods = getAllMethodsForClass( objectClass ); // throws SecurityException - for ( int i = 0; i < methods.length; i++ ) - { - name = methods[i].getName(); - methods[i].setAccessible( true ); // throws SecurityException - if ( name.startsWith( "set" ) ) - { - name = name.substring( 3 ); - if ( ! "".equals( name ) ) // excludes "set()" - { - putMethodIntoPropertyMap( name, methods[i], writeProperties ); - } - } - else - if ( methods[i].getReturnType() != void.class ) - { - String fullname = name; - if ( name.startsWith( "get" ) ) - { - name = name.substring( 3 ); - } - else - if ( name.startsWith( "is" ) ) - { - name = name.substring( 2 ); - } - else - if ( name.startsWith( "has" ) && ( !strict ) ) // what about hashCode()? - { - name = name.substring( 3 ); - } - - if ( ! "".equals( name ) && ( !strict ) ) // excludes "get()", "has()", and "is()" - { - putMethodIntoPropertyMap( name, methods[i], readProperties ); - if ( fullname != name ) - { // allows us to match properties that include the get/set prefix as well - putMethodIntoPropertyMap( fullname, methods[i], readProperties ); - } - } - } - } - } - catch ( SecurityException se ) - { - System.out.println( "Introspector.getMethodFromClass: " + se ); - // this class will show up with empty getter/setter maps - } - } - - /** - * Places a property-method pair into one of the properties maps. - * This in effect maps a property to an array of methods. - */ - private static void putMethodIntoPropertyMap( String aProperty, Method aMethod, Map aMap ) - { - // ensure first character is lower case - StringBuffer buffer = new StringBuffer( aProperty ); - buffer.setCharAt(0, Character.toLowerCase(buffer.charAt(0))); - String key = buffer.toString(); - - // build array of methods for property - Method[] result = (Method[]) aMap.get( key ); - if ( result == null ) - { - result = new Method[] { aMethod }; - } - else - { - // create new array that's larger by one and copy - int i; - Method[] enlarged = new Method[ result.length + 1 ]; - for ( i = 0; i < result.length; i ++ ) - { - enlarged[i] = result[i]; - } - // add the new method to end - enlarged[i] = aMethod; - result = enlarged; - } - aMap.put( key, result ); - } + continue methods_loop; // continue with outer loop + } + } -/** -* Utility method to get a method for a property belonging to a class. -* Use this if you don't feel like making the Class array from the parameters -* you will be using - pass in the parameters themselves. -* @param objectClass the Class whose property methods will be retrieved. -* @param aProperty The property whose method will be retrieved. -* @param params An array of parameters to be used. -* @return The appropriate method for the class, or null if not found. -*/ - static public Method getPropertyReadMethod( - Class objectClass, String aProperty, Object[] params ) - { - // optimization: avoid allocating class array for common case - if ( params.length == 0 ) - { - return getPropertyReadMethod( - objectClass, aProperty, EMPTY_CLASS_ARRAY ); - } - - Class[] paramList = new Class[ params.length ]; - for ( int i = 0; i < params.length; i++ ) - { - if ( params[i] != null ) - { - paramList[i] = params[i].getClass(); - } - else - { - paramList[i] = WILD; - } - } - return getPropertyReadMethod( objectClass, aProperty, paramList ); - } + // all params match + return methods[i]; + } -/** -* Utility method to get a method for a property belonging to a class. -* Use this if you don't feel like making the Class array from the parameters -* you will be using - pass in the parameters themselves. -* @param objectClass the Class whose property methods will be retrieved. -* @param aProperty The property whose method will be retrieved. -* @param params An array of parameters to be used. -* @return The appropriate method for the class, or null if not found. -*/ - static public Method getPropertyWriteMethod( - Class objectClass, String aProperty, Object[] params ) - { - Class[] paramList = new Class[ params.length ]; - for ( int i = 0; i < params.length; i++ ) - { - if ( params[i] != null ) - { - paramList[i] = params[i].getClass(); - } - else - { - paramList[i] = WILD; - } - } - return getPropertyWriteMethod( objectClass, aProperty, paramList ); - } - - /** - * Gets a list of the readable properties for the given class. - * Note that readable properties may not be writable - see getWriteProperties(). - * @return An array of property names in no particular order - * where each name is a string with the first character in lower case. - */ - public static String[] getReadPropertiesForClass( Class objectClass ) - { - Map properties = (Map) getterMethods.get( objectClass ); - if ( properties == null ) - { - // need to build maps for this class - mapPropertiesForClass( objectClass ); - // now the map should exist - properties = (Map) getterMethods.get( objectClass ); - } - - // put property names into string array - Set keys = properties.keySet(); - Iterator it = keys.iterator(); - int len = keys.size(); - String[] result = new String[ len ]; - for ( int i = 0; i < len; i++ ) - { - result[i] = (String) it.next(); - } - return result; - } - - /** - * Gets a list of the writable properties for the given class. - * Note that writable properties may not be writable - see getReadProperties(). - * @return An array of property names in no particular order - * where each name is a string with the first character in lower case. - */ - public static String[] getWritePropertiesForClass( Class objectClass ) - { - Map properties = (Map) setterMethods.get( objectClass ); - if ( properties == null ) - { - // need to build maps for this class - mapPropertiesForClass( objectClass ); - // now the map should exist - properties = (Map) setterMethods.get( objectClass ); - } - - // put property names into string array - Set keys = properties.keySet(); - Iterator it = keys.iterator(); - int len = keys.size(); - String[] result = new String[ len ]; - for ( int i = 0; i < len; i++ ) - { - result[i] = (String) it.next(); - } - return result; - } - - /** - * Gets a list of the readable properties for the given object, which may - * not be null. This method is more useful than getReadPropertiesForClass - * in that Maps will return their keys as properties and Lists will return - * their element indices as properties. - * Note that readable properties may not be writable - see getWriteProperties(). - * @return An array of property names in no particular order - * where each name is a string with the first character in lower case. - */ - public static String[] getReadPropertiesForObject( Object anObject ) - { - List properties = new ArrayList(); - String[] classProperties = - getReadPropertiesForClass( anObject.getClass() ); - if ( anObject instanceof List ) - { - properties.addAll( getPropertiesForList( (List) anObject ) ); - } - if ( anObject instanceof Map ) - { - properties.addAll( getPropertiesForMap( (Map) anObject ) ); - } - int i; - int len = classProperties.length + properties.size(); - String[] result = new String[ len ]; - for ( i = 0; i < classProperties.length; i++ ) - { - result[i] = classProperties[i]; - } - Iterator it = properties.iterator(); - while ( it.hasNext() ) - { - result[i++] = it.next().toString(); - } - return result; - } - - /** - * Gets a list of the writable properties for the given object, which may - * not be null. This method is more useful than getWritePropertiesForClass - * in that Maps will return their keys as properties and Lists will return - * their element indices as properties. - * Note that writable properties may not be writable - see getReadProperties(). - * @return An array of property names in no particular order - * where each name is a string with the first character in lower case. - */ - public static String[] getWritePropertiesForObject( Object anObject ) - { - List properties = new ArrayList(); - String[] classProperties = - getWritePropertiesForClass( anObject.getClass() ); - if ( anObject instanceof List ) - { - properties.addAll( getPropertiesForList( (List) anObject ) ); - } - if ( anObject instanceof Map ) - { - properties.addAll( getPropertiesForMap( (Map) anObject ) ); - } - - int i; - int len = classProperties.length + properties.size(); - String[] result = new String[ len ]; - for ( i = 0; i < classProperties.length; i++ ) - { - result[i] = classProperties[i]; - } - Iterator it = properties.iterator(); - while ( it.hasNext() ) - { - result[i++] = it.next().toString(); - } - return result; - } - - private static List getPropertiesForList( List aList ) - { - List result = new ArrayList(); - int len = aList.size(); - for ( int i = 0; i < len; i++ ) - { - result.add( new Integer( i ).toString() ); - } - return result; - } - - private static List getPropertiesForMap( Map aMap ) - { - List result = new ArrayList(); - Iterator it = ((Map)aMap).keySet().iterator(); - while ( it.hasNext() ) - { - result.add( it.next().toString() ); - } - return result; - } - - private static Object[] EMPTY_ARRAY = new Object[0]; - - /** - * Convenience to get a value for a property from an object. - * An empty property string is considered the identity property - * and simply returns the object. - * @throws MissingPropertyException if the property cannot be - * found on the object. - */ - public static Object getValueForObject( Object anObject, String aProperty ) - { - if ( ( aProperty == null ) || ( "".equals( aProperty ) ) ) - { - return anObject; - } - - if ( useOGNL && aProperty.startsWith( "ognl:" ) ) - { - try - { - return ognl.Ognl.getValue( aProperty, anObject ); - } - catch ( Throwable t ) - { - if ( debug ) - { - System.err.println( - "Introspector.getValueForObject: " - + anObject + "' ( " + anObject.getClass() + " )" - + ", ognl:" + aProperty ); - System.err.println( t ); - } - return null; - } - } - - boolean invert = false; - if ( aProperty.startsWith( "!" ) ) - { - aProperty = aProperty.substring(1); - invert = true; - } - - Object result = null; - try - { - Method m = Introspector.getPropertyReadMethod( - anObject.getClass(), aProperty, EMPTY_ARRAY ); - if ( m != null ) - { - result = m.invoke( anObject, EMPTY_ARRAY ); + // no match + return null; + } + + static private final Method[] getAllMethodsForClass(Class aClass) { + Method[] local = aClass.getDeclaredMethods(); // only local + Method[] all = aClass.getMethods(); // all public + Method[] result = new Method[local.length + all.length]; + System.arraycopy(local, 0, result, 0, local.length); + System.arraycopy(all, 0, result, local.length, all.length); + return result; + } + + /** + * Generates a map of properties to both getter or setter methods for the given + * class. Then assigned those maps into the appropriate getterMethods and + * setterMethods maps keyed by the specified class. Even on error, this method + * will at least place empty property maps into each of the methods maps. + */ + static private void mapPropertiesForClass(Class objectClass) { + try { + Map readProperties = new HashMap(); + getterMethods.put(objectClass, readProperties); + Map writeProperties = new HashMap(); + setterMethods.put(objectClass, writeProperties); + + String name, property; + Method[] methods = getAllMethodsForClass(objectClass); // throws SecurityException + for (int i = 0; i < methods.length; i++) { + name = methods[i].getName(); + methods[i].setAccessible(true); // throws SecurityException + if (name.startsWith("set")) { + name = name.substring(3); + if (!"".equals(name)) // excludes "set()" + { + putMethodIntoPropertyMap(name, methods[i], writeProperties); + } + } else if (methods[i].getReturnType() != void.class) { + String fullname = name; + if (name.startsWith("get")) { + name = name.substring(3); + } else if (name.startsWith("is")) { + name = name.substring(2); + } else if (name.startsWith("has") && (!strict)) // what about hashCode()? + { + name = name.substring(3); + } + + if (!"".equals(name) && (!strict)) // excludes "get()", "has()", and "is()" + { + putMethodIntoPropertyMap(name, methods[i], readProperties); + if (fullname != name) { // allows us to match properties that include the get/set prefix as well + putMethodIntoPropertyMap(fullname, methods[i], readProperties); + } + } + } } - else // no method, try for field - { - try - { - Field field = anObject.getClass().getDeclaredField( aProperty ); - if ( field != null ) - { - field.setAccessible( true ); // throws SecurityException - result = field.get( anObject ); - } - } - catch ( Throwable t ) - { - // ignore for now - } - } - - if ( result == null ) - { - if ( anObject instanceof Map ) - { - result = ((Map)anObject).get( aProperty ); - } - else - if ( anObject instanceof List ) - { - result = ((List)anObject).get( Integer.parseInt( aProperty ) ); - } - } - - if ( invert ) - { - Object inverted = ValueConverter.invert( result ); - if ( inverted != null ) result = inverted; - } - //System.out.println( "getValueForObject: " + anObject + " : " + aProperty + " : " + result ); - return result; - } - catch ( Throwable exc ) - { - if ( exc instanceof InvocationTargetException ) - { - exc = ((InvocationTargetException)exc).getTargetException(); - } - if ( exc instanceof RuntimeException ) - { - throw (RuntimeException)exc; - } - if ( debug ) + } catch (SecurityException se) { + System.out.println("Introspector.getMethodFromClass: " + se); + // this class will show up with empty getter/setter maps + } + } + + /** + * Places a property-method pair into one of the properties maps. This in effect + * maps a property to an array of methods. + */ + private static void putMethodIntoPropertyMap(String aProperty, Method aMethod, Map aMap) { + // ensure first character is lower case + StringBuffer buffer = new StringBuffer(aProperty); + buffer.setCharAt(0, Character.toLowerCase(buffer.charAt(0))); + String key = buffer.toString(); + + // build array of methods for property + Method[] result = (Method[]) aMap.get(key); + if (result == null) { + result = new Method[] { aMethod }; + } else { + // create new array that's larger by one and copy + int i; + Method[] enlarged = new Method[result.length + 1]; + for (i = 0; i < result.length; i++) { + enlarged[i] = result[i]; + } + // add the new method to end + enlarged[i] = aMethod; + result = enlarged; + } + aMap.put(key, result); + } + + /** + * Utility method to get a method for a property belonging to a class. Use this + * if you don't feel like making the Class array from the parameters you will be + * using - pass in the parameters themselves. + * + * @param objectClass the Class whose property methods will be retrieved. + * @param aProperty The property whose method will be retrieved. + * @param params An array of parameters to be used. + * @return The appropriate method for the class, or null if not found. + */ + static public Method getPropertyReadMethod(Class objectClass, String aProperty, Object[] params) { + // optimization: avoid allocating class array for common case + if (params.length == 0) { + return getPropertyReadMethod(objectClass, aProperty, EMPTY_CLASS_ARRAY); + } + + Class[] paramList = new Class[params.length]; + for (int i = 0; i < params.length; i++) { + if (params[i] != null) { + paramList[i] = params[i].getClass(); + } else { + paramList[i] = WILD; + } + } + return getPropertyReadMethod(objectClass, aProperty, paramList); + } + + /** + * Utility method to get a method for a property belonging to a class. Use this + * if you don't feel like making the Class array from the parameters you will be + * using - pass in the parameters themselves. + * + * @param objectClass the Class whose property methods will be retrieved. + * @param aProperty The property whose method will be retrieved. + * @param params An array of parameters to be used. + * @return The appropriate method for the class, or null if not found. + */ + static public Method getPropertyWriteMethod(Class objectClass, String aProperty, Object[] params) { + Class[] paramList = new Class[params.length]; + for (int i = 0; i < params.length; i++) { + if (params[i] != null) { + paramList[i] = params[i].getClass(); + } else { + paramList[i] = WILD; + } + } + return getPropertyWriteMethod(objectClass, aProperty, paramList); + } + + /** + * Gets a list of the readable properties for the given class. Note that + * readable properties may not be writable - see getWriteProperties(). + * + * @return An array of property names in no particular order where each name is + * a string with the first character in lower case. + */ + public static String[] getReadPropertiesForClass(Class objectClass) { + Map properties = (Map) getterMethods.get(objectClass); + if (properties == null) { + // need to build maps for this class + mapPropertiesForClass(objectClass); + // now the map should exist + properties = (Map) getterMethods.get(objectClass); + } + + // put property names into string array + Set keys = properties.keySet(); + Iterator it = keys.iterator(); + int len = keys.size(); + String[] result = new String[len]; + for (int i = 0; i < len; i++) { + result[i] = (String) it.next(); + } + return result; + } + + /** + * Gets a list of the writable properties for the given class. Note that + * writable properties may not be writable - see getReadProperties(). + * + * @return An array of property names in no particular order where each name is + * a string with the first character in lower case. + */ + public static String[] getWritePropertiesForClass(Class objectClass) { + Map properties = (Map) setterMethods.get(objectClass); + if (properties == null) { + // need to build maps for this class + mapPropertiesForClass(objectClass); + // now the map should exist + properties = (Map) setterMethods.get(objectClass); + } + + // put property names into string array + Set keys = properties.keySet(); + Iterator it = keys.iterator(); + int len = keys.size(); + String[] result = new String[len]; + for (int i = 0; i < len; i++) { + result[i] = (String) it.next(); + } + return result; + } + + /** + * Gets a list of the readable properties for the given object, which may not be + * null. This method is more useful than getReadPropertiesForClass in that Maps + * will return their keys as properties and Lists will return their element + * indices as properties. Note that readable properties may not be writable - + * see getWriteProperties(). + * + * @return An array of property names in no particular order where each name is + * a string with the first character in lower case. + */ + public static String[] getReadPropertiesForObject(Object anObject) { + List properties = new ArrayList(); + String[] classProperties = getReadPropertiesForClass(anObject.getClass()); + if (anObject instanceof List) { + properties.addAll(getPropertiesForList((List) anObject)); + } + if (anObject instanceof Map) { + properties.addAll(getPropertiesForMap((Map) anObject)); + } + int i; + int len = classProperties.length + properties.size(); + String[] result = new String[len]; + for (i = 0; i < classProperties.length; i++) { + result[i] = classProperties[i]; + } + Iterator it = properties.iterator(); + while (it.hasNext()) { + result[i++] = it.next().toString(); + } + return result; + } + + /** + * Gets a list of the writable properties for the given object, which may not be + * null. This method is more useful than getWritePropertiesForClass in that Maps + * will return their keys as properties and Lists will return their element + * indices as properties. Note that writable properties may not be writable - + * see getReadProperties(). + * + * @return An array of property names in no particular order where each name is + * a string with the first character in lower case. + */ + public static String[] getWritePropertiesForObject(Object anObject) { + List properties = new ArrayList(); + String[] classProperties = getWritePropertiesForClass(anObject.getClass()); + if (anObject instanceof List) { + properties.addAll(getPropertiesForList((List) anObject)); + } + if (anObject instanceof Map) { + properties.addAll(getPropertiesForMap((Map) anObject)); + } + + int i; + int len = classProperties.length + properties.size(); + String[] result = new String[len]; + for (i = 0; i < classProperties.length; i++) { + result[i] = classProperties[i]; + } + Iterator it = properties.iterator(); + while (it.hasNext()) { + result[i++] = it.next().toString(); + } + return result; + } + + private static List getPropertiesForList(List aList) { + List result = new ArrayList(); + int len = aList.size(); + for (int i = 0; i < len; i++) { + result.add(new Integer(i).toString()); + } + return result; + } + + private static List getPropertiesForMap(Map aMap) { + List result = new ArrayList(); + Iterator it = ((Map) aMap).keySet().iterator(); + while (it.hasNext()) { + result.add(it.next().toString()); + } + return result; + } + + private static Object[] EMPTY_ARRAY = new Object[0]; + + /** + * Convenience to get a value for a property from an object. An empty property + * string is considered the identity property and simply returns the object. + * + * @throws MissingPropertyException if the property cannot be found on the + * object. + */ + public static Object getValueForObject(Object anObject, String aProperty) { + if ((aProperty == null) || ("".equals(aProperty))) { + return anObject; + } + + if (useOGNL && aProperty.startsWith("ognl:")) { + try { + return ognl.Ognl.getValue(aProperty, anObject); + } catch (Throwable t) { + if (debug) { + System.err.println("Introspector.getValueForObject: " + anObject + "' ( " + anObject.getClass() + + " )" + ", ognl:" + aProperty); + System.err.println(t); + } + return null; + } + } + + boolean invert = false; + if (aProperty.startsWith("!")) { + aProperty = aProperty.substring(1); + invert = true; + } + + Object result = null; + try { + Method m = Introspector.getPropertyReadMethod(anObject.getClass(), aProperty, EMPTY_ARRAY); + if (m != null) { + result = m.invoke(anObject, EMPTY_ARRAY); + } else // no method, try for field { - System.out.println( - "Introspector.getValueForObject: " - + anObject + "' ( " + anObject.getClass() + " )" - + ", " + aProperty + ": " ); - } - throw new WotonomyException( exc ); - } + try { + Field field = anObject.getClass().getDeclaredField(aProperty); + if (field != null) { + field.setAccessible(true); // throws SecurityException + result = field.get(anObject); + } + } catch (Throwable t) { + // ignore for now + } + } + + if (result == null) { + if (anObject instanceof Map) { + result = ((Map) anObject).get(aProperty); + } else if (anObject instanceof List) { + result = ((List) anObject).get(Integer.parseInt(aProperty)); + } + } + + if (invert) { + Object inverted = ValueConverter.invert(result); + if (inverted != null) + result = inverted; + } + // System.out.println( "getValueForObject: " + anObject + " : " + aProperty + " + // : " + result ); + return result; + } catch (Throwable exc) { + if (exc instanceof InvocationTargetException) { + exc = ((InvocationTargetException) exc).getTargetException(); + } + if (exc instanceof RuntimeException) { + throw (RuntimeException) exc; + } + if (debug) { + System.out.println("Introspector.getValueForObject: " + anObject + "' ( " + anObject.getClass() + " )" + + ", " + aProperty + ": "); + } + throw new WotonomyException(exc); + } //! throw new MissingPropertyException(); - } - - /** - * Convenience to set a value for a property from an object. - * Returns the return value from executing the specified method, - * or null if the method returns type void. - * @throws MissingPropertyException if the property cannot be - * found on the object. - * @throws NullPrimitiveException if the property is of primitive - * type and the value is null. - */ - public static Object setValueForObject( - Object anObject, String aProperty, Object aValue ) - { - if ( useOGNL && aProperty.startsWith( "ognl:" ) ) - { - try - { - ognl.Ognl.setValue( aProperty, anObject, aValue ); - } - catch ( Throwable t ) - { - if ( debug ) - { - System.err.println( - "Introspector.setValueForObject: " - + anObject + "' ( " + anObject.getClass() + " )" - + ", ognl:" + aProperty + " : " + aValue ); - System.err.println( t ); - } - } - return null; - } - - try - { - if ( aProperty.startsWith( "!" ) ) - { - aProperty = aProperty.substring(1); - Object inverted = ValueConverter.invert( aValue ); - if ( inverted != null ) aValue = inverted; - } - - Method m = null; - if ( aValue != null ) - { - m = Introspector.getPropertyWriteMethod( - anObject.getClass(), aProperty, new Class[] { aValue.getClass() } ); - } - if ( m == null ) - { - m = Introspector.getPropertyWriteMethod( - anObject.getClass(), aProperty, new Class[] { WILD } ); - if ( ( m != null ) && ( aValue != null ) ) - { - // check for null primitive - if ( ( aValue == null ) && - ( m.getParameterTypes()[0].isPrimitive() ) ) - { - throw new NullPrimitiveException(); - } - - // convert if possible - Object o = ValueConverter.convertObjectToClass( - aValue, m.getParameterTypes()[0] ); - if ( o != null ) - { - aValue = o; - } - } - } - if ( m != null ) - { - return m.invoke( anObject, new Object[] { aValue } ); + } + + /** + * Convenience to set a value for a property from an object. Returns the return + * value from executing the specified method, or null if the method returns type + * void. + * + * @throws MissingPropertyException if the property cannot be found on the + * object. + * @throws NullPrimitiveException if the property is of primitive type and the + * value is null. + */ + public static Object setValueForObject(Object anObject, String aProperty, Object aValue) { + if (useOGNL && aProperty.startsWith("ognl:")) { + try { + ognl.Ognl.setValue(aProperty, anObject, aValue); + } catch (Throwable t) { + if (debug) { + System.err.println("Introspector.setValueForObject: " + anObject + "' ( " + anObject.getClass() + + " )" + ", ognl:" + aProperty + " : " + aValue); + System.err.println(t); + } } - else // no method, try for field - { - try - { - Field field = anObject.getClass().getDeclaredField( aProperty ); - if ( field != null ) - { - field.setAccessible( true ); // throws SecurityException - field.set( anObject, aValue ); - return null; - } - } - catch ( Throwable t ) - { - // ignore for now - } - } - - if ( anObject instanceof Map ) - { - return ((Map)anObject).put( aProperty, aValue ); + return null; + } + + try { + if (aProperty.startsWith("!")) { + aProperty = aProperty.substring(1); + Object inverted = ValueConverter.invert(aValue); + if (inverted != null) + aValue = inverted; + } + + Method m = null; + if (aValue != null) { + m = Introspector.getPropertyWriteMethod(anObject.getClass(), aProperty, + new Class[] { aValue.getClass() }); } - if ( anObject instanceof List ) + if (m == null) { + m = Introspector.getPropertyWriteMethod(anObject.getClass(), aProperty, new Class[] { WILD }); + if ((m != null) && (aValue != null)) { + // check for null primitive + if ((aValue == null) && (m.getParameterTypes()[0].isPrimitive())) { + throw new NullPrimitiveException(); + } + + // convert if possible + Object o = ValueConverter.convertObjectToClass(aValue, m.getParameterTypes()[0]); + if (o != null) { + aValue = o; + } + } + } + if (m != null) { + return m.invoke(anObject, new Object[] { aValue }); + } else // no method, try for field { - List list = (List) anObject; - int i = Integer.parseInt( aProperty ); - if ( list.size() < i+1 ) - { - // expand list as necessary - for ( int j = list.size(); j <= i; j++ ) - { - list.add( new Object() ); // placeholder - } - } - return list.set( i, aValue ); + try { + Field field = anObject.getClass().getDeclaredField(aProperty); + if (field != null) { + field.setAccessible(true); // throws SecurityException + field.set(anObject, aValue); + return null; + } + } catch (Throwable t) { + // ignore for now + } + } + + if (anObject instanceof Map) { + return ((Map) anObject).put(aProperty, aValue); + } + if (anObject instanceof List) { + List list = (List) anObject; + int i = Integer.parseInt(aProperty); + if (list.size() < i + 1) { + // expand list as necessary + for (int j = list.size(); j <= i; j++) { + list.add(new Object()); // placeholder + } + } + return list.set(i, aValue); } - } - catch ( Throwable exc ) - { - if ( exc instanceof IllegalArgumentException ) - { + } catch (Throwable exc) { + if (exc instanceof IllegalArgumentException) { System.out.println( - "Introspector.setValueForObject: " - + anObject + " , " + aProperty + " , '" - + aValue + "' ):" ); - System.out.println( exc ); - } - else - if ( exc instanceof InvocationTargetException ) - { - exc = ((InvocationTargetException)exc).getTargetException(); - } - if ( exc instanceof RuntimeException ) - { - throw (RuntimeException)exc; - } - if ( debug ) - { + "Introspector.setValueForObject: " + anObject + " , " + aProperty + " , '" + aValue + "' ):"); + System.out.println(exc); + } else if (exc instanceof InvocationTargetException) { + exc = ((InvocationTargetException) exc).getTargetException(); + } + if (exc instanceof RuntimeException) { + throw (RuntimeException) exc; + } + if (debug) { System.out.println( - "Introspector.setValueForObject: " - + anObject + " , " + aProperty + " , '" - + aValue + "' ):" ); + "Introspector.setValueForObject: " + anObject + " , " + aProperty + " , '" + aValue + "' ):"); } - throw new WotonomyException( exc ); - } - return null; + throw new WotonomyException(exc); + } + return null; //! throw new MissingPropertyException(); - } - - /** - * Gets a value from an object or any of its child objects. - * This will parse the property string for "."'s and get - * values for each successive object's property in the path. - * An empty property string is considered the identity property - * and simply returns the object. - */ - public static Object get( Object anObject, String aProperty ) - { - int i = aProperty.indexOf( SEPARATOR ); - if ( i == -1 ) return getValueForObject( anObject, aProperty ); - - String pathElement = aProperty.substring( 0, i ); - String remainder = aProperty.substring( i+1 ); - - Object result = getValueForObject( anObject, pathElement ); - if ( result == null ) return null; - return get( result, remainder ); - } - - /** - * Sets a value in an object or any of its child objects. - * This will parse the property string for "."'s and set - * values for each successive object's property in the path.<br><br> - * - * If a property is not found, this method will try to - * implicitly create hash maps (if possible) to fill out the path. - * This is useful when dealing with trees of nested maps. - */ - public static Object set( Object anObject, String aProperty, Object aValue ) - { - int i = aProperty.indexOf( SEPARATOR ); - if ( i == -1 ) return setValueForObject( anObject, aProperty, aValue ); - - String pathElement = aProperty.substring( 0, i ); - String remainder = aProperty.substring( i+1 ); - - Object result = getValueForObject( anObject, pathElement ); - if ( result == null ) - { + } + + /** + * Gets a value from an object or any of its child objects. This will parse the + * property string for "."'s and get values for each successive object's + * property in the path. An empty property string is considered the identity + * property and simply returns the object. + */ + public static Object get(Object anObject, String aProperty) { + int i = aProperty.indexOf(SEPARATOR); + if (i == -1) + return getValueForObject(anObject, aProperty); + + String pathElement = aProperty.substring(0, i); + String remainder = aProperty.substring(i + 1); + + Object result = getValueForObject(anObject, pathElement); + if (result == null) + return null; + return get(result, remainder); + } + + /** + * Sets a value in an object or any of its child objects. This will parse the + * property string for "."'s and set values for each successive object's + * property in the path.<br> + * <br> + * + * If a property is not found, this method will try to implicitly create hash + * maps (if possible) to fill out the path. This is useful when dealing with + * trees of nested maps. + */ + public static Object set(Object anObject, String aProperty, Object aValue) { + int i = aProperty.indexOf(SEPARATOR); + if (i == -1) + return setValueForObject(anObject, aProperty, aValue); + + String pathElement = aProperty.substring(0, i); + String remainder = aProperty.substring(i + 1); + + Object result = getValueForObject(anObject, pathElement); + if (result == null) { result = new HashMap(2); - setValueForObject( anObject, pathElement, result ); + setValueForObject(anObject, pathElement, result); } - return set( result, remainder, aValue ); - } - + return set(result, remainder, aValue); + } + /** - * If set to true, exceptions printed to System.out.println. - * Defaults to true. - */ - public void setDebug( boolean isDebug ) - { + * If set to true, exceptions printed to System.out.println. Defaults to true. + */ + public void setDebug(boolean isDebug) { debug = isDebug; - } + } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:11:47 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:11:47 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.19 2004/02/05 02:20:34 mpowers - * Added experimental ognl support (if ognl is present). + * Revision 1.19 2004/02/05 02:20:34 mpowers Added experimental ognl support (if + * ognl is present). * - * Revision 1.18 2003/03/26 16:44:35 mpowers - * Now correctly reflecting on all methods, not just locally declared ones. + * Revision 1.18 2003/03/26 16:44:35 mpowers Now correctly reflecting on all + * methods, not just locally declared ones. * - * Revision 1.17 2003/02/21 21:10:51 mpowers - * Now reaching package, protected, and private methods and fields. + * Revision 1.17 2003/02/21 21:10:51 mpowers Now reaching package, protected, + * and private methods and fields. * - * Revision 1.16 2003/01/28 22:11:59 mpowers - * Now more lenient in resolving properties starting with "is" "get" or "has". + * Revision 1.16 2003/01/28 22:11:59 mpowers Now more lenient in resolving + * properties starting with "is" "get" or "has". * - * Revision 1.15 2003/01/27 15:10:54 mpowers - * Better handling for illegal argument exceptions. + * Revision 1.15 2003/01/27 15:10:54 mpowers Better handling for illegal + * argument exceptions. * - * Revision 1.14 2003/01/18 23:30:42 mpowers - * WODisplayGroup now compiles. + * Revision 1.14 2003/01/18 23:30:42 mpowers WODisplayGroup now compiles. * - * Revision 1.13 2002/10/11 15:35:12 mpowers - * Removed printlns. + * Revision 1.13 2002/10/11 15:35:12 mpowers Removed printlns. * - * Revision 1.11 2001/05/02 17:58:41 mpowers - * Removed debugging code, added comments. + * Revision 1.11 2001/05/02 17:58:41 mpowers Removed debugging code, added + * comments. * - * Revision 1.10 2001/04/08 21:00:54 mpowers - * Changes to support new objectsForFetchSpecification scheme. + * Revision 1.10 2001/04/08 21:00:54 mpowers Changes to support new + * objectsForFetchSpecification scheme. * - * Revision 1.9 2001/03/29 03:30:36 mpowers - * Refactored duplicator a bit. + * Revision 1.9 2001/03/29 03:30:36 mpowers Refactored duplicator a bit. * Disabled MissingPropertyExceptions for now. * - * Revision 1.8 2001/03/28 17:52:45 mpowers - * Corrected the throws in the docs. + * Revision 1.8 2001/03/28 17:52:45 mpowers Corrected the throws in the docs. * - * Revision 1.7 2001/03/28 17:49:13 mpowers - * Better exception handling in Introspector. + * Revision 1.7 2001/03/28 17:49:13 mpowers Better exception handling in + * Introspector. * - * Revision 1.6 2001/03/13 21:40:20 mpowers - * Improved handling of runtime exceptions. + * Revision 1.6 2001/03/13 21:40:20 mpowers Improved handling of runtime + * exceptions. * - * Revision 1.5 2001/03/09 22:06:35 mpowers - * Now extracting the wrapped exception from InvocationTargetExceptions. + * Revision 1.5 2001/03/09 22:06:35 mpowers Now extracting the wrapped exception + * from InvocationTargetExceptions. * - * Revision 1.4 2001/03/01 20:36:35 mpowers - * Better error handling and better handling of nulls. + * Revision 1.4 2001/03/01 20:36:35 mpowers Better error handling and better + * handling of nulls. * - * Revision 1.3 2001/01/17 16:20:57 mpowers - * Introspector now handles the identity property. + * Revision 1.3 2001/01/17 16:20:57 mpowers Introspector now handles the + * identity property. * - * Revision 1.2 2001/01/09 20:08:17 mpowers - * Slight optimization. + * Revision 1.2 2001/01/09 20:08:17 mpowers Slight optimization. * - * Revision 1.1.1.1 2000/12/21 15:52:04 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:52:04 mpowers Contributing wotonomy. * - * Revision 1.5 2000/12/20 16:25:46 michael - * Added log to all files. + * Revision 1.5 2000/12/20 16:25:46 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/IntrospectorException.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/IntrospectorException.java index b1ad824..45080a2 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/IntrospectorException.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/IntrospectorException.java @@ -19,14 +19,13 @@ License along with this library; if not, see http://www.gnu.org package net.wotonomy.foundation.internal; /** -* A WotonomyException that is thrown by Introspector. -* This class serves as a base class for other exceptions. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ + * A WotonomyException that is thrown by Introspector. This class serves as a + * base class for other exceptions. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ -public class IntrospectorException extends WotonomyException -{ +public class IntrospectorException extends WotonomyException { } diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/MissingPropertyException.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/MissingPropertyException.java index c1e30d3..c89742f 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/MissingPropertyException.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/MissingPropertyException.java @@ -19,14 +19,13 @@ License along with this library; if not, see http://www.gnu.org package net.wotonomy.foundation.internal; /** -* A IntrospectorException that is thrown by Introspector when -* a property does not exist for an object. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ + * A IntrospectorException that is thrown by Introspector when a property does + * not exist for an object. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ -public class MissingPropertyException extends IntrospectorException -{ +public class MissingPropertyException extends IntrospectorException { } diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NetworkClassLoader.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NetworkClassLoader.java index 43c14a5..7761876 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NetworkClassLoader.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NetworkClassLoader.java @@ -47,7 +47,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== - */ + */ package net.wotonomy.foundation.internal; @@ -59,310 +59,284 @@ import java.util.Enumeration; import java.util.Hashtable; /** - * The correct name for this class should be URLClassLoader. - * But there is already a class by that name in JDK1.2. + * The correct name for this class should be URLClassLoader. But there is + * already a class by that name in JDK1.2. * - * I have had quite a few problems with URLClassLoader in - * past, so I ended up writing this ClassLoader. I found that - * the Java 2's URLClassLoader, does not close the Jar file once - * opened. It is a pretty good optimization step, but if you - * modify the class in the jar file, it does not pick it up. Some - * operating systems may not let you modify the jar file while it is - * still open. IMHO, it does make sense to close the jar file - * after you are done reading the class data. But this approach may not - * get you the performance of the URLClassLoader, but it works in all - * cases and also runs on JDK1.1. I have enhanced this class loader - * to read all the zip/jar entries once & cache the data, so that - * there is no overhead of opening/closing jar file to pick up + * I have had quite a few problems with URLClassLoader in past, so I ended up + * writing this ClassLoader. I found that the Java 2's URLClassLoader, does not + * close the Jar file once opened. It is a pretty good optimization step, but if + * you modify the class in the jar file, it does not pick it up. Some operating + * systems may not let you modify the jar file while it is still open. IMHO, it + * does make sense to close the jar file after you are done reading the class + * data. But this approach may not get you the performance of the + * URLClassLoader, but it works in all cases and also runs on JDK1.1. I have + * enhanced this class loader to read all the zip/jar entries once & cache the + * data, so that there is no overhead of opening/closing jar file to pick up * each entry. * * * @author Harish Prabandham */ public class NetworkClassLoader extends ClassLoader { - private ClassLoader parent = null; // parent classloader - private Hashtable classCache = new Hashtable(); - private Hashtable urlset = new Hashtable(); - - /** - * Creates a new instance of the class loader. - * @param delegate/parent class loader. - */ - public NetworkClassLoader(ClassLoader parent) { - setParent(parent); - } - - /** - * Sets the parent/delegate class loader. - * @param delegate/parent class loader. - */ - protected final void setParent(ClassLoader parent) { - this.parent = parent; - } - - /** - * Adds the given URL to this class loader. If the URL - * ends with "/", then it is assumed to be a directory - * otherwise, it is assumed to be a zip/jar file. If the - * same URL is added again, the URL is re-opened and this - * zip/jar file is used for serving any future class requests. - * @param URL where to look for the classes. - */ - public synchronized void addURL(URL url) { - // System.out.println("Adding url: " + url); - if(!urlset.containsKey(url)) { - try { - urlset.put(url, new URLResourceReader(url)); - }catch(IOException ioe){ - // Probably a bad url... - } - } else { - // remove the old one & add a new one... - try{ - URLResourceReader newu = new URLResourceReader(url); - URLResourceReader oldu = (URLResourceReader) urlset.get(url); - oldu.close(); - urlset.remove(url); - urlset.put(url, newu); - } catch (IOException ioe) { - } - } - } - - /** - * @return An enumeration of URLs where this class loader - * looks for classes. - */ - public Enumeration getURLs() { - return urlset.keys(); - } - - /** - * Call this to bypass the implementation of loadClass. - */ - public Class findClass(String name) { - byte[] b = loadClassData(name); - if ( b == null ) return null; - return defineClass(name, b, 0, b.length); - } - - protected byte[] loadResource(URL url, String resourceName) - throws IOException { - URLResourceReader urr = (URLResourceReader) urlset.get(url); - // System.out.println("Loading from " + urr + " " + resourceName); - if(urr != null) { - return urr.getResource(resourceName); - } - - return null; - } - - protected byte[] loadResource(String resource) { - byte[] barray = null; - for(Enumeration e = urlset.keys(); e.hasMoreElements();) { - URL url = (URL) e.nextElement(); - - try { - barray = loadResource(url, resource); - } catch(Exception ex) { - } finally { - if(barray != null) - break; - } - } - - return barray; - } - - protected byte[] loadClassData(String classname) { - String resourceName = classname.replace('.', '/') + ".class"; - return loadResource(resourceName); - } - - /** - * Overridden to search for a resource and return - * a "jar"-style URL or normal "file" URL as necessary. - */ - protected URL findResource(String name) - { //System.out.println( "findResource: " + name ); - URL url; - byte[] barray = null; - - for ( Enumeration e = urlset.keys(); e.hasMoreElements(); ) - { - url = (URL) e.nextElement(); - try - { - barray = loadResource(url, name); // loads fully: wasteful - } - catch(Exception ex) - { - // do nothing - } - if( barray != null ) - { - try - { - String ref = url.toString(); - if ( ref.endsWith( ".jar" ) ) - { - //System.out.println( "jar:" + ref + "!/" + name ); - return new URL( "jar:" + ref + "!/" + name ); - } - else - { - //System.out.println( new URL( url, name ).toString() ); - return new URL( url, name ); - } - } - catch ( Throwable t ) - { - t.printStackTrace(); - } - } - } - - return null; - } - - /** - * @return The resource as the input stream if such a resource - * exists, otherwise returns null. - */ - public InputStream getResourceAsStream(String name) { - //System.out.println( "getResourceAsStream: " + name ); - InputStream istream = null; - - // Algorithm: - // - // 1. first check the system path for the resource - // 2. next check the delegate/parent class loader for the resource - // 3. then attempt to get the resource from the url set. - // - - // Lets check the system path for the resource. - istream = getSystemResourceAsStream(name); - if(istream != null) - return istream; - - // Lets check the parent/delegate class loader for the resource. - if(parent != null) { - istream = parent.getResourceAsStream(name); - if(istream != null) - return istream; - } - - // Lets load it ourselves. - byte[] data = loadResource(name); - if(data != null) { - istream = new ByteArrayInputStream(data); - } - - return istream; - } - - /** - * java.lang.ClassLoader's defineClass method is final, so the - * its subclasses cannot override this method. But, this class - * calls this method in the loadClass() instead. - * @param The name of the class without ".class" extension. - * @param The class data bytes. - * @return The class object. - */ - protected Class defineClass(String classname, byte[] classdata) { - return defineClass(classname, classdata, 0, classdata.length); - } - - public synchronized Class loadClass(String name, boolean resolve) - throws ClassNotFoundException { - Class c = null; - - // Algorithm: (Please do not change the order; unless you - // have a good reason to do so). - // - // 1. first check the system class loader. - // 2. next check the delegate/parent class loader. - // 3. next check the class cache - // 4. then attempt to load classes from the URL set. - // - - // Lets see if the class is in system class loader. - try { - c = findSystemClass(name); - }catch(ClassNotFoundException cnfe) { - }finally { - if(c != null) - return c; - } - - // Lets see if the class is in parent class loader. - try { - if(parent != null) - c = parent.loadClass(name); - }catch(ClassNotFoundException cnfe) { - }finally { - if(c != null) - return c; - } - - // Lets see if the class is in the cache.. - c = (Class) classCache.get(name); - - if(c != null) - return c; - - - // Lets see if we find the class all by ourselves. - byte[] data = loadClassData(name); - - if(data != null) { - // we did !! - c = defineClass(name, data); - classCache.put(name, c); - if(resolve) - resolveClass(c); - } else { - // We are out of luck at this point... - throw new ClassNotFoundException(name); - } - - return c; - } - - /** - * This method resets this ClassLoader's state. It completely - * removes all the URLs and classes in this class loader cache. - */ - public final void clear() { - urlset.clear(); - classCache.clear(); - } - - /** - * This method resets this ClassLoader's state and resets the - * references for garbage collection. - */ - protected void finalize() throws Throwable { - // Cleanup real well. Otherwise, this can be - // a major source of memory leaks... - - // remove all the urls & class entries. - clear(); - - parent = null; - urlset = null; - classCache = null; - } + private ClassLoader parent = null; // parent classloader + private Hashtable classCache = new Hashtable(); + private Hashtable urlset = new Hashtable(); + + /** + * Creates a new instance of the class loader. + * + * @param delegate/parent class loader. + */ + public NetworkClassLoader(ClassLoader parent) { + setParent(parent); + } + + /** + * Sets the parent/delegate class loader. + * + * @param delegate/parent class loader. + */ + protected final void setParent(ClassLoader parent) { + this.parent = parent; + } + + /** + * Adds the given URL to this class loader. If the URL ends with "/", then it is + * assumed to be a directory otherwise, it is assumed to be a zip/jar file. If + * the same URL is added again, the URL is re-opened and this zip/jar file is + * used for serving any future class requests. + * + * @param URL where to look for the classes. + */ + public synchronized void addURL(URL url) { + // System.out.println("Adding url: " + url); + if (!urlset.containsKey(url)) { + try { + urlset.put(url, new URLResourceReader(url)); + } catch (IOException ioe) { + // Probably a bad url... + } + } else { + // remove the old one & add a new one... + try { + URLResourceReader newu = new URLResourceReader(url); + URLResourceReader oldu = (URLResourceReader) urlset.get(url); + oldu.close(); + urlset.remove(url); + urlset.put(url, newu); + } catch (IOException ioe) { + } + } + } + + /** + * @return An enumeration of URLs where this class loader looks for classes. + */ + public Enumeration getURLs() { + return urlset.keys(); + } + + /** + * Call this to bypass the implementation of loadClass. + */ + public Class findClass(String name) { + byte[] b = loadClassData(name); + if (b == null) + return null; + return defineClass(name, b, 0, b.length); + } + + protected byte[] loadResource(URL url, String resourceName) throws IOException { + URLResourceReader urr = (URLResourceReader) urlset.get(url); + // System.out.println("Loading from " + urr + " " + resourceName); + if (urr != null) { + return urr.getResource(resourceName); + } + + return null; + } + + protected byte[] loadResource(String resource) { + byte[] barray = null; + for (Enumeration e = urlset.keys(); e.hasMoreElements();) { + URL url = (URL) e.nextElement(); + + try { + barray = loadResource(url, resource); + } catch (Exception ex) { + } finally { + if (barray != null) + break; + } + } + + return barray; + } + + protected byte[] loadClassData(String classname) { + String resourceName = classname.replace('.', '/') + ".class"; + return loadResource(resourceName); + } + + /** + * Overridden to search for a resource and return a "jar"-style URL or normal + * "file" URL as necessary. + */ + protected URL findResource(String name) { // System.out.println( "findResource: " + name ); + URL url; + byte[] barray = null; + + for (Enumeration e = urlset.keys(); e.hasMoreElements();) { + url = (URL) e.nextElement(); + try { + barray = loadResource(url, name); // loads fully: wasteful + } catch (Exception ex) { + // do nothing + } + if (barray != null) { + try { + String ref = url.toString(); + if (ref.endsWith(".jar")) { + // System.out.println( "jar:" + ref + "!/" + name ); + return new URL("jar:" + ref + "!/" + name); + } else { + // System.out.println( new URL( url, name ).toString() ); + return new URL(url, name); + } + } catch (Throwable t) { + t.printStackTrace(); + } + } + } + + return null; + } + + /** + * @return The resource as the input stream if such a resource exists, otherwise + * returns null. + */ + public InputStream getResourceAsStream(String name) { + // System.out.println( "getResourceAsStream: " + name ); + InputStream istream = null; + + // Algorithm: + // + // 1. first check the system path for the resource + // 2. next check the delegate/parent class loader for the resource + // 3. then attempt to get the resource from the url set. + // + + // Lets check the system path for the resource. + istream = getSystemResourceAsStream(name); + if (istream != null) + return istream; + + // Lets check the parent/delegate class loader for the resource. + if (parent != null) { + istream = parent.getResourceAsStream(name); + if (istream != null) + return istream; + } + + // Lets load it ourselves. + byte[] data = loadResource(name); + if (data != null) { + istream = new ByteArrayInputStream(data); + } + + return istream; + } + + /** + * java.lang.ClassLoader's defineClass method is final, so the its subclasses + * cannot override this method. But, this class calls this method in the + * loadClass() instead. + * + * @param The name of the class without ".class" extension. + * @param The class data bytes. + * @return The class object. + */ + protected Class defineClass(String classname, byte[] classdata) { + return defineClass(classname, classdata, 0, classdata.length); + } + + public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + Class c = null; + + // Algorithm: (Please do not change the order; unless you + // have a good reason to do so). + // + // 1. first check the system class loader. + // 2. next check the delegate/parent class loader. + // 3. next check the class cache + // 4. then attempt to load classes from the URL set. + // + + // Lets see if the class is in system class loader. + try { + c = findSystemClass(name); + } catch (ClassNotFoundException cnfe) { + } finally { + if (c != null) + return c; + } + + // Lets see if the class is in parent class loader. + try { + if (parent != null) + c = parent.loadClass(name); + } catch (ClassNotFoundException cnfe) { + } finally { + if (c != null) + return c; + } + + // Lets see if the class is in the cache.. + c = (Class) classCache.get(name); + + if (c != null) + return c; + + // Lets see if we find the class all by ourselves. + byte[] data = loadClassData(name); + + if (data != null) { + // we did !! + c = defineClass(name, data); + classCache.put(name, c); + if (resolve) + resolveClass(c); + } else { + // We are out of luck at this point... + throw new ClassNotFoundException(name); + } + + return c; + } + + /** + * This method resets this ClassLoader's state. It completely removes all the + * URLs and classes in this class loader cache. + */ + public final void clear() { + urlset.clear(); + classCache.clear(); + } + + /** + * This method resets this ClassLoader's state and resets the references for + * garbage collection. + */ + protected void finalize() throws Throwable { + // Cleanup real well. Otherwise, this can be + // a major source of memory leaks... + + // remove all the urls & class entries. + clear(); + + parent = null; + urlset = null; + classCache = null; + } } - - - - - - - - - - - - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NullPrimitiveException.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NullPrimitiveException.java index e367211..bf1dffd 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NullPrimitiveException.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/NullPrimitiveException.java @@ -19,14 +19,13 @@ License along with this library; if not, see http://www.gnu.org package net.wotonomy.foundation.internal; /** -* A IntrospectorException that is thrown by Introspector when -* trying to set a primitive type to null. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ + * A IntrospectorException that is thrown by Introspector when trying to set a + * primitive type to null. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ -public class NullPrimitiveException extends IntrospectorException -{ +public class NullPrimitiveException extends IntrospectorException { } diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyComparator.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyComparator.java index abdc82f..c804893 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyComparator.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyComparator.java @@ -21,80 +21,61 @@ package net.wotonomy.foundation.internal; import java.io.Serializable; import java.util.Comparator; - /** -* A Comparator that will sort elements based on the -* property specified in the constructor. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public class PropertyComparator implements Comparator, Serializable -{ - private String property; + * A Comparator that will sort elements based on the property specified in the + * constructor. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public class PropertyComparator implements Comparator, Serializable { + private String property; -/** -* Standard constructor to configure the comparator. -* @param aProperty A property whose value is used to sort elements. -*/ - public PropertyComparator( String aProperty ) - { + /** + * Standard constructor to configure the comparator. + * + * @param aProperty A property whose value is used to sort elements. + */ + public PropertyComparator(String aProperty) { property = aProperty; - } + } - // interface Comparator + // interface Comparator - public int compare(Object o1, Object o2) - { - Object v1 = Introspector.get( o1, property ); - Object v2 = Introspector.get( o2, property ); - if ( v1 instanceof Comparable ) - { - return ((Comparable)v1).compareTo( v2 ); - } - else - if ( v2 instanceof Comparable ) - { - return ((Comparable)v2).compareTo( v1 ); - } - else - { - if ( v1 == null ) - { - if ( v2 == null ) - { + public int compare(Object o1, Object o2) { + Object v1 = Introspector.get(o1, property); + Object v2 = Introspector.get(o2, property); + if (v1 instanceof Comparable) { + return ((Comparable) v1).compareTo(v2); + } else if (v2 instanceof Comparable) { + return ((Comparable) v2).compareTo(v1); + } else { + if (v1 == null) { + if (v2 == null) { return 0; // both nulls are equal } return -1; // null is less than any object - } - else - if ( v2 == null ) - { + } else if (v2 == null) { return 1; // any object is greater than null } } // last resort: compare string conversions - return v1.toString().compareTo( v2.toString() ); + return v1.toString().compareTo(v2.toString()); } - - public boolean equals( Object obj ) - { - return ( obj instanceof PropertyComparator ); + + public boolean equals(Object obj) { + return (obj instanceof PropertyComparator); } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:11:47 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:11:47 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.1.1.1 2000/12/21 15:52:07 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:52:07 mpowers Contributing wotonomy. * - * Revision 1.2 2000/12/20 16:25:46 michael - * Added log to all files. + * Revision 1.2 2000/12/20 16:25:46 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyListParser.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyListParser.java index 03231c7..3698325 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyListParser.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/PropertyListParser.java @@ -23,23 +23,26 @@ import java.io.*; /** * PropertyListParser can parse a property list (plist) file or string, and - * return the top-level object represented by the plist. <p> + * return the top-level object represented by the plist. + * <p> * - * A property list is a heirarchical data structure containing only Maps, - * Lists, and Strings -- nothing else. In other words, a property list is - * either a Map, List, or String instance, with the restrictions that the - * collections may only contain Map, List, or String instances. <p> + * A property list is a heirarchical data structure containing only Maps, Lists, + * and Strings -- nothing else. In other words, a property list is either a Map, + * List, or String instance, with the restrictions that the collections may only + * contain Map, List, or String instances. + * <p> * - * This class can read a particularly-formatted string or file, and create - * the property list structure described. It provides a convenient means - * for having a structured data file, letting programs simply deal with the - * structure rather than having to do a lot of string parsing work as well. - * The concept is similar to Properties files, except that the values can - * be nested Maps or Lists instead of only Strings. <p> + * This class can read a particularly-formatted string or file, and create the + * property list structure described. It provides a convenient means for having + * a structured data file, letting programs simply deal with the structure + * rather than having to do a lot of string parsing work as well. The concept is + * similar to Properties files, except that the values can be nested Maps or + * Lists instead of only Strings. + * <p> * * A Map is specified in a file by key/value pairs surrounded by brace - * characters. An equal sign (=) must be between the key and value, and - * there must be a semicolon (;) following the value. + * characters. An equal sign (=) must be between the key and value, and there + * must be a semicolon (;) following the value. * * <pre> * { @@ -49,35 +52,42 @@ import java.io.*; * } * </pre> * - * A List is specified by a comma-separated list of values surrounded by parentheses, like: + * A List is specified by a comma-separated list of values surrounded by + * parentheses, like: + * * <pre> * ( value1, value2, value3, etc... ) * </pre> * - * A String can either be quoted in the manner of a constant string in - * Java, or unquoted. If unquoted, the string can only contain - * alphanumerics, underscores (_), periods (.), dollar signs ($), colons - * (:), or forward slashes (/). If any other character appears in the - * string, it must be quoted (i.e., surrounded by " characters). - * Quoted strings may also contain \n, \t, \f, \v, \b, and \a escapes, - * octal escapes of the form \000, and unicode escapes of the form of \U - * followed by four hexadecimal characters. Any other character escaped - * by a backslash will be treated as that character, and the escaping - * backslash character will be omitted. Thus, to represent an actual - * backslash, it must appear as \\ in the quoted string. <p> + * A String can either be quoted in the manner of a constant string in Java, or + * unquoted. If unquoted, the string can only contain alphanumerics, underscores + * (_), periods (.), dollar signs ($), colons (:), or forward slashes (/). If + * any other character appears in the string, it must be quoted (i.e., + * surrounded by " characters). Quoted strings may also contain \n, \t, \f, + * \v, \b, and \a escapes, octal escapes of the form \000, and unicode escapes + * of the form of \U followed by four hexadecimal characters. Any other + * character escaped by a backslash will be treated as that character, and the + * escaping backslash character will be omitted. Thus, to represent an actual + * backslash, it must appear as \\ in the quoted string. + * <p> + * + * All whitespace between elements is ignored, and both //-style and /*-style + * comments are allowed to appear anywhere between elements. + * <p> * - * All whitespace between elements is ignored, and both //-style and - * /*-style comments are allowed to appear anywhere between elements. <p> + * If there are any syntax errors encountered while parsing, RuntimeExceptions + * are thrown with the line number and column of the problem. + * <p> * - * If there are any syntax errors encountered while parsing, - * RuntimeExceptions are thrown with the line number and column of the - * problem. <p> + * Currenty, HashMaps and ArrayLists are the actual Map and List classes used + * when creating the property list. + * <p> * - * Currenty, HashMaps and ArrayLists are the actual Map and List classes - * used when creating the property list. <p> + * Examples: + * <p> + * <blockquote> * - * Examples: <p><blockquote> - <pre> + * <pre> // This plist file represents a Map, since it starts with a '{'. { Map1 = { subkey1 = "foo"; }; @@ -104,443 +114,425 @@ import java.io.*; } ); } - </pre> - </blockquote> - * For those wondering, this is essentially a re-implementation of + * </pre> + * + * </blockquote> For those wondering, this is essentially a re-implementation of * NeXT/Apple's property lists, except that data values are not supported. * * @author clindberg@blacksmith.com * @version $Revision: 899 $ */ -public class PropertyListParser -{ - private char buffer[]; - private int currIndex; - private int lineNumber; - private int currLineStartIndex; - - /** Reads an object (String, List, or Map) from plistString and returns it. - * RuntimeExceptions are raised if there are parse problems. - */ - public static Object propertyListFromString(String plistString) - { - PropertyListParser parser = new PropertyListParser(plistString); - return parser.readTopLevelObject(); - } - - /** - * Reads all remaining characters from the Reader, and returns the - * result of propertyListFromString(). RuntimeExceptions are raised if - * there are parse problems - */ - public static Object propertyListFromReader(Reader reader) throws IOException - { - char charBuffer[] = new char[2048]; - StringBuffer stringBuffer = new StringBuffer(); - int numRead = 0; - - while (numRead >= 0) - { - numRead = reader.read(charBuffer); - if (numRead > 0) stringBuffer.append(charBuffer, 0, numRead); - } - - return propertyListFromString(stringBuffer.toString()); - } - - /** - * Reads the contents of the specified file, and parses the contents. - * If any error occurs, prints out a message using System.out.println() - * and returns null. - */ - public static Object propertyListFromFile(String filename) - { - try { - FileInputStream stream = new FileInputStream(filename); - return propertyListFromReader(new InputStreamReader(stream)); - } catch (Exception exception) { - String errorMessage = exception.getMessage(); - System.out.println("Error parsing property list from "+filename+": "+errorMessage); - } - - return null; - } - - /** - * Creates a new PropertyListParser to parse the contents of the - * specified String. - */ - public PropertyListParser(String plistString) - { - this(plistString.toCharArray()); - } - - /** - * Creates a new PropertyListParser to parse the specified char array. - */ - public PropertyListParser(char[] charArray) - { - buffer = charArray; - lineNumber = 1; - currLineStartIndex = 1; - currIndex = 0; - } - - public Object readTopLevelObject() - { - Object plist = readObject(); - - skipCommentWhitespace(); - if (!isAtEnd()) - { - throwParseException("Extra characters in plist string after parsing object. A plist should only contain one top-level object."); - } - - return plist; - } - - private void throwParseException(String errorMessage) - { - int column = currIndex - currLineStartIndex + 1; - throw new RuntimeException(errorMessage + " (Line " + lineNumber + ", column " + column + ")"); - } - - private void updateLineNumberWithIndex(int lineStartIndex) - { - lineNumber++; - currLineStartIndex = lineStartIndex; - } - - private boolean isAtEnd() - { - return currIndex >= buffer.length; - } - - private void skipDoubleslashComment() - { - while (!isAtEnd() && buffer[currIndex] != '\n') { - currIndex++; - } - } - - private void skipStandardCComment() - { - currIndex++; //skip over the starting '/' - - while (!isAtEnd()) - { - if (buffer[currIndex] == '\n') - updateLineNumberWithIndex(currIndex+1); - - currIndex++; - - if (buffer[currIndex-2] == '*' && buffer[currIndex-1] == '/') - { - return; - } - } - - throwParseException("Input exhausted while parsing comment"); - } - - private void skipWhitespace() - { - while (!isAtEnd() && isWhitespace(buffer[currIndex])) - { - if (buffer[currIndex] == '\n') - updateLineNumberWithIndex(currIndex+1); - currIndex++; - } - } - - private void skipCommentWhitespace() - { - boolean done = false; - - while (!done) - { - done = true; - - skipWhitespace(); - if ((buffer.length - currIndex) > 1 && buffer[currIndex] == '/') - { - if (buffer[currIndex+1] == '/') { - done = false; //iterate again - skipDoubleslashComment(); - } - else if (buffer[currIndex+1] == '*') { - done = false; //iterate again - skipStandardCComment(); - } - } - } - } - - private Object readObject() - { - skipCommentWhitespace(); - if (isAtEnd()) return null; - - // Data (i.e. byte[]) not supported - if (buffer[currIndex] == '"') - return readQuotedString(); - if (buffer[currIndex] == '(') - return readList(); - if (buffer[currIndex] == '{') - return readMap(); - - return readUnquotedString(); - } - - private static final byte valueForHexDigit(char c) - { - if(c >= '0' && c <= '9') return (byte)(c - '0'); - if(c >= 'a' && c <= 'f') return (byte)((c - 'a') + 10); - if(c >= 'A' && c <= 'F') return (byte)((c - 'A') + 10); - - return 0; - } - - private static final boolean isOctalDigit(char c) - { - return c >= '0' && c <= '7'; - } - - private static final boolean isHexDigit(char c) - { - return (c >= '0' && c <= '9') || - (c >= 'a' && c <= 'f') || - (c >= 'A' && c <= 'F'); - } - - private static String unquotedStringChars = "._$:/"; // chars allowed in unquoted strings - private static String whitespaceChars = " \t\n\r\f"; - - private static final boolean isWhitespace(char c) - { - return whitespaceChars.indexOf(c) >= 0; - } - - private static final boolean isValidUnquotedStringChar(char c) - { - return ((c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || - unquotedStringChars.indexOf(c) >= 0); - } - - private String readUnquotedString() - { - int startIndex = currIndex; - - while (!isAtEnd() && isValidUnquotedStringChar(buffer[currIndex])) - currIndex++; - - if (startIndex == currIndex) - throwParseException("No allowable characters found to parse unquoted string"); - - return new String(buffer, startIndex, currIndex - startIndex); - } - - private String readQuotedString() - { - currIndex++; //skip over '"' - - StringBuffer stringBuffer = new StringBuffer(); - int startIndex = currIndex; - - while (!isAtEnd() && buffer[currIndex] != '"') - { - if (buffer[currIndex] != '\\') - { - if (buffer[currIndex] == '\n') - updateLineNumberWithIndex(currIndex+1); - - /* - * Just increment the index -- all these characters will be - * appended in chunks, either before an escape sequence or - * at the end. - */ - currIndex++; - } - else // it's an escape - { - /* Append anything scanned past before the '\\' */ - if (startIndex < currIndex) - stringBuffer.append(buffer, startIndex, currIndex - startIndex); - currIndex++; // skip over '\\' - - if (isAtEnd()) - throwParseException("Input exhausted while parsing escape sequence"); - - switch (buffer[currIndex]) - { - case 't': stringBuffer.append('\t'); currIndex++; break; // tab - case 'n': stringBuffer.append('\n'); currIndex++; break; // newline - case 'r': stringBuffer.append('\r'); currIndex++; break; // carriage return - case 'f': stringBuffer.append('\f'); currIndex++; break; // form feed - case 'b': stringBuffer.append('\b'); currIndex++; break; // backspace - case 'a': stringBuffer.append('\007'); currIndex++; break; // bell - case 'v': stringBuffer.append('\013'); currIndex++; break; // vertical tab - case 'U': - case 'u': - { - /* A Unicode escape. Always followed by 4 hex digits. */ - currIndex++; // skip past the 'U' - if ((currIndex+4) > buffer.length) - throwParseException("Not enough chars to parse \\U sequence"); - - if(!isHexDigit(buffer[currIndex]) || !isHexDigit(buffer[currIndex+1]) || - !isHexDigit(buffer[currIndex+2]) || !isHexDigit(buffer[currIndex+3])) - { - throwParseException("Four hex digits not found for \\U sequence"); - } - - byte byte3 = valueForHexDigit(buffer[currIndex]); - byte byte2 = valueForHexDigit(buffer[currIndex+1]); - byte byte1 = valueForHexDigit(buffer[currIndex+2]); - byte byte0 = valueForHexDigit(buffer[currIndex+3]); - char theChar = (char)((byte3 << 12) + (byte2 << 8) + (byte1 << 4) + byte0); - stringBuffer.append(theChar); - currIndex += 4; - break; - } - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - { - /* An octal escape. Expect 1, 2, or 3 octal digits. */ - int digits = 0; - int value = 0; - - do { - value *= 8; - value += (int)(buffer[currIndex] - '0'); - currIndex++; - digits++; - } while (digits <= 3 && !isAtEnd() && isOctalDigit(buffer[currIndex])); - - if (value > 255) - throwParseException("Value too large in octal escape sequence (> 0377)"); - - // This assumes value is in ISO Latin 1 encoding - stringBuffer.append((char)value); - break; - } - /* I guess plists can't have the \x{HEX}{HEX} escapes */ - default: - { - // Unknown escape sequence, just add the character. - // GCC warns if this isn't a '"', '\'', or '\\'... - stringBuffer.append(buffer[currIndex]); - if (buffer[currIndex] == '\n') - updateLineNumberWithIndex(currIndex+1); - currIndex++; - break; - } - } // end case - - /* Reset startIndex, so a verbatim copy will now start from this index */ - startIndex = currIndex; - - } //end '\\' escape - } - - if (isAtEnd()) - throwParseException("Input exhausted while parsing quoted string"); - if (startIndex < currIndex) - stringBuffer.append(buffer, startIndex, currIndex - startIndex); - currIndex++; //skip past '"' - - return stringBuffer.toString(); - } - - private List readList() - { - List newList = new ArrayList(); - - currIndex++; //skip over '(' - skipCommentWhitespace(); - while (!isAtEnd() && buffer[currIndex] != ')') - { - /* A comma is required between list elements */ - if (newList.size() > 0) - { - if (buffer[currIndex] != ',') - throwParseException("List parsing failed: expecting ','"); - currIndex++; - skipCommentWhitespace(); - if (isAtEnd()) - throwParseException("Input exhausted while parsing list"); - } - - if (buffer[currIndex] != ')') - { - Object plistObject = readObject(); - if (plistObject == null) - throwParseException("List parsing failed: could not read contained object."); - newList.add(plistObject); - skipCommentWhitespace(); - } - } - - if (isAtEnd()) - throwParseException("Input exhausted while parsing list"); - currIndex++; //skip past ')' - - return newList; - } - - private Map readMap() - { - HashMap newMap = new HashMap(); - - currIndex++; // skip over open brace - skipCommentWhitespace(); - - while (!isAtEnd() && buffer[currIndex] != '}') - { - Object key; - Object value; - - key = readObject(); - if (key == null || !(key instanceof String)) - throwParseException("Map parsing failed: could not parse key or key is not a String"); - - skipCommentWhitespace(); - if (isAtEnd() || buffer[currIndex] != '=') - throwParseException("Map parsing failed: expecting '='"); - currIndex++; //skip over '=' - skipCommentWhitespace(); - if (isAtEnd()) - throwParseException("Input exhausted while parsing map"); - - value = readObject(); - if (value == null) - throwParseException("Map parsing failed: could not parse value object"); - - skipCommentWhitespace(); - if (isAtEnd() || buffer[currIndex] != ';') - throwParseException("Map parsing failed: expecting ';'"); - currIndex++; //skip over ';' - skipCommentWhitespace(); - - newMap.put(key, value); - } - - if (isAtEnd()) - throwParseException("Input exhausted while parsing map"); - currIndex++; //skip past '}' - - return newMap; - } - - - public static void main(String[] args) - { - String filename = args[0]; - Object plist = PropertyListParser.propertyListFromFile(filename); - System.out.println(plist); - } +public class PropertyListParser { + private char buffer[]; + private int currIndex; + private int lineNumber; + private int currLineStartIndex; + + /** + * Reads an object (String, List, or Map) from plistString and returns it. + * RuntimeExceptions are raised if there are parse problems. + */ + public static Object propertyListFromString(String plistString) { + PropertyListParser parser = new PropertyListParser(plistString); + return parser.readTopLevelObject(); + } + + /** + * Reads all remaining characters from the Reader, and returns the result of + * propertyListFromString(). RuntimeExceptions are raised if there are parse + * problems + */ + public static Object propertyListFromReader(Reader reader) throws IOException { + char charBuffer[] = new char[2048]; + StringBuffer stringBuffer = new StringBuffer(); + int numRead = 0; + + while (numRead >= 0) { + numRead = reader.read(charBuffer); + if (numRead > 0) + stringBuffer.append(charBuffer, 0, numRead); + } + + return propertyListFromString(stringBuffer.toString()); + } + + /** + * Reads the contents of the specified file, and parses the contents. If any + * error occurs, prints out a message using System.out.println() and returns + * null. + */ + public static Object propertyListFromFile(String filename) { + try { + FileInputStream stream = new FileInputStream(filename); + return propertyListFromReader(new InputStreamReader(stream)); + } catch (Exception exception) { + String errorMessage = exception.getMessage(); + System.out.println("Error parsing property list from " + filename + ": " + errorMessage); + } + + return null; + } + + /** + * Creates a new PropertyListParser to parse the contents of the specified + * String. + */ + public PropertyListParser(String plistString) { + this(plistString.toCharArray()); + } + + /** + * Creates a new PropertyListParser to parse the specified char array. + */ + public PropertyListParser(char[] charArray) { + buffer = charArray; + lineNumber = 1; + currLineStartIndex = 1; + currIndex = 0; + } + + public Object readTopLevelObject() { + Object plist = readObject(); + + skipCommentWhitespace(); + if (!isAtEnd()) { + throwParseException( + "Extra characters in plist string after parsing object. A plist should only contain one top-level object."); + } + + return plist; + } + + private void throwParseException(String errorMessage) { + int column = currIndex - currLineStartIndex + 1; + throw new RuntimeException(errorMessage + " (Line " + lineNumber + ", column " + column + ")"); + } + + private void updateLineNumberWithIndex(int lineStartIndex) { + lineNumber++; + currLineStartIndex = lineStartIndex; + } + + private boolean isAtEnd() { + return currIndex >= buffer.length; + } + + private void skipDoubleslashComment() { + while (!isAtEnd() && buffer[currIndex] != '\n') { + currIndex++; + } + } + + private void skipStandardCComment() { + currIndex++; // skip over the starting '/' + + while (!isAtEnd()) { + if (buffer[currIndex] == '\n') + updateLineNumberWithIndex(currIndex + 1); + + currIndex++; + + if (buffer[currIndex - 2] == '*' && buffer[currIndex - 1] == '/') { + return; + } + } + + throwParseException("Input exhausted while parsing comment"); + } + + private void skipWhitespace() { + while (!isAtEnd() && isWhitespace(buffer[currIndex])) { + if (buffer[currIndex] == '\n') + updateLineNumberWithIndex(currIndex + 1); + currIndex++; + } + } + + private void skipCommentWhitespace() { + boolean done = false; + + while (!done) { + done = true; + + skipWhitespace(); + if ((buffer.length - currIndex) > 1 && buffer[currIndex] == '/') { + if (buffer[currIndex + 1] == '/') { + done = false; // iterate again + skipDoubleslashComment(); + } else if (buffer[currIndex + 1] == '*') { + done = false; // iterate again + skipStandardCComment(); + } + } + } + } + + private Object readObject() { + skipCommentWhitespace(); + if (isAtEnd()) + return null; + + // Data (i.e. byte[]) not supported + if (buffer[currIndex] == '"') + return readQuotedString(); + if (buffer[currIndex] == '(') + return readList(); + if (buffer[currIndex] == '{') + return readMap(); + + return readUnquotedString(); + } + + private static final byte valueForHexDigit(char c) { + if (c >= '0' && c <= '9') + return (byte) (c - '0'); + if (c >= 'a' && c <= 'f') + return (byte) ((c - 'a') + 10); + if (c >= 'A' && c <= 'F') + return (byte) ((c - 'A') + 10); + + return 0; + } + + private static final boolean isOctalDigit(char c) { + return c >= '0' && c <= '7'; + } + + private static final boolean isHexDigit(char c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); + } + + private static String unquotedStringChars = "._$:/"; // chars allowed in unquoted strings + private static String whitespaceChars = " \t\n\r\f"; + + private static final boolean isWhitespace(char c) { + return whitespaceChars.indexOf(c) >= 0; + } + + private static final boolean isValidUnquotedStringChar(char c) { + return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') + || unquotedStringChars.indexOf(c) >= 0); + } + + private String readUnquotedString() { + int startIndex = currIndex; + + while (!isAtEnd() && isValidUnquotedStringChar(buffer[currIndex])) + currIndex++; + + if (startIndex == currIndex) + throwParseException("No allowable characters found to parse unquoted string"); + + return new String(buffer, startIndex, currIndex - startIndex); + } + + private String readQuotedString() { + currIndex++; // skip over '"' + + StringBuffer stringBuffer = new StringBuffer(); + int startIndex = currIndex; + + while (!isAtEnd() && buffer[currIndex] != '"') { + if (buffer[currIndex] != '\\') { + if (buffer[currIndex] == '\n') + updateLineNumberWithIndex(currIndex + 1); + + /* + * Just increment the index -- all these characters will be appended in chunks, + * either before an escape sequence or at the end. + */ + currIndex++; + } else // it's an escape + { + /* Append anything scanned past before the '\\' */ + if (startIndex < currIndex) + stringBuffer.append(buffer, startIndex, currIndex - startIndex); + currIndex++; // skip over '\\' + + if (isAtEnd()) + throwParseException("Input exhausted while parsing escape sequence"); + + switch (buffer[currIndex]) { + case 't': + stringBuffer.append('\t'); + currIndex++; + break; // tab + case 'n': + stringBuffer.append('\n'); + currIndex++; + break; // newline + case 'r': + stringBuffer.append('\r'); + currIndex++; + break; // carriage return + case 'f': + stringBuffer.append('\f'); + currIndex++; + break; // form feed + case 'b': + stringBuffer.append('\b'); + currIndex++; + break; // backspace + case 'a': + stringBuffer.append('\007'); + currIndex++; + break; // bell + case 'v': + stringBuffer.append('\013'); + currIndex++; + break; // vertical tab + case 'U': + case 'u': { + /* A Unicode escape. Always followed by 4 hex digits. */ + currIndex++; // skip past the 'U' + if ((currIndex + 4) > buffer.length) + throwParseException("Not enough chars to parse \\U sequence"); + + if (!isHexDigit(buffer[currIndex]) || !isHexDigit(buffer[currIndex + 1]) + || !isHexDigit(buffer[currIndex + 2]) || !isHexDigit(buffer[currIndex + 3])) { + throwParseException("Four hex digits not found for \\U sequence"); + } + + byte byte3 = valueForHexDigit(buffer[currIndex]); + byte byte2 = valueForHexDigit(buffer[currIndex + 1]); + byte byte1 = valueForHexDigit(buffer[currIndex + 2]); + byte byte0 = valueForHexDigit(buffer[currIndex + 3]); + char theChar = (char) ((byte3 << 12) + (byte2 << 8) + (byte1 << 4) + byte0); + stringBuffer.append(theChar); + currIndex += 4; + break; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { + /* An octal escape. Expect 1, 2, or 3 octal digits. */ + int digits = 0; + int value = 0; + + do { + value *= 8; + value += (int) (buffer[currIndex] - '0'); + currIndex++; + digits++; + } while (digits <= 3 && !isAtEnd() && isOctalDigit(buffer[currIndex])); + + if (value > 255) + throwParseException("Value too large in octal escape sequence (> 0377)"); + + // This assumes value is in ISO Latin 1 encoding + stringBuffer.append((char) value); + break; + } + /* I guess plists can't have the \x{HEX}{HEX} escapes */ + default: { + // Unknown escape sequence, just add the character. + // GCC warns if this isn't a '"', '\'', or '\\'... + stringBuffer.append(buffer[currIndex]); + if (buffer[currIndex] == '\n') + updateLineNumberWithIndex(currIndex + 1); + currIndex++; + break; + } + } // end case + + /* Reset startIndex, so a verbatim copy will now start from this index */ + startIndex = currIndex; + + } // end '\\' escape + } + + if (isAtEnd()) + throwParseException("Input exhausted while parsing quoted string"); + if (startIndex < currIndex) + stringBuffer.append(buffer, startIndex, currIndex - startIndex); + currIndex++; // skip past '"' + + return stringBuffer.toString(); + } + + private List readList() { + List newList = new ArrayList(); + + currIndex++; // skip over '(' + skipCommentWhitespace(); + while (!isAtEnd() && buffer[currIndex] != ')') { + /* A comma is required between list elements */ + if (newList.size() > 0) { + if (buffer[currIndex] != ',') + throwParseException("List parsing failed: expecting ','"); + currIndex++; + skipCommentWhitespace(); + if (isAtEnd()) + throwParseException("Input exhausted while parsing list"); + } + + if (buffer[currIndex] != ')') { + Object plistObject = readObject(); + if (plistObject == null) + throwParseException("List parsing failed: could not read contained object."); + newList.add(plistObject); + skipCommentWhitespace(); + } + } + + if (isAtEnd()) + throwParseException("Input exhausted while parsing list"); + currIndex++; // skip past ')' + + return newList; + } + + private Map readMap() { + HashMap newMap = new HashMap(); + + currIndex++; // skip over open brace + skipCommentWhitespace(); + + while (!isAtEnd() && buffer[currIndex] != '}') { + Object key; + Object value; + + key = readObject(); + if (key == null || !(key instanceof String)) + throwParseException("Map parsing failed: could not parse key or key is not a String"); + + skipCommentWhitespace(); + if (isAtEnd() || buffer[currIndex] != '=') + throwParseException("Map parsing failed: expecting '='"); + currIndex++; // skip over '=' + skipCommentWhitespace(); + if (isAtEnd()) + throwParseException("Input exhausted while parsing map"); + + value = readObject(); + if (value == null) + throwParseException("Map parsing failed: could not parse value object"); + + skipCommentWhitespace(); + if (isAtEnd() || buffer[currIndex] != ';') + throwParseException("Map parsing failed: expecting ';'"); + currIndex++; // skip over ';' + skipCommentWhitespace(); + + newMap.put(key, value); + } + + if (isAtEnd()) + throwParseException("Input exhausted while parsing map"); + currIndex++; // skip past '}' + + return newMap; + } + + public static void main(String[] args) { + String filename = args[0]; + Object plist = PropertyListParser.propertyListFromFile(filename); + System.out.println(plist); + } } - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/QueueMap.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/QueueMap.java index 6d35b7b..59104e5 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/QueueMap.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/QueueMap.java @@ -21,518 +21,488 @@ package net.wotonomy.foundation.internal; import java.util.*; //collections /** -* A queue based implementation of the Map interface. This class provides for -* all the opertions of a map, but keeps the entries in the same sequence as -* originally added. The first entry placed in the map will be the first -* entry retreived during iteration: first-in, first-out (FIFO). <BR><BR> -* -* Keys cannot be duplicated. If an entry is made using a key that already -* exists, the value for that key will be replaced with that new value. There -* are no such restrictions on the values. The values may be null. <BR><BR> -* -* Some convenience methods are provided for the queue type operations. The -* first key can be retreived as well as the last key. A key can be used -* to retreive its corresponding value from the map. A value can also be used -* to retreive its key from the map, however, since there may be multiple values -* of the same equality, the first key found will be returned. <BR><BR> -* -* @author rglista@blacksmith.com -* @author mpowers@blacksmith.com -* @date $Date: 2006-02-18 17:41:36 -0500 (Sat, 18 Feb 2006) $ -* @revision $Revision: 899 $ -*/ -public class QueueMap implements Map -{ - List values; - List keys; - Map keyToValue; - -/** -* Creates an empty QueueMap. -*/ - public QueueMap() - { - values = new LinkedList(); - keys = new LinkedList(); - keyToValue = new HashMap(); - } - -/** -* Creates a QueueMap and places the entries from the passed in map into this map. -* The order of the entries is based on however the iterator iteratated through -* the map entries. -* @param t A map object. -*/ - public QueueMap( Map t ) - { - values = new ArrayList(); - keys = new ArrayList(); - keyToValue = new HashMap(); - - putAll( t ); - } - -/** -* Removes all the entries from this map. -*/ - public void clear() - { - values.clear(); - keys.clear(); - keyToValue.clear(); - } - -/** -* Tests to see if the key is contained in the map. If the key is present in -* the map, then TRUE is returned, otherwise FALSE is returned. The equals() -* operation is used to determine equality. -* @return True if the map contains the given key, false otherwise. -*/ - public boolean containsKey( Object key ) - { - return keyToValue.containsKey( key ); - } - -/** -* Tests to see if the value is contained in the map. If the value is present in -* the map, then TRUE is returned, otherwise FALSE is returned. The equals() -* operation is used to determine equality. The value can be null and will -* return TRUE if null is a value in the map. If TRUE is returned, then there -* may be more than one values in the map. -* @return True if the map contains the given value, false otherwise. -*/ - public boolean containsValue( Object value ) - { - return keyToValue.containsValue( value ); - } - -/** -* Returns a set view of the mappings contained in this map. Each element -* in the returned set is a <tt>Map.Entry</tt>. The returned set is NOT backed -* by the map, so changes to the map are NOT reflected in the set, and vice-versa. -* The returned set is independent of this Map and its underlying structure. -* -* @return a set view of the mappings contained in this map. -*/ - public Set entrySet() - { - Set result = new HashSet(keys.size(), 1F); - - for ( int i = 0; i < keys.size(); i++ ) - { - result.add( new KeyValuePair( keys.get(i), values.get(i) ) ); - } - - return result; - } - -/** -* Compares the specified object with this map for equality. Returns -* <tt>true</tt> if the given object is also a map and the two Maps -* represent the same mappings. More formally, two maps <tt>t1</tt> and -* <tt>t2</tt> represent the same mappings if -* <tt>t1.entrySet().equals(t2.entrySet())</tt>. This ensures that the -* <tt>equals</tt> method works properly across different implementations -* of the <tt>Map</tt> interface. -* -* @param o object to be compared for equality with this map. -* @return <tt>true</tt> if the specified object is equal to this map. -*/ - public boolean equals( Object o ) - { - return keyToValue.equals( o ); - } - -/** -* Returns the corresponding value for the given key. The returned value may be -* null as that is a legal value in this map. However, if the key is not -* contained in this map then null is also returned. Use the containsKey() -* method to distinguish between the two cases. -* @param key A key into the map. -* @return The value corresponding to the key (can be null), or null if the key -* is not contained in the map. -*/ - public Object get( Object key ) - { - return keyToValue.get( key ); - } - -/** -* Returns the hash code value for this map. The hash code of a map -* is defined to be the sum of the hashCodes of each entry in the map's -* entrySet view. This ensures that <tt>t1.equals(t2)</tt> implies -* that <tt>t1.hashCode()==t2.hashCode()</tt> for any two maps -* <tt>t1</tt> and <tt>t2</tt>, as required by the general -* contract of Object.hashCode. -* -* @return the hash code value for this map. -*/ - public int hashCode() - { - return keyToValue.hashCode(); - } - -/** -* Returns true is this map contains no key-value mappings. -* @return True is this map contains no entries, false otherwise. -*/ - public boolean isEmpty() - { - return keyToValue.isEmpty(); - } - -/** -* Returns the keys used in the map. There is no order implied in the returned -* set and may be different than the the order in which they were inserted. -* @return A Set containing all the keys used in the map. -*/ - public Set keySet() - { - Set result = new HashSet(keys.size(), 1F); - - for ( int i = 0; i < keys.size(); i++ ) - { - result.add( keys.get(i) ); - } - - return result; - } - -/** -* Places the key/value entry into the map at the end position. If the key -* already exists in the map, then its value is replaced by the new given -* value. The mapping does not change order in this case. The specified -* key cannot be null. -* @param key The key to place into the map, cannot be null. -* @param value The value to associate with the key, may be null. -* @return Null if the key is new, the replaced value if the key already -* existed. (Note: If the key was null, then null is returned.) -*/ - public Object put( Object key, Object value ) - { - if ( key == null ) return null; - - if ( keys.contains( key ) ) - { - values.remove( keys.indexOf( key ) ); - values.add( keys.indexOf( key ), value ); - } - else - { - values.add( value ); - keys.add( key ); - } - - return keyToValue.put( key, value ); - } - -/** -* Places all the entries from this given map into this map. If the keys -* already exist, then there values are replaced. -* @param t A map of key/value entries. -*/ - public void putAll( Map t ) - { - if ( t == null ) - { - // Nothing to do! - return; - } - - // Place the entries from the passed in map into this map. - for ( Iterator it = t.keySet().iterator(); it.hasNext(); ) - { - Object aKey = it.next(); - put( aKey, t.get( aKey ) ); - } - } - -/** -* Remove the mapping of the key and associated value from this map. -* Note: null is a valid value in the map. -* @param key A key to remove from the map, cannot be null. -* @return The value of the removed mapping, null if the mapping did not exist. -* Null could also be returned if the associated value of the key was null. -*/ - public Object remove( Object key ) - { - if ( key == null ) return null; - - Object value = null; - - if ( containsKey( key ) ) - { - value = keyToValue.remove( key ); - int i = values.indexOf( value ); - if ( i != -1 ) - { - keys.remove( i ); - values.remove( i ); - } - } - - return value; - } - -/** -* Returns the number of key/value pairs in this map. -* @return The number of pairs. -*/ - public int size() - { - return values.size(); - } - -/** -* Returns an ordered list of keys from the map. The order is the same -* as the added order of the mapped items.<br> -* NOTE: The returned list is the underlying keys list used by this class. -* If modification are to be made to this list, it should be cloned first. -* @return An ordered list of keys. -*/ - public List keys() - { - return keys; - } - -/** -* Returns an ordered list of values from the map. The order is the same -* as the added order of the mapped items. -* NOTE: The returned list is the underlying keys list used by this class. -* If modification are to be made to this list, it should be cloned first. -* @return An ordered list of values. -*/ - public Collection values() - { - return values; - } - -/** -* Returns the corresponding value for the given key. The returned value may be -* null as that is a legal value in this map. However, if the key is not -* contained in this map then null is also returned. Use the containsKey() -* method to distinguish between the two cases. -* @param key A key into the map. -* @return The value corresponding to the key (can be null), or null if the key -* is not contained in the map. -*/ - public Object getValueForKey( Object key ) - { - return keyToValue.get( key ); - } - -/** -* Returns the associated key for this value. Since there may be more than one -* of the same value in the map, this returns the first key associated with this -* value. Null is returned if the value is not in the map. -* @param value A value that is contained in this map. -* @return A first key that corresponds to this value. -*/ - public Object getKeyForValue( Object value ) - { - int i = values.indexOf( value ); - if ( i != -1 ) - { - return keys.get( i ); - } - return null; - } - -/** -* Returns the first key in the map. If the map is empty, then null is -* returned. -* @return The first key in the map, null if there are no mappings. -*/ - public Object getFirstKey() - { - if ( keys.size() < 1 ) - { - return null; - } - return keys.get(0); - } - -/** -* Returns the last key in the map. If the map is empty, then null is -* returned. -* @return The last key in the map, null if there are no mappings. -*/ - public Object getLastKey() - { - if ( keys.size() < 1 ) - { - return null; - } - return keys.get( keys.size() -1 ); - } - -/** -* This class contains a key/value pair. The key must be a valid object, -* it cannot be null. The value can be a valid object or null. -*/ - static public class KeyValuePair implements Map.Entry - { - Object key; - Object value; - - /** - * Default constructor. The constructor takes the key and value as parameters. - * Since the key cannot be null, it must be specified during initialization. - * The value can be null. - * @param key The key object of this pair. The key cannot be null. - * @param value The value object of this pair. The value can be null. - */ - public KeyValuePair( Object aKey, Object aValue ) - { - key = aKey; - value = aValue; - } - - /** - * Returns the key object of this pair. - * @return The key object. - */ - public Object getKey() - { - return key; - } - - /** - * Returns the the value object of this pair. May be null. - * @return The value object. - */ - public Object getValue() - { - return value; - } - - /** - * Sets the value object of this pair. May be an object or null. - * @param aValue The value object to place into this pair. - */ - public Object setValue( Object aValue ) - { - Object result = value; - value = aValue; - return result; - } - - public boolean equals( Object o ) - { - if ( o instanceof KeyValuePair ) - { - KeyValuePair p = (KeyValuePair) o; - if ( ( key.equals( p.getKey() ) ) && ( value.equals( p.getValue() ) ) ) - { - return true; - } - } - return false; - } - } - - /** - * Returns a string reprsentation of this class. The contents of the - * map are placed in the string in its proper order. - */ - public String toString() - { - int max = size() - 1; - StringBuffer buf = new StringBuffer(); - - buf.append("{"); - for (int j = 0; j <= max; j++) - { - buf.append(keys.get(j) + "=" + values.get(j)); - if (j < max) - { - buf.append(", "); - } - } - buf.append("}"); - - return buf.toString(); - } - - // unit test - public static void main( String[] argv ) - { - QueueMap qMap; - - qMap = new QueueMap(); - for (int i = 0; i < 5; i++) - { - qMap.put(Integer.toString(i), Integer.toString(i)); - } - System.out.println("\nMap = " + qMap); - System.out.println("Keys = " + qMap.keys()); - System.out.println("Values = " + qMap.values()); - - qMap = new QueueMap(); - for (int i = 0; i < 5; i++) - { - qMap.put(Integer.toString(i), "A"); - } - System.out.println("\nMap = " + qMap); - System.out.println("Keys = " + qMap.keys()); - System.out.println("Values = " + qMap.values()); - - qMap = new QueueMap(); - for (int i = 0; i < 5; i++) - { - qMap.put(Integer.toString(i), null); - } - System.out.println("\nMap = " + qMap); - System.out.println("Keys = " + qMap.keys()); - System.out.println("Values = " + qMap.values()); - - Map aMap = new HashMap(); - for (int i = 0; i < 5; i++) - { - aMap.put(Integer.toString(i), Integer.toString(i)); - } - qMap = new QueueMap( aMap ); - System.out.println("\nHashMap = " + aMap); - System.out.println("Map = " + qMap); - System.out.println("Keys = " + qMap.keys()); - System.out.println("Values = " + qMap.values()); - - qMap = new QueueMap(); - qMap.put( "Test1", "String1" ); - qMap.put( "Test2", "String2" ); - qMap.put( "Test3", "String3" ); - qMap.put( "Test4", "String4" ); - qMap.put( "Test5", "String5" ); - System.out.println("\nStandard Test, Map = " + qMap); - qMap.put( "Test6", "String6" ); - qMap.put( "Test7", "String7" ); - System.out.println("Put New Test, Map = " + qMap); - qMap.put( "Test2", "New String2" ); - qMap.put( "Test6", "New String6" ); - System.out.println("Put Existing Test, Map = " + qMap); - qMap.put( "Test5", null ); - qMap.put( "Test8", null ); - System.out.println("Put Null Test, Map = " + qMap); - qMap.remove( "Test1" ); - qMap.remove( "Test3" ); - qMap.remove( "Test5" ); - qMap.remove( "Test9" ); - System.out.println("Remove Test, Map = " + qMap); - System.out.println(" Keys = " + qMap.keys()); - System.out.println(" Values = " + qMap.values()); - qMap.clear(); - qMap.put( "Test10", "String10" ); - qMap.put( "Test11", "String11" ); - qMap.put( "Test12", "String12" ); - System.out.println("Clear Test, Map = " + qMap); - - aMap = new HashMap(); - aMap.put( "Test10", "String10" ); - aMap.put( "Test11", "String11" ); - aMap.put( "Test12", "String12" ); - System.out.println("Equality Test, Equal = " + qMap.equals( aMap )); - } + * A queue based implementation of the Map interface. This class provides for + * all the opertions of a map, but keeps the entries in the same sequence as + * originally added. The first entry placed in the map will be the first entry + * retreived during iteration: first-in, first-out (FIFO). <BR> + * <BR> + * + * Keys cannot be duplicated. If an entry is made using a key that already + * exists, the value for that key will be replaced with that new value. There + * are no such restrictions on the values. The values may be null. <BR> + * <BR> + * + * Some convenience methods are provided for the queue type operations. The + * first key can be retreived as well as the last key. A key can be used to + * retreive its corresponding value from the map. A value can also be used to + * retreive its key from the map, however, since there may be multiple values of + * the same equality, the first key found will be returned. <BR> + * <BR> + * + * @author rglista@blacksmith.com + * @author mpowers@blacksmith.com + * @date $Date: 2006-02-18 17:41:36 -0500 (Sat, 18 Feb 2006) $ + * @revision $Revision: 899 $ + */ +public class QueueMap implements Map { + List values; + List keys; + Map keyToValue; + + /** + * Creates an empty QueueMap. + */ + public QueueMap() { + values = new LinkedList(); + keys = new LinkedList(); + keyToValue = new HashMap(); + } + + /** + * Creates a QueueMap and places the entries from the passed in map into this + * map. The order of the entries is based on however the iterator iteratated + * through the map entries. + * + * @param t A map object. + */ + public QueueMap(Map t) { + values = new ArrayList(); + keys = new ArrayList(); + keyToValue = new HashMap(); + + putAll(t); + } + + /** + * Removes all the entries from this map. + */ + public void clear() { + values.clear(); + keys.clear(); + keyToValue.clear(); + } + + /** + * Tests to see if the key is contained in the map. If the key is present in the + * map, then TRUE is returned, otherwise FALSE is returned. The equals() + * operation is used to determine equality. + * + * @return True if the map contains the given key, false otherwise. + */ + public boolean containsKey(Object key) { + return keyToValue.containsKey(key); + } + + /** + * Tests to see if the value is contained in the map. If the value is present in + * the map, then TRUE is returned, otherwise FALSE is returned. The equals() + * operation is used to determine equality. The value can be null and will + * return TRUE if null is a value in the map. If TRUE is returned, then there + * may be more than one values in the map. + * + * @return True if the map contains the given value, false otherwise. + */ + public boolean containsValue(Object value) { + return keyToValue.containsValue(value); + } + + /** + * Returns a set view of the mappings contained in this map. Each element in the + * returned set is a <tt>Map.Entry</tt>. The returned set is NOT backed by the + * map, so changes to the map are NOT reflected in the set, and vice-versa. The + * returned set is independent of this Map and its underlying structure. + * + * @return a set view of the mappings contained in this map. + */ + public Set entrySet() { + Set result = new HashSet(keys.size(), 1F); + + for (int i = 0; i < keys.size(); i++) { + result.add(new KeyValuePair(keys.get(i), values.get(i))); + } + + return result; + } + + /** + * Compares the specified object with this map for equality. Returns + * <tt>true</tt> if the given object is also a map and the two Maps represent + * the same mappings. More formally, two maps <tt>t1</tt> and <tt>t2</tt> + * represent the same mappings if <tt>t1.entrySet().equals(t2.entrySet())</tt>. + * This ensures that the <tt>equals</tt> method works properly across different + * implementations of the <tt>Map</tt> interface. + * + * @param o object to be compared for equality with this map. + * @return <tt>true</tt> if the specified object is equal to this map. + */ + public boolean equals(Object o) { + return keyToValue.equals(o); + } + + /** + * Returns the corresponding value for the given key. The returned value may be + * null as that is a legal value in this map. However, if the key is not + * contained in this map then null is also returned. Use the containsKey() + * method to distinguish between the two cases. + * + * @param key A key into the map. + * @return The value corresponding to the key (can be null), or null if the key + * is not contained in the map. + */ + public Object get(Object key) { + return keyToValue.get(key); + } + + /** + * Returns the hash code value for this map. The hash code of a map is defined + * to be the sum of the hashCodes of each entry in the map's entrySet view. This + * ensures that <tt>t1.equals(t2)</tt> implies that + * <tt>t1.hashCode()==t2.hashCode()</tt> for any two maps <tt>t1</tt> and + * <tt>t2</tt>, as required by the general contract of Object.hashCode. + * + * @return the hash code value for this map. + */ + public int hashCode() { + return keyToValue.hashCode(); + } + + /** + * Returns true is this map contains no key-value mappings. + * + * @return True is this map contains no entries, false otherwise. + */ + public boolean isEmpty() { + return keyToValue.isEmpty(); + } + + /** + * Returns the keys used in the map. There is no order implied in the returned + * set and may be different than the the order in which they were inserted. + * + * @return A Set containing all the keys used in the map. + */ + public Set keySet() { + Set result = new HashSet(keys.size(), 1F); + + for (int i = 0; i < keys.size(); i++) { + result.add(keys.get(i)); + } + + return result; + } + + /** + * Places the key/value entry into the map at the end position. If the key + * already exists in the map, then its value is replaced by the new given value. + * The mapping does not change order in this case. The specified key cannot be + * null. + * + * @param key The key to place into the map, cannot be null. + * @param value The value to associate with the key, may be null. + * @return Null if the key is new, the replaced value if the key already + * existed. (Note: If the key was null, then null is returned.) + */ + public Object put(Object key, Object value) { + if (key == null) + return null; + + if (keys.contains(key)) { + values.remove(keys.indexOf(key)); + values.add(keys.indexOf(key), value); + } else { + values.add(value); + keys.add(key); + } + + return keyToValue.put(key, value); + } + + /** + * Places all the entries from this given map into this map. If the keys already + * exist, then there values are replaced. + * + * @param t A map of key/value entries. + */ + public void putAll(Map t) { + if (t == null) { + // Nothing to do! + return; + } + + // Place the entries from the passed in map into this map. + for (Iterator it = t.keySet().iterator(); it.hasNext();) { + Object aKey = it.next(); + put(aKey, t.get(aKey)); + } + } + + /** + * Remove the mapping of the key and associated value from this map. Note: null + * is a valid value in the map. + * + * @param key A key to remove from the map, cannot be null. + * @return The value of the removed mapping, null if the mapping did not exist. + * Null could also be returned if the associated value of the key was + * null. + */ + public Object remove(Object key) { + if (key == null) + return null; + + Object value = null; + + if (containsKey(key)) { + value = keyToValue.remove(key); + int i = values.indexOf(value); + if (i != -1) { + keys.remove(i); + values.remove(i); + } + } + + return value; + } + + /** + * Returns the number of key/value pairs in this map. + * + * @return The number of pairs. + */ + public int size() { + return values.size(); + } + + /** + * Returns an ordered list of keys from the map. The order is the same as the + * added order of the mapped items.<br> + * NOTE: The returned list is the underlying keys list used by this class. If + * modification are to be made to this list, it should be cloned first. + * + * @return An ordered list of keys. + */ + public List keys() { + return keys; + } + + /** + * Returns an ordered list of values from the map. The order is the same as the + * added order of the mapped items. NOTE: The returned list is the underlying + * keys list used by this class. If modification are to be made to this list, it + * should be cloned first. + * + * @return An ordered list of values. + */ + public Collection values() { + return values; + } + + /** + * Returns the corresponding value for the given key. The returned value may be + * null as that is a legal value in this map. However, if the key is not + * contained in this map then null is also returned. Use the containsKey() + * method to distinguish between the two cases. + * + * @param key A key into the map. + * @return The value corresponding to the key (can be null), or null if the key + * is not contained in the map. + */ + public Object getValueForKey(Object key) { + return keyToValue.get(key); + } + + /** + * Returns the associated key for this value. Since there may be more than one + * of the same value in the map, this returns the first key associated with this + * value. Null is returned if the value is not in the map. + * + * @param value A value that is contained in this map. + * @return A first key that corresponds to this value. + */ + public Object getKeyForValue(Object value) { + int i = values.indexOf(value); + if (i != -1) { + return keys.get(i); + } + return null; + } + + /** + * Returns the first key in the map. If the map is empty, then null is returned. + * + * @return The first key in the map, null if there are no mappings. + */ + public Object getFirstKey() { + if (keys.size() < 1) { + return null; + } + return keys.get(0); + } + + /** + * Returns the last key in the map. If the map is empty, then null is returned. + * + * @return The last key in the map, null if there are no mappings. + */ + public Object getLastKey() { + if (keys.size() < 1) { + return null; + } + return keys.get(keys.size() - 1); + } + + /** + * This class contains a key/value pair. The key must be a valid object, it + * cannot be null. The value can be a valid object or null. + */ + static public class KeyValuePair implements Map.Entry { + Object key; + Object value; + + /** + * Default constructor. The constructor takes the key and value as parameters. + * Since the key cannot be null, it must be specified during initialization. The + * value can be null. + * + * @param key The key object of this pair. The key cannot be null. + * @param value The value object of this pair. The value can be null. + */ + public KeyValuePair(Object aKey, Object aValue) { + key = aKey; + value = aValue; + } + + /** + * Returns the key object of this pair. + * + * @return The key object. + */ + public Object getKey() { + return key; + } + + /** + * Returns the the value object of this pair. May be null. + * + * @return The value object. + */ + public Object getValue() { + return value; + } + + /** + * Sets the value object of this pair. May be an object or null. + * + * @param aValue The value object to place into this pair. + */ + public Object setValue(Object aValue) { + Object result = value; + value = aValue; + return result; + } + + public boolean equals(Object o) { + if (o instanceof KeyValuePair) { + KeyValuePair p = (KeyValuePair) o; + if ((key.equals(p.getKey())) && (value.equals(p.getValue()))) { + return true; + } + } + return false; + } + } + + /** + * Returns a string reprsentation of this class. The contents of the map are + * placed in the string in its proper order. + */ + public String toString() { + int max = size() - 1; + StringBuffer buf = new StringBuffer(); + + buf.append("{"); + for (int j = 0; j <= max; j++) { + buf.append(keys.get(j) + "=" + values.get(j)); + if (j < max) { + buf.append(", "); + } + } + buf.append("}"); + + return buf.toString(); + } + + // unit test + public static void main(String[] argv) { + QueueMap qMap; + + qMap = new QueueMap(); + for (int i = 0; i < 5; i++) { + qMap.put(Integer.toString(i), Integer.toString(i)); + } + System.out.println("\nMap = " + qMap); + System.out.println("Keys = " + qMap.keys()); + System.out.println("Values = " + qMap.values()); + + qMap = new QueueMap(); + for (int i = 0; i < 5; i++) { + qMap.put(Integer.toString(i), "A"); + } + System.out.println("\nMap = " + qMap); + System.out.println("Keys = " + qMap.keys()); + System.out.println("Values = " + qMap.values()); + + qMap = new QueueMap(); + for (int i = 0; i < 5; i++) { + qMap.put(Integer.toString(i), null); + } + System.out.println("\nMap = " + qMap); + System.out.println("Keys = " + qMap.keys()); + System.out.println("Values = " + qMap.values()); + + Map aMap = new HashMap(); + for (int i = 0; i < 5; i++) { + aMap.put(Integer.toString(i), Integer.toString(i)); + } + qMap = new QueueMap(aMap); + System.out.println("\nHashMap = " + aMap); + System.out.println("Map = " + qMap); + System.out.println("Keys = " + qMap.keys()); + System.out.println("Values = " + qMap.values()); + + qMap = new QueueMap(); + qMap.put("Test1", "String1"); + qMap.put("Test2", "String2"); + qMap.put("Test3", "String3"); + qMap.put("Test4", "String4"); + qMap.put("Test5", "String5"); + System.out.println("\nStandard Test, Map = " + qMap); + qMap.put("Test6", "String6"); + qMap.put("Test7", "String7"); + System.out.println("Put New Test, Map = " + qMap); + qMap.put("Test2", "New String2"); + qMap.put("Test6", "New String6"); + System.out.println("Put Existing Test, Map = " + qMap); + qMap.put("Test5", null); + qMap.put("Test8", null); + System.out.println("Put Null Test, Map = " + qMap); + qMap.remove("Test1"); + qMap.remove("Test3"); + qMap.remove("Test5"); + qMap.remove("Test9"); + System.out.println("Remove Test, Map = " + qMap); + System.out.println(" Keys = " + qMap.keys()); + System.out.println(" Values = " + qMap.values()); + qMap.clear(); + qMap.put("Test10", "String10"); + qMap.put("Test11", "String11"); + qMap.put("Test12", "String12"); + System.out.println("Clear Test, Map = " + qMap); + + aMap = new HashMap(); + aMap.put("Test10", "String10"); + aMap.put("Test11", "String11"); + aMap.put("Test12", "String12"); + System.out.println("Equality Test, Equal = " + qMap.equals(aMap)); + } } - - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/URLResourceReader.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/URLResourceReader.java index 9133a8d..8694564 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/URLResourceReader.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/URLResourceReader.java @@ -47,7 +47,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== - */ + */ package net.wotonomy.foundation.internal; @@ -61,147 +61,134 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; /** - * This implementation of URL Resource Reader assumes 2 types - * of base urls. A base url that ends with / is considered a - * resource folder, whereas a resource that does not end with - * / is considered a zip/jar resource folder. + * This implementation of URL Resource Reader assumes 2 types of base urls. A + * base url that ends with / is considered a resource folder, whereas a resource + * that does not end with / is considered a zip/jar resource folder. * - * If the resource folder happens is a zip/jar archive, the - * entries are always cached. - * For non-zip base urls, one could specify whether or not it should - * be cached. + * If the resource folder happens is a zip/jar archive, the entries are always + * cached. For non-zip base urls, one could specify whether or not it should be + * cached. * * @author Harish Prabandham */ -public class URLResourceReader { - private Hashtable resourceCache = new Hashtable(); - private boolean iszip = true; - private URL url = null; - private boolean cache = true; - - /** - * Creates a new URLResourceReader object. You can either give - * the URL of the zip/jar file or a base url where to - * look for additional resources. If the url ends with - * "/" then it is assumed to be a Base URL. - * @param The base url to look for the resources. - * @param If the base url is not a zip/jar, then true indicates - * that entries should be cached, false otherwise. - */ - public URLResourceReader(URL baseurl, boolean cache) throws IOException { - this.url = baseurl; - this.cache = cache; - this.iszip = !url.getFile().endsWith("/"); - if(this.iszip) - this.cache = true; - initialize(); - } - - /** - * equivalent to URLResourceReader(baseurl, false) - */ - public URLResourceReader(URL baseurl) throws IOException { - this(baseurl, false); - } - - /** - * Creates a new URLResourceReader object with the given - * input stream. The stream is assumed to be a zip/jar - * stream. - */ - public URLResourceReader(InputStream is) throws IOException { - init(is); - } - - private void initialize() throws IOException { - if(iszip) { - InputStream is = url.openStream(); - init(is); - is.close(); - } - } - - private byte[] readFully(InputStream is) throws IOException { - byte[] buf = new byte[1024]; - int num = 0; - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - - while( (num = is.read(buf)) != -1) { - bout.write(buf, 0, num); - } - - return bout.toByteArray(); - } - - private void init(InputStream is) throws IOException { - ZipInputStream zstream = new ZipInputStream(is); - ZipEntry entry; - - while( (entry = zstream.getNextEntry()) != null) { - byte[] entryData = readFully(zstream); - if(cache) - resourceCache.put(entry.getName(), entryData); - zstream.closeEntry(); - } - - zstream.close(); - } - - /** - * Returns an Enumeration of all "known" resource names. - */ - public Enumeration getResourceNames() { - return resourceCache.keys(); - } - - /** - * Returns an array of bytes read for this resource if the - * resource exists. This method blocks until the resource - * has been fully read. If the resource does not exist, - * this method returns null. - */ - public byte[] getResource(String resource) { - // lookup the data in the cache... - byte[] data = (byte[]) resourceCache.get(resource); - if(data != null) { - return data; - } - - // if the data was to come from a zip file that we - // already read fully & cached , then it is probably - // not there. - if(iszip) { - return null; - } - - // Now the only choice left is to make a url connection. - try { - URL realURL = new URL(url.getProtocol(), url.getHost(), - url.getFile() + resource); - data = readFully(realURL.openStream()); - // add it to cache if needed... - if(cache) - resourceCache.put(resource, data); - return data; - } catch(Exception e) { - return null; - } - } - - public void close() { - resourceCache.clear(); - resourceCache = null; - } - - public String toString() { - return url.toString(); - } +public class URLResourceReader { + private Hashtable resourceCache = new Hashtable(); + private boolean iszip = true; + private URL url = null; + private boolean cache = true; + + /** + * Creates a new URLResourceReader object. You can either give the URL of the + * zip/jar file or a base url where to look for additional resources. If the url + * ends with "/" then it is assumed to be a Base URL. + * + * @param The base url to look for the resources. + * @param If the base url is not a zip/jar, then true indicates that entries + * should be cached, false otherwise. + */ + public URLResourceReader(URL baseurl, boolean cache) throws IOException { + this.url = baseurl; + this.cache = cache; + this.iszip = !url.getFile().endsWith("/"); + if (this.iszip) + this.cache = true; + initialize(); + } + + /** + * equivalent to URLResourceReader(baseurl, false) + */ + public URLResourceReader(URL baseurl) throws IOException { + this(baseurl, false); + } + + /** + * Creates a new URLResourceReader object with the given input stream. The + * stream is assumed to be a zip/jar stream. + */ + public URLResourceReader(InputStream is) throws IOException { + init(is); + } + + private void initialize() throws IOException { + if (iszip) { + InputStream is = url.openStream(); + init(is); + is.close(); + } + } + + private byte[] readFully(InputStream is) throws IOException { + byte[] buf = new byte[1024]; + int num = 0; + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + + while ((num = is.read(buf)) != -1) { + bout.write(buf, 0, num); + } + + return bout.toByteArray(); + } + + private void init(InputStream is) throws IOException { + ZipInputStream zstream = new ZipInputStream(is); + ZipEntry entry; + + while ((entry = zstream.getNextEntry()) != null) { + byte[] entryData = readFully(zstream); + if (cache) + resourceCache.put(entry.getName(), entryData); + zstream.closeEntry(); + } + + zstream.close(); + } + + /** + * Returns an Enumeration of all "known" resource names. + */ + public Enumeration getResourceNames() { + return resourceCache.keys(); + } + + /** + * Returns an array of bytes read for this resource if the resource exists. This + * method blocks until the resource has been fully read. If the resource does + * not exist, this method returns null. + */ + public byte[] getResource(String resource) { + // lookup the data in the cache... + byte[] data = (byte[]) resourceCache.get(resource); + if (data != null) { + return data; + } + + // if the data was to come from a zip file that we + // already read fully & cached , then it is probably + // not there. + if (iszip) { + return null; + } + + // Now the only choice left is to make a url connection. + try { + URL realURL = new URL(url.getProtocol(), url.getHost(), url.getFile() + resource); + data = readFully(realURL.openStream()); + // add it to cache if needed... + if (cache) + resourceCache.put(resource, data); + return data; + } catch (Exception e) { + return null; + } + } + + public void close() { + resourceCache.clear(); + resourceCache = null; + } + + public String toString() { + return url.toString(); + } } - - - - - - - - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ValueConverter.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ValueConverter.java index d6bc797..7f28e06 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ValueConverter.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ValueConverter.java @@ -17,6 +17,7 @@ License along with this library; if not, see http://www.gnu.org */ package net.wotonomy.foundation.internal; + import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.util.Collection; @@ -25,694 +26,562 @@ import java.util.LinkedList; import java.util.Map; /** -* A utility class to convert objects to a desired class. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public class ValueConverter -{ - /** - * Returns the specified object as converted to an instance of the - * specified class, or null if the conversion could not be performed. - */ - static public Object convertObjectToClass( Object anObject, Class aClass ) - { - if ( aClass == String.class ) - { - return getString( anObject ); - } - if ( aClass == Short.class ) - { - return getShort( anObject ); - } - if ( aClass == short.class ) - { - return getShort( anObject ); - } - if ( aClass == Integer.class ) - { - return getInteger( anObject ); - } - if ( aClass == int.class ) - { - return getInteger( anObject ); - } - if ( aClass == Long.class ) - { - return getLong( anObject ); - } - if ( aClass == long.class ) - { - return getLong( anObject ); - } - if ( aClass == Float.class ) - { - return getFloat( anObject ); - } - if ( aClass == float.class ) - { - return getFloat( anObject ); - } - if ( aClass == Double.class ) - { - return getDouble( anObject ); - } - if ( aClass == double.class ) - { - return getDouble( anObject ); - } - if ( aClass == java.util.Date.class ) - { - return getDate( anObject ); - } - if ( aClass == Boolean.class ) - { - return getBoolean( anObject ); - } - if ( aClass == boolean.class ) - { - return getBoolean( anObject ); - } - if ( aClass == Character.class ) - { - return getCharacter( anObject ); - } - if ( aClass == char.class ) - { - return getCharacter( anObject ); - } - if ( aClass == Byte.class ) - { - return getByte( anObject ); - } - if ( aClass == byte.class ) - { - return getByte( anObject ); - } - if ( Collection.class.isAssignableFrom( aClass ) ) - { - return getCollection( anObject, aClass ); - } - if ( aClass.isArray() ) - { - return getArray( anObject, aClass ); - } - - return convert( anObject, aClass ); - } - - /** - * Called by convertObjectToClass() when we need to - * convert to an unrecognized type. - * This implementation scans the constructors of the - * specified class for the best fit to the object. - * and returns a new instance with that constructor. - * Subclasses can override to directly support specific - * types. - */ - static protected Object convert( Object anObject, Class aClass ) - { - Constructor[] ctors = aClass.getConstructors(); - - Class[] types; - for ( int i = 0; i < ctors.length; i++ ) - { - types = ctors[i].getParameterTypes(); - if ( types.length == 1 ) - { - if ( types[0].equals( anObject.getClass() ) ) - { - try - { - return ctors[i].newInstance( new Object[] { anObject } ); - } - catch ( Exception exc ) - { - // fall through - } - } - } - } - - for ( int i = 0; i < ctors.length; i++ ) - { - types = ctors[i].getParameterTypes(); - if ( types.length == 1 ) - { - if ( anObject.getClass().isAssignableFrom( types[0] ) ) - { - try - { - return ctors[i].newInstance( new Object[] { anObject } ); - } - catch ( Exception exc ) - { - // fall through - } - } - } - } - - return null; - } - - /** - * Tries to convert all objects to either Numbers or objects - * that will produce a parsable toString result. - */ - static protected Object preprocess( Object anObject ) - { - if ( anObject instanceof Boolean ) - { - if ( ((Boolean)anObject).booleanValue() ) - { - return new Double( 1.0 ); - } - return new Double( 0.0 ); - } - - if ( anObject instanceof Character ) - { - return anObject.toString(); - } - - return anObject; - } - - static public short getShortValue( Object anObject ) - { - Short result = getShort( anObject ); - return ( result == null ) ? (short) 0 : result.shortValue(); - } - static public Short getShort( Object anObject ) - { - if ( anObject == null ) return new Short( (short) 0 ); - if ( "".equals( anObject ) ) return new Short( (short) 0 ); - if ( anObject instanceof Short ) return (Short) anObject; - - anObject = preprocess( anObject ); - - if ( anObject instanceof Number ) - { - return new Short( ((Number)anObject).shortValue() ); - } - - try - { - return Short.valueOf( anObject.toString() ); - } - catch ( Exception exc ) - { - return null; - } - } - - static public int getIntValue( Object anObject ) - { - Integer result = getInteger( anObject ); - return ( result == null ) ? 0 : result.intValue(); - } - static public Integer getInteger( Object anObject ) - { - if ( anObject == null ) return new Integer( 0 ); - if ( "".equals( anObject ) ) return new Integer( 0 ); - if ( anObject instanceof Integer ) return (Integer) anObject; - - anObject = preprocess( anObject ); - - if ( anObject instanceof Number ) - { - return new Integer( ((Number)anObject).intValue() ); - } - - try - { - return Integer.valueOf( anObject.toString() ); - } - catch ( Exception exc ) - { - return null; - } - } - - static public long getLongValue ( Object anObject ) - { - Long result = getLong( anObject ); - return ( result == null ) ? (long) 0 : result.longValue(); - } - static public Long getLong( Object anObject ) - { - if ( anObject == null ) return new Long( 0 ); - if ( "".equals( anObject ) ) return new Long( 0 ); - if ( anObject instanceof Long ) return (Long) anObject; - - anObject = preprocess( anObject ); - - if ( anObject instanceof Number ) - { - return new Long( ((Number)anObject).longValue() ); - } - - try - { - return Long.valueOf( anObject.toString() ); - } - catch ( Exception exc ) - { - return null; - } - } - - static public double getDoubleValue ( Object anObject ) - { - Double result = getDouble( anObject ); - return ( result == null ) ? 0.0f : result.doubleValue(); - } - static public Double getDouble( Object anObject ) - { - if ( anObject == null ) return new Double( 0.0 ); - if ( "".equals( anObject ) ) return new Double( 0 ); - if ( anObject instanceof Double ) return (Double) anObject; - - anObject = preprocess( anObject ); - - if ( anObject instanceof Number ) - { - return new Double( ((Number)anObject).doubleValue() ); - } - - try - { - return Double.valueOf( anObject.toString() ); - } - catch ( Exception exc ) - { - return null; - } - } - - static public float getFloatValue( Object anObject ) - { - Float result = getFloat( anObject ); - return ( result == null ) ? 0.0f : result.floatValue(); - } - static public Float getFloat( Object anObject ) - { - if ( anObject == null ) return new Float( 0.0 ); - if ( "".equals( anObject ) ) return new Float( 0.0 ); - if ( anObject instanceof Float ) return (Float) anObject; - - anObject = preprocess( anObject ); - - if ( anObject instanceof Number ) - { - return new Float( ((Number)anObject).floatValue() ); - } - - try - { - return Float.valueOf( anObject.toString() ); - } - catch ( Exception exc ) - { - return null; - } - } - - static public char getCharValue( Object anObject ) - { - Character result = getCharacter( anObject ); - return ( result == null ) ? (char) 0 : result.charValue(); - } - static public Character getCharacter( Object anObject ) - { - if ( anObject == null ) return new Character( (char) 0 ); - if ( anObject instanceof Character ) return (Character) anObject; - - anObject = preprocess( anObject ); - - if ( anObject instanceof Number ) - { - return new Character( (char) ((Number)anObject).byteValue() ); - } - - try - { - return new Character( anObject.toString().charAt( 0 ) ); - } - catch ( Exception exc ) - { - return null; - } - } - - static public byte getByteValue( Object anObject ) - { - Byte result = getByte ( anObject ); - return ( result == null ) ? (byte) 0 : result.byteValue(); - } - static public Byte getByte( Object anObject ) - { - if ( anObject == null ) return new Byte( Byte.MIN_VALUE ); - if ( "".equals( anObject ) ) return new Byte( Byte.MIN_VALUE ); - if ( anObject instanceof Byte ) return (Byte) anObject; - - anObject = preprocess( anObject ); - - if ( anObject instanceof Number ) - { - return new Byte( ((Number)anObject).byteValue() ); - } - - try - { - return Byte.decode( anObject.toString() ); - } - catch ( Exception exc ) - { - // fall through - } - - try - { - return Byte.valueOf( anObject.toString() ); - } - catch ( Exception exc ) - { - return null; - } - } + * A utility class to convert objects to a desired class. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public class ValueConverter { + /** + * Returns the specified object as converted to an instance of the specified + * class, or null if the conversion could not be performed. + */ + static public Object convertObjectToClass(Object anObject, Class aClass) { + if (aClass == String.class) { + return getString(anObject); + } + if (aClass == Short.class) { + return getShort(anObject); + } + if (aClass == short.class) { + return getShort(anObject); + } + if (aClass == Integer.class) { + return getInteger(anObject); + } + if (aClass == int.class) { + return getInteger(anObject); + } + if (aClass == Long.class) { + return getLong(anObject); + } + if (aClass == long.class) { + return getLong(anObject); + } + if (aClass == Float.class) { + return getFloat(anObject); + } + if (aClass == float.class) { + return getFloat(anObject); + } + if (aClass == Double.class) { + return getDouble(anObject); + } + if (aClass == double.class) { + return getDouble(anObject); + } + if (aClass == java.util.Date.class) { + return getDate(anObject); + } + if (aClass == Boolean.class) { + return getBoolean(anObject); + } + if (aClass == boolean.class) { + return getBoolean(anObject); + } + if (aClass == Character.class) { + return getCharacter(anObject); + } + if (aClass == char.class) { + return getCharacter(anObject); + } + if (aClass == Byte.class) { + return getByte(anObject); + } + if (aClass == byte.class) { + return getByte(anObject); + } + if (Collection.class.isAssignableFrom(aClass)) { + return getCollection(anObject, aClass); + } + if (aClass.isArray()) { + return getArray(anObject, aClass); + } + + return convert(anObject, aClass); + } + + /** + * Called by convertObjectToClass() when we need to convert to an unrecognized + * type. This implementation scans the constructors of the specified class for + * the best fit to the object. and returns a new instance with that constructor. + * Subclasses can override to directly support specific types. + */ + static protected Object convert(Object anObject, Class aClass) { + Constructor[] ctors = aClass.getConstructors(); + + Class[] types; + for (int i = 0; i < ctors.length; i++) { + types = ctors[i].getParameterTypes(); + if (types.length == 1) { + if (types[0].equals(anObject.getClass())) { + try { + return ctors[i].newInstance(new Object[] { anObject }); + } catch (Exception exc) { + // fall through + } + } + } + } + + for (int i = 0; i < ctors.length; i++) { + types = ctors[i].getParameterTypes(); + if (types.length == 1) { + if (anObject.getClass().isAssignableFrom(types[0])) { + try { + return ctors[i].newInstance(new Object[] { anObject }); + } catch (Exception exc) { + // fall through + } + } + } + } + + return null; + } + + /** + * Tries to convert all objects to either Numbers or objects that will produce a + * parsable toString result. + */ + static protected Object preprocess(Object anObject) { + if (anObject instanceof Boolean) { + if (((Boolean) anObject).booleanValue()) { + return new Double(1.0); + } + return new Double(0.0); + } + + if (anObject instanceof Character) { + return anObject.toString(); + } + + return anObject; + } + + static public short getShortValue(Object anObject) { + Short result = getShort(anObject); + return (result == null) ? (short) 0 : result.shortValue(); + } + + static public Short getShort(Object anObject) { + if (anObject == null) + return new Short((short) 0); + if ("".equals(anObject)) + return new Short((short) 0); + if (anObject instanceof Short) + return (Short) anObject; + + anObject = preprocess(anObject); + + if (anObject instanceof Number) { + return new Short(((Number) anObject).shortValue()); + } + + try { + return Short.valueOf(anObject.toString()); + } catch (Exception exc) { + return null; + } + } + + static public int getIntValue(Object anObject) { + Integer result = getInteger(anObject); + return (result == null) ? 0 : result.intValue(); + } + + static public Integer getInteger(Object anObject) { + if (anObject == null) + return new Integer(0); + if ("".equals(anObject)) + return new Integer(0); + if (anObject instanceof Integer) + return (Integer) anObject; + + anObject = preprocess(anObject); + + if (anObject instanceof Number) { + return new Integer(((Number) anObject).intValue()); + } + + try { + return Integer.valueOf(anObject.toString()); + } catch (Exception exc) { + return null; + } + } + + static public long getLongValue(Object anObject) { + Long result = getLong(anObject); + return (result == null) ? (long) 0 : result.longValue(); + } + + static public Long getLong(Object anObject) { + if (anObject == null) + return new Long(0); + if ("".equals(anObject)) + return new Long(0); + if (anObject instanceof Long) + return (Long) anObject; + + anObject = preprocess(anObject); + + if (anObject instanceof Number) { + return new Long(((Number) anObject).longValue()); + } + + try { + return Long.valueOf(anObject.toString()); + } catch (Exception exc) { + return null; + } + } + + static public double getDoubleValue(Object anObject) { + Double result = getDouble(anObject); + return (result == null) ? 0.0f : result.doubleValue(); + } + + static public Double getDouble(Object anObject) { + if (anObject == null) + return new Double(0.0); + if ("".equals(anObject)) + return new Double(0); + if (anObject instanceof Double) + return (Double) anObject; + + anObject = preprocess(anObject); + + if (anObject instanceof Number) { + return new Double(((Number) anObject).doubleValue()); + } + + try { + return Double.valueOf(anObject.toString()); + } catch (Exception exc) { + return null; + } + } + + static public float getFloatValue(Object anObject) { + Float result = getFloat(anObject); + return (result == null) ? 0.0f : result.floatValue(); + } + + static public Float getFloat(Object anObject) { + if (anObject == null) + return new Float(0.0); + if ("".equals(anObject)) + return new Float(0.0); + if (anObject instanceof Float) + return (Float) anObject; + + anObject = preprocess(anObject); + + if (anObject instanceof Number) { + return new Float(((Number) anObject).floatValue()); + } + + try { + return Float.valueOf(anObject.toString()); + } catch (Exception exc) { + return null; + } + } + + static public char getCharValue(Object anObject) { + Character result = getCharacter(anObject); + return (result == null) ? (char) 0 : result.charValue(); + } + + static public Character getCharacter(Object anObject) { + if (anObject == null) + return new Character((char) 0); + if (anObject instanceof Character) + return (Character) anObject; + + anObject = preprocess(anObject); + + if (anObject instanceof Number) { + return new Character((char) ((Number) anObject).byteValue()); + } + + try { + return new Character(anObject.toString().charAt(0)); + } catch (Exception exc) { + return null; + } + } + + static public byte getByteValue(Object anObject) { + Byte result = getByte(anObject); + return (result == null) ? (byte) 0 : result.byteValue(); + } + + static public Byte getByte(Object anObject) { + if (anObject == null) + return new Byte(Byte.MIN_VALUE); + if ("".equals(anObject)) + return new Byte(Byte.MIN_VALUE); + if (anObject instanceof Byte) + return (Byte) anObject; + + anObject = preprocess(anObject); + + if (anObject instanceof Number) { + return new Byte(((Number) anObject).byteValue()); + } + + try { + return Byte.decode(anObject.toString()); + } catch (Exception exc) { + // fall through + } + + try { + return Byte.valueOf(anObject.toString()); + } catch (Exception exc) { + return null; + } + } /** - * Calls getBoolean and converts result to primitive. - */ - static public boolean getBooleanValue( Object anObject ) - { - Boolean result = getBoolean( anObject ); - return ( result == null ) ? false : result.booleanValue(); - } - + * Calls getBoolean and converts result to primitive. + */ + static public boolean getBooleanValue(Object anObject) { + Boolean result = getBoolean(anObject); + return (result == null) ? false : result.booleanValue(); + } + /** - * Numbers equal to zero are true; Strings equal to "yes" are true; - * Strings are then passed to the Boolean constructor. - * Other values return null. - */ - static public Boolean getBoolean( Object anObject ) - { - if ( anObject instanceof Boolean ) - { + * Numbers equal to zero are true; Strings equal to "yes" are true; Strings are + * then passed to the Boolean constructor. Other values return null. + */ + static public Boolean getBoolean(Object anObject) { + if (anObject instanceof Boolean) { return (Boolean) anObject; } - if ( anObject instanceof Number ) - { - return new Boolean( ((Number)anObject).doubleValue() == 0.0 ); - } - - if ( anObject instanceof String ) - { - if ( anObject.toString().toLowerCase().equals( "yes" ) ) - { + if (anObject instanceof Number) { + return new Boolean(((Number) anObject).doubleValue() == 0.0); + } + + if (anObject instanceof String) { + if (anObject.toString().toLowerCase().equals("yes")) { return Boolean.TRUE; } - return new Boolean( (String) anObject ); - } - - return null; - } - - /** - * Get an appropriate String representation for the - * object. Nulls are converted to "null". Date are - * formatted according to the current date format. - * All else uses toString. - */ - static public String getString( Object anObject ) - { - if ( anObject == null ) return "null"; - if ( anObject instanceof java.util.Date ) - { - return dateFormat.format( (java.util.Date) anObject ); - } - return anObject.toString(); - } - - /** - * Converts the object into the specified collection class. - * If unable to convert in any other way, resorts to creating - * a new collection of the specified type containing the - * specified object. - */ - static public Collection getCollection( Object anObject, Class aCollectionClass ) - { - if ( anObject == null ) return null; - if ( aCollectionClass.isAssignableFrom( anObject.getClass() ) ) - { - return (Collection) anObject; - } - - Collection converted = null; - - // convert to collection class - if ( anObject instanceof Collection ) - { - converted = (Collection) anObject; - } - else - // try to convert an array - if ( anObject.getClass().isArray() ) - { - try - { - int length = Array.getLength( anObject ); - converted = new LinkedList(); - for ( int i = 0; i < length; i++ ) - { - converted.add( Array.get( anObject, i ) ); - } - } - catch ( Exception exc ) - { - // try another approach - } - } - else - // convert map values to collection and pass through - if ( anObject instanceof Map ) - { - converted = ((Map)anObject).values(); - } - - // fall back on list containing the object - if ( converted == null ) - { - converted = new LinkedList(); - converted.add( anObject ); - } - - Collection result = null; - - if ( converted != null ) - { - try - { - // collections required to have the copy constructor. - Constructor ctor = aCollectionClass.getConstructor( - new Class[] { Collection.class } ); - result = (Collection) ctor.newInstance( new Object[] { converted } ); - } - catch ( Exception exc ) - { - try - { - result = new LinkedList(); - result.addAll( converted ); - } - catch ( Exception exc2 ) - { - // all attempts failed - result = null; - } - } - } - - return result; - } - - /** - * Convert the object to the specified array type. - */ - static public Object getArray( Object anObject, Class anArrayClass ) - { - if ( anObject == null ) return null; - - // try to convert an array - if ( anObject.getClass().isArray() ) - { - try - { - int length = Array.getLength( anObject ); - Object result = Array.newInstance( - anArrayClass.getComponentType(), length ); - for ( int i = 0; i < length; i++ ) - { - Array.set( result, i, Array.get( anObject, i ) ); - } - return result; - } - catch ( Exception exc ) - { - // try another approach - } - } - // convert map values to collection and pass through - if ( anObject instanceof Map ) - { - anObject = ((Map)anObject).values(); - } - // try to convert a collection - if ( anObject instanceof Collection ) - { - try - { - int length = ((Collection)anObject).size(); - Object result = Array.newInstance( - anArrayClass.getComponentType(), length ); - Iterator it = ((Collection)anObject).iterator(); - for ( int i = 0; i < length; i++ ) - { - Array.set( result, i, it.next() ); - } - return result; - } - catch ( Exception exc ) - { - // try another approach - } - } - // if appropriate type, put the object in a single element array - if ( anObject.getClass().equals( anArrayClass.getComponentType() ) ) - { - try - { - Object result = Array.newInstance( - anArrayClass.getComponentType(), 1 ); - Array.set( result, 0, anObject ); - return result; - } - catch ( Exception exc ) - { - // try another approach - } - } - return null; - } - - /** - * Get an appropriate Date from the given object. - */ - static public java.util.Date getDate( Object anObject ) - { - if ( anObject == null ) return new java.util.Date( 0 ); - if ( anObject instanceof java.util.Date ) - return (java.util.Date) anObject; - - if ( anObject instanceof Number ) - { - return new java.util.Date( getLongValue( anObject ) ); - } - - try - { - return dateFormat.parse( anObject.toString() ); - } - catch ( Exception exc ) - { - return null; - } - } - - static private java.text.DateFormat dateFormat = - new java.text.SimpleDateFormat(); - static public java.text.DateFormat getDateFormat() - { - return dateFormat; - } - static public void setDateFormat( java.text.DateFormat aDateFormat ) - { - if ( aDateFormat != null ) - { - dateFormat = aDateFormat; - } - } - - /** - * Returns the "inverted" value of the specified object. - * Numbers except for chars and bytes are converted to - * their negative representation. Chars and bytes are - * treated as booleans. String are converted to booleans. - * Booleans are converted to their opposite. - * All other types return null. - */ - public static Object invert( Object anObject ) - { - if ( anObject == null ) return null; - Class aClass = anObject.getClass(); - - if ( ( ( anObject instanceof Number ) - &&! ( anObject instanceof Byte ) - &&! ( anObject instanceof Character ) ) - || ( aClass == short.class ) - || ( aClass == int.class ) - || ( aClass == long.class ) - || ( aClass == float.class ) - || ( aClass == double.class ) ) - { - return convertObjectToClass( - new Double( getDoubleValue( anObject ) * -1 ), aClass ); - } - - Boolean converted = getBoolean( anObject ); - if ( converted != null ) - { - if ( converted.booleanValue() ) - { - return convertObjectToClass( - Boolean.FALSE, anObject.getClass() ); - } - else - { - return convertObjectToClass( - Boolean.TRUE, anObject.getClass() ); - } - } - - return null; - } + return new Boolean((String) anObject); + } + + return null; + } + + /** + * Get an appropriate String representation for the object. Nulls are converted + * to "null". Date are formatted according to the current date format. All else + * uses toString. + */ + static public String getString(Object anObject) { + if (anObject == null) + return "null"; + if (anObject instanceof java.util.Date) { + return dateFormat.format((java.util.Date) anObject); + } + return anObject.toString(); + } + + /** + * Converts the object into the specified collection class. If unable to convert + * in any other way, resorts to creating a new collection of the specified type + * containing the specified object. + */ + static public Collection getCollection(Object anObject, Class aCollectionClass) { + if (anObject == null) + return null; + if (aCollectionClass.isAssignableFrom(anObject.getClass())) { + return (Collection) anObject; + } + + Collection converted = null; + + // convert to collection class + if (anObject instanceof Collection) { + converted = (Collection) anObject; + } else + // try to convert an array + if (anObject.getClass().isArray()) { + try { + int length = Array.getLength(anObject); + converted = new LinkedList(); + for (int i = 0; i < length; i++) { + converted.add(Array.get(anObject, i)); + } + } catch (Exception exc) { + // try another approach + } + } else + // convert map values to collection and pass through + if (anObject instanceof Map) { + converted = ((Map) anObject).values(); + } + + // fall back on list containing the object + if (converted == null) { + converted = new LinkedList(); + converted.add(anObject); + } + + Collection result = null; + + if (converted != null) { + try { + // collections required to have the copy constructor. + Constructor ctor = aCollectionClass.getConstructor(new Class[] { Collection.class }); + result = (Collection) ctor.newInstance(new Object[] { converted }); + } catch (Exception exc) { + try { + result = new LinkedList(); + result.addAll(converted); + } catch (Exception exc2) { + // all attempts failed + result = null; + } + } + } + + return result; + } + + /** + * Convert the object to the specified array type. + */ + static public Object getArray(Object anObject, Class anArrayClass) { + if (anObject == null) + return null; + + // try to convert an array + if (anObject.getClass().isArray()) { + try { + int length = Array.getLength(anObject); + Object result = Array.newInstance(anArrayClass.getComponentType(), length); + for (int i = 0; i < length; i++) { + Array.set(result, i, Array.get(anObject, i)); + } + return result; + } catch (Exception exc) { + // try another approach + } + } + // convert map values to collection and pass through + if (anObject instanceof Map) { + anObject = ((Map) anObject).values(); + } + // try to convert a collection + if (anObject instanceof Collection) { + try { + int length = ((Collection) anObject).size(); + Object result = Array.newInstance(anArrayClass.getComponentType(), length); + Iterator it = ((Collection) anObject).iterator(); + for (int i = 0; i < length; i++) { + Array.set(result, i, it.next()); + } + return result; + } catch (Exception exc) { + // try another approach + } + } + // if appropriate type, put the object in a single element array + if (anObject.getClass().equals(anArrayClass.getComponentType())) { + try { + Object result = Array.newInstance(anArrayClass.getComponentType(), 1); + Array.set(result, 0, anObject); + return result; + } catch (Exception exc) { + // try another approach + } + } + return null; + } + + /** + * Get an appropriate Date from the given object. + */ + static public java.util.Date getDate(Object anObject) { + if (anObject == null) + return new java.util.Date(0); + if (anObject instanceof java.util.Date) + return (java.util.Date) anObject; + + if (anObject instanceof Number) { + return new java.util.Date(getLongValue(anObject)); + } + + try { + return dateFormat.parse(anObject.toString()); + } catch (Exception exc) { + return null; + } + } + + static private java.text.DateFormat dateFormat = new java.text.SimpleDateFormat(); + + static public java.text.DateFormat getDateFormat() { + return dateFormat; + } + + static public void setDateFormat(java.text.DateFormat aDateFormat) { + if (aDateFormat != null) { + dateFormat = aDateFormat; + } + } + + /** + * Returns the "inverted" value of the specified object. Numbers except for + * chars and bytes are converted to their negative representation. Chars and + * bytes are treated as booleans. String are converted to booleans. Booleans are + * converted to their opposite. All other types return null. + */ + public static Object invert(Object anObject) { + if (anObject == null) + return null; + Class aClass = anObject.getClass(); + + if (((anObject instanceof Number) && !(anObject instanceof Byte) && !(anObject instanceof Character)) + || (aClass == short.class) || (aClass == int.class) || (aClass == long.class) || (aClass == float.class) + || (aClass == double.class)) { + return convertObjectToClass(new Double(getDoubleValue(anObject) * -1), aClass); + } + + Boolean converted = getBoolean(anObject); + if (converted != null) { + if (converted.booleanValue()) { + return convertObjectToClass(Boolean.FALSE, anObject.getClass()); + } else { + return convertObjectToClass(Boolean.TRUE, anObject.getClass()); + } + } + + return null; + } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:11:47 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:11:47 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.4 2002/10/11 15:33:53 mpowers - * Now supporting "!" to invert the value of a string property. + * Revision 1.4 2002/10/11 15:33:53 mpowers Now supporting "!" to invert the + * value of a string property. * - * Revision 1.3 2001/07/02 16:29:08 mpowers - * XMLRPC decoder was relying on ValueConverter to convert LinkedLists into - * the appropriate type. This is now implemented in ValueConverter. + * Revision 1.3 2001/07/02 16:29:08 mpowers XMLRPC decoder was relying on + * ValueConverter to convert LinkedLists into the appropriate type. This is now + * implemented in ValueConverter. * - * Revision 1.2 2001/03/01 20:36:35 mpowers - * Better error handling and better handling of nulls. + * Revision 1.2 2001/03/01 20:36:35 mpowers Better error handling and better + * handling of nulls. * - * Revision 1.1.1.1 2000/12/21 15:52:33 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:52:33 mpowers Contributing wotonomy. * - * Revision 1.8 2000/12/20 16:25:48 michael - * Added log to all files. + * Revision 1.8 2000/12/20 16:25:48 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/WotonomyException.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/WotonomyException.java index e2210d0..21b47b3 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/WotonomyException.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/WotonomyException.java @@ -22,113 +22,96 @@ import java.io.PrintStream; import java.io.PrintWriter; /** -* This is a simple RuntimeException that can encapsulate -* another throwable. Behaves as a normal RuntimeException -* except that it prints a stack trace of the wrapped -* throwable if one is specified. -* -* Intended to be used anytime you'd -* report an exception with System.out.println: that is, -* for debugging and non-user-visible exceptions. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ + * This is a simple RuntimeException that can encapsulate another throwable. + * Behaves as a normal RuntimeException except that it prints a stack trace of + * the wrapped throwable if one is specified. + * + * Intended to be used anytime you'd report an exception with + * System.out.println: that is, for debugging and non-user-visible exceptions. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ -public class WotonomyException extends RuntimeException -{ +public class WotonomyException extends RuntimeException { protected String message; protected Throwable wrappedThrowable; - + /** - * Default constructor. - */ - public WotonomyException() - { + * Default constructor. + */ + public WotonomyException() { super(); message = null; - wrappedThrowable = null; + wrappedThrowable = null; } - + /** - * Standard constructor with message. - */ - public WotonomyException( String aMessage ) - { - super( aMessage ); + * Standard constructor with message. + */ + public WotonomyException(String aMessage) { + super(aMessage); message = aMessage; wrappedThrowable = null; } - + /** - * Specifies a throwable to wrap. - */ - public WotonomyException( Throwable aThrowable ) - { + * Specifies a throwable to wrap. + */ + public WotonomyException(Throwable aThrowable) { super(); message = null; wrappedThrowable = aThrowable; } - + /** - * Specifies a message and a throwable to wrap. - */ - public WotonomyException( String aMessage, Throwable aThrowable ) - { - super( aMessage ); + * Specifies a message and a throwable to wrap. + */ + public WotonomyException(String aMessage, Throwable aThrowable) { + super(aMessage); message = aMessage; wrappedThrowable = aThrowable; } - - /** - * Returns the wrapped throwable. - */ - public Throwable getWrappedThrowable() - { - return wrappedThrowable; - } - - public void printStackTrace(PrintWriter s) - { - if ( message != null ) - { - s.println( "Exception: " + message ); + + /** + * Returns the wrapped throwable. + */ + public Throwable getWrappedThrowable() { + return wrappedThrowable; + } + + public void printStackTrace(PrintWriter s) { + if (message != null) { + s.println("Exception: " + message); } - if ( wrappedThrowable != null ) - { - wrappedThrowable.printStackTrace( s ); + if (wrappedThrowable != null) { + wrappedThrowable.printStackTrace(s); return; } - super.printStackTrace( s ); + super.printStackTrace(s); } - - public void printStackTrace(PrintStream s) - { - if ( message != null ) - { - s.println( "Exception: " + message ); + + public void printStackTrace(PrintStream s) { + if (message != null) { + s.println("Exception: " + message); } - if ( wrappedThrowable != null ) - { - wrappedThrowable.printStackTrace( s ); + if (wrappedThrowable != null) { + wrappedThrowable.printStackTrace(s); return; } - super.printStackTrace( s ); + super.printStackTrace(s); } - - public void printStackTrace() - { - if ( message != null ) - { - System.err.println( "Exception: " + message ); + + public void printStackTrace() { + if (message != null) { + System.err.println("Exception: " + message); } - if ( wrappedThrowable != null ) - { - wrappedThrowable.printStackTrace(); + if (wrappedThrowable != null) { + wrappedThrowable.printStackTrace(); return; } super.printStackTrace(); } - + } diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLDecoder.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLDecoder.java index 64ac4b2..79b3967 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLDecoder.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLDecoder.java @@ -22,47 +22,42 @@ import java.io.InputStream; import java.net.URL; /** -* Defines an interface for classes that can de-serialize -* java objects from an XML representation. -*/ -public interface XMLDecoder -{ - /** - * Decodes an object from the specified input stream. - * @param anInputStream The input stream from which to read. - * The stream will be read fully. - * @param aDescription A description to accompany error messages - * for the stream, typically a file name. - * @param aURL A URL against which relative references within the - * XML will be resolved. - * @return The object that was constructed from the XML content, - * or null if no object could be constructed. - */ - public Object decode( - InputStream anInputStream, String aDescription, URL aURL ); + * Defines an interface for classes that can de-serialize java objects from an + * XML representation. + */ +public interface XMLDecoder { + /** + * Decodes an object from the specified input stream. + * + * @param anInputStream The input stream from which to read. The stream will be + * read fully. + * @param aDescription A description to accompany error messages for the + * stream, typically a file name. + * @param aURL A URL against which relative references within the XML + * will be resolved. + * @return The object that was constructed from the XML content, or null if no + * object could be constructed. + */ + public Object decode(InputStream anInputStream, String aDescription, URL aURL); } /* - * $Log$ - * Revision 1.1 2006/02/18 22:21:10 cgruber - * Add in simple xml interfaces from net.wotonomy.xml project. - * Add cobertura.ser to .cvsignore. God I wish sourceforge would move on this subversion thing... + * $Log$ Revision 1.1 2006/02/18 22:21:10 cgruber Add in simple xml interfaces + * from net.wotonomy.xml project. Add cobertura.ser to .cvsignore. God I wish + * sourceforge would move on this subversion thing... * - * Revision 1.1 2006/02/16 13:22:22 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.2 2001/02/06 14:34:23 mpowers - * Forgot to rename the package declarations. + * Revision 1.2 2001/02/06 14:34:23 mpowers Forgot to rename the package + * declarations. * - * Revision 1.1 2001/02/06 14:31:19 mpowers - * Moving XML utilities from util to xml package. + * Revision 1.1 2001/02/06 14:31:19 mpowers Moving XML utilities from util to + * xml package. * - * Revision 1.1.1.1 2000/12/21 15:52:33 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:52:33 mpowers Contributing wotonomy. * - * Revision 1.2 2000/12/20 16:25:48 michael - * Added log to all files. + * Revision 1.2 2000/12/20 16:25:48 michael Added log to all files. * * */ - diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLEncoder.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLEncoder.java index e543bca..0d180aa 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLEncoder.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/xml/XMLEncoder.java @@ -21,41 +21,37 @@ package net.wotonomy.foundation.xml; import java.io.OutputStream; /** -* Defines an interface for classes that can serialize -* an arbitrary java object into XML format. -*/ -public interface XMLEncoder -{ - /** - * Encodes an object to the specified output stream as XML. - * @param anObject The object to be serialized to XML format. - * @param anOutputStream The output stream to which the object - * will be written. The stream will not be flushed nor closed. - */ - public void encode( Object anObject, OutputStream anOutputStream ); + * Defines an interface for classes that can serialize an arbitrary java object + * into XML format. + */ +public interface XMLEncoder { + /** + * Encodes an object to the specified output stream as XML. + * + * @param anObject The object to be serialized to XML format. + * @param anOutputStream The output stream to which the object will be written. + * The stream will not be flushed nor closed. + */ + public void encode(Object anObject, OutputStream anOutputStream); } /* - * $Log$ - * Revision 1.1 2006/02/18 22:21:10 cgruber - * Add in simple xml interfaces from net.wotonomy.xml project. - * Add cobertura.ser to .cvsignore. God I wish sourceforge would move on this subversion thing... + * $Log$ Revision 1.1 2006/02/18 22:21:10 cgruber Add in simple xml interfaces + * from net.wotonomy.xml project. Add cobertura.ser to .cvsignore. God I wish + * sourceforge would move on this subversion thing... * - * Revision 1.1 2006/02/16 13:22:22 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.2 2001/02/06 14:34:23 mpowers - * Forgot to rename the package declarations. + * Revision 1.2 2001/02/06 14:34:23 mpowers Forgot to rename the package + * declarations. * - * Revision 1.1 2001/02/06 14:31:19 mpowers - * Moving XML utilities from util to xml package. + * Revision 1.1 2001/02/06 14:31:19 mpowers Moving XML utilities from util to + * xml package. * - * Revision 1.1.1.1 2000/12/21 15:52:33 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:52:33 mpowers Contributing wotonomy. * - * Revision 1.2 2000/12/20 16:25:48 michael - * Added log to all files. + * Revision 1.2 2000/12/20 16:25:48 michael Added log to all files. * * */ - |
