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.InternalFactHandle;
021: import org.drools.common.InternalWorkingMemory;
022: import org.drools.spi.PropagationContext;
023: import org.drools.util.FactEntry;
024: import org.drools.util.Iterator;
025:
026: /**
027: * <code>JoinNode</code> extends <code>BetaNode</code> to perform
028: * <code>ReteTuple</code> and <code>FactHandle</code> joins. Tuples are
029: * considered to be asserted from the left input and facts from the right input.
030: * The <code>BetaNode</code> provides the BetaMemory to store assserted
031: * ReteTuples and
032: * <code>FactHandleImpl<code>s. Each fact handle is stored in the right memory as a key in a <code>HashMap</code>, the value is an <code>ObjectMatches</code>
033: * instance which maintains a <code>LinkedList of <code>TuplesMatches - The tuples that are matched with the handle. the left memory is a <code>LinkedList</code>
034: * of <code>ReteTuples</code> which maintains a <code>HashMa</code>, where the keys are the matching <code>FactHandleImpl</code>s and the value is
035: * populated <code>TupleMatche</code>es, the keys are matched fact handles. <code>TupleMatch</code> maintains a <code>List</code> of resulting joins,
036: * where there is joined <code>ReteTuple</code> per <code>TupleSink</code>.
037: *
038: *
039: * The BetaNode provides
040: * the BetaMemory which stores the
041: *
042: * @see BetaNode
043: * @see ObjectMatches
044: * @see TupleMatch
045: * @see TupleSink
046: *
047: * @author <a href="mailto:mark.proctor@jboss.com">Mark Proctor</a>
048: * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
049: *
050: */
051: public class JoinNode extends BetaNode {
052: // ------------------------------------------------------------
053: // Instance methods
054: // ------------------------------------------------------------
055:
056: /**
057: *
058: */
059: private static final long serialVersionUID = 400L;
060:
061: /**
062: * Construct.
063: *
064: * @param leftInput
065: * The left input <code>TupleSource</code>.
066: * @param rightInput
067: * The right input <code>TupleSource</code>.
068: */
069: public JoinNode(final int id, final TupleSource leftInput,
070: final ObjectSource rightInput) {
071: super (id, leftInput, rightInput);
072: }
073:
074: public JoinNode(final int id, final TupleSource leftInput,
075: final ObjectSource rightInput, final BetaConstraints binder) {
076: super (id, leftInput, rightInput, binder);
077: }
078:
079: /**
080: * Assert a new <code>ReteTuple</code>. The right input of
081: * <code>FactHandleInput</code>'s is iterated and joins attemped, via the
082: * binder, any successful bindings results in joined tuples being created
083: * and propaged. there is a joined tuple per TupleSink.
084: *
085: * @see ReteTuple
086: * @see ObjectMatches
087: * @see TupleSink
088: * @see TupleMatch
089: *
090: * @param tuple
091: * The <code>Tuple</code> being asserted.
092: * @param context
093: * The <code>PropagationContext</code>
094: * @param workingMemory
095: * The working memory seesion.
096: */
097: public void assertTuple(final ReteTuple leftTuple,
098: final PropagationContext context,
099: final InternalWorkingMemory workingMemory) {
100: final BetaMemory memory = (BetaMemory) workingMemory
101: .getNodeMemory(this );
102:
103: if (!workingMemory.isSequential()) {
104: memory.getTupleMemory().add(leftTuple);
105: }
106:
107: final Iterator it = memory.getFactHandleMemory().iterator(
108: leftTuple);
109: this .constraints.updateFromTuple(workingMemory, leftTuple);
110: for (FactEntry entry = (FactEntry) it.next(); entry != null; entry = (FactEntry) it
111: .next()) {
112: final InternalFactHandle handle = entry.getFactHandle();
113: if (this .constraints
114: .isAllowedCachedLeft(handle.getObject())) {
115: this .sink.propagateAssertTuple(leftTuple, handle,
116: context, workingMemory);
117: }
118: }
119: }
120:
121: /**
122: * Assert a new <code>FactHandleImpl</code>. The left input of
123: * <code>ReteTuple</code>s is iterated and joins attemped, via the
124: * binder, any successful bindings results in joined tuples being created
125: * and propaged. there is a joined tuple per TupleSink.
126: *
127: * @see ReteTuple
128: * @see ObjectMatches
129: * @see TupleSink
130: * @see TupleMatch
131: *
132: * @param handle
133: * The <code>FactHandleImpl</code> being asserted.
134: * @param context
135: * The <code>PropagationContext</code>
136: * @param workingMemory
137: * The working memory seesion.
138: */
139: public void assertObject(final InternalFactHandle handle,
140: final PropagationContext context,
141: final InternalWorkingMemory workingMemory) {
142: final BetaMemory memory = (BetaMemory) workingMemory
143: .getNodeMemory(this );
144:
145: memory.getFactHandleMemory().add(handle);
146: if (workingMemory.isSequential()) {
147: // do nothing here, as we know there are no left tuples at this stage in sequential mode.
148: return;
149: }
150:
151: final Iterator it = memory.getTupleMemory().iterator(handle);
152: this .constraints.updateFromFactHandle(workingMemory, handle);
153: for (ReteTuple tuple = (ReteTuple) it.next(); tuple != null; tuple = (ReteTuple) it
154: .next()) {
155: if (this .constraints.isAllowedCachedRight(tuple)) {
156: this .sink.propagateAssertTuple(tuple, handle, context,
157: workingMemory);
158: }
159: }
160: }
161:
162: /**
163: * Retract a FactHandleImpl. Iterates the referenced TupleMatches stored in
164: * the handle's ObjectMatches retracting joined tuples.
165: *
166: * @param handle
167: * the <codeFactHandleImpl</code> being retracted
168: * @param context
169: * The <code>PropagationContext</code>
170: * @param workingMemory
171: * The working memory seesion.
172: */
173: public void retractObject(final InternalFactHandle handle,
174: final PropagationContext context,
175: final InternalWorkingMemory workingMemory) {
176: final BetaMemory memory = (BetaMemory) workingMemory
177: .getNodeMemory(this );
178: if (!memory.getFactHandleMemory().remove(handle)) {
179: return;
180: }
181:
182: final Iterator it = memory.getTupleMemory().iterator(handle);
183: this .constraints.updateFromFactHandle(workingMemory, handle);
184: for (ReteTuple tuple = (ReteTuple) it.next(); tuple != null; tuple = (ReteTuple) it
185: .next()) {
186: if (this .constraints.isAllowedCachedRight(tuple)) {
187: this .sink.propagateRetractTuple(tuple, handle, context,
188: workingMemory);
189: }
190: }
191: }
192:
193: /**
194: * Retract a <code>ReteTuple</code>. Iterates the referenced
195: * <code>TupleMatche</code>'s stored in the tuples <code>Map</code>
196: * retracting all joined tuples.
197: *
198: * @param key
199: * The tuple key.
200: * @param context
201: * The <code>PropagationContext</code>
202: * @param workingMemory
203: * The working memory seesion.
204: */
205: public void retractTuple(final ReteTuple leftTuple,
206: final PropagationContext context,
207: final InternalWorkingMemory workingMemory) {
208: final BetaMemory memory = (BetaMemory) workingMemory
209: .getNodeMemory(this );
210: final ReteTuple tuple = memory.getTupleMemory().remove(
211: leftTuple);
212: if (tuple == null) {
213: return;
214: }
215:
216: final Iterator it = memory.getFactHandleMemory().iterator(
217: leftTuple);
218: this .constraints.updateFromTuple(workingMemory, leftTuple);
219: for (FactEntry entry = (FactEntry) it.next(); entry != null; entry = (FactEntry) it
220: .next()) {
221: final InternalFactHandle handle = entry.getFactHandle();
222: if (this .constraints
223: .isAllowedCachedLeft(handle.getObject())) {
224: this .sink.propagateRetractTuple(leftTuple, handle,
225: context, workingMemory);
226: }
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:
237: final BetaMemory memory = (BetaMemory) workingMemory
238: .getNodeMemory(this );
239:
240: final Iterator tupleIter = memory.getTupleMemory().iterator();
241: for (ReteTuple tuple = (ReteTuple) tupleIter.next(); tuple != null; tuple = (ReteTuple) tupleIter
242: .next()) {
243: final Iterator objectIter = memory.getFactHandleMemory()
244: .iterator(tuple);
245: this .constraints.updateFromTuple(workingMemory, tuple);
246: for (FactEntry entry = (FactEntry) objectIter.next(); entry != null; entry = (FactEntry) objectIter
247: .next()) {
248: final InternalFactHandle handle = entry.getFactHandle();
249: if (this .constraints.isAllowedCachedLeft(handle
250: .getObject())) {
251: sink.assertTuple(new ReteTuple(tuple, handle),
252: context, workingMemory);
253: }
254: }
255: }
256: }
257:
258: public String toString() {
259: ObjectSource source = this .rightInput;
260: while (!(source instanceof ObjectTypeNode)) {
261: source = source.objectSource;
262: }
263:
264: return "[JoinNode - "
265: + ((ObjectTypeNode) source).getObjectType() + "]";
266: }
267: }
|