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