diff options
Diffstat (limited to 'projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/PropertyDataSource.java')
| -rw-r--r-- | projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/PropertyDataSource.java | 863 |
1 files changed, 380 insertions, 483 deletions
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/PropertyDataSource.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/PropertyDataSource.java index 76f7219..c02c3e2 100644 --- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/PropertyDataSource.java +++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/PropertyDataSource.java @@ -34,516 +34,413 @@ import net.wotonomy.foundation.internal.Introspector; import net.wotonomy.foundation.internal.WotonomyException; /** -* A data source that reads and writes to an indexed -* property of a java object. This class is used by -* MasterDetailAssociation to retreive objects from -* the master display group. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 894 $ -*/ -public class PropertyDataSource extends OrderedDataSource -{ - protected Object source; - protected String key; - protected Class lastKnownType; // for best-guessing - protected EOClassDescription classDesc; - protected EOEditingContext context; - - /** - * Creates a new PropertyDataSource with no editing context - * and will try to guess the appropriate class description - * when trying to create objects. - */ - public PropertyDataSource() - { - this( null, (EOClassDescription) null ); - } - - /** - * Creates a new PropertyDataSource that uses the specified - * editing context, but will try to guess the appropriate - * class description when trying to create objects. - */ - public PropertyDataSource( EOEditingContext aContext ) - { - this( aContext, (EOClassDescription) null ); - } - - /** - * Creates a new PropertyDataSource that uses the specified - * editing context and vends objects of the specified class. - */ - public PropertyDataSource( - EOEditingContext aContext, Class aClass ) - { - this( aContext, EOClassDescription.classDescriptionForClass( aClass ) ); - } - - /** - * Creates a new PropertyDataSource that uses the specified - * editing context and vends objects of the specified - * class description. - */ - public PropertyDataSource( - EOEditingContext aContext, EOClassDescription aClassDesc ) - { - source = null; - key = null; - lastKnownType = null; - classDesc = aClassDesc; - context = aContext; - } - - /** - * Provides the master object for detail display groups. - */ - public Object source() - { - return source; - } - - /** - * Allows a detail display group to set the master object. - */ - public void setSource( Object anObject ) - { - source = anObject; - } - - /** - * Provides the detail key for detail display groups. - */ - public String key() - { - return key; - } - - /** - * Allows a detail display group to set the detail key. - */ - public void setKey( String aKey ) - { - key = aKey; - } - - /** - * Inserts the specified object into this data source. - * Calls insertObjectAtIndex and appends to the end - * of the list. - */ - public void insertObject ( Object anObject ) - { - insertObjectAtIndex( anObject, -1 ); // trick to force to end - } - - /** - * Inserts the specified object into this data source, - * at the specified index. - */ - public void insertObjectAtIndex ( - Object anObject, int anIndex ) - { - if ( source == null ) return; - List list = readAsList(); - if ( anIndex == -1 ) anIndex = list.size(); // force to end - if ( anIndex > list.size() ) anIndex = list.size(); // force to end - list.add( anIndex, anObject ); - writeAsList( list ); - } - - /** - * Deletes the specified object from this data source. - */ - public void deleteObject ( Object anObject ) - { - if ( source == null ) return; - List list = readAsList(); - list.remove( anObject ); - writeAsList( list ); - } - - public EOEditingContext editingContext () - { - return context; - } - - /** - * Returns a List containing the objects in this - * data source. - */ - public NSArray fetchObjects () - { - if ( source == null ) return NSArray.EmptyArray; - return readAsList(); - } - - /** - * Returns a new instance of this class. - */ - public EODataSource - dataSourceQualifiedByKey ( String aKey ) - { - // determine the target class desc if possible - EOClassDescription keyClassDesc = null; - if ( classDesc != null ) - { - keyClassDesc = classDesc.classDescriptionForDestinationKey( aKey ); - } - return new PropertyDataSource( editingContext(), keyClassDesc ); - } - - /** - * Restricts this data source to vend those - * objects that are associated with the specified - * key on the specified object. - */ - public void - qualifyWithRelationshipKey ( - String aKey, Object anObject ) - { - source = anObject; - key = aKey; - } - - /** - * Returns the class description passed to the - * constructor, if any. If no class description and - * if the bound property is an indexed property, - * the type of the array is returned, otherwise - * this method returns null. This method is called - * by createObject(). - */ - public EOClassDescription - classDescriptionForObjects () - { - // just return the class description if we have one - if ( classDesc != null ) return classDesc; - - // otherwise, try to do some guesswork - EOClassDescription result = null; - - // lastKnownType is not updated here - Class type = lastKnownType; - - // if no last known type - if ( type == null ) - { - // if source and key were specified - if ( ( source != null ) && ( key != null ) ) - { - // try to get an array type - Method m = Introspector.getPropertyReadMethod( - source.getClass(), key, new Class[0] ); - if ( m != null ) - { - Class returnType = m.getReturnType(); - if ( returnType.isArray() ) - { - type = returnType.getComponentType(); - } - } - else - { - throw new WotonomyException( "Key does not exist for object: " + key + " : " + source ); - } - } - - // does not update lastKnownType because - // we prefer to get that info from a fetch. - } - - // if type has been determined - if ( type != null ) - { - result = - EOClassDescription.classDescriptionForClass( type ); - } - - return result; - } - - /** - * Calls getValue() and returns the result as a List. - * Sets lastKnownType to the retrieved type. - */ - protected NSMutableArray readAsList() - { - Object value = getValue(); - if ( value == null ) - { - return new NSMutableArray(); - } - - Object o; - NSMutableArray result = new NSMutableArray(); - boolean hasReadType = false; - lastKnownType = null; - - // if instance of array, convert to list - if ( value.getClass().isArray() ) - { - int count = Array.getLength( value ); - for ( int i = 0; i < count; i++ ) - { - o = Array.get( value, i ); - if ( o != null ) - { - // we've already found a type - if ( hasReadType ) - { - // check that this matches the last known type - if ( o.getClass() != lastKnownType ) - { - // not all of the same type: set to null - lastKnownType = null; - } - } - else // this is the first type we've found - { - // remember it - hasReadType = true; - lastKnownType = o.getClass(); - } - } - result.add( o ); + * A data source that reads and writes to an indexed property of a java object. + * This class is used by MasterDetailAssociation to retreive objects from the + * master display group. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 894 $ + */ +public class PropertyDataSource extends OrderedDataSource { + protected Object source; + protected String key; + protected Class lastKnownType; // for best-guessing + protected EOClassDescription classDesc; + protected EOEditingContext context; + + /** + * Creates a new PropertyDataSource with no editing context and will try to + * guess the appropriate class description when trying to create objects. + */ + public PropertyDataSource() { + this(null, (EOClassDescription) null); + } + + /** + * Creates a new PropertyDataSource that uses the specified editing context, but + * will try to guess the appropriate class description when trying to create + * objects. + */ + public PropertyDataSource(EOEditingContext aContext) { + this(aContext, (EOClassDescription) null); + } + + /** + * Creates a new PropertyDataSource that uses the specified editing context and + * vends objects of the specified class. + */ + public PropertyDataSource(EOEditingContext aContext, Class aClass) { + this(aContext, EOClassDescription.classDescriptionForClass(aClass)); + } + + /** + * Creates a new PropertyDataSource that uses the specified editing context and + * vends objects of the specified class description. + */ + public PropertyDataSource(EOEditingContext aContext, EOClassDescription aClassDesc) { + source = null; + key = null; + lastKnownType = null; + classDesc = aClassDesc; + context = aContext; + } + + /** + * Provides the master object for detail display groups. + */ + public Object source() { + return source; + } + + /** + * Allows a detail display group to set the master object. + */ + public void setSource(Object anObject) { + source = anObject; + } + + /** + * Provides the detail key for detail display groups. + */ + public String key() { + return key; + } + + /** + * Allows a detail display group to set the detail key. + */ + public void setKey(String aKey) { + key = aKey; + } + + /** + * Inserts the specified object into this data source. Calls insertObjectAtIndex + * and appends to the end of the list. + */ + public void insertObject(Object anObject) { + insertObjectAtIndex(anObject, -1); // trick to force to end + } + + /** + * Inserts the specified object into this data source, at the specified index. + */ + public void insertObjectAtIndex(Object anObject, int anIndex) { + if (source == null) + return; + List list = readAsList(); + if (anIndex == -1) + anIndex = list.size(); // force to end + if (anIndex > list.size()) + anIndex = list.size(); // force to end + list.add(anIndex, anObject); + writeAsList(list); + } + + /** + * Deletes the specified object from this data source. + */ + public void deleteObject(Object anObject) { + if (source == null) + return; + List list = readAsList(); + list.remove(anObject); + writeAsList(list); + } + + public EOEditingContext editingContext() { + return context; + } + + /** + * Returns a List containing the objects in this data source. + */ + public NSArray fetchObjects() { + if (source == null) + return NSArray.EmptyArray; + return readAsList(); + } + + /** + * Returns a new instance of this class. + */ + public EODataSource dataSourceQualifiedByKey(String aKey) { + // determine the target class desc if possible + EOClassDescription keyClassDesc = null; + if (classDesc != null) { + keyClassDesc = classDesc.classDescriptionForDestinationKey(aKey); + } + return new PropertyDataSource(editingContext(), keyClassDesc); + } + + /** + * Restricts this data source to vend those objects that are associated with the + * specified key on the specified object. + */ + public void qualifyWithRelationshipKey(String aKey, Object anObject) { + source = anObject; + key = aKey; + } + + /** + * Returns the class description passed to the constructor, if any. If no class + * description and if the bound property is an indexed property, the type of the + * array is returned, otherwise this method returns null. This method is called + * by createObject(). + */ + public EOClassDescription classDescriptionForObjects() { + // just return the class description if we have one + if (classDesc != null) + return classDesc; + + // otherwise, try to do some guesswork + EOClassDescription result = null; + + // lastKnownType is not updated here + Class type = lastKnownType; + + // if no last known type + if (type == null) { + // if source and key were specified + if ((source != null) && (key != null)) { + // try to get an array type + Method m = Introspector.getPropertyReadMethod(source.getClass(), key, new Class[0]); + if (m != null) { + Class returnType = m.getReturnType(); + if (returnType.isArray()) { + type = returnType.getComponentType(); + } + } else { + throw new WotonomyException("Key does not exist for object: " + key + " : " + source); + } } + + // does not update lastKnownType because + // we prefer to get that info from a fetch. } - else - if ( value instanceof Collection ) - { + + // if type has been determined + if (type != null) { + result = EOClassDescription.classDescriptionForClass(type); + } + + return result; + } + + /** + * Calls getValue() and returns the result as a List. Sets lastKnownType to the + * retrieved type. + */ + protected NSMutableArray readAsList() { + Object value = getValue(); + if (value == null) { + return new NSMutableArray(); + } + + Object o; + NSMutableArray result = new NSMutableArray(); + boolean hasReadType = false; + lastKnownType = null; + + // if instance of array, convert to list + if (value.getClass().isArray()) { + int count = Array.getLength(value); + for (int i = 0; i < count; i++) { + o = Array.get(value, i); + if (o != null) { + // we've already found a type + if (hasReadType) { + // check that this matches the last known type + if (o.getClass() != lastKnownType) { + // not all of the same type: set to null + lastKnownType = null; + } + } else // this is the first type we've found + { + // remember it + hasReadType = true; + lastKnownType = o.getClass(); + } + } + result.add(o); + } + } else if (value instanceof Collection) { // convert to list so we handle sets, etc. - Iterator i = ((Collection)value).iterator(); - while ( i.hasNext() ) - { - o = i.next(); - if ( o != null ) - { - // we've already found a type - if ( hasReadType ) - { - // check that this matches the last known type - if ( o.getClass() != lastKnownType ) - { - // not all of the same type: set to null - lastKnownType = null; - } - } - else // this is the first type we've found - { - // remember it - hasReadType = true; - lastKnownType = o.getClass(); - } - } - result.add( o ); - } + Iterator i = ((Collection) value).iterator(); + while (i.hasNext()) { + o = i.next(); + if (o != null) { + // we've already found a type + if (hasReadType) { + // check that this matches the last known type + if (o.getClass() != lastKnownType) { + // not all of the same type: set to null + lastKnownType = null; + } + } else // this is the first type we've found + { + // remember it + hasReadType = true; + lastKnownType = o.getClass(); + } + } + result.add(o); + } + } else { + lastKnownType = null; + throw new WotonomyException("PropertyDataSource: " + "bound property was not an indexed property: " + key); } - else - { - lastKnownType = null; - throw new WotonomyException( "PropertyDataSource: " + - "bound property was not an indexed property: " + key ); + + return result; + } + + /** + * Converts the specified List to lastKnownType and calls setValue(). + */ + protected void writeAsList(List anObjectList) { + if (source == null) { + throw new WotonomyException("PropertyDataSource: " + "no source object: " + key); + } + + Class c = source.getClass(); + Method m = Introspector.getPropertyReadMethod(c, key, new Class[0]); + if (m == null) { + throw new WotonomyException("Could not read property for object: " + key + " : " + source + " (" + c + ")"); } - return result; - } - - /** - * Converts the specified List to lastKnownType - * and calls setValue(). - */ - protected void writeAsList( List anObjectList ) - { - if ( source == null ) - { - throw new WotonomyException( "PropertyDataSource: " + - "no source object: " + key ); - } - - Class c = source.getClass(); - Method m = Introspector.getPropertyReadMethod( c, key, new Class[0] ); - if ( m == null ) - { - throw new WotonomyException( "Could not read property for object: " - + key + " : " + source + " (" + c + ")" ); - } - - Class returnType = m.getReturnType(); - - int count = anObjectList.size(); - Object result = null; - - if ( returnType.isArray() ) - { - Class type = returnType.getComponentType(); - result = Array.newInstance( type, count ); - for ( int i = 0; i < count; i++ ) - { - Array.set( result, i, anObjectList.get( i ) ); - } - } - else - { - Collection collection = null; - - if ( ! returnType.isInterface() ) - { - try - { - collection = (Collection) returnType.newInstance(); - } - catch ( Exception exc ) - { - // no default constructor, leave null - } - } - - // try to find an acceptable collections type - if ( collection == null ) - { - if ( returnType.isAssignableFrom( NSMutableArray.class ) ) - { - collection = new NSMutableArray(); - } - else - if ( returnType.isAssignableFrom( LinkedList.class ) ) - { - collection = new LinkedList(); - } - else - if ( returnType.isAssignableFrom( ArrayList.class ) ) - { - collection = new ArrayList(); - } - else - if ( returnType.isAssignableFrom( HashSet.class ) ) - { - collection = new HashSet(); - } - else - if ( returnType.isAssignableFrom( TreeSet.class ) ) - { - collection = new TreeSet(); - } - } - - if ( collection == null ) - { - throw new WotonomyException( "Could not create a collection of type: " + returnType ); - } - - collection.addAll( anObjectList ); - result = collection; - } - - setValue( result ); - } - - /** - * Returns the value of the indexed property - * specified by qualifyWithRelationshipKey. - */ - protected Object getValue() - { - if ( source instanceof EOKeyValueCoding ) - { - return ((EOKeyValueCoding)source).valueForKey( key ); - } - return EOKeyValueCodingSupport.valueForKey( source, key ); - } - - /** - * Sets the value of the indexed property - * specified by qualifyWithRelationshipKey. - * The argument is assumed to be of appropriate - * type for the property. EOObserverCenter is - * notified that the object will change. - */ - protected void setValue( Object aValue ) - { - EOClassDescription sourceDesc = - EOClassDescription.classDescriptionForClass( source.getClass() ); - - - // if we're not editing a relationship (?) + Class returnType = m.getReturnType(); + + int count = anObjectList.size(); + Object result = null; + + if (returnType.isArray()) { + Class type = returnType.getComponentType(); + result = Array.newInstance(type, count); + for (int i = 0; i < count; i++) { + Array.set(result, i, anObjectList.get(i)); + } + } else { + Collection collection = null; + + if (!returnType.isInterface()) { + try { + collection = (Collection) returnType.newInstance(); + } catch (Exception exc) { + // no default constructor, leave null + } + } + + // try to find an acceptable collections type + if (collection == null) { + if (returnType.isAssignableFrom(NSMutableArray.class)) { + collection = new NSMutableArray(); + } else if (returnType.isAssignableFrom(LinkedList.class)) { + collection = new LinkedList(); + } else if (returnType.isAssignableFrom(ArrayList.class)) { + collection = new ArrayList(); + } else if (returnType.isAssignableFrom(HashSet.class)) { + collection = new HashSet(); + } else if (returnType.isAssignableFrom(TreeSet.class)) { + collection = new TreeSet(); + } + } + + if (collection == null) { + throw new WotonomyException("Could not create a collection of type: " + returnType); + } + + collection.addAll(anObjectList); + result = collection; + } + + setValue(result); + } + + /** + * Returns the value of the indexed property specified by + * qualifyWithRelationshipKey. + */ + protected Object getValue() { + if (source instanceof EOKeyValueCoding) { + return ((EOKeyValueCoding) source).valueForKey(key); + } + return EOKeyValueCodingSupport.valueForKey(source, key); + } + + /** + * Sets the value of the indexed property specified by + * qualifyWithRelationshipKey. The argument is assumed to be of appropriate type + * for the property. EOObserverCenter is notified that the object will change. + */ + protected void setValue(Object aValue) { + EOClassDescription sourceDesc = EOClassDescription.classDescriptionForClass(source.getClass()); + + // if we're not editing a relationship (?) // if ( ! sourceDesc.toManyRelationshipKeys().containsObject( key ) ) - { - // mark the parent as changed - EOObserverCenter.notifyObserversObjectWillChange( source ); - } - - - if ( source instanceof EOKeyValueCoding ) - { - ((EOKeyValueCoding)source).takeValueForKey( aValue, key ); - } - else - { - EOKeyValueCodingSupport.takeValueForKey( source, aValue, key ); - } - } - + { + // mark the parent as changed + EOObserverCenter.notifyObserversObjectWillChange(source); + } + + if (source instanceof EOKeyValueCoding) { + ((EOKeyValueCoding) source).takeValueForKey(aValue, key); + } else { + EOKeyValueCodingSupport.takeValueForKey(source, aValue, key); + } + } + } /* - * $Log$ - * Revision 1.2 2006/02/16 16:47:14 cgruber - * Move some classes in to "internal" packages and re-work imports, etc. + * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to + * "internal" packages and re-work imports, etc. * - * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions. + * Also use UnsupportedOperationExceptions where appropriate, instead of + * WotonomyExceptions. * - * Revision 1.1 2006/02/16 13:19:57 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * 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/24 21:15:36 mpowers - * New implementations of NSArray and subclasses. + * Revision 1.13 2002/10/24 21:15:36 mpowers New implementations of NSArray and + * subclasses. * - * Revision 1.12 2002/10/24 18:18:12 mpowers - * NSArray's are now considered read-only, so we can return our internal - * representation to reduce unnecessary object allocation. + * Revision 1.12 2002/10/24 18:18:12 mpowers NSArray's are now considered + * read-only, so we can return our internal representation to reduce unnecessary + * object allocation. * - * Revision 1.11 2002/04/15 21:55:33 mpowers - * Catching a condition where the get may not return the value passed to set. + * Revision 1.11 2002/04/15 21:55:33 mpowers Catching a condition where the get + * may not return the value passed to set. * - * Revision 1.10 2002/03/08 23:20:37 mpowers - * insertObject now calls insertObjectAtIndex. + * Revision 1.10 2002/03/08 23:20:37 mpowers insertObject now calls + * insertObjectAtIndex. * - * Revision 1.9 2001/06/05 19:10:41 mpowers - * Better handling of null properties. + * Revision 1.9 2001/06/05 19:10:41 mpowers Better handling of null properties. * - * Revision 1.8 2001/05/21 14:03:35 mpowers - * Added a convenience constructor for java classes. + * Revision 1.8 2001/05/21 14:03:35 mpowers Added a convenience constructor for + * java classes. * - * Revision 1.7 2001/04/30 13:15:24 mpowers - * Child contexts re-initializing objects invalidated in parent now - * propery transpose relationships. + * Revision 1.7 2001/04/30 13:15:24 mpowers Child contexts re-initializing + * objects invalidated in parent now propery transpose relationships. * - * Revision 1.6 2001/04/29 02:29:31 mpowers - * Debugging relationship faulting. + * Revision 1.6 2001/04/29 02:29:31 mpowers Debugging relationship faulting. * - * Revision 1.5 2001/04/28 22:17:51 mpowers - * Revised PropertyDataSource to be EOClassDescription-aware. + * Revision 1.5 2001/04/28 22:17:51 mpowers Revised PropertyDataSource to be + * EOClassDescription-aware. * - * Revision 1.4 2001/04/27 23:37:20 mpowers - * Now using EOClassDescription in the EODataSource class, as we should. + * Revision 1.4 2001/04/27 23:37:20 mpowers Now using EOClassDescription in the + * EODataSource class, as we should. * - * Revision 1.3 2001/03/29 03:29:49 mpowers - * Now using KeyValueCoding and Support instead of Introspector. + * Revision 1.3 2001/03/29 03:29:49 mpowers Now using KeyValueCoding and Support + * instead of Introspector. * - * Revision 1.2 2001/01/24 14:10:53 mpowers - * Contributing OrderedDataSource, and PropertyDataSource extends it. + * Revision 1.2 2001/01/24 14:10:53 mpowers Contributing OrderedDataSource, and + * PropertyDataSource extends it. * - * Revision 1.1.1.1 2000/12/21 15:46:50 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:46:50 mpowers Contributing wotonomy. * - * Revision 1.3 2000/12/20 16:25:35 michael - * Added log to all files. + * Revision 1.3 2000/12/20 16:25:35 michael Added log to all files. * * */ - |
