summaryrefslogtreecommitdiff
path: root/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifier.java
diff options
context:
space:
mode:
Diffstat (limited to 'projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifier.java')
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOQualifier.java680
1 files changed, 680 insertions, 0 deletions
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. <br><br>
+*
+* 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.
+ *
+ *
+ */
+
+