001: package org.drools.common;
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.io.Serializable;
020: import java.util.ArrayList;
021: import java.util.List;
022:
023: import org.drools.RuleBaseConfiguration;
024: import org.drools.base.evaluators.Operator;
025: import org.drools.reteoo.BetaMemory;
026: import org.drools.reteoo.FactHandleMemory;
027: import org.drools.reteoo.ReteTuple;
028: import org.drools.reteoo.TupleMemory;
029: import org.drools.rule.ContextEntry;
030: import org.drools.rule.VariableConstraint;
031: import org.drools.spi.BetaNodeFieldConstraint;
032: import org.drools.spi.Constraint;
033: import org.drools.util.Entry;
034: import org.drools.util.FactHashTable;
035: import org.drools.util.FactHandleIndexHashTable;
036: import org.drools.util.FactList;
037: import org.drools.util.Iterator;
038: import org.drools.util.LinkedList;
039: import org.drools.util.LinkedListEntry;
040: import org.drools.util.TupleHashTable;
041: import org.drools.util.TupleIndexHashTable;
042: import org.drools.util.AbstractHashTable.FieldIndex;
043:
044: public class DefaultBetaConstraints implements Serializable,
045: BetaConstraints {
046:
047: /**
048: *
049: */
050: private static final long serialVersionUID = 400L;
051:
052: private final LinkedList constraints;
053:
054: private ContextEntry contexts;
055:
056: private int indexed;
057:
058: public DefaultBetaConstraints(
059: final BetaNodeFieldConstraint[] constraints,
060: final RuleBaseConfiguration conf) {
061: this (constraints, conf, false);
062:
063: }
064:
065: public DefaultBetaConstraints(
066: final BetaNodeFieldConstraint[] constraints,
067: final RuleBaseConfiguration conf,
068: final boolean disableIndexing) {
069: this .indexed = -1;
070: this .constraints = new LinkedList();
071: ContextEntry current = null;
072: final int depth = conf.getCompositeKeyDepth();
073:
074: // First create a LinkedList of constraints, with the indexed constraints first.
075: for (int i = 0, length = constraints.length; i < length; i++) {
076: // Determine if this constraint is indexable
077: if ((!disableIndexing) && conf.isIndexLeftBetaMemory()
078: && conf.isIndexRightBetaMemory()
079: && isIndexable(constraints[i])
080: && (this .indexed < depth - 1)) {
081: if (depth >= 1 && this .indexed == -1) {
082: // first index, so just add to the front
083: this .constraints.insertAfter(null,
084: new LinkedListEntry(constraints[i]));
085: this .indexed++;
086: } else {
087: // insert this index after the previous index
088: this .constraints.insertAfter(
089: findNode(this .indexed++),
090: new LinkedListEntry(constraints[i]));
091: }
092: } else {
093: // not indexed, so just add to the end
094: this .constraints
095: .add(new LinkedListEntry(constraints[i]));
096: }
097: }
098:
099: // Now create the ContextEntries in the same order the constraints
100: for (LinkedListEntry entry = (LinkedListEntry) this .constraints
101: .getFirst(); entry != null; entry = (LinkedListEntry) entry
102: .getNext()) {
103: final BetaNodeFieldConstraint constraint = (BetaNodeFieldConstraint) entry
104: .getObject();
105: final ContextEntry context = constraint.getContextEntry();
106: if (current == null) {
107: current = context;
108: this .contexts = context;
109: } else {
110: current.setNext(context);
111: }
112: current = context;
113: }
114: }
115:
116: private LinkedListEntry findNode(final int pos) {
117: LinkedListEntry current = (LinkedListEntry) this .constraints
118: .getFirst();
119: for (int i = 0; i < pos; i++) {
120: current = (LinkedListEntry) current.getNext();
121: }
122: return current;
123: }
124:
125: private ContextEntry findContext(final int pos) {
126: ContextEntry current = this .contexts;
127: for (int i = 0; i < pos; i++) {
128: current = current.getNext();
129: }
130: return current;
131: }
132:
133: private boolean isIndexable(final BetaNodeFieldConstraint constraint) {
134: if (constraint instanceof VariableConstraint) {
135: final VariableConstraint variableConstraint = (VariableConstraint) constraint;
136: return (variableConstraint.getEvaluator().getOperator() == Operator.EQUAL);
137: } else {
138: return false;
139: }
140: }
141:
142: /* (non-Javadoc)
143: * @see org.drools.common.BetaNodeConstraints#updateFromTuple(org.drools.reteoo.ReteTuple)
144: */
145: public void updateFromTuple(
146: final InternalWorkingMemory workingMemory,
147: final ReteTuple tuple) {
148: for (ContextEntry context = this .contexts; context != null; context = context
149: .getNext()) {
150: context.updateFromTuple(workingMemory, tuple);
151: }
152: }
153:
154: /* (non-Javadoc)
155: * @see org.drools.common.BetaNodeConstraints#updateFromFactHandle(org.drools.common.InternalFactHandle)
156: */
157: public void updateFromFactHandle(
158: final InternalWorkingMemory workingMemory,
159: final InternalFactHandle handle) {
160: for (ContextEntry context = this .contexts; context != null; context = context
161: .getNext()) {
162: context.updateFromFactHandle(workingMemory, handle);
163: }
164: }
165:
166: /* (non-Javadoc)
167: * @see org.drools.common.BetaNodeConstraints#isAllowedCachedLeft(java.lang.Object)
168: */
169: public boolean isAllowedCachedLeft(final Object object) {
170: // skip the indexed constraints
171: LinkedListEntry entry = (LinkedListEntry) findNode(this .indexed);
172:
173: ContextEntry context = findContext(this .indexed);
174: while (entry != null) {
175: if (!((BetaNodeFieldConstraint) entry.getObject())
176: .isAllowedCachedLeft(context, object)) {
177: return false;
178: }
179: entry = (LinkedListEntry) entry.getNext();
180: context = context.getNext();
181: }
182: return true;
183: }
184:
185: /* (non-Javadoc)
186: * @see org.drools.common.BetaNodeConstraints#isAllowedCachedRight(org.drools.reteoo.ReteTuple)
187: */
188: public boolean isAllowedCachedRight(final ReteTuple tuple) {
189: // skip the indexed constraints
190: LinkedListEntry entry = (LinkedListEntry) findNode(this .indexed);
191:
192: ContextEntry context = findContext(this .indexed);
193: while (entry != null) {
194: if (!((BetaNodeFieldConstraint) entry.getObject())
195: .isAllowedCachedRight(tuple, context)) {
196: return false;
197: }
198: entry = (LinkedListEntry) entry.getNext();
199: context = context.getNext();
200: }
201: return true;
202: }
203:
204: public boolean isIndexed() {
205: // false if -1
206: return this .indexed >= 0;
207: }
208:
209: public int getIndexCount() {
210: return this .indexed + 1;
211: }
212:
213: public boolean isEmpty() {
214: return false;
215: }
216:
217: public BetaMemory createBetaMemory(RuleBaseConfiguration config) {
218: BetaMemory memory;
219: if (this .indexed >= 0) {
220: LinkedListEntry entry = (LinkedListEntry) this .constraints
221: .getFirst();
222: final List list = new ArrayList();
223:
224: for (int pos = 0; pos <= this .indexed; pos++) {
225: final Constraint constraint = (Constraint) entry
226: .getObject();
227: final VariableConstraint variableConstraint = (VariableConstraint) constraint;
228: final FieldIndex index = new FieldIndex(
229: variableConstraint.getFieldExtractor(),
230: variableConstraint.getRequiredDeclarations()[0],
231: variableConstraint.getEvaluator());
232: list.add(index);
233: entry = (LinkedListEntry) entry.getNext();
234: }
235:
236: final FieldIndex[] indexes = (FieldIndex[]) list
237: .toArray(new FieldIndex[list.size()]);
238: TupleMemory tupleMemory;
239: if (config.isIndexLeftBetaMemory()) {
240: tupleMemory = new TupleIndexHashTable(indexes);
241: } else {
242: tupleMemory = new TupleHashTable();
243: }
244:
245: FactHandleMemory factHandleMemory;
246: if (config.isIndexRightBetaMemory()) {
247: factHandleMemory = new FactHandleIndexHashTable(indexes);
248: } else {
249: factHandleMemory = config.isSequential() ? (FactHandleMemory) new FactList()
250: : (FactHandleMemory) new FactHashTable();
251: }
252: memory = new BetaMemory(config.isSequential() ? null
253: : tupleMemory, factHandleMemory);
254: } else {
255: memory = new BetaMemory(
256: config.isSequential() ? null : new TupleHashTable(),
257: config.isSequential() ? (FactHandleMemory) new FactList()
258: : (FactHandleMemory) new FactHashTable());
259: }
260:
261: return memory;
262: }
263:
264: public int hashCode() {
265: return this .constraints.hashCode();
266: }
267:
268: /* (non-Javadoc)
269: * @see org.drools.common.BetaNodeConstraints#getConstraints()
270: */
271: public LinkedList getConstraints() {
272: return this .constraints;
273: }
274:
275: /**
276: * Determine if another object is equal to this.
277: *
278: * @param object
279: * The object to test.
280: *
281: * @return <code>true</code> if <code>object</code> is equal to this,
282: * otherwise <code>false</code>.
283: */
284: public boolean equals(final Object object) {
285: if (this == object) {
286: return true;
287: }
288:
289: if (object == null
290: || !(object instanceof DefaultBetaConstraints)) {
291: return false;
292: }
293:
294: final DefaultBetaConstraints other = (DefaultBetaConstraints) object;
295:
296: if (this .constraints == other.constraints) {
297: return true;
298: }
299:
300: if (this .constraints.size() != other.constraints.size()) {
301: return false;
302: }
303:
304: return this.constraints.equals(other);
305: }
306:
307: }
|