/** * * * <pre> * * * ( Cheese (type "cheddar") ) * * * </pre> * * This is currently the same as using a ReturnValueConstraint just that it doesn't need any * requiredDeclarations * * @throws IntrospectionException */ public void testLiteralConstraint() throws IntrospectionException { 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 constraint = new LiteralConstraint(extractor, evaluator, field); final ContextEntry context = constraint.createContextEntry(); final Cheese cheddar = new Cheese("cheddar", 5); final InternalFactHandle cheddarHandle = (InternalFactHandle) workingMemory.insert(cheddar); // check constraint assertTrue(constraint.isAllowed(cheddarHandle.getObject(), workingMemory, context)); final Cheese stilton = new Cheese("stilton", 5); final InternalFactHandle stiltonHandle = (InternalFactHandle) workingMemory.insert(stilton); // check constraint assertFalse(constraint.isAllowed(stiltonHandle.getObject(), workingMemory, context)); }
private void addMatch( final LeftTuple leftTuple, final RightTuple rightTuple, final LeftTuple currentLeftChild, final LeftTuple currentRightChild, final InternalWorkingMemory workingMemory, final AccumulateMemory memory, final AccumulateContext accresult, final boolean useLeftMemory) { LeftTuple tuple = leftTuple; InternalFactHandle handle = rightTuple.getFactHandle(); if (this.unwrapRightObject) { // if there is a subnetwork, handle must be unwrapped tuple = (LeftTuple) handle.getObject(); // handle = tuple.getLastHandle(); } this.accumulate.accumulate( memory.workingMemoryContext, accresult.context, tuple, handle, workingMemory); // in sequential mode, we don't need to keep record of matched tuples if (useLeftMemory) { // linking left and right by creating a new left tuple createLeftTuple(leftTuple, rightTuple, currentLeftChild, currentRightChild, this, true); } }
/** * Removes a match between left and right tuple * * @param rightTuple * @param match * @param result */ private void removeMatch( final RightTuple rightTuple, final LeftTuple match, final InternalWorkingMemory workingMemory, final AccumulateMemory memory, final AccumulateContext accctx, final boolean reaccumulate) { // save the matching tuple LeftTuple leftTuple = match.getLeftParent(); if (match != null) { // removing link between left and right match.unlinkFromLeftParent(); match.unlinkFromRightParent(); } // if there is a subnetwork, we need to unwrap the object from inside the tuple InternalFactHandle handle = rightTuple.getFactHandle(); LeftTuple tuple = leftTuple; if (this.unwrapRightObject) { tuple = (LeftTuple) handle.getObject(); // handle = tuple.getLastHandle(); } if (this.accumulate.supportsReverse()) { // just reverse this single match this.accumulate.reverse( memory.workingMemoryContext, accctx.context, tuple, handle, workingMemory); } else { // otherwise need to recalculate all matches for the given leftTuple if (reaccumulate) { reaccumulateForLeftTuple(leftTuple, workingMemory, memory, accctx); } } }
public static void readTruthMaintenanceSystem(MarshallerReaderContext context) throws IOException { ObjectInputStream stream = context.stream; TruthMaintenanceSystem tms = context.wm.getTruthMaintenanceSystem(); while (stream.readShort() == PersisterEnums.EQUALITY_KEY) { int status = stream.readInt(); int factHandleId = stream.readInt(); InternalFactHandle handle = (InternalFactHandle) context.handles.get(factHandleId); // ObjectTypeConf state is not marshalled, so it needs to be re-determined ObjectTypeConf typeConf = context .wm .getObjectTypeConfigurationRegistry() .getObjectTypeConf(context.wm.getEntryPoint(), handle.getObject()); if (!typeConf.isTMSEnabled()) { typeConf.enableTMS(); } EqualityKey key = new EqualityKey(handle, status); handle.setEqualityKey(key); while (stream.readShort() == PersisterEnums.FACT_HANDLE) { factHandleId = stream.readInt(); handle = (InternalFactHandle) context.handles.get(factHandleId); key.addFactHandle(handle); handle.setEqualityKey(key); } tms.put(key); } }
public static Map<String, Object> valuesAsMap( Object object, InternalWorkingMemory workingMemory, LeftTuple leftTuple, Declaration[] declarations) { if (declarations.length == 0) { return null; } Map<String, Object> map = new HashMap<String, Object>(); for (Declaration declaration : declarations) { if (leftTuple == null) { map.put( declaration.getBindingName(), declaration.getExtractor().getValue(workingMemory, object)); } else { InternalFactHandle fact = leftTuple.get(declaration); map.put( declaration.getBindingName(), declaration .getExtractor() .getValue(workingMemory, fact != null ? fact.getObject() : object)); } } return map; }
/** * Propagate the <code>FactHandleimpl</code> through the <code>Rete</code> network. All <code> * FactHandleImpl</code> should be remembered in the node memory, so that later runtime rule * attachmnents can have the matched facts propagated to them. * * @param factHandle The fact handle. * @param object The object to assert. * @param workingMemory The working memory session. */ public void assertObject( final InternalFactHandle factHandle, final PropagationContext context, final InternalWorkingMemory workingMemory) { if (objectMemoryEnabled && !(queryNode && !((DroolsQuery) factHandle.getObject()).isOpen())) { final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this); memory.add(factHandle, false); } if (compiledNetwork != null) { compiledNetwork.assertObject(factHandle, context, workingMemory); } else { context.setCurrentPropagatingOTN(this); this.sink.propagateAssertObject(factHandle, context, workingMemory); } if (this.objectType.isEvent() && this.expirationOffset >= 0 && this.expirationOffset != Long.MAX_VALUE) { // schedule expiration WorkingMemoryReteExpireAction expire = new WorkingMemoryReteExpireAction(factHandle, this); TimerService clock = workingMemory.getTimerService(); long nextTimestamp = Math.max( clock.getCurrentTime() + this.expirationOffset, ((EventFactHandle) factHandle).getStartTimestamp() + this.expirationOffset); JobContext jobctx = new ExpireJobContext(expire, workingMemory); JobHandle handle = clock.scheduleJob(job, jobctx, new PointInTimeTrigger(nextTimestamp, null, null)); jobctx.setJobHandle(handle); } }
public static void readFactHandles(MarshallerReaderContext context, ObjectStore objectStore) throws IOException, ClassNotFoundException { ObjectInputStream stream = context.stream; InternalWorkingMemory wm = context.wm; int size = stream.readInt(); // load the handles InternalFactHandle[] handles = new InternalFactHandle[size]; for (int i = 0; i < size; i++) { InternalFactHandle handle = readFactHandle(context); context.handles.put(handle.getId(), handle); handles[i] = handle; if (handle.getObject() != null) { objectStore.addHandle(handle, handle.getObject()); } readRightTuples(handle, context); } readLeftTuples(context); // object store if (stream.readBoolean()) { readLeftTuples(context); // activation fact handles } // add handles to object type nodes for (InternalFactHandle factHandle : handles) { Object object = factHandle.getObject(); EntryPoint ep = ((InternalWorkingMemoryEntryPoint) factHandle.getEntryPoint()).getEntryPoint(); ObjectTypeConf typeConf = ((InternalWorkingMemoryEntryPoint) factHandle.getEntryPoint()) .getObjectTypeConfigurationRegistry() .getObjectTypeConf(ep, object); ObjectTypeNode[] cachedNodes = typeConf.getObjectTypeNodes(); for (int i = 0, length = cachedNodes.length; i < length; i++) { ObjectHashSet set = (ObjectHashSet) wm.getNodeMemory(cachedNodes[i]); set.add(factHandle, false); } } }
private static ProtobufMessages.FactHandle.HandleType getHandleType(InternalFactHandle handle) { if (handle instanceof EventFactHandle) { return ProtobufMessages.FactHandle.HandleType.EVENT; } else if (handle instanceof QueryElementFactHandle) { return ProtobufMessages.FactHandle.HandleType.QUERY; } else if (handle.getObject() instanceof InitialFact) { return ProtobufMessages.FactHandle.HandleType.INITIAL_FACT; } return ProtobufMessages.FactHandle.HandleType.FACT; }
public boolean evaluateCachedRight( InternalWorkingMemory workingMemory, VariableContextEntry context, InternalFactHandle left) { Object target = left.getObject(); Object source = context.getObject(); return compare(source, target, workingMemory); }
public boolean evaluateCachedLeft( InternalWorkingMemory workingMemory, VariableContextEntry context, InternalFactHandle right) { Object target = ((VariableRestriction.ObjectVariableContextEntry) context).left; Object source = right.getObject(); return compare(source, target, workingMemory); }
public void accumulate( Object workingMemoryContext, Object context, Tuple leftTuple, InternalFactHandle handle, Declaration[] declarations, Declaration[] innerDeclarations, WorkingMemory workingMemory) throws Exception { this.matchingObjects.add(handle.getObject()); }
public boolean evaluate( InternalWorkingMemory workingMemory, final InternalReadAccessor extractor1, final InternalFactHandle handle1, final InternalReadAccessor extractor2, final InternalFactHandle handle2) { if (extractor1.isNullValue(workingMemory, handle1.getObject()) || extractor2.isNullValue(workingMemory, handle2.getObject())) { return false; } long distStart = ((EventFactHandle) handle1).getStartTimestamp() - ((EventFactHandle) handle2).getStartTimestamp(); long distEnd = Math.abs( ((EventFactHandle) handle2).getEndTimestamp() - ((EventFactHandle) handle1).getEndTimestamp()); return this.getOperator().isNegated() ^ (distStart > 0 && distEnd <= this.endDev); }
private static void writeFactHandle( MarshallerWriteContext context, ObjectOutputStream stream, ObjectMarshallingStrategyStore objectMarshallingStrategyStore, int type, InternalFactHandle handle) throws IOException { stream.writeInt(type); stream.writeInt(handle.getId()); stream.writeLong(handle.getRecency()); if (type == 2) { // is event EventFactHandle efh = (EventFactHandle) handle; stream.writeLong(efh.getStartTimestamp()); stream.writeLong(efh.getDuration()); stream.writeBoolean(efh.isExpired()); stream.writeLong(efh.getActivationsCount()); } // context.out.println( "Object : int:" + handle.getId() + " long:" + handle.getRecency() ); // context.out.println( handle.getObject() ); Object object = handle.getObject(); // Old versions wrote -1 and tested >= 0 to see if there was a strategy available // Now, we write -2 to indicate that we write the strategy class name to the stream stream.writeInt(-2); if (object != null) { ObjectMarshallingStrategy strategy = objectMarshallingStrategyStore.getStrategyObject(object); String strategyClassName = strategy.getClass().getName(); stream.writeUTF(strategyClassName); strategy.write(stream, object); } else { stream.writeUTF(""); } if (handle.getEntryPoint() instanceof InternalWorkingMemoryEntryPoint) { String entryPoint = ((InternalWorkingMemoryEntryPoint) handle.getEntryPoint()) .getEntryPoint() .getEntryPointId(); if (entryPoint != null && !entryPoint.equals("")) { stream.writeBoolean(true); stream.writeUTF(entryPoint); } else { stream.writeBoolean(false); } } else { stream.writeBoolean(false); } }
public boolean isAllowedCachedLeft(ContextEntry context, InternalFactHandle handle) { if (((UnificationContextEntry) context).getVariable() == null) { return this.vr.isAllowedCachedLeft( ((UnificationContextEntry) context).getContextEntry(), handle); } else { VariableContextEntry vContext = (VariableContextEntry) ((UnificationContextEntry) context).getContextEntry(); ((UnificationContextEntry) context) .getVariable() .setValue(vContext.getFieldExtractor().getValue(handle.getObject())); return true; } }
public void rowUpdated( final Rule rule, final LeftTuple resultLeftTuple, final PropagationContext context, final InternalWorkingMemory workingMemory) { RightTuple rightTuple = (RightTuple) resultLeftTuple.getObject(); if (rightTuple.getMemory() != null) { // Already sheduled as an insert return; } rightTuple.setLeftTuple(null); resultLeftTuple.setObject(null); // We need to recopy everything back again, as we don't know what has or hasn't changed QueryTerminalNode node = (QueryTerminalNode) resultLeftTuple.getLeftTupleSink(); Declaration[] decls = node.getDeclarations(); InternalFactHandle rootHandle = resultLeftTuple.get(0); DroolsQuery query = (DroolsQuery) rootHandle.getObject(); Object[] objects = new Object[query.getElements().length]; Declaration decl; for (int i = 0, length = this.variables.length; i < length; i++) { decl = decls[this.variables[i]]; objects[this.variables[i]] = decl.getValue(workingMemory, resultLeftTuple.get(decl).getObject()); } QueryElementFactHandle handle = (QueryElementFactHandle) rightTuple.getFactHandle(); handle.setRecency(workingMemory.getFactHandleFactory().getAtomicRecency().incrementAndGet()); handle.setObject(objects); if (query.isOpen()) { rightTuple.setLeftTuple(resultLeftTuple); resultLeftTuple.setObject(rightTuple); } // Don't need to recreate child links, as they will already be there form the first "add" RightTupleList rightTuples = query.getResultUpdateRightTupleList(); if (rightTuples == null) { rightTuples = new RightTupleList(); query.setResultUpdateRightTupleList(rightTuples); QueryResultUpdateAction updateAction = new QueryResultUpdateAction(context, this.factHandle, leftTuple, this.node); context.getQueue2().addFirst(updateAction); } rightTuples.add(rightTuple); }
public static void writeFactHandles(MarshallerWriteContext context, ObjectStore objectStore) throws IOException { ObjectOutputStream stream = context.stream; InternalWorkingMemory wm = context.wm; ObjectMarshallingStrategyStore objectMarshallingStrategyStore = context.objectMarshallingStrategyStore; List<InternalFactHandle> matchFactHandles = null; if (((InternalAgenda) wm.getAgenda()).isDeclarativeAgenda()) { ActivationIterator it = ActivationIterator.iterator(wm); matchFactHandles = new ArrayList<InternalFactHandle>(100); for (Activation item = (Activation) it.next(); item != null; item = (Activation) it.next()) { matchFactHandles.add(item.getFactHandle()); } } stream.writeInt( objectStore.size() + ((matchFactHandles == null) ? 0 : matchFactHandles.size())); // Write out FactHandles for (InternalFactHandle handle : orderFacts(objectStore)) { // stream.writeShort( PersisterEnums.FACT_HANDLE ); // InternalFactHandle handle = (InternalFactHandle) it.next(); writeFactHandle(context, stream, objectMarshallingStrategyStore, handle); writeRightTuples(handle, context); } if (matchFactHandles != null) { for (InternalFactHandle handle : orderFacts(matchFactHandles)) { Object object = handle.getObject(); handle.setObject( null); // we must set it to null as we don't want to write out the Activation writeFactHandle(context, stream, objectMarshallingStrategyStore, handle); handle.setObject(object); // restore object writeRightTuples(handle, context); } } // writeLeftTuples( context ); writeLeftTuples(context, orderFacts(objectStore)); if (matchFactHandles != null) { stream.writeBoolean(true); writeLeftTuples(context, orderFacts(matchFactHandles)); } else { stream.writeBoolean(false); } }
/** * * * <pre> * * * type == "cheddar" && price > 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)); }
public boolean evaluateCachedLeft( InternalWorkingMemory workingMemory, final VariableContextEntry context, final InternalFactHandle right) { if (context.leftNull || context.extractor.isNullValue(workingMemory, right.getObject())) { return false; } long distStart = ((EventFactHandle) right).getStartTimestamp() - ((TemporalVariableContextEntry) context).startTS; long distEnd = Math.abs( ((TemporalVariableContextEntry) context).endTS - ((EventFactHandle) right).getEndTimestamp()); return this.getOperator().isNegated() ^ (distStart > 0 && distEnd <= this.endDev); }
public void assertObject( final InternalFactHandle handle, final PropagationContext context, final ObjectTypeConf objectTypeConf, final InternalWorkingMemory workingMemory) { // checks if shadow is enabled if (objectTypeConf.isShadowEnabled()) { // the user has implemented the ShadowProxy interface, let their implementation // know it is safe to update the information the engine can see. ((ShadowProxy) handle.getObject()).updateProxy(); } ObjectTypeNode[] cachedNodes = objectTypeConf.getObjectTypeNodes(); for (int i = 0, length = cachedNodes.length; i < length; i++) { cachedNodes[i].assertObject(handle, context, workingMemory); } }
private void reaccumulateForLeftTuple( final LeftTuple leftTuple, final InternalWorkingMemory workingMemory, final AccumulateMemory memory, final AccumulateContext accctx) { this.accumulate.init(memory.workingMemoryContext, accctx.context, leftTuple, workingMemory); for (LeftTuple childMatch = getFirstMatch(leftTuple, accctx, false); childMatch != null; childMatch = childMatch.getLeftParentNext()) { InternalFactHandle childHandle = childMatch.getRightParent().getFactHandle(); LeftTuple tuple = leftTuple; if (this.unwrapRightObject) { tuple = (LeftTuple) childHandle.getObject(); childHandle = tuple.getLastHandle(); } this.accumulate.accumulate( memory.workingMemoryContext, accctx.context, tuple, childHandle, workingMemory); } }
/** @inheridDoc */ public boolean evaluate( InternalWorkingMemory workingMemory, InternalReadAccessor extractor, InternalFactHandle handle, FieldValue value) { final Object objectValue = extractor.getValue(workingMemory, handle.getObject()); final Object literal = value.getValue(); if (cachedValue != literal) { cachedValue = literal; cacheLiteral(literal, workingMemory); } TraitableBean core; if (objectValue instanceof Thing) { Thing thing = (Thing) objectValue; core = (TraitableBean) thing.getCore(); BitSet code = core.getCurrentTypeCode(); if (code != null) { return this.getOperator().isNegated() ^ isA(code, cachedLiteral); } else { return this.getOperator().isNegated() ^ hasTrait(core, literal); } } else if (objectValue instanceof TraitableBean) { core = (TraitableBean) objectValue; BitSet code = core.getCurrentTypeCode(); if (code != null) { return this.getOperator().isNegated() ^ isA(code, cachedLiteral); } else { return this.getOperator().isNegated() ^ hasTrait(core, literal); } } else { core = lookForWrapper(objectValue, workingMemory); if (core == null) { return this.getOperator().isNegated(); } BitSet code = core.getCurrentTypeCode(); if (code != null) { return this.getOperator().isNegated() ^ isA(code, cachedLiteral); } else { return this.getOperator().isNegated() ^ hasTrait(core, literal); } } }
/** * Retract the <code>FactHandleimpl</code> from the <code>Rete</code> network. Also remove the * <code>FactHandleImpl</code> from the node memory. * * @param rightTuple The fact handle. * @param object The object to assert. * @param workingMemory The working memory session. */ public void retractObject( final InternalFactHandle factHandle, final PropagationContext context, final InternalWorkingMemory workingMemory) { if (objectMemoryEnabled && !(queryNode && !((DroolsQuery) factHandle.getObject()).isOpen())) { final ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory(this); memory.remove(factHandle); } for (RightTuple rightTuple = factHandle.getFirstRightTuple(); rightTuple != null; rightTuple = (RightTuple) rightTuple.getHandleNext()) { rightTuple.getRightTupleSink().retractRightTuple(rightTuple, context, workingMemory); } factHandle.clearRightTuples(); for (LeftTuple leftTuple = factHandle.getFirstLeftTuple(); leftTuple != null; leftTuple = (LeftTuple) leftTuple.getLeftParentNext()) { leftTuple.getLeftTupleSink().retractLeftTuple(leftTuple, context, workingMemory); } factHandle.clearLeftTuples(); }
public void modifyObject( final InternalFactHandle handle, final PropagationContext context, final ObjectTypeConf objectTypeConf, final InternalWorkingMemory workingMemory) { // checks if shadow is enabled if (objectTypeConf.isShadowEnabled()) { // the user has implemented the ShadowProxy interface, let their implementation // know it is safe to update the information the engine can see. ((ShadowProxy) handle.getObject()).updateProxy(); } ObjectTypeNode[] cachedNodes = objectTypeConf.getObjectTypeNodes(); // make a reference to the previous tuples, then null then on the handle ModifyPreviousTuples modifyPreviousTuples = new ModifyPreviousTuples(handle.getFirstLeftTuple(), handle.getFirstRightTuple()); handle.clearLeftTuples(); handle.clearRightTuples(); for (int i = 0, length = cachedNodes.length; i < length; i++) { cachedNodes[i].modifyObject(handle, modifyPreviousTuples, context, workingMemory); // remove any right tuples that matches the current OTN before continue the modify on the next // OTN cache entry if (i < cachedNodes.length - 1) { RightTuple rightTuple = modifyPreviousTuples.peekRightTuple(); while (rightTuple != null && rightTuple.getRightTupleSink() instanceof BetaNode && ((BetaNode) rightTuple.getRightTupleSink()).getObjectTypeNode() == cachedNodes[i]) { modifyPreviousTuples.removeRightTuple(); rightTuple = modifyPreviousTuples.peekRightTuple(); } } } modifyPreviousTuples.retractTuples(context, workingMemory); }
private static ProtobufMessages.FactHandle writeFactHandle( MarshallerWriteContext context, ObjectMarshallingStrategyStore objectMarshallingStrategyStore, InternalFactHandle handle) throws IOException { ProtobufMessages.FactHandle.Builder _handle = ProtobufMessages.FactHandle.newBuilder(); _handle.setType(getHandleType(handle)); _handle.setId(handle.getId()); _handle.setRecency(handle.getRecency()); if (_handle.getType() == ProtobufMessages.FactHandle.HandleType.EVENT) { // is event EventFactHandle efh = (EventFactHandle) handle; _handle.setTimestamp(efh.getStartTimestamp()); _handle.setDuration(efh.getDuration()); _handle.setIsExpired(efh.isExpired()); _handle.setActivationsCount(efh.getActivationsCount()); } Object object = handle.getObject(); if (object != null) { ObjectMarshallingStrategy strategy = objectMarshallingStrategyStore.getStrategyObject(object); String strategyClassName = strategy.getClass().getName(); Integer index = context.usedStrategies.get(strategyClassName); if (index == null) { index = Integer.valueOf(context.usedStrategies.size()); context.usedStrategies.put(strategyClassName, index); } _handle.setStrategyIndex(index.intValue()); _handle.setObject(ByteString.copyFrom(strategy.marshal(context, object))); } return _handle.build(); }
public static void writeLeftTuple( LeftTuple leftTuple, MarshallerWriteContext context, boolean recurse) throws IOException { ObjectOutputStream stream = context.stream; InternalRuleBase ruleBase = context.ruleBase; InternalWorkingMemory wm = context.wm; LeftTupleSink sink = leftTuple.getLeftTupleSink(); switch (sink.getType()) { case NodeTypeEnums.JoinNode: { // context.out.println( "JoinNode" ); for (LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getLeftParentNext()) { stream.writeShort(PersisterEnums.RIGHT_TUPLE); int childSinkId = childLeftTuple.getLeftTupleSink().getId(); stream.writeInt(childSinkId); stream.writeInt(childLeftTuple.getRightParent().getFactHandle().getId()); // context.out.println( "RightTuple int:" + childLeftTuple.getLeftTupleSink().getId() + // " int:" + childLeftTuple.getRightParent().getFactHandle().getId() ); writeLeftTuple(childLeftTuple, context, recurse); } stream.writeShort(PersisterEnums.END); // context.out.println( "JoinNode --- END" ); break; } case NodeTypeEnums.QueryRiaFixerNode: case NodeTypeEnums.EvalConditionNode: { // context.out.println( ".... EvalConditionNode" ); for (LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getLeftParentNext()) { stream.writeShort(PersisterEnums.LEFT_TUPLE); stream.writeInt(childLeftTuple.getLeftTupleSink().getId()); writeLeftTuple(childLeftTuple, context, recurse); } stream.writeShort(PersisterEnums.END); // context.out.println( "---- EvalConditionNode --- END" ); break; } case NodeTypeEnums.NotNode: case NodeTypeEnums.ForallNotNode: { if (leftTuple.getBlocker() == null) { // is not blocked so has children stream.writeShort(PersisterEnums.LEFT_TUPLE_NOT_BLOCKED); for (LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getLeftParentNext()) { stream.writeShort(PersisterEnums.LEFT_TUPLE); stream.writeInt(childLeftTuple.getLeftTupleSink().getId()); writeLeftTuple(childLeftTuple, context, recurse); } stream.writeShort(PersisterEnums.END); } else { stream.writeShort(PersisterEnums.LEFT_TUPLE_BLOCKED); stream.writeInt(leftTuple.getBlocker().getFactHandle().getId()); } break; } case NodeTypeEnums.ExistsNode: { if (leftTuple.getBlocker() == null) { // is blocked so has children stream.writeShort(PersisterEnums.LEFT_TUPLE_NOT_BLOCKED); } else { stream.writeShort(PersisterEnums.LEFT_TUPLE_BLOCKED); stream.writeInt(leftTuple.getBlocker().getFactHandle().getId()); for (LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getLeftParentNext()) { stream.writeShort(PersisterEnums.LEFT_TUPLE); stream.writeInt(childLeftTuple.getLeftTupleSink().getId()); writeLeftTuple(childLeftTuple, context, recurse); } stream.writeShort(PersisterEnums.END); } break; } case NodeTypeEnums.AccumulateNode: { // context.out.println( ".... AccumulateNode" ); // accumulate nodes generate new facts on-demand and need special procedures when // serializing to persistent storage AccumulateMemory memory = (AccumulateMemory) context.wm.getNodeMemory((BetaNode) sink); AccumulateContext accctx = (AccumulateContext) leftTuple.getObject(); // first we serialize the generated fact handle writeFactHandle( context, stream, context.objectMarshallingStrategyStore, accctx.result.getFactHandle()); // then we serialize the associated accumulation context stream.writeObject(accctx.context); // then we serialize the boolean propagated flag stream.writeBoolean(accctx.propagated); // then we serialize all the propagated tuples for (LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getLeftParentNext()) { if (leftTuple.getLeftTupleSink().getId() == childLeftTuple.getLeftTupleSink().getId()) { // this is a matching record, so, associate the right tuples // context.out.println( "RightTuple(match) int:" + // childLeftTuple.getLeftTupleSink().getId() + " int:" + // childLeftTuple.getRightParent().getFactHandle().getId() ); stream.writeShort(PersisterEnums.RIGHT_TUPLE); stream.writeInt(childLeftTuple.getRightParent().getFactHandle().getId()); } else { // this is a propagation record // context.out.println( "RightTuple(propagation) int:" + // childLeftTuple.getLeftTupleSink().getId() + " int:" + // childLeftTuple.getRightParent().getFactHandle().getId() ); stream.writeShort(PersisterEnums.LEFT_TUPLE); int sinkId = childLeftTuple.getLeftTupleSink().getId(); stream.writeInt(sinkId); writeLeftTuple(childLeftTuple, context, recurse); } } stream.writeShort(PersisterEnums.END); // context.out.println( "---- AccumulateNode --- END" ); break; } case NodeTypeEnums.RightInputAdaterNode: { // context.out.println( ".... RightInputAdapterNode" ); // RIANs generate new fact handles on-demand to wrap tuples and need special procedures // when serializing to persistent storage ObjectHashMap memory = (ObjectHashMap) context.wm.getNodeMemory((NodeMemory) sink); InternalFactHandle ifh = (InternalFactHandle) memory.get(leftTuple); // first we serialize the generated fact handle ID // context.out.println( "FactHandle id:"+ifh.getId() ); stream.writeInt(ifh.getId()); stream.writeLong(ifh.getRecency()); writeRightTuples(ifh, context); stream.writeShort(PersisterEnums.END); // context.out.println( "---- RightInputAdapterNode --- END" ); break; } case NodeTypeEnums.FromNode: { // context.out.println( ".... FromNode" ); // FNs generate new fact handles on-demand to wrap objects and need special procedures // when serializing to persistent storage FromMemory memory = (FromMemory) context.wm.getNodeMemory((NodeMemory) sink); Map<Object, RightTuple> matches = (Map<Object, RightTuple>) leftTuple.getObject(); for (RightTuple rightTuples : matches.values()) { // first we serialize the generated fact handle ID stream.writeShort(PersisterEnums.FACT_HANDLE); writeFactHandle( context, stream, context.objectMarshallingStrategyStore, rightTuples.getFactHandle()); writeRightTuples(rightTuples.getFactHandle(), context); } stream.writeShort(PersisterEnums.END); for (LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getLeftParentNext()) { stream.writeShort(PersisterEnums.RIGHT_TUPLE); stream.writeInt(childLeftTuple.getLeftTupleSink().getId()); stream.writeInt(childLeftTuple.getRightParent().getFactHandle().getId()); // context.out.println( "RightTuple int:" + childLeftTuple.getLeftTupleSink().getId() + // " int:" + childLeftTuple.getRightParent().getFactHandle().getId() ); writeLeftTuple(childLeftTuple, context, recurse); } stream.writeShort(PersisterEnums.END); // context.out.println( "---- FromNode --- END" ); break; } case NodeTypeEnums.UnificationNode: { // context.out.println( ".... UnificationNode" ); QueryElementNode node = (QueryElementNode) sink; boolean isOpen = node.isOpenQuery(); context.writeBoolean(isOpen); if (isOpen) { InternalFactHandle factHandle = (InternalFactHandle) leftTuple.getObject(); DroolsQuery query = (DroolsQuery) factHandle.getObject(); // context.out.println( "factHandle:" + factHandle ); factHandle.setObject(null); writeFactHandle(context, stream, context.objectMarshallingStrategyStore, 0, factHandle); factHandle.setObject(query); writeLeftTuples(context, new InternalFactHandle[] {factHandle}); } else { for (LeftTuple childLeftTuple = leftTuple.getFirstChild(); childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getLeftParentNext()) { stream.writeShort(PersisterEnums.LEFT_TUPLE); stream.writeInt(childLeftTuple.getLeftTupleSink().getId()); InternalFactHandle factHandle = childLeftTuple.getLastHandle(); writeFactHandle( context, stream, context.objectMarshallingStrategyStore, 1, factHandle); writeLeftTuple(childLeftTuple, context, recurse); } stream.writeShort(PersisterEnums.END); } // context.out.println( "---- EvalConditionNode --- END" ); break; } case NodeTypeEnums.RuleTerminalNode: { // context.out.println( "RuleTerminalNode" ); int pos = context.terminalTupleMap.size(); context.terminalTupleMap.put(leftTuple, pos); break; } case NodeTypeEnums.QueryTerminalNode: { // context.out.println( ".... QueryTerminalNode" ); // LeftTuple entry = leftTuple; // // // find the DroolsQuery object // while ( entry.getParent() != null ) { // entry = entry.getParent(); // } // // // Now output all the child tuples in the caller network // DroolsQuery query = (DroolsQuery) entry.getLastHandle().getObject(); // if ( query.getQueryResultCollector() instanceof // UnificationNodeViewChangedEventListener ) { // context.writeBoolean( true ); // UnificationNodeViewChangedEventListener collector = // (UnificationNodeViewChangedEventListener) query.getQueryResultCollector(); // leftTuple = collector.getLeftTuple(); // context.writeBoolean(true); RightTuple rightTuple = (RightTuple) leftTuple.getObject(); // context.out.println( "rightTuple:" + rightTuple.getFactHandle() ); writeFactHandle( context, stream, context.objectMarshallingStrategyStore, 1, rightTuple.getFactHandle()); for (LeftTuple childLeftTuple = rightTuple.firstChild; childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getRightParentNext()) { stream.writeShort(PersisterEnums.LEFT_TUPLE); stream.writeInt(childLeftTuple.getLeftTupleSink().getId()); writeLeftTuple(childLeftTuple, context, recurse); } // for ( LeftTuple childLeftTuple = leftTuple.getFirstChild(); // childLeftTuple != null; childLeftTuple = (LeftTuple) childLeftTuple.getLeftParentNext() // ) { // stream.writeShort( PersisterEnums.LEFT_TUPLE ); // stream.writeInt( childLeftTuple.getLeftTupleSink().getId() ); // writeFactHandle( context, // stream, // context.objectMarshallingStrategyStore, // 1, // childLeftTuple.getLastHandle() ); // writeLeftTuple( childLeftTuple, // context, // recurse ); // } // } else { // context.writeBoolean( false ); // } stream.writeShort(PersisterEnums.END); // context.out.println( "---- QueryTerminalNode --- END" ); break; } } }
public static Activation readActivation(MarshallerReaderContext context) throws IOException { ObjectInputStream stream = context.stream; InternalRuleBase ruleBase = context.ruleBase; InternalWorkingMemory wm = context.wm; long activationNumber = stream.readLong(); int pos = stream.readInt(); LeftTuple leftTuple = context.terminalTupleMap.get(pos); int salience = stream.readInt(); String pkgName = stream.readUTF(); String ruleName = stream.readUTF(); Package pkg = ruleBase.getPackage(pkgName); Rule rule = pkg.getRule(ruleName); RuleTerminalNode ruleTerminalNode = (RuleTerminalNode) leftTuple.getLeftTupleSink(); PropagationContext pc = context.propagationContexts.get(stream.readLong()); AgendaItem activation; boolean scheduled = false; if (rule.getTimer() != null) { activation = new ScheduledAgendaItem( activationNumber, leftTuple, (InternalAgenda) wm.getAgenda(), pc, ruleTerminalNode); scheduled = true; } else { activation = new AgendaItem(activationNumber, leftTuple, salience, pc, ruleTerminalNode); } leftTuple.setObject(activation); if (stream.readBoolean()) { String activationGroupName = stream.readUTF(); ((DefaultAgenda) wm.getAgenda()) .getActivationGroup(activationGroupName) .addActivation(activation); } boolean activated = stream.readBoolean(); activation.setActivated(activated); if (stream.readBoolean()) { InternalFactHandle handle = context.handles.get(stream.readInt()); activation.setFactHandle(handle); handle.setObject(activation); } InternalAgendaGroup agendaGroup; if (rule.getAgendaGroup() == null || rule.getAgendaGroup().equals("") || rule.getAgendaGroup().equals(AgendaGroup.MAIN)) { // Is the Rule AgendaGroup undefined? If it is use MAIN, // which is added to the Agenda by default agendaGroup = (InternalAgendaGroup) ((DefaultAgenda) wm.getAgenda()).getAgendaGroup(AgendaGroup.MAIN); } else { // AgendaGroup is defined, so try and get the AgendaGroup // from the Agenda agendaGroup = (InternalAgendaGroup) ((DefaultAgenda) wm.getAgenda()).getAgendaGroup(rule.getAgendaGroup()); } activation.setAgendaGroup(agendaGroup); if (!scheduled && activated) { if (rule.getRuleFlowGroup() == null) { agendaGroup.add(activation); } else { InternalRuleFlowGroup rfg = (InternalRuleFlowGroup) ((DefaultAgenda) wm.getAgenda()).getRuleFlowGroup(rule.getRuleFlowGroup()); rfg.addActivation(activation); } } TruthMaintenanceSystem tms = context.wm.getTruthMaintenanceSystem(); while (stream.readShort() == PersisterEnums.LOGICAL_DEPENDENCY) { int factHandleId = stream.readInt(); InternalFactHandle handle = (InternalFactHandle) context.handles.get(factHandleId); ObjectTypeConf typeConf = context .wm .getObjectTypeConfigurationRegistry() .getObjectTypeConf( ((NamedEntryPoint) handle.getEntryPoint()).getEntryPoint(), handle.getObject()); tms.addLogicalDependency(handle, activation, pc, rule, typeConf); } return activation; }
public void modifyLeftTuple( LeftTuple leftTuple, PropagationContext context, InternalWorkingMemory workingMemory) { boolean executeAsOpenQuery = openQuery; if (executeAsOpenQuery) { // There is no point in doing an open query if the caller is a non-open query. Object object = ((InternalFactHandle) leftTuple.get(0)).getObject(); if (object instanceof DroolsQuery && !((DroolsQuery) object).isOpen()) { executeAsOpenQuery = false; } } if (!executeAsOpenQuery) { // Was never open so execute as a retract + assert if (leftTuple.getFirstChild() != null) { this.sink.propagateRetractLeftTuple(leftTuple, context, workingMemory); } assertLeftTuple(leftTuple, context, workingMemory); return; } InternalFactHandle handle = (InternalFactHandle) leftTuple.getObject(); DroolsQuery queryObject = (DroolsQuery) handle.getObject(); if (queryObject.getAction() != null) { // we already have an insert scheduled for this query, but have re-entered it // do nothing return; } Object[] argTemplate = this.queryElement.getArgTemplate(); // an array of declr, variable and literals Object[] args = new Object[argTemplate.length]; // the actual args, to be created from the template // first copy everything, so that we get the literals. We will rewrite the declarations and // variables next System.arraycopy(argTemplate, 0, args, 0, args.length); int[] declIndexes = this.queryElement.getDeclIndexes(); for (int i = 0, length = declIndexes.length; i < length; i++) { Declaration declr = (Declaration) argTemplate[declIndexes[i]]; Object tupleObject = leftTuple.get(declr).getObject(); Object o; if (tupleObject instanceof DroolsQuery) { // If the query passed in a Variable, we need to use it ArrayElementReader arrayReader = (ArrayElementReader) declr.getExtractor(); if (((DroolsQuery) tupleObject).getVariables()[arrayReader.getIndex()] != null) { o = Variable.v; } else { o = declr.getValue(workingMemory, tupleObject); } } else { o = declr.getValue(workingMemory, tupleObject); } args[declIndexes[i]] = o; } int[] varIndexes = this.queryElement.getVariableIndexes(); for (int i = 0, length = varIndexes.length; i < length; i++) { if (argTemplate[varIndexes[i]] == Variable.v) { // Need to check against the arg template, as the varIndexes also includes re-declared // declarations args[varIndexes[i]] = Variable.v; } } queryObject.setParameters(args); ((UnificationNodeViewChangedEventListener) queryObject.getQueryResultCollector()) .setVariables(varIndexes); QueryUpdateAction action = new QueryUpdateAction(context, handle, leftTuple, this); context.getQueue1().addFirst(action); }
/** * * * <pre> * * * (Cheese (price ?price1 ) * (Cheese (price ?price2&:(= ?price2 (* 2 ?price1) ) * * * </pre> * * @throws IntrospectionException */ public void testPredicateConstraint() throws IntrospectionException { final ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory.newRuleBase(); final InternalWorkingMemory workingMemory = (InternalWorkingMemory) ruleBase.newStatefulSession(); final FieldExtractor priceExtractor = cache.getExtractor(Cheese.class, "price", getClass().getClassLoader()); Pattern pattern = new Pattern(0, new ClassObjectType(Cheese.class)); // Bind the extractor to a decleration // Declarations know the pattern they derive their value form final Declaration price1Declaration = new Declaration("price1", priceExtractor, pattern); pattern = new Pattern(1, new ClassObjectType(Cheese.class)); // Bind the extractor to a decleration // Declarations know the pattern they derive their value form final Declaration price2Declaration = new Declaration("price2", priceExtractor, pattern); final PredicateExpression evaluator = new PredicateExpression() { /** */ private static final long serialVersionUID = 400L; public boolean evaluate( Object object, Tuple tuple, Declaration[] previousDeclarations, Declaration[] localDeclarations, WorkingMemory workingMemory, Object context) { int price1 = previousDeclarations[0].getIntValue( (InternalWorkingMemory) workingMemory, workingMemory.getObject(tuple.get(previousDeclarations[0]))); int price2 = localDeclarations[0].getIntValue((InternalWorkingMemory) workingMemory, object); return (price2 == (price1 * 2)); } public Object createContext() { return null; } }; final PredicateConstraint constraint1 = new PredicateConstraint( evaluator, new Declaration[] {price1Declaration}, new Declaration[] {price2Declaration}, new String[] {}); final Cheese cheddar0 = new Cheese("cheddar", 5); final FactHandle f0 = workingMemory.insert(cheddar0); InstrumentedReteTuple tuple = new InstrumentedReteTuple(f0); final Cheese cheddar1 = new Cheese("cheddar", 10); final InternalFactHandle f1 = (InternalFactHandle) workingMemory.insert(cheddar1); tuple = new InstrumentedReteTuple(tuple, f1); final PredicateContextEntry context = (PredicateContextEntry) constraint1.createContextEntry(); context.updateFromTuple(workingMemory, tuple); assertTrue(constraint1.isAllowedCachedLeft(context, f1.getObject())); }
/** * * * <pre> * * * Cheese( ( type == "cheddar" && price > 10) || ( type == "e;stilton"e; && price < 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)); }
/** * * * <pre> * * * (Cheese (price ?price ) * (Cheese (price =(* 2 ?price) ) * (Cheese (price >(* 2 ?price) ) * * * </pre> * * @throws IntrospectionException */ public void testReturnValueConstraint() throws IntrospectionException { final ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory.newRuleBase(); final InternalWorkingMemory workingMemory = (InternalWorkingMemory) ruleBase.newStatefulSession(); final FieldExtractor priceExtractor = cache.getExtractor(Cheese.class, "price", getClass().getClassLoader()); final Pattern pattern = new Pattern(0, new ClassObjectType(Cheese.class)); // Bind the extractor to a decleration // Declarations know the pattern they derive their value form final Declaration priceDeclaration = new Declaration("price1", priceExtractor, pattern); final ReturnValueExpression isDoubleThePrice = new ReturnValueExpression() { /** */ private static final long serialVersionUID = 400L; public FieldValue evaluate( Object object, Tuple tuple, // ?price Declaration[] previousDeclarations, Declaration[] localDeclarations, WorkingMemory workingMemory, Object context) { int price = ((Number) previousDeclarations[0].getValue( (InternalWorkingMemory) workingMemory, workingMemory.getObject(tuple.get(previousDeclarations[0])))) .intValue(); return FieldFactory.getFieldValue(2 * price); } public Object createContext() { return null; } }; final ReturnValueRestriction restriction1 = new ReturnValueRestriction( priceExtractor, isDoubleThePrice, new Declaration[] {priceDeclaration}, new Declaration[0], new String[0], ValueType.INTEGER_TYPE.getEvaluator(Operator.EQUAL)); final ReturnValueConstraint constraint1 = new ReturnValueConstraint(priceExtractor, restriction1); final ReturnValueRestriction restriction2 = new ReturnValueRestriction( priceExtractor, isDoubleThePrice, new Declaration[] {priceDeclaration}, new Declaration[0], new String[0], ValueType.INTEGER_TYPE.getEvaluator(Operator.GREATER)); final ReturnValueConstraint constraint2 = new ReturnValueConstraint(priceExtractor, restriction2); final Cheese cheddar0 = new Cheese("cheddar", 5); final FactHandle f0 = workingMemory.insert(cheddar0); InstrumentedReteTuple tuple = new InstrumentedReteTuple(f0); final Cheese cheddar1 = new Cheese("cheddar", 10); final InternalFactHandle f1 = (InternalFactHandle) workingMemory.insert(cheddar1); tuple = new InstrumentedReteTuple(tuple, f1); final ReturnValueContextEntry context1 = (ReturnValueContextEntry) constraint1.createContextEntry(); context1.updateFromTuple(workingMemory, tuple); assertTrue(constraint1.isAllowedCachedLeft(context1, f1.getObject())); final ReturnValueContextEntry context2 = (ReturnValueContextEntry) constraint2.createContextEntry(); context2.updateFromTuple(workingMemory, tuple); assertFalse(constraint2.isAllowedCachedLeft(context2, f1.getObject())); final Cheese cheddar2 = new Cheese("cheddar", 11); final InternalFactHandle f2 = (InternalFactHandle) workingMemory.insert(cheddar2); assertTrue(constraint2.isAllowedCachedLeft(context2, f2.getObject())); }