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: import org.drools.FactException;
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.AlphaNodeFieldConstraint;
026: import org.drools.spi.PropagationContext;
027: import org.drools.util.FactEntry;
028: import org.drools.util.FactHashTable;
029: import org.drools.util.Iterator;
030: import org.drools.util.AbstractHashTable.FactEntryImpl;
031:
032: /**
033: * <code>AlphaNodes</code> are nodes in the <code>Rete</code> network used
034: * to apply <code>FieldConstraint<.code>s on asserted fact
035: * objects where the <code>FieldConstraint</code>s have no dependencies on any other of the facts in the current <code>Rule</code>.
036: *
037: * @see AlphaNodeFieldConstraint
038: *
039: * @author <a href="mailto:mark.proctor@jboss.com">Mark Proctor</a>
040: * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
041: *
042: */
043: public class AlphaNode extends ObjectSource implements ObjectSinkNode,
044: NodeMemory {
045:
046: /**
047: *
048: */
049: private static final long serialVersionUID = 400L;
050:
051: /** The <code>FieldConstraint</code> */
052: private final AlphaNodeFieldConstraint constraint;
053:
054: private ObjectSinkNode previousObjectSinkNode;
055: private ObjectSinkNode nextObjectSinkNode;
056:
057: /**
058: * Construct an <code>AlphaNode</code> with a unique id using the provided
059: * <code>FieldConstraint</code> and the given <code>ObjectSource</code>.
060: * Set the boolean flag to true if the node is supposed to have local
061: * memory, or false otherwise. Memory is optional for <code>AlphaNode</code>s
062: * and is only of benefic when adding additional <code>Rule</code>s at runtime.
063: *
064: * @param id Node's ID
065: * @param constraint Node's constraints
066: * @param objectSource Node's object source
067: * @param hasMemory true if node shall be configured with local memory. False otherwise.
068: */
069: public AlphaNode(final int id,
070: final AlphaNodeFieldConstraint constraint,
071: final ObjectSource objectSource, final boolean hasMemory,
072: final int alphaNodeHashingThreshold) {
073: super (id, objectSource, alphaNodeHashingThreshold);
074: this .constraint = constraint;
075: setHasMemory(hasMemory);
076: }
077:
078: /**
079: * Retruns the <code>FieldConstraint</code>
080: *
081: * @return <code>FieldConstraint</code>
082: */
083: public AlphaNodeFieldConstraint getConstraint() {
084: return this .constraint;
085: }
086:
087: /*
088: * (non-Javadoc)
089: *
090: * @see org.drools.reteoo.BaseNode#attach()
091: */
092: public void attach() {
093: this .objectSource.addObjectSink(this );
094: }
095:
096: public void attach(final InternalWorkingMemory[] workingMemories) {
097: attach();
098:
099: // we are attaching this node with existing working memories
100: // so this node must also have memory
101: setHasMemory(true);
102: for (int i = 0, length = workingMemories.length; i < length; i++) {
103: final InternalWorkingMemory workingMemory = workingMemories[i];
104: final PropagationContext propagationContext = new PropagationContextImpl(
105: workingMemory.getNextPropagationIdCounter(),
106: PropagationContext.RULE_ADDITION, null, null);
107: this .objectSource.updateSink(this , propagationContext,
108: workingMemory);
109: }
110: }
111:
112: public void assertObject(final InternalFactHandle handle,
113: final PropagationContext context,
114: final InternalWorkingMemory workingMemory)
115: throws FactException {
116: if (this .constraint
117: .isAllowed(handle.getObject(), workingMemory)) {
118: if (hasMemory() && !workingMemory.isSequential()) {
119: final FactHashTable memory = (FactHashTable) workingMemory
120: .getNodeMemory(this );
121: memory.add(handle, false);
122: }
123:
124: this .sink.propagateAssertObject(handle, context,
125: workingMemory);
126: }
127: }
128:
129: public void retractObject(final InternalFactHandle handle,
130: final PropagationContext context,
131: final InternalWorkingMemory workingMemory) {
132: boolean propagate = true;
133: if (hasMemory()) {
134: final FactHashTable memory = (FactHashTable) workingMemory
135: .getNodeMemory(this );
136: propagate = memory.remove(handle);
137: } else {
138: propagate = this .constraint.isAllowed(handle.getObject(),
139: workingMemory);
140: }
141: if (propagate) {
142: this .sink.propagateRetractObject(handle, context,
143: workingMemory, true);
144: }
145: }
146:
147: public void updateSink(final ObjectSink sink,
148: final PropagationContext context,
149: final InternalWorkingMemory workingMemory) {
150: FactHashTable memory = null;
151:
152: if (!hasMemory()) {
153: // get the objects from the parent
154: this .objectSource.updateSink(sink, context, workingMemory);
155: } else {
156: // if already has memory, just iterate and propagate
157: memory = (FactHashTable) workingMemory.getNodeMemory(this );
158: final Iterator it = memory.iterator();
159: for (FactEntry entry = (FactEntry) it.next(); entry != null; entry = (FactEntry) it
160: .next()) {
161: sink.assertObject(entry.getFactHandle(), context,
162: workingMemory);
163: }
164: }
165: }
166:
167: public void remove(final BaseNode node,
168: final InternalWorkingMemory[] workingMemories) {
169:
170: if (!node.isInUse()) {
171: removeObjectSink((ObjectSink) node);
172: }
173: removeShare();
174: if (!this .isInUse()) {
175: for (int i = 0, length = workingMemories.length; i < length; i++) {
176: workingMemories[i].clearNodeMemory(this );
177: }
178: }
179: this .objectSource.remove(this , workingMemories);
180: }
181:
182: /**
183: * Creates a HashSet for the AlphaNode's memory.
184: */
185: public Object createMemory(final RuleBaseConfiguration config) {
186: return new FactHashTable();
187: }
188:
189: public String toString() {
190: return "[AlphaNode(" + this .id + ") constraint="
191: + this .constraint + "]";
192: }
193:
194: public int hashCode() {
195: return this .objectSource.hashCode()
196: * 17
197: + ((this .constraint != null) ? this .constraint
198: .hashCode() : 0);
199: }
200:
201: /*
202: * (non-Javadoc)
203: *
204: * @see java.lang.Object#equals(java.lang.Object)
205: */
206: public boolean equals(final Object object) {
207: if (this == object) {
208: return true;
209: }
210:
211: if (object == null || !(object instanceof AlphaNode)) {
212: return false;
213: }
214:
215: final AlphaNode other = (AlphaNode) object;
216:
217: return this .objectSource.equals(other.objectSource)
218: && this .constraint.equals(other.constraint);
219: }
220:
221: /**
222: * Returns the next node
223: * @return
224: * The next ObjectSinkNode
225: */
226: public ObjectSinkNode getNextObjectSinkNode() {
227: return this .nextObjectSinkNode;
228: }
229:
230: /**
231: * Sets the next node
232: * @param next
233: * The next ObjectSinkNode
234: */
235: public void setNextObjectSinkNode(final ObjectSinkNode next) {
236: this .nextObjectSinkNode = next;
237: }
238:
239: /**
240: * Returns the previous node
241: * @return
242: * The previous ObjectSinkNode
243: */
244: public ObjectSinkNode getPreviousObjectSinkNode() {
245: return this .previousObjectSinkNode;
246: }
247:
248: /**
249: * Sets the previous node
250: * @param previous
251: * The previous ObjectSinkNode
252: */
253: public void setPreviousObjectSinkNode(final ObjectSinkNode previous) {
254: this.previousObjectSinkNode = previous;
255: }
256:
257: }
|