[jboss-svn-commits] JBL Code SVN: r24127 - in labs/jbossrules/trunk/drools-core/src: test/java/org/drools/base and 1 other directory.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Thu Nov 27 23:07:09 EST 2008


Author: tirelli
Date: 2008-11-27 23:07:09 -0500 (Thu, 27 Nov 2008)
New Revision: 24127

Modified:
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/evaluators/CoincidesEvaluatorDefinition.java
   labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/TemporalEvaluatorFactoryTest.java
Log:
JBRULES-1873: fixing 'coincides' evaluator and improving javadocs

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/evaluators/CoincidesEvaluatorDefinition.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/evaluators/CoincidesEvaluatorDefinition.java	2008-11-28 02:50:40 UTC (rev 24126)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/evaluators/CoincidesEvaluatorDefinition.java	2008-11-28 04:07:09 UTC (rev 24127)
@@ -38,29 +38,78 @@
 import org.drools.time.Interval;
 
 /**
- * The implementation of the 'coincides' evaluator definition
+ * <p>The implementation of the 'coincides' evaluator definition.</p>
+ * 
+ * <p>The <b><code>coincides</code></b> evaluator correlates two events and matches when both
+ * happen at the same time. Optionally, the evaluator accept thresholds for the distance between
+ * events start and finish timestamps.</p> 
+ * 
+ * <p>Lets look at an example:</p>
+ * 
+ * <pre>$eventA : EventA( this coincides $eventB )</pre>
  *
+ * <p>The previous pattern will match if and only if the start timestamps of both $eventA
+ * and $eventB are the same AND the end timestamp of both $eventA and $eventB also are
+ * the same.</p>
+ * 
+ * <p>Optionally, this operator accepts one or two parameters. These parameters are the thresholds
+ * for the distance between matching timestamps. If only one paratemer is given, it is used for 
+ * both start and end timestamps. If two parameters are given, then the first is used as a threshold
+ * for the start timestamp and the second one is used as a parameter for the end timestamp.</p>
+ * 
+ * ---------------------- NEED TO FINISH WRITING THE JAVADOC -----------------------------
+ * 
+ * <pre> 3m30s <= $eventA.startTimestamp - $eventB.endTimeStamp <= 4m </pre>
+ * 
+ * <p>The temporal distance interval for the <b><code>after</code></b> operator is optional:</p>
+ * 
+ * <ul><li>If two values are defined (like in the example bellow), the interval starts on the
+ * first value and finishes on the second.</li>
+ * <li>If only one value is defined, we have two cases. If the value is negative, then the interval
+ * starts on the value and finishes on -1ms. If the value is positive, then the interval starts on 
+ * +1ms and finishes on the value.</li>
+ * <li>If no value is defined, it is assumed that the initial value is 1ms and the final value
+ * is the positive infinity.</li></ul>
+ * 
+ * <p><b>NOTE:</b> it is allowed to define negative distances for this operator. Example:</p>
+ * 
+ * <pre>$eventA : EventA( this after[ -3m30s, -2m ] $eventB )</pre>
+ *
+ * <p><b>NOTE:</b> if the initial value is greater than the finish value, the engine automatically
+ * reverse them, as there is no reason to have the initial value greater than the finish value. Example: 
+ * the following two patterns are considered to have the same semantics:</p>
+ * 
+ * <pre>
+ * $eventA : EventA( this after[ -3m30s, -2m ] $eventB )
+ * $eventA : EventA( this after[ -2m, -3m30s ] $eventB )
+ * </pre>
+ * 
+ *
+ * @author etirelli
  * @author mgroch
  */
 public class CoincidesEvaluatorDefinition
     implements
     EvaluatorDefinition {
 
-    public static final Operator  COINCIDES       = Operator.addOperatorToRegistry( "coincides",
-                                                                                  false );
-    public static final Operator  COINCIDES_NOT   = Operator.addOperatorToRegistry( "coincides",
-                                                                                  true );
+    public static final Operator            COINCIDES     = Operator.addOperatorToRegistry( "coincides",
+                                                                                            false );
+    public static final Operator            COINCIDES_NOT = Operator.addOperatorToRegistry( "coincides",
+                                                                                            true );
 
-    private static final String[] SUPPORTED_IDS = { COINCIDES.getOperatorString() };
+    private static final String[]           SUPPORTED_IDS = {COINCIDES.getOperatorString()};
 
-    private Map<String, CoincidesEvaluator> cache        = Collections.emptyMap();
+    private Map<String, CoincidesEvaluator> cache         = Collections.emptyMap();
+    private volatile TimeIntervalParser     parser        = new TimeIntervalParser();
 
-    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
-        cache  = (Map<String, CoincidesEvaluator>)in.readObject();
+    @SuppressWarnings("unchecked")
+    public void readExternal(ObjectInput in) throws IOException,
+                                            ClassNotFoundException {
+        cache = (Map<String, CoincidesEvaluator>) in.readObject();
     }
 
     public void writeExternal(ObjectOutput out) throws IOException {
-        out.writeObject(cache);
+        out.writeObject( cache );
     }
 
     /**
@@ -99,9 +148,11 @@
         String key = isNegated + ":" + parameterText;
         CoincidesEvaluator eval = this.cache.get( key );
         if ( eval == null ) {
+            Long[] params = parser.parse( parameterText );
             eval = new CoincidesEvaluator( type,
-                                       isNegated,
-                                       parameterText );
+                                           isNegated,
+                                           params,
+                                           parameterText );
             this.cache.put( key,
                             eval );
         }
@@ -142,32 +193,36 @@
      * Implements the 'coincides' evaluator itself
      */
     public static class CoincidesEvaluator extends BaseEvaluator {
-		private static final long serialVersionUID = 6031520837249122183L;
+        private static final long serialVersionUID = 6031520837249122183L;
 
-		private long                  startDev;
-        private long                  endDev;
+        private long              startDev;
+        private long              endDev;
+        private String            paramText;
 
         public CoincidesEvaluator() {
         }
 
         public CoincidesEvaluator(final ValueType type,
-                              final boolean isNegated,
-                              final String parameters) {
+                                  final boolean isNegated,
+                                  final Long[] parameters,
+                                  final String paramText) {
             super( type,
                    isNegated ? COINCIDES_NOT : COINCIDES );
-            this.parseParameters( parameters );
+            this.paramText = paramText;
+            this.setParameters( parameters );
         }
 
-        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
-            super.readExternal(in);
+        public void readExternal(ObjectInput in) throws IOException,
+                                                ClassNotFoundException {
+            super.readExternal( in );
             startDev = in.readLong();
             endDev = in.readLong();
         }
 
         public void writeExternal(ObjectOutput out) throws IOException {
-            super.writeExternal(out);
-            out.writeLong(startDev);
-            out.writeLong(endDev);
+            super.writeExternal( out );
+            out.writeLong( startDev );
+            out.writeLong( endDev );
         }
 
         @Override
@@ -179,15 +234,17 @@
         public boolean isTemporal() {
             return true;
         }
-        
+
         @Override
         public Interval getInterval() {
-            if( this.getOperator().isNegated() ) {
-                return new Interval( Interval.MIN, Interval.MAX );
+            if ( this.getOperator().isNegated() ) {
+                return new Interval( Interval.MIN,
+                                     Interval.MAX );
             }
-            return new Interval( 0, 0 );
+            return new Interval( 0,
+                                 0 );
         }
-        
+
         public boolean evaluate(InternalWorkingMemory workingMemory,
                                 final InternalReadAccessor extractor,
                                 final Object object1,
@@ -201,11 +258,9 @@
             if ( context.rightNull ) {
                 return false;
             }
-            long distStart = Math.abs(((EventFactHandle)((ObjectVariableContextEntry) context).right).getStartTimestamp() -
-                        	 ((EventFactHandle) left ).getStartTimestamp());
-            long distEnd = Math.abs(((EventFactHandle)((ObjectVariableContextEntry) context).right).getEndTimestamp() -
-       	 				   ((EventFactHandle) left ).getEndTimestamp());
-            return this.getOperator().isNegated() ^ ( distStart <= this.startDev && distEnd <= this.endDev);
+            long distStart = Math.abs( ((EventFactHandle) ((ObjectVariableContextEntry) context).right).getStartTimestamp() - ((EventFactHandle) left).getStartTimestamp() );
+            long distEnd = Math.abs( ((EventFactHandle) ((ObjectVariableContextEntry) context).right).getEndTimestamp() - ((EventFactHandle) left).getEndTimestamp() );
+            return this.getOperator().isNegated() ^ (distStart <= this.startDev && distEnd <= this.endDev);
         }
 
         public boolean evaluateCachedLeft(InternalWorkingMemory workingMemory,
@@ -215,11 +270,9 @@
                                                 right ) ) {
                 return false;
             }
-            long distStart = Math.abs(((EventFactHandle) right ).getStartTimestamp() -
-                        	 ((EventFactHandle) ((ObjectVariableContextEntry) context).left).getStartTimestamp());
-            long distEnd = Math.abs(((EventFactHandle) right ).getEndTimestamp() -
-               	 		   ((EventFactHandle) ((ObjectVariableContextEntry) context).left).getEndTimestamp());
-            return this.getOperator().isNegated() ^ ( distStart <= this.startDev && distEnd <= this.endDev );
+            long distStart = Math.abs( ((EventFactHandle) right).getStartTimestamp() - ((EventFactHandle) ((ObjectVariableContextEntry) context).left).getStartTimestamp() );
+            long distEnd = Math.abs( ((EventFactHandle) right).getEndTimestamp() - ((EventFactHandle) ((ObjectVariableContextEntry) context).left).getEndTimestamp() );
+            return this.getOperator().isNegated() ^ (distStart <= this.startDev && distEnd <= this.endDev);
         }
 
         public boolean evaluate(InternalWorkingMemory workingMemory,
@@ -231,9 +284,9 @@
                                          object1 ) ) {
                 return false;
             }
-            long distStart = Math.abs(((EventFactHandle) object1 ).getStartTimestamp() - ((EventFactHandle) object2 ).getStartTimestamp());
-            long distEnd = Math.abs(((EventFactHandle) object1 ).getEndTimestamp() - ((EventFactHandle) object2 ).getEndTimestamp());
-            return this.getOperator().isNegated() ^ ( distStart <= this.startDev && distEnd <= this.endDev );
+            long distStart = Math.abs( ((EventFactHandle) object1).getStartTimestamp() - ((EventFactHandle) object2).getStartTimestamp() );
+            long distEnd = Math.abs( ((EventFactHandle) object1).getEndTimestamp() - ((EventFactHandle) object2).getEndTimestamp() );
+            return this.getOperator().isNegated() ^ (distStart <= this.startDev && distEnd <= this.endDev);
         }
 
         public String toString() {
@@ -265,36 +318,27 @@
         }
 
         /**
-         * This methods tries to parse the string of parameters to customize
-         * the evaluator.
+         * This methods sets the parameters appropriately.
          *
          * @param parameters
          */
-        private void parseParameters(String parameters) {
-            if ( parameters == null || parameters.trim().length() == 0 ) {
-                // exact matching
+        private void setParameters(Long[] parameters) {
+            if ( parameters == null || parameters.length == 0 ) {
+                // open bounded range
                 this.startDev = 0;
                 this.endDev = 0;
                 return;
+            } else if ( parameters.length == 1 ) {
+                // same deviation for both
+                this.startDev = parameters[0].longValue();
+                this.endDev = parameters[0].longValue();
+            } else if ( parameters.length == 2 ) {
+                // different deviation 
+                this.startDev = parameters[0].longValue();
+                this.endDev = parameters[1].longValue();
+            } else {
+                throw new RuntimeDroolsException( "[Coincides Evaluator]: Not possible to have more than 2 parameters: '" + paramText + "'" );
             }
-
-            try {
-                String[] ranges = parameters.split( "," );
-                if ( ranges.length == 1 ) {
-                    // same max. deviation at start and end of interval
-                    this.startDev = Long.parseLong( ranges[0] );
-                    this.endDev = this.startDev;
-                } else if ( ranges.length == 2 ) {
-                    // different max. deviation at start and end of interval
-                    this.startDev = Long.parseLong( ranges[0] );
-                    this.endDev = Long.parseLong( ranges[1] );
-                } else {
-                    throw new RuntimeDroolsException( "[Coincides Evaluator]: Not possible to parse parameters: '" + parameters + "'" );
-                }
-            } catch ( NumberFormatException e ) {
-                throw new RuntimeDroolsException( "[Coincides Evaluator]: Not possible to parse parameters: '" + parameters + "'",
-                                                  e );
-            }
         }
 
     }

Modified: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/TemporalEvaluatorFactoryTest.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/TemporalEvaluatorFactoryTest.java	2008-11-28 02:50:40 UTC (rev 24126)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/TemporalEvaluatorFactoryTest.java	2008-11-28 04:07:09 UTC (rev 24127)
@@ -242,13 +242,39 @@
                                                     1,
                                                     2 );
 
-        final Object[][] data = {{foo, "coincides", bar, Boolean.TRUE}, {foo, "coincides", drool, Boolean.FALSE}, {foo, "coincides", mole, Boolean.FALSE}, {drool, "coincides", mole, Boolean.FALSE}, {foo, "not coincides", bar, Boolean.FALSE},
-                {foo, "not coincides", drool, Boolean.TRUE}, {foo, "not coincides", mole, Boolean.TRUE}, {drool, "not coincides", mole, Boolean.TRUE}, {foo, "coincides[1]", bar, Boolean.TRUE}, {foo, "coincides[1]", drool, Boolean.TRUE},
-                {foo, "coincides[2]", mole, Boolean.TRUE}, {foo, "coincides[1]", mole, Boolean.FALSE}, {drool, "coincides[1]", mole, Boolean.TRUE}, {foo, "not coincides[1]", bar, Boolean.FALSE}, {foo, "not coincides[1]", drool, Boolean.FALSE},
-                {foo, "not coincides[2]", mole, Boolean.FALSE}, {foo, "not coincides[1]", mole, Boolean.TRUE}, {drool, "not coincides[1]", mole, Boolean.FALSE}, {foo, "coincides[1,2]", bar, Boolean.TRUE},
-                {foo, "coincides[0,1]", drool, Boolean.TRUE}, {foo, "coincides[1,0]", drool, Boolean.FALSE}, {foo, "coincides[1,2]", mole, Boolean.TRUE}, {foo, "coincides[1,1]", mole, Boolean.FALSE}, {drool, "coincides[1,1]", mole, Boolean.TRUE},
-                {drool, "coincides[0,1]", mole, Boolean.FALSE}, {foo, "not coincides[1,2]", bar, Boolean.FALSE}, {foo, "not coincides[0,1]", drool, Boolean.FALSE}, {foo, "not coincides[1,0]", drool, Boolean.TRUE},
-                {foo, "not coincides[1,2]", mole, Boolean.FALSE}, {foo, "not coincides[1,1]", mole, Boolean.TRUE}, {drool, "not coincides[1,1]", mole, Boolean.FALSE}, {drool, "not coincides[0,1]", mole, Boolean.TRUE}};
+        final Object[][] data = {
+                {foo, "coincides", bar, Boolean.TRUE}, 
+                {foo, "coincides", drool, Boolean.FALSE}, 
+                {foo, "coincides", mole, Boolean.FALSE}, 
+                {drool, "coincides", mole, Boolean.FALSE}, 
+                {foo, "not coincides", bar, Boolean.FALSE},
+                {foo, "not coincides", drool, Boolean.TRUE}, 
+                {foo, "not coincides", mole, Boolean.TRUE}, 
+                {drool, "not coincides", mole, Boolean.TRUE}, 
+                {foo, "coincides[1]", bar, Boolean.TRUE}, 
+                {foo, "coincides[1]", drool, Boolean.TRUE},
+                {foo, "coincides[2]", mole, Boolean.TRUE}, 
+                {foo, "coincides[1]", mole, Boolean.FALSE}, 
+                {drool, "coincides[1]", mole, Boolean.TRUE},
+                {foo, "not coincides[1]", bar, Boolean.FALSE}, 
+                {foo, "not coincides[1]", drool, Boolean.FALSE},
+                {foo, "not coincides[2]", mole, Boolean.FALSE}, 
+                {foo, "not coincides[1]", mole, Boolean.TRUE}, 
+                {drool, "not coincides[1]", mole, Boolean.FALSE}, 
+                {foo, "coincides[1,2]", bar, Boolean.TRUE},
+                {foo, "coincides[0,1]", drool, Boolean.TRUE},
+                {foo, "coincides[1,0]", drool, Boolean.FALSE}, 
+                {foo, "coincides[1,2]", mole, Boolean.TRUE}, 
+                {foo, "coincides[1,1]", mole, Boolean.FALSE}, 
+                {drool, "coincides[1,1]", mole, Boolean.TRUE},
+                {drool, "coincides[0,1]", mole, Boolean.FALSE},
+                {foo, "not coincides[1,2]", bar, Boolean.FALSE}, 
+                {foo, "not coincides[0,1]", drool, Boolean.FALSE},
+                {foo, "not coincides[1,0]", drool, Boolean.TRUE},
+                {foo, "not coincides[1,2]", mole, Boolean.FALSE},
+                {foo, "not coincides[1,1]", mole, Boolean.TRUE}, 
+                {drool, "not coincides[1,1]", mole, Boolean.FALSE}, 
+                {drool, "not coincides[0,1]", mole, Boolean.TRUE}};
 
         runEvaluatorTest( data,
                           ValueType.OBJECT_TYPE );




More information about the jboss-svn-commits mailing list