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.RuleBaseConfiguration;
020: import org.drools.common.BaseNode;
021: import org.drools.common.InternalFactHandle;
022: import org.drools.common.InternalWorkingMemory;
023: import org.drools.common.NodeMemory;
024: import org.drools.common.PropagationContextImpl;
025: import org.drools.spi.PropagationContext;
026: import org.drools.util.FactEntry;
027: import org.drools.util.FactHashTable;
028: import org.drools.util.Iterator;
029: import org.drools.util.AbstractHashTable.FactEntryImpl;
030:
031: /**
032: * All asserting Facts must propagated into the right <code>ObjectSink</code> side of a BetaNode, if this is the first Pattern
033: * then there are no BetaNodes to propagate to. <code>LeftInputAdapter</code> is used to adapt an ObjectSink propagation into a
034: * <code>TupleSource</code> which propagates a <code>ReteTuple</code> suitable fot the right <code>ReteTuple</code> side
035: * of a <code>BetaNode</code>.
036: *
037: * @author <a href="mailto:mark.proctor@jboss.com">Mark Proctor</a>
038: * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
039: *
040: */
041: public class LeftInputAdapterNode extends TupleSource implements
042: ObjectSinkNode, NodeMemory {
043:
044: /**
045: *
046: */
047: private static final long serialVersionUID = 400L;
048: private final ObjectSource objectSource;
049:
050: private ObjectSinkNode previousObjectSinkNode;
051: private ObjectSinkNode nextObjectSinkNode;
052:
053: // private final AlphaNodeFieldConstraint constraints;
054:
055: // /**
056: // * Constructus a LeftInputAdapterNode with a unique id that receives <code>FactHandle</code> from a
057: // * parent <code>ObjectSource</code> and adds it to a given pattern in the resulting Tuples.
058: // *
059: // * @param id
060: // * The unique id of this node in the current Rete network
061: // * @param source
062: // * The parent node, where Facts are propagated from
063: // */
064: // public LeftInputAdapterNode(final int id,
065: // final ObjectSource source) {
066: // this( id,
067: // source,
068: // null );
069: // }
070:
071: /**
072: * Constructus a LeftInputAdapterNode with a unique id that receives <code>FactHandle</code> from a
073: * parent <code>ObjectSource</code> and adds it to a given pattern in the resulting Tuples.
074: *
075: * @param id
076: * The unique id of this node in the current Rete network
077: * @param source
078: * The parent node, where Facts are propagated from
079: * @param binder
080: * An optional binder to filter out propagations. This binder will exist when
081: * a predicate is used in the first pattern, for instance
082: */
083: public LeftInputAdapterNode(final int id, final ObjectSource source) {
084: super (id);
085: this .objectSource = source;
086: //this.constraints = constraints;
087: setHasMemory(false);
088: }
089:
090: /* (non-Javadoc)
091: * @see org.drools.reteoo.BaseNode#attach()
092: */
093: public void attach() {
094: this .objectSource.addObjectSink(this );
095: }
096:
097: public void attach(final InternalWorkingMemory[] workingMemories) {
098: attach();
099:
100: for (int i = 0, length = workingMemories.length; i < length; i++) {
101: final InternalWorkingMemory workingMemory = workingMemories[i];
102: final PropagationContext propagationContext = new PropagationContextImpl(
103: workingMemory.getNextPropagationIdCounter(),
104: PropagationContext.RULE_ADDITION, null, null);
105: this .objectSource.updateSink(this , propagationContext,
106: workingMemory);
107: }
108: }
109:
110: /**
111: * Takes the asserted <code>FactHandleImpl</code> received from the <code>ObjectSource</code> and puts it
112: * in a new <code>ReteTuple</code> before propagating to the <code>TupleSinks</code>
113: *
114: * @param handle
115: * The asserted <code>FactHandle/code>.
116: * @param context
117: * The <code>PropagationContext</code> of the <code>WorkingMemory<code> action.
118: * @param workingMemory
119: * the <code>WorkingMemory</code> session.
120: */
121: public void assertObject(final InternalFactHandle handle,
122: final PropagationContext context,
123: final InternalWorkingMemory workingMemory) {
124:
125: if (!workingMemory.isSequential()) {
126: this .sink.createAndPropagateAssertTuple(handle, context,
127: workingMemory);
128:
129: if (this .hasMemory) {
130: final FactHashTable memory = (FactHashTable) workingMemory
131: .getNodeMemory(this );
132: memory.add(handle, false);
133: }
134: } else {
135: workingMemory.addLIANodePropagation(new LIANodePropagation(
136: this , handle, context));
137: }
138: }
139:
140: /**
141: * Retract an existing <code>FactHandleImpl</code> by placing it in a new <code>ReteTuple</code> before
142: * proagating to the <code>TupleSinks</code>
143: *
144: * @param handle
145: * The <code>FactHandle/code> to retract.
146: * @param context
147: * The <code>PropagationContext</code> of the <code>WorkingMemory<code> action.
148: * @param workingMemory
149: * the <code>WorkingMemory</code> session.
150: */
151: public void retractObject(final InternalFactHandle handle,
152: final PropagationContext context,
153: final InternalWorkingMemory workingMemory) {
154: boolean propagate = true;
155: if (this .hasMemory) {
156: final FactHashTable memory = (FactHashTable) workingMemory
157: .getNodeMemory(this );
158: propagate = memory.remove(handle);
159: }
160:
161: if (propagate) {
162: this .sink.createAndPropagateRetractTuple(handle, context,
163: workingMemory);
164: }
165: }
166:
167: public void updateSink(final TupleSink sink,
168: final PropagationContext context,
169: final InternalWorkingMemory workingMemory) {
170: if (this .hasMemory) {
171: // We have memory so iterate over all entries
172: final FactHashTable memory = (FactHashTable) workingMemory
173: .getNodeMemory(this );
174: final Iterator it = memory.iterator();
175: for (FactEntry entry = (FactEntry) it.next(); entry != null; entry = (FactEntry) it
176: .next()) {
177: final InternalFactHandle handle = entry.getFactHandle();
178: sink.assertTuple(new ReteTuple(handle), context,
179: workingMemory);
180: }
181: } else {
182: final ObjectSinkAdapter adapter = new ObjectSinkAdapter(
183: sink);
184: this .objectSource.updateSink(adapter, context,
185: workingMemory);
186: }
187: }
188:
189: public void remove(final BaseNode node,
190: final InternalWorkingMemory[] workingMemories) {
191: if (!node.isInUse()) {
192: removeTupleSink((TupleSink) node);
193: }
194: removeShare();
195: if (!this .isInUse()) {
196: for (int i = 0, length = workingMemories.length; i < length; i++) {
197: workingMemories[i].clearNodeMemory(this );
198: }
199: }
200: this .objectSource.remove(this , workingMemories);
201: }
202:
203: /**
204: * Returns the next node
205: * @return
206: * The next ObjectSinkNode
207: */
208: public ObjectSinkNode getNextObjectSinkNode() {
209: return this .nextObjectSinkNode;
210: }
211:
212: /**
213: * Sets the next node
214: * @param next
215: * The next ObjectSinkNode
216: */
217: public void setNextObjectSinkNode(final ObjectSinkNode next) {
218: this .nextObjectSinkNode = next;
219: }
220:
221: /**
222: * Returns the previous node
223: * @return
224: * The previous ObjectSinkNode
225: */
226: public ObjectSinkNode getPreviousObjectSinkNode() {
227: return this .previousObjectSinkNode;
228: }
229:
230: /**
231: * Sets the previous node
232: * @param previous
233: * The previous ObjectSinkNode
234: */
235: public void setPreviousObjectSinkNode(final ObjectSinkNode previous) {
236: this .previousObjectSinkNode = previous;
237: }
238:
239: public int hashCode() {
240: return this .objectSource.hashCode();
241: }
242:
243: public boolean equals(final Object object) {
244: if (object == this ) {
245: return true;
246: }
247:
248: if (object == null || !(object instanceof LeftInputAdapterNode)) {
249: return false;
250: }
251:
252: final LeftInputAdapterNode other = (LeftInputAdapterNode) object;
253: // if ( this.constraints == null ) {
254: // return this.objectSource.equals( other.objectSource ) && other.constraints == null;
255: // } else {
256: return this .objectSource.equals(other.objectSource); //&& this.constraints.equals( other.constraints );
257: // }
258: }
259:
260: public Object createMemory(final RuleBaseConfiguration config) {
261: return new FactHashTable();
262: }
263:
264: /**
265: * Used with the updateSink method, so that the parent ObjectSource
266: * can update the TupleSink
267: * @author mproctor
268: *
269: */
270: private static class ObjectSinkAdapter implements ObjectSink {
271: private TupleSink sink;
272:
273: public ObjectSinkAdapter(final TupleSink sink) {
274: this .sink = sink;
275: }
276:
277: public void assertObject(final InternalFactHandle handle,
278: final PropagationContext context,
279: final InternalWorkingMemory workingMemory) {
280: final ReteTuple tuple = new ReteTuple(handle);
281: this .sink.assertTuple(tuple, context, workingMemory);
282: }
283:
284: public void modifyObject(final InternalFactHandle handle,
285: final PropagationContext context,
286: final InternalWorkingMemory workingMemory) {
287: throw new UnsupportedOperationException(
288: "ObjectSinkAdapter onlys supports assertObject method calls");
289: }
290:
291: public void retractObject(final InternalFactHandle handle,
292: final PropagationContext context,
293: final InternalWorkingMemory workingMemory) {
294: throw new UnsupportedOperationException(
295: "ObjectSinkAdapter onlys supports assertObject method calls");
296: }
297: }
298:
299: }
|