001: /*
002: * Copyright 2006 JBoss Inc
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.drools.rule;
017:
018: import java.util.Arrays;
019:
020: import org.drools.common.InternalFactHandle;
021: import org.drools.common.InternalWorkingMemory;
022: import org.drools.reteoo.ReteTuple;
023: import org.drools.spi.AlphaNodeFieldConstraint;
024: import org.drools.spi.BetaNodeFieldConstraint;
025: import org.drools.spi.Constraint;
026: import org.drools.util.ArrayUtils;
027:
028: /**
029: * A superclass for all composite constraints, like "OR" and "AND"
030: *
031: * @author etirelli
032: */
033: public abstract class AbstractCompositeConstraint implements
034: AlphaNodeFieldConstraint, BetaNodeFieldConstraint {
035:
036: protected AlphaNodeFieldConstraint[] alphaConstraints = new AlphaNodeFieldConstraint[0];
037: protected BetaNodeFieldConstraint[] betaConstraints = new BetaNodeFieldConstraint[0];
038: protected Declaration[] requiredDeclarations = new Declaration[0];
039:
040: /**
041: * Adds an alpha constraint to the multi field OR constraint
042: *
043: * @param constraint
044: */
045: public void addAlphaConstraint(AlphaNodeFieldConstraint constraint) {
046: if (constraint != null) {
047: AlphaNodeFieldConstraint[] tmp = this .alphaConstraints;
048: this .alphaConstraints = new AlphaNodeFieldConstraint[tmp.length + 1];
049: System.arraycopy(tmp, 0, this .alphaConstraints, 0,
050: tmp.length);
051: this .alphaConstraints[this .alphaConstraints.length - 1] = constraint;
052: this .updateRequiredDeclarations(constraint);
053: }
054: }
055:
056: /**
057: * Adds a beta constraint to this multi field OR constraint
058: * @param constraint
059: */
060: public void addBetaConstraint(BetaNodeFieldConstraint constraint) {
061: if (constraint != null) {
062: BetaNodeFieldConstraint[] tmp = this .betaConstraints;
063: this .betaConstraints = new BetaNodeFieldConstraint[tmp.length + 1];
064: System.arraycopy(tmp, 0, this .betaConstraints, 0,
065: tmp.length);
066: this .betaConstraints[this .betaConstraints.length - 1] = constraint;
067: this .updateRequiredDeclarations(constraint);
068: }
069: }
070:
071: /**
072: * Adds a constraint too all lists it belongs to by checking for its type
073: * @param constraint
074: */
075: public void addConstraint(Constraint constraint) {
076: if (constraint instanceof AlphaNodeFieldConstraint) {
077: this
078: .addAlphaConstraint((AlphaNodeFieldConstraint) constraint);
079: }
080: if (constraint instanceof BetaNodeFieldConstraint) {
081: this
082: .addBetaConstraint((BetaNodeFieldConstraint) constraint);
083: }
084: }
085:
086: /**
087: * Updades the cached required declaration array
088: *
089: * @param constraint
090: */
091: private void updateRequiredDeclarations(Constraint constraint) {
092: Declaration[] decs = constraint.getRequiredDeclarations();
093: if (decs != null && decs.length > 0) {
094: for (int i = 0; i < decs.length; i++) {
095: Declaration dec = decs[i];
096: // check for duplications
097: for (int j = 0; j < this .requiredDeclarations.length; j++) {
098: if (dec.equals(this .requiredDeclarations[j])) {
099: dec = null;
100: break;
101: }
102: }
103: if (dec != null) {
104: Declaration[] tmp = this .requiredDeclarations;
105: this .requiredDeclarations = new Declaration[tmp.length + 1];
106: System.arraycopy(tmp, 0, this .requiredDeclarations,
107: 0, tmp.length);
108: this .requiredDeclarations[this .requiredDeclarations.length - 1] = dec;
109: }
110: }
111: }
112: }
113:
114: /**
115: * {@inheritDoc}
116: */
117: public Declaration[] getRequiredDeclarations() {
118: return this .requiredDeclarations;
119: }
120:
121: /**
122: * {@inheritDoc}
123: */
124: public ContextEntry getContextEntry() {
125: return new MultiFieldConstraintContextEntry(
126: this .betaConstraints);
127: }
128:
129: public int hashCode() {
130: final int PRIME = 31;
131: int result = 1;
132: result = PRIME * result
133: + ArrayUtils.hashCode(this .alphaConstraints);
134: result = PRIME * result
135: + ArrayUtils.hashCode(this .betaConstraints);
136: result = PRIME * result
137: + ArrayUtils.hashCode(this .requiredDeclarations);
138: return result;
139: }
140:
141: public boolean equals(final Object object) {
142: if (this == object) {
143: return true;
144: }
145: if (object == null
146: || object.getClass() != AbstractCompositeConstraint.class) {
147: return false;
148: }
149: final AbstractCompositeConstraint other = (AbstractCompositeConstraint) object;
150:
151: return Arrays.equals(this .alphaConstraints,
152: other.alphaConstraints)
153: && Arrays.equals(this .betaConstraints,
154: other.betaConstraints)
155: && Arrays.equals(this .requiredDeclarations,
156: other.requiredDeclarations);
157: }
158:
159: public AbstractCompositeConstraint() {
160: super ();
161: }
162:
163: /**
164: * A context entry for composite restrictions
165: *
166: * @author etirelli
167: */
168: protected static class MultiFieldConstraintContextEntry implements
169: ContextEntry {
170:
171: private static final long serialVersionUID = 400L;
172:
173: public final ContextEntry[] contexts;
174: public ContextEntry next;
175:
176: public MultiFieldConstraintContextEntry(
177: BetaNodeFieldConstraint[] constraints) {
178: contexts = new ContextEntry[constraints.length];
179: for (int i = 0; i < contexts.length; i++) {
180: contexts[i] = constraints[i].getContextEntry();
181: }
182: }
183:
184: public ContextEntry getNext() {
185: return this .next;
186: }
187:
188: public void setNext(ContextEntry entry) {
189: this .next = entry;
190: }
191:
192: public void updateFromFactHandle(
193: InternalWorkingMemory workingMemory,
194: InternalFactHandle handle) {
195: for (int i = 0; i < contexts.length; i++) {
196: contexts[i].updateFromFactHandle(workingMemory, handle);
197: }
198: }
199:
200: public void updateFromTuple(
201: InternalWorkingMemory workingMemory, ReteTuple tuple) {
202: for (int i = 0; i < contexts.length; i++) {
203: contexts[i].updateFromTuple(workingMemory, tuple);
204: }
205: }
206:
207: }
208:
209: }
|