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 java.util.ArrayList;
020: import java.util.List;
021:
022: import org.drools.RuleBaseConfiguration;
023: import org.drools.common.BaseNode;
024: import org.drools.common.BetaConstraints;
025: import org.drools.common.EmptyBetaConstraints;
026: import org.drools.common.InternalWorkingMemory;
027: import org.drools.common.NodeMemory;
028: import org.drools.common.PropagationContextImpl;
029: import org.drools.spi.BetaNodeFieldConstraint;
030: import org.drools.spi.PropagationContext;
031: import org.drools.util.LinkedList;
032: import org.drools.util.LinkedListEntry;
033:
034: /**
035: * <code>BetaNode</code> provides the base abstract class for <code>JoinNode</code> and <code>NotNode</code>. It implements
036: * both TupleSink and ObjectSink and as such can receive <code>Tuple</code>s and <code>FactHandle</code>s. BetaNode uses BetaMemory
037: * to store the propagated instances.
038: *
039: * @see org.drools.reteoo.TupleSource
040: * @see org.drools.reteoo.TupleSink
041: * @see org.drools.reteoo.BetaMemory
042: *
043: * @author <a href="mailto:mark.proctor@jboss.com">Mark Proctor</a>
044: * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
045: */
046: abstract class BetaNode extends TupleSource implements TupleSinkNode,
047: ObjectSinkNode, NodeMemory {
048: // ------------------------------------------------------------
049: // Instance members
050: // ------------------------------------------------------------
051:
052: /** The left input <code>TupleSource</code>. */
053: protected final TupleSource leftInput;
054:
055: /** The right input <code>TupleSource</code>. */
056: protected final ObjectSource rightInput;
057:
058: protected final BetaConstraints constraints;
059:
060: private TupleSinkNode previousTupleSinkNode;
061: private TupleSinkNode nextTupleSinkNode;
062:
063: private ObjectSinkNode previousObjectSinkNode;
064: private ObjectSinkNode nextObjectSinkNode;
065:
066: // ------------------------------------------------------------
067: // Constructors
068: // ------------------------------------------------------------
069:
070: /**
071: * The constructor defaults to using a BetaNodeBinder with no constraints
072: *
073: * @param leftInput
074: * The left input <code>TupleSource</code>.
075: * @param rightInput
076: * The right input <code>ObjectSource</code>.
077: */
078: BetaNode(final int id, final TupleSource leftInput,
079: final ObjectSource rightInput) {
080: this (id, leftInput, rightInput, EmptyBetaConstraints
081: .getInstance());
082: }
083:
084: /**
085: * Constructs a <code>BetaNode</code> using the specified <code>BetaNodeBinder</code>.
086: *
087: * @param leftInput
088: * The left input <code>TupleSource</code>.
089: * @param rightInput
090: * The right input <code>ObjectSource</code>.
091: */
092: BetaNode(final int id, final TupleSource leftInput,
093: final ObjectSource rightInput,
094: final BetaConstraints constraints) {
095: super (id);
096: super .setHasMemory(true);
097: this .leftInput = leftInput;
098: this .rightInput = rightInput;
099: this .constraints = constraints;
100:
101: if (this .constraints == null) {
102: throw new RuntimeException(
103: "cannot have null constraints, must atleast be an instanceof EmptyBetaCosntraints");
104: }
105: }
106:
107: public BetaNodeFieldConstraint[] getConstraints() {
108: final LinkedList constraints = this .constraints
109: .getConstraints();
110:
111: final BetaNodeFieldConstraint[] array = new BetaNodeFieldConstraint[constraints
112: .size()];
113: int i = 0;
114: for (LinkedListEntry entry = (LinkedListEntry) constraints
115: .getFirst(); entry != null; entry = (LinkedListEntry) entry
116: .getNext()) {
117: array[i++] = (BetaNodeFieldConstraint) entry.getObject();
118: }
119: return array;
120: }
121:
122: /* (non-Javadoc)
123: * @see org.drools.reteoo.BaseNode#attach()
124: */
125: public void attach() {
126: this .leftInput.addTupleSink(this );
127: this .rightInput.addObjectSink(this );
128: }
129:
130: public List getRules() {
131: final List list = new ArrayList();
132:
133: final TupleSink[] sinks = this .sink.getSinks();
134: for (int i = 0, length = sinks.length; i < length; i++) {
135: if (sinks[i] instanceof RuleTerminalNode) {
136: list.add(((RuleTerminalNode) sinks[i]).getRule()
137: .getName());
138: } else if (sinks[i] instanceof BetaNode) {
139: list.addAll(((BetaNode) sinks[i]).getRules());
140: }
141: }
142:
143: return list;
144: }
145:
146: public ObjectTypeNode getObjectTypeNode() {
147: ObjectSource source = this .rightInput;
148: while (!(source instanceof ObjectTypeNode)) {
149: source = source.objectSource;
150: }
151: return ((ObjectTypeNode) source);
152: }
153:
154: public void attach(final InternalWorkingMemory[] workingMemories) {
155: attach();
156:
157: for (int i = 0, length = workingMemories.length; i < length; i++) {
158: final InternalWorkingMemory workingMemory = workingMemories[i];
159: final PropagationContext propagationContext = new PropagationContextImpl(
160: workingMemory.getNextPropagationIdCounter(),
161: PropagationContext.RULE_ADDITION, null, null);
162: this .leftInput.updateSink(this , propagationContext,
163: workingMemory);
164: this .rightInput.updateSink(this , propagationContext,
165: workingMemory);
166: }
167:
168: }
169:
170: public void remove(final BaseNode node,
171: final InternalWorkingMemory[] workingMemories) {
172: if (!node.isInUse()) {
173: removeTupleSink((TupleSink) node);
174: }
175: removeShare();
176:
177: if (!this .isInUse()) {
178: for (int i = 0, length = workingMemories.length; i < length; i++) {
179: workingMemories[i].clearNodeMemory(this );
180: }
181: }
182: this .rightInput.remove(this , workingMemories);
183: this .leftInput.remove(this , workingMemories);
184:
185: }
186:
187: //public abstract TupleSink getTupleSink();
188:
189: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
190:
191: public String toString() {
192: return "";
193: }
194:
195: public void dumpMemory(final InternalWorkingMemory workingMemory) {
196: final MemoryVisitor visitor = new MemoryVisitor(workingMemory);
197: visitor.visit(this );
198: }
199:
200: /* (non-Javadoc)
201: * @see org.drools.reteoo.BaseNode#hashCode()
202: */
203: public int hashCode() {
204: return this .leftInput.hashCode() ^ this .rightInput.hashCode();
205: }
206:
207: /* (non-Javadoc)
208: * @see java.lang.Object#equals(java.lang.Object)
209: */
210: public boolean equals(final Object object) {
211: if (this == object) {
212: return true;
213: }
214:
215: if (object == null || !(object instanceof BetaNode)) {
216: return false;
217: }
218:
219: final BetaNode other = (BetaNode) object;
220:
221: return this .getClass() == other.getClass()
222: && this .leftInput.equals(other.leftInput)
223: && this .rightInput.equals(other.rightInput)
224: && this .constraints.equals(other.constraints);
225: }
226:
227: /**
228: * Creates a BetaMemory for the BetaNode's memory.
229: */
230: public Object createMemory(final RuleBaseConfiguration config) {
231: return this .constraints.createBetaMemory(config);
232: }
233:
234: /**
235: * Returns the next node
236: * @return
237: * The next TupleSinkNode
238: */
239: public TupleSinkNode getNextTupleSinkNode() {
240: return this .nextTupleSinkNode;
241: }
242:
243: /**
244: * Sets the next node
245: * @param next
246: * The next TupleSinkNode
247: */
248: public void setNextTupleSinkNode(final TupleSinkNode next) {
249: this .nextTupleSinkNode = next;
250: }
251:
252: /**
253: * Returns the previous node
254: * @return
255: * The previous TupleSinkNode
256: */
257: public TupleSinkNode getPreviousTupleSinkNode() {
258: return this .previousTupleSinkNode;
259: }
260:
261: /**
262: * Sets the previous node
263: * @param previous
264: * The previous TupleSinkNode
265: */
266: public void setPreviousTupleSinkNode(final TupleSinkNode previous) {
267: this .previousTupleSinkNode = previous;
268: }
269:
270: /**
271: * Returns the next node
272: * @return
273: * The next ObjectSinkNode
274: */
275: public ObjectSinkNode getNextObjectSinkNode() {
276: return this .nextObjectSinkNode;
277: }
278:
279: /**
280: * Sets the next node
281: * @param next
282: * The next ObjectSinkNode
283: */
284: public void setNextObjectSinkNode(final ObjectSinkNode next) {
285: this .nextObjectSinkNode = next;
286: }
287:
288: /**
289: * Returns the previous node
290: * @return
291: * The previous ObjectSinkNode
292: */
293: public ObjectSinkNode getPreviousObjectSinkNode() {
294: return this .previousObjectSinkNode;
295: }
296:
297: /**
298: * Sets the previous node
299: * @param previous
300: * The previous ObjectSinkNode
301: */
302: public void setPreviousObjectSinkNode(final ObjectSinkNode previous) {
303: this.previousObjectSinkNode = previous;
304: }
305:
306: }
|