/**
   *
   *
   * <pre>
   *
   *
   *                type == &quot;cheddar&quot &amp;&amp; price &gt; 10
   *
   *
   * </pre>
   *
   * Test the use of the composite AND constraint. Composite AND constraints are only used when
   * nested inside other field constraints, as the top level AND is implicit
   *
   * @throws IntrospectionException
   */
  public void testCompositeAndConstraint() {
    final ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory.newRuleBase();
    final InternalWorkingMemory workingMemory =
        (InternalWorkingMemory) ruleBase.newStatefulSession();

    final ClassFieldExtractor extractor =
        cache.getExtractor(Cheese.class, "type", getClass().getClassLoader());

    final FieldValue field = FieldFactory.getFieldValue("cheddar");

    final Evaluator evaluator = ValueType.STRING_TYPE.getEvaluator(Operator.EQUAL);

    final LiteralConstraint constraint1 = new LiteralConstraint(extractor, evaluator, field);

    final ClassFieldExtractor priceExtractor =
        cache.getExtractor(Cheese.class, "price", getClass().getClassLoader());

    final FieldValue priceField = FieldFactory.getFieldValue(10);

    final Evaluator priceEvaluator = ValueType.INTEGER_TYPE.getEvaluator(Operator.GREATER);

    final LiteralConstraint constraint2 =
        new LiteralConstraint(priceExtractor, priceEvaluator, priceField);

    final Cheese cheddar = new Cheese("cheddar", 15);

    final AndConstraint constraint = new AndConstraint();
    constraint.addAlphaConstraint(constraint1);
    constraint.addAlphaConstraint(constraint2);

    final ContextEntry context = constraint.createContextEntry();

    final InternalFactHandle cheddarHandle = (InternalFactHandle) workingMemory.insert(cheddar);

    // check constraint
    assertTrue(constraint.isAllowed(cheddarHandle.getObject(), workingMemory, context));

    cheddar.setPrice(5);
    ((ShadowProxy) cheddarHandle.getObject()).updateProxy();
    assertFalse(constraint.isAllowed(cheddarHandle.getObject(), workingMemory, context));

    cheddar.setType("stilton");
    ((ShadowProxy) cheddarHandle.getObject()).updateProxy();
    assertFalse(constraint.isAllowed(cheddarHandle.getObject(), workingMemory, context));

    cheddar.setPrice(15);
    ((ShadowProxy) cheddarHandle.getObject()).updateProxy();
    assertFalse(constraint.isAllowed(cheddarHandle.getObject(), workingMemory, context));
  }
  /**
   *
   *
   * <pre>
   *
   *
   *                Cheese( ( type == &quot;cheddar&quot &amp;&amp; price &gt; 10) || ( type == &quote;stilton&quote; && price &lt; 10 ) )
   *
   *
   * </pre>
   *
   * Test the use of the composite OR constraint.
   *
   * @throws IntrospectionException
   */
  public void testNestedCompositeConstraints() {
    final ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory.newRuleBase();
    final InternalWorkingMemory workingMemory =
        (InternalWorkingMemory) ruleBase.newStatefulSession();

    final ClassFieldExtractor typeExtractor =
        cache.getExtractor(Cheese.class, "type", getClass().getClassLoader());

    final FieldValue cheddarField = FieldFactory.getFieldValue("cheddar");

    final Evaluator stringEqual = ValueType.STRING_TYPE.getEvaluator(Operator.EQUAL);

    // type == 'cheddar'
    final LiteralConstraint constraint1 =
        new LiteralConstraint(typeExtractor, stringEqual, cheddarField);

    final ClassFieldExtractor priceExtractor =
        cache.getExtractor(Cheese.class, "price", getClass().getClassLoader());

    final FieldValue field10 = FieldFactory.getFieldValue(10);

    final Evaluator integerGreater = ValueType.INTEGER_TYPE.getEvaluator(Operator.GREATER);

    // price > 10
    final LiteralConstraint constraint2 =
        new LiteralConstraint(priceExtractor, integerGreater, field10);

    // type == 'cheddar' && price > 10
    final AndConstraint and1 = new AndConstraint();
    and1.addAlphaConstraint(constraint1);
    and1.addAlphaConstraint(constraint2);

    final FieldValue stiltonField = FieldFactory.getFieldValue("stilton");
    // type == 'stilton'
    final LiteralConstraint constraint3 =
        new LiteralConstraint(typeExtractor, stringEqual, stiltonField);

    final Evaluator integerLess = ValueType.INTEGER_TYPE.getEvaluator(Operator.LESS);

    // price < 10
    final LiteralConstraint constraint4 =
        new LiteralConstraint(priceExtractor, integerLess, field10);

    // type == 'stilton' && price < 10
    final AndConstraint and2 = new AndConstraint();
    and2.addAlphaConstraint(constraint3);
    and2.addAlphaConstraint(constraint4);

    // ( type == 'cheddar' && price > 10 ) || ( type == 'stilton' && price < 10 )
    final OrConstraint constraint = new OrConstraint();
    constraint.addAlphaConstraint(and1);
    constraint.addAlphaConstraint(and2);
    final ContextEntry context = constraint.createContextEntry();

    final Cheese cheddar = new Cheese("cheddar", 15);

    final InternalFactHandle cheddarHandle = (InternalFactHandle) workingMemory.insert(cheddar);

    // check constraint
    assertTrue(constraint.isAllowed(cheddarHandle.getObject(), workingMemory, context));

    cheddar.setPrice(5);
    ((ShadowProxy) cheddarHandle.getObject()).updateProxy();
    assertFalse(constraint.isAllowed(cheddarHandle.getObject(), workingMemory, context));

    cheddar.setType("stilton");
    ((ShadowProxy) cheddarHandle.getObject()).updateProxy();
    assertTrue(constraint.isAllowed(cheddarHandle.getObject(), workingMemory, context));

    cheddar.setPrice(15);
    ((ShadowProxy) cheddarHandle.getObject()).updateProxy();
    assertFalse(constraint.isAllowed(cheddarHandle.getObject(), workingMemory, context));
  }