001: package org.drools.reteoo;
002:
003: import java.util.ArrayList;
004: import java.util.List;
005:
006: import org.drools.base.ShadowProxy;
007: import org.drools.common.InternalFactHandle;
008: import org.drools.rule.Declaration;
009: import org.drools.spi.Activation;
010: import org.drools.spi.Tuple;
011: import org.drools.util.Entry;
012:
013: public class ReteTuple implements Tuple, Entry {
014: private static final long serialVersionUID = 400L;
015:
016: private int index;
017:
018: private final InternalFactHandle handle;
019:
020: private ReteTuple parent;
021:
022: private Activation activation;
023:
024: private long recency;
025:
026: private int hashCode;
027:
028: private boolean fieldIndexed;
029:
030: private int matches;
031:
032: private Entry next;
033:
034: // ------------------------------------------------------------
035: // Constructors
036: // ------------------------------------------------------------
037: public ReteTuple(final InternalFactHandle handle) {
038: this .index = 0;
039: this .parent = null;
040: this .recency = handle.getRecency();
041: this .handle = handle;
042: int h = handle.hashCode();
043: h += ~(h << 9);
044: h ^= (h >>> 14);
045: h += (h << 4);
046: h ^= (h >>> 10);
047: this .hashCode = h;
048: }
049:
050: public ReteTuple(final ReteTuple tuple) {
051: this .index = tuple.index;
052: this .parent = tuple.parent;
053: this .recency = tuple.recency;
054: this .handle = tuple.handle;
055: this .hashCode = tuple.hashCode();
056: }
057:
058: public ReteTuple(final ReteTuple parentTuple,
059: final InternalFactHandle handle) {
060: this .index = parentTuple.index + 1;
061: this .parent = parentTuple;
062: this .recency = parentTuple.recency + handle.getRecency();
063: this .handle = handle;
064: this .hashCode = parentTuple.hashCode ^ (handle.hashCode() * 31);
065: }
066:
067: public InternalFactHandle get(final int index) {
068: ReteTuple entry = this ;
069: while (entry.index != index) {
070: entry = entry.parent;
071: }
072: return entry.handle;
073: }
074:
075: public void setNext(final Entry next) {
076: this .next = next;
077: }
078:
079: public Entry getNext() {
080: return this .next;
081: }
082:
083: public boolean isFieldIndexed() {
084: return this .fieldIndexed;
085: }
086:
087: public void setIsFieldIndexHashCode(final boolean fieldIndexed) {
088: this .fieldIndexed = fieldIndexed;
089: }
090:
091: public int getMatches() {
092: return this .matches;
093: }
094:
095: public void setMatches(final int matches) {
096: this .matches = matches;
097: }
098:
099: public InternalFactHandle getLastHandle() {
100: return this .handle;
101: }
102:
103: public InternalFactHandle get(final Declaration declaration) {
104: return get(declaration.getPattern().getOffset());
105: }
106:
107: public Activation getActivation() {
108: return this .activation;
109: }
110:
111: /**
112: * Returns the fact handles in reverse order
113: */
114: public InternalFactHandle[] getFactHandles() {
115: final List list = new ArrayList();
116: ReteTuple entry = this ;
117: while (entry != null) {
118: list.add(entry.handle);
119: entry = entry.parent;
120: }
121:
122: return (InternalFactHandle[]) list
123: .toArray(new InternalFactHandle[list.size()]);
124: }
125:
126: public long getRecency() {
127: return this .recency;
128: }
129:
130: public void setActivation(final Activation activation) {
131: this .activation = activation;
132: }
133:
134: public int hashCode() {
135: return this .hashCode;
136: }
137:
138: public String toString() {
139: final StringBuffer buffer = new StringBuffer();
140:
141: ReteTuple entry = this ;
142: while (entry != null) {
143: //buffer.append( entry.handle );
144: buffer.append(entry.handle + "\n");
145: entry = entry.parent;
146: }
147: return buffer.toString();
148: }
149:
150: /**
151: * We use this equals method to avoid the cast
152: * @param tuple
153: * @return
154: */
155: public boolean equals(final ReteTuple other) {
156: // we know the object is never null and always of the type ReteTuple
157: if (other == this ) {
158: return true;
159: }
160:
161: // A ReteTuple is only the same if it has the same hashCode, factId and parent
162: if ((other == null) || (this .hashCode != other.hashCode)) {
163: return false;
164: }
165:
166: if (this .handle != other.handle) {
167: return false;
168: }
169:
170: if (this .parent == null) {
171: return (other.parent == null);
172: } else {
173: return this .parent.equals(other.parent);
174: }
175: }
176:
177: public boolean equals(final Object object) {
178: // we know the object is never null and always of the type ReteTuple
179: return equals((ReteTuple) object);
180: }
181:
182: public int size() {
183: return this .index + 1;
184: }
185:
186: /**
187: * Returns the ReteTuple that contains the "elements"
188: * first elements in this tuple.
189: *
190: * Use carefully as no cloning is made during this process.
191: *
192: * This method is used by TupleStartEqualsConstraint when
193: * joining a subnetwork tuple into the main network tuple;
194: *
195: * @param elements the number of elements to return, starting from
196: * the begining of the tuple
197: *
198: * @return a ReteTuple containing the "elements" first elements
199: * of this tuple or null if "elements" is greater than size;
200: */
201: public ReteTuple getSubTuple(final int elements) {
202: ReteTuple entry = this ;
203: if (elements < this .size()) {
204: final int lastindex = elements - 1;
205:
206: while (entry.index != lastindex) {
207: entry = entry.parent;
208: }
209: }
210: return entry;
211: }
212:
213: public Object[] toObjectArray() {
214: Object[] objects = new Object[this .index + 1];
215: ReteTuple entry = this ;
216: while (entry != null) {
217: Object object = entry.getLastHandle().getObject();
218: if (object instanceof ShadowProxy) {
219: object = ((ShadowProxy) object).getShadowedObject();
220: }
221: objects[entry.index] = object;
222: entry = entry.parent;
223: }
224: return objects;
225: }
226: }
|