001: package org.drools.reteoo;
002:
003: /*
004: * Copyright 2005 JBoss Inc
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: import org.drools.common.BetaConstraints;
020: import org.drools.common.EmptyBetaConstraints;
021: import org.drools.common.InternalFactHandle;
022: import org.drools.common.InternalWorkingMemory;
023: import org.drools.spi.PropagationContext;
024: import org.drools.util.FactEntry;
025: import org.drools.util.Iterator;
026:
027: /**
028: * <code>NotNode</code> extends <code>BetaNode</code> to perform tests for
029: * the non existence of a Fact plus one or more conditions. Where none existence
030: * is found the left ReteTuple is copied and propgated. Further to this it
031: * maintains the "truth" by cancelling any
032: * <code>Activation<code>s that are nolonger
033: * considered true by the assertion of ReteTuple's or FactHandleImpl. Tuples are considered to be asserted from the left input and facts from the right input.
034: * The <code>BetaNode</code> provides the BetaMemory to store assserted ReteTuples and <code>FactHandleImpl<code>s. Each fact handle is stored in the right
035: * memory as a key in a <code>HashMap</code>, the value is an <code>ObjectMatches</code> instance which maintains a <code>LinkedList of <code>TuplesMatches -
036: * The tuples that are matched with the handle. the left memory is a <code>LinkedList</code> of <code>ReteTuples</code> which maintains a <code>HashMa</code>,
037: * where the keys are the matching <code>FactHandleImpl</code>s and the value is populated <code>TupleMatche</code>es, the keys are matched fact handles.
038: * <code>TupleMatch</code> maintains a <code>List</code> of resulting joins, where there is joined <code>ReteTuple</code> per <code>TupleSink</code>.
039: *
040: * @author <a href="mailto:mark.proctor@jboss.com">Mark Proctor</a>
041: * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
042: *
043: */
044: public class NotNode extends BetaNode {
045:
046: private static final long serialVersionUID = 400L;
047: static int notAssertObject = 0;
048: static int notAssertTuple = 0;
049:
050: // ------------------------------------------------------------
051: // Instance methods
052: // ------------------------------------------------------------
053:
054: /**
055: * Construct.
056: *
057: * @param leftInput
058: * The left input <code>TupleSource</code>.
059: * @param rightInput
060: * The right input <code>TupleSource</code>.
061: */
062: public NotNode(final int id, final TupleSource leftInput,
063: final ObjectSource rightInput) {
064: super (id, leftInput, rightInput, EmptyBetaConstraints
065: .getInstance());
066: }
067:
068: /**
069: * Construct.
070: *
071: * @param leftInput
072: * The left input <code>TupleSource</code>.
073: * @param rightInput
074: * The right input <code>TupleSource</code>.
075: */
076: public NotNode(final int id, final TupleSource leftInput,
077: final ObjectSource rightInput,
078: final BetaConstraints joinNodeBinder) {
079: super (id, leftInput, rightInput, joinNodeBinder);
080: }
081:
082: /**
083: * Assert a new <code>ReteTuple</code> from the left input. It iterates
084: * over the right <code>FactHandleImpl</code>'s if no matches are found
085: * the a copy of the <code>ReteTuple</code> is made and propagated.
086: *
087: * @param tuple
088: * The <code>Tuple</code> being asserted.
089: * @param context
090: * The <code>PropagationContext</code>
091: * @param workingMemory
092: * The working memory seesion.
093: */
094: public void assertTuple(final ReteTuple leftTuple,
095: final PropagationContext context,
096: final InternalWorkingMemory workingMemory) {
097: final BetaMemory memory = (BetaMemory) workingMemory
098: .getNodeMemory(this );
099:
100: if (!workingMemory.isSequential()) {
101: memory.getTupleMemory().add(leftTuple);
102: }
103:
104: final Iterator it = memory.getFactHandleMemory().iterator(
105: leftTuple);
106: this .constraints.updateFromTuple(workingMemory, leftTuple);
107: int matches = 0;
108: for (FactEntry entry = (FactEntry) it.next(); entry != null; entry = (FactEntry) it
109: .next()) {
110: final InternalFactHandle handle = entry.getFactHandle();
111: if (this .constraints
112: .isAllowedCachedLeft(handle.getObject())) {
113: matches++;
114: }
115: }
116:
117: leftTuple.setMatches(matches);
118:
119: if (matches == 0) {
120: this .sink.propagateAssertTuple(leftTuple, context,
121: workingMemory);
122: }
123: }
124:
125: /**
126: * Assert a new <code>FactHandleImpl</code> from the right input. If it
127: * matches any left ReteTuple's that already has propagations then those
128: * propagations are retracted.
129: *
130: * @param handle
131: * The <code>FactHandleImpl</code> being asserted.
132: * @param context
133: * The <code>PropagationContext</code>
134: * @param workingMemory
135: * The working memory seesion.
136: */
137: public void assertObject(final InternalFactHandle handle,
138: final PropagationContext context,
139: final InternalWorkingMemory workingMemory) {
140: final BetaMemory memory = (BetaMemory) workingMemory
141: .getNodeMemory(this );
142: memory.getFactHandleMemory().add(handle);
143:
144: if (workingMemory.isSequential()) {
145: // do nothing here, as we know there are no left tuples at this stage in sequential mode.
146: return;
147: }
148:
149: final Iterator it = memory.getTupleMemory().iterator(handle);
150: this .constraints.updateFromFactHandle(workingMemory, handle);
151: for (ReteTuple tuple = (ReteTuple) it.next(); tuple != null; tuple = (ReteTuple) it
152: .next()) {
153: if (this .constraints.isAllowedCachedRight(tuple)) {
154: final int matches = tuple.getMatches();
155: tuple.setMatches(matches + 1);
156: if (matches == 0) {
157: this .sink.propagateRetractTuple(tuple, context,
158: workingMemory);
159: }
160: }
161: }
162: }
163:
164: /**
165: * Retract the <code>FactHandleImpl</code>. If the handle has any
166: * <code>ReteTuple</code> matches then those matches copied are propagated
167: * as new joins.
168: *
169: * @param handle
170: * the <codeFactHandleImpl</code> being retracted
171: * @param context
172: * The <code>PropagationContext</code>
173: * @param workingMemory
174: * The working memory seesion.
175: * @throws AssertionException
176: */
177: public void retractObject(final InternalFactHandle handle,
178: final PropagationContext context,
179: final InternalWorkingMemory workingMemory) {
180: final BetaMemory memory = (BetaMemory) workingMemory
181: .getNodeMemory(this );
182: if (!memory.getFactHandleMemory().remove(handle)) {
183: return;
184: }
185:
186: final Iterator it = memory.getTupleMemory().iterator(handle);
187: this .constraints.updateFromFactHandle(workingMemory, handle);
188: for (ReteTuple tuple = (ReteTuple) it.next(); tuple != null; tuple = (ReteTuple) it
189: .next()) {
190: if (this .constraints.isAllowedCachedRight(tuple)) {
191: tuple.setMatches(tuple.getMatches() - 1);
192: if (tuple.getMatches() == 0) {
193: this .sink.propagateAssertTuple(tuple, context,
194: workingMemory);
195: }
196: }
197: }
198: }
199:
200: /**
201: * Retract the
202: * <code>ReteTuple<code>, any resulting proppagated joins are also retracted.
203: *
204: * @param key
205: * The tuple key.
206: * @param context
207: * The <code>PropagationContext</code>
208: * @param workingMemory
209: * The working memory seesion.
210: */
211: public void retractTuple(final ReteTuple leftTuple,
212: final PropagationContext context,
213: final InternalWorkingMemory workingMemory) {
214: final BetaMemory memory = (BetaMemory) workingMemory
215: .getNodeMemory(this );
216:
217: // Must use the tuple in memory as it has the tuple matches count
218: final ReteTuple tuple = memory.getTupleMemory().remove(
219: leftTuple);
220: if (tuple == null) {
221: return;
222: }
223:
224: if (tuple.getMatches() == 0) {
225: this .sink.propagateRetractTuple(tuple, context,
226: workingMemory);
227: }
228: }
229:
230: /* (non-Javadoc)
231: * @see org.drools.reteoo.BaseNode#updateNewNode(org.drools.reteoo.WorkingMemoryImpl, org.drools.spi.PropagationContext)
232: */
233: public void updateSink(final TupleSink sink,
234: final PropagationContext context,
235: final InternalWorkingMemory workingMemory) {
236: final BetaMemory memory = (BetaMemory) workingMemory
237: .getNodeMemory(this );
238:
239: final Iterator tupleIter = memory.getTupleMemory().iterator();
240: for (ReteTuple tuple = (ReteTuple) tupleIter.next(); tuple != null; tuple = (ReteTuple) tupleIter
241: .next()) {
242: if (tuple.getMatches() == 0) {
243: sink.assertTuple(new ReteTuple(tuple), context,
244: workingMemory);
245: }
246: }
247: }
248:
249: public String toString() {
250: ObjectSource source = this .rightInput;
251: while (!(source instanceof ObjectTypeNode)) {
252: source = source.objectSource;
253: }
254:
255: return "[NotNode - "
256: + ((ObjectTypeNode) source).getObjectType() + "]";
257: }
258: }
|