From aedc34d55462a75e329bbf342251ff6504cd117e Mon Sep 17 00:00:00 2001 From: Benjamin Culkin Date: Sun, 19 May 2024 17:56:33 -0400 Subject: Initial import from SVN --- .../java/net/wotonomy/control/EOQualifier.java | 680 +++++++++++++++++++++ 1 file changed, 680 insertions(+) create mode 100644 projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifier.java (limited to 'projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifier.java') diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifier.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifier.java new file mode 100644 index 0000000..6fffea4 --- /dev/null +++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifier.java @@ -0,0 +1,680 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2000 Michael Powers + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, see http://www.gnu.org +*/ + +package net.wotonomy.control; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; + +import net.wotonomy.foundation.NSArray; +import net.wotonomy.foundation.NSMutableArray; +import net.wotonomy.foundation.NSMutableDictionary; +import net.wotonomy.foundation.NSSelector; +import net.wotonomy.foundation.NSSet; +import net.wotonomy.foundation.internal.ValueConverter; +import net.wotonomy.foundation.internal.WotonomyException; + +/** +* EOQualifiers are used to perform property-based +* qualifications on objects: for a set of criteria, +* a qualifier either qualifies or disqualifies an +* given object. EOKeyValueQualifiers can be joined +* by EOAndQualifier and EOOrQualifier, and so can +* form a tree of qualifications.

+* +* Certain qualifiers +* can accept a variable in place of a value; variable +* names are marked by a "$", as in "$name". Variables +* are resolved with the qualifierWithBindings() method. +* +* @author michael@mpowers.net +* @author yjcheung@intersectsoft.com +* @author $Author: cgruber $ +* @version $Revision: 894 $ +*/ +public abstract class EOQualifier +{ + public static final NSSelector + QualifierOperatorCaseInsensitiveLike = new OperatorCaseInsensitiveLike(); + public static final NSSelector + QualifierOperatorContains = new OperatorContains(); + public static final NSSelector + QualifierOperatorEqual = new OperatorEqual(); + public static final NSSelector + QualifierOperatorGreaterThan = new OperatorGreaterThan(); + public static final NSSelector + QualifierOperatorGreaterThanOrEqualTo = new OperatorGreaterThanOrEqualTo(); + public static final NSSelector + QualifierOperatorLessThan = new OperatorLessThan(); + public static final NSSelector + QualifierOperatorLessThanOrEqualTo = new OperatorLessThanOrEqualTo(); + public static final NSSelector + QualifierOperatorLike = new OperatorLike(); + public static final NSSelector + QualifierOperatorNotEqual = new OperatorNotEqual(); + + /** + * Default constructor. + */ + public EOQualifier () + { + } + + /** + * Adds all qualifier keys in this qualifier to + * the specified Set, which is expected to be + * mutable. The tree of qualifiers is traversed + * and the left-hand-side of each expression is + * added to the set. + */ + public void addQualifierKeysToSet ( Set aSet ) + { + throw new RuntimeException( "Not implemented yet." ); + } + + /** + * Returns a Set of all property names used for + * comparisons by this qualifier. The tree of + * qualifiers is traversed and the left-hand-side + * of each expression is added to the set. + */ + public NSSet allQualifierKeys () + { + throw new RuntimeException( "Not implemented yet." ); + } + + /** + * Returns a List containing the variables used + * at compare-time by this qualifier. Each variable + * will appear only once in the list. + */ + public NSArray bindingKeys () + { + throw new RuntimeException( "Not implemented yet." ); + } + + /** + * Returns whether the specified object meets the + * criteria defined by this qualifier. + */ + public boolean evaluateWithObject ( Object anObject ) + { + return true; + } + + /** + * Returns the key (which can be a key path) that + * is tested against the specified binding variable. + * The tree is traversed looking for the first instance + * of the specified variable, and the corresponding + * left-hand-side of the expression is returned. + */ + public String keyPathForBindingKey ( String aVariable ) + { + throw new RuntimeException( "Not implemented yet." ); + } + + /** + * Returns a qualifier that is like this qualifier, + * except all variables will be replaced with values + * from the specified Map whose keys match the variable + * names. If requireAll is true, an exception will be + * thrown if there is no key that matches on of the + * variables in the tree; otherwise, the qualifier + * containing the unmatched variable is removed. + */ + public EOQualifier qualifierWithBindings ( + Map aMap, + boolean requireAll ) + { + throw new WotonomyException( "Not implemented yet." ); + } + + + /** + * Tests whether all the keys in this qualifier can + * be applied to an object of the specified class. + * @return A Throwable if the validation fails, + * otherwise returns null if the class can be used + * with this qualifier. + */ + public Throwable validateKeysWithRootClassDescription ( + Class aClass ) + { + throw new WotonomyException( "Not implemented yet." ); + } + + // statics + + /** + * Convenience to retain only those objects from the specified + * List that meet the specified qualifier's requirements. + */ + public static void filterArrayWithQualifier ( + List anObjectList, EOQualifier aQualifier ) + { + ListIterator iterator = anObjectList.listIterator(); + while ( iterator.hasNext() ) + { + if ( ! aQualifier.evaluateWithObject( iterator.next() ) ) + { + iterator.remove(); + } + } + } + + /** + * Convenience to return a List consisting only + * of those objects in the specified List that meet + * the specified qualifier's requirements. + */ + public static NSArray filteredArrayWithQualifier ( + List anObjectList, EOQualifier aQualifier ) + { + Object o; + List result = new LinkedList(); + Iterator iterator = anObjectList.iterator(); + while ( iterator.hasNext() ) + { + o = iterator.next(); + if ( aQualifier.evaluateWithObject( o ) ) + { + result.add( o ); + } + } + return new NSArray( (Collection) result ); + } + + /** + * Convenience to create a set of EOKeyValueQualifiers + * joined by an EOAndQualifier. Each pair of keys and + * values are used to create EOKeyValueQualifiers. + */ + public static EOQualifier + qualifierToMatchAllValues ( Map aMap ) + { + Object key, value; + List qualifierList = new LinkedList(); + Iterator iterator = aMap.keySet().iterator(); + while ( iterator.hasNext() ) + { + key = iterator.next(); + value = aMap.get( key ); + qualifierList.add( new EOKeyValueQualifier( + key.toString(), QualifierOperatorEqual, value ) ); + } + return new EOAndQualifier( qualifierList ); + } + + /** + * Convenience to create a set of EOKeyValueQualifiers + * joined by an EOOrQualifier. Each pair of keys and + * values are used to create EOKeyValueQualifiers. + */ + public static EOQualifier + qualifierToMatchAnyValue ( Map aMap ) + { + Object key, value; + List qualifierList = new LinkedList(); + Iterator iterator = aMap.keySet().iterator(); + while ( iterator.hasNext() ) + { + key = iterator.next(); + value = aMap.get( key ); + qualifierList.add( new EOKeyValueQualifier( + key.toString(), QualifierOperatorEqual, value ) ); + } + return new EOOrQualifier( qualifierList ); + } + + /** + * Returns an EOQualifier that meets the criteria + * represented by the specified string and variable + * length argument list. This method parses the string + * and returns a tree of qualifiers. Each token beginning + * with "%" is replaced with the corresponding object + * from the argument list. The parser recognizes the + * operation tokens returned from the allQualifierOperators() + * method. + */ + public static EOQualifier qualifierWithQualifierFormat ( + String aString, List anArgumentList ) + { + throw new RuntimeException( "Not implemented yet." ); + } + + /** + * Returns a List of operators that are supported for + * relational operations. This excludes string comparison + * operators. + */ + public static NSArray relationalQualifierOperators () + { + NSMutableArray result = new NSMutableArray(); + BaseSelector selector; + Iterator iterator = allQualifierOperators().iterator(); + while ( iterator.hasNext() ) + { + selector = (BaseSelector) iterator.next(); + if ( selector.isRelationalOperator() ) + { + result.addObject( selector ); + } + } + return result; + } + + /** + * Returns a List of valid operators. + */ + public static NSArray allQualifierOperators () + { + return operators.allKeys(); + } + + /** + * Returns a selector the corresponds to the operation + * represented by the specified string. For example, + * ">" represents QualifierOperatorGreaterThan. + */ + public static NSSelector operatorSelectorForString ( + String anOperatorString ) + { + return (NSSelector) + operators.objectForKey( anOperatorString ); + } + + /** + * Returns a string the corresponds to the operation + * represented by the specified selector. For example, + * QualifierOperatorGreaterThan is represented with ">". + */ + public static String stringForOperatorSelector ( + NSSelector aSelector ) + { + return (String) + operators.allKeysForObject( aSelector ).lastObject(); + } + + /** + * Returns a string representation of this qualifier. + */ + public String toString() + { + //TODO: implement this + return super.toString(); + } + + // built-in qualifiers + + private static NSMutableDictionary operators; + static + { + operators = new NSMutableDictionary(); + operators.setObjectForKey( + QualifierOperatorCaseInsensitiveLike, + QualifierOperatorCaseInsensitiveLike.toString() ); + operators.setObjectForKey( + QualifierOperatorContains, + QualifierOperatorContains.toString() ); + operators.setObjectForKey( + QualifierOperatorEqual, + QualifierOperatorEqual.toString() ); + operators.setObjectForKey( + QualifierOperatorGreaterThan, + QualifierOperatorGreaterThan.toString() ); + operators.setObjectForKey( + QualifierOperatorGreaterThanOrEqualTo, + QualifierOperatorGreaterThanOrEqualTo.toString() ); + operators.setObjectForKey( + QualifierOperatorLessThan, + QualifierOperatorLessThan.toString() ); + operators.setObjectForKey( + QualifierOperatorLessThanOrEqualTo, + QualifierOperatorLessThanOrEqualTo.toString() ); + operators.setObjectForKey( + QualifierOperatorLike, + QualifierOperatorLike.toString() ); + operators.setObjectForKey( + QualifierOperatorNotEqual, + QualifierOperatorNotEqual.toString() ); + } + + static private abstract class BaseSelector extends NSSelector + { + public String name () + { + return "BaseSelector"; + } + + public Class[] parameterTypes () + { + return new Class[] { Object.class, Object.class }; + } + + public Method methodOnClass (Class aClass) + throws NoSuchMethodException + { + throw new NoSuchMethodException(); + } + + public Method methodOnObject (Object anObject) + throws NoSuchMethodException + { + throw new NoSuchMethodException(); + } + + public boolean implementedByClass (Class aClass) + { + return true; + } + + public boolean implementedByObject (Object anObject) + { + return true; + } + + public boolean isRelationalOperator() + { + return true; + } + + public Object invoke (Object anObject, Object[] parameters) + throws IllegalAccessException, IllegalArgumentException, + InvocationTargetException, NoSuchMethodException + { + return qualify( anObject, parameters[0] ); + } + + abstract protected Boolean qualify( Object target, Object parameter ); + + protected int doCompare(Object o1, Object o2) + { + Class firstClass = o1.getClass(); + Class secondClass = o2.getClass(); + + if ( ! ( secondClass.equals( firstClass ) ) ) + { + Object converted = null; + if ( o2 instanceof Comparable ) + { + converted = ValueConverter.convertObjectToClass( o1, secondClass ); + if (converted != null) + { + o1 = converted; + } + } + + if (converted == null && (o1 instanceof Comparable)) + { + converted = ValueConverter.convertObjectToClass( o2, firstClass ); + if ( converted != null ) + { + o2 = converted; + } + } + + if (converted == null) + { + throw new WotonomyException("Qualifier: Not Comparable Objects"); + // no way to compare + } + } + + return ((Comparable)o2).compareTo( o1 ); + } + + } + + + static class OperatorCaseInsensitiveLike extends BaseSelector { + + public boolean isRelationalOperator() + { + return false; + } + + protected Boolean qualify( Object o1, Object o2 ) + { + String myString1 = o1.toString(); + String myString2 = o2.toString(); + myString1 = myString1.toLowerCase(); + myString2 = myString2.toLowerCase(); + StringTokenizer st = new StringTokenizer(myString1, "%"); + + while (st.hasMoreTokens()) { + String part = st.nextToken(); + int index = myString2.indexOf(part); + if (index > -1) + { + myString2 = myString2.substring(index + part.length()); + } + else + { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + + } + + public String toString() + { + return "caseInsensitiveLike"; + } + } + + static class OperatorContains extends BaseSelector { + + public boolean isRelationalOperator() + { + return false; + } + + protected Boolean qualify( Object o1, Object o2 ) + { + String myString1 = o1.toString(); + String myString2 = o2.toString(); + return new Boolean( + myString2.indexOf(myString1) > -1 ); + } + + public String toString() + { + return "contains"; + } + } + + static class OperatorEqual extends BaseSelector { + + protected Boolean qualify( Object o1, Object o2 ) + { + return new Boolean( doCompare(o1, o2) == 0 ); + } + + public String toString() + { + return "="; + } + } + + static class OperatorGreaterThan extends BaseSelector { + + protected Boolean qualify( Object o1, Object o2 ) + { + return new Boolean( doCompare(o1, o2) > 0 ); + } + + public String toString() + { + return ">"; + } + } + + static class OperatorGreaterThanOrEqualTo extends BaseSelector { + + protected Boolean qualify( Object o1, Object o2 ) + { + return new Boolean( doCompare(o1, o2) >= 0 ); + } + + public String toString() + { + return new String(" >= "); + } + } + + static class OperatorLessThan extends BaseSelector { + + protected Boolean qualify( Object o1, Object o2 ) + { + return new Boolean( doCompare(o1, o2) < 0 ); + } + + public String toString() + { + return ">"; + } + } + + static class OperatorLessThanOrEqualTo extends BaseSelector { + + protected Boolean qualify( Object o1, Object o2 ) + { + return new Boolean (doCompare(o1, o2) <= 0); + } + + public String toString() + { + return "<="; + } + } + + static class OperatorLike extends BaseSelector { + + public boolean isRelationalOperator() + { + return false; + } + + protected Boolean qualify( Object o1, Object o2 ) + { + String myString1 = o1.toString(); + String myString2 = o2.toString(); + StringTokenizer st = new StringTokenizer(myString1, "%"); + while (st.hasMoreTokens()) { + String part = st.nextToken(); + int index = myString2.indexOf(part); + if (index > -1) + { + myString2 = myString2.substring(index + part.length()); + } + else + { + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + public String toString() + { + return "like"; + } + } + + static class OperatorNotEqual extends BaseSelector { + + protected Boolean qualify( Object o1, Object o2 ) + { + return new Boolean(!(o1.equals(o2))); + } + + public String toString() + { + return "!="; + } + } + + + public static Object decodeWithKeyValueUnarchiver(EOKeyValueUnarchiver ua) { + String cname = (String)ua.decodeObjectForKey("class"); + if (cname.equals("EOKeyValueQualifier")) + return (EOQualifier)EOKeyValueQualifier.decodeWithKeyValueUnarchiver(ua); + if (cname.equals("EOAndQualifier")) + return (EOQualifier)EOAndQualifier.decodeWithKeyValueUnarchiver(ua); + if (cname.equals("EOOrQualifier")) + return (EOQualifier)EOOrQualifier.decodeWithKeyValueUnarchiver(ua); + if (cname.equals("EONotQualifier")) + return (EOQualifier)EONotQualifier.decodeWithKeyValueUnarchiver(ua); + return null; + } + +} +/* + * $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. + * + * Revision 1.1 2006/02/16 13:19:57 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.10 2003/08/09 01:22:51 chochos + * qualifiers implement EOKeyValueArchiving + * + * Revision 1.9 2001/11/04 18:29:11 mpowers + * Better handling for non-string types used with non-relational operators. + * + * Revision 1.8 2001/10/31 15:25:14 mpowers + * Cleanup of qualifiers. + * + * Revision 1.7 2001/10/30 22:57:28 mpowers + * EOQualifier framework is now working. + * + * Revision 1.6 2001/10/30 22:16:37 mpowers + * Implemented operators as selectors. + * + * Revision 1.5 2001/09/14 14:21:28 mpowers + * Updated javadoc. + * + * Revision 1.3 2001/09/13 15:25:56 mpowers + * Started implementation of the EOQualifier framework. + * + * Revision 1.2 2001/02/27 03:33:04 mpowers + * Initial draft of the key-value qualifier. + * + * Revision 1.1.1.1 2000/12/21 15:46:47 mpowers + * Contributing wotonomy. + * + * Revision 1.2 2000/12/20 16:25:35 michael + * Added log to all files. + * + * + */ + + -- cgit v1.2.3