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:
017: package org.drools.reteoo.builder;
018:
019: import java.util.ArrayList;
020: import java.util.HashMap;
021: import java.util.List;
022: import java.util.ListIterator;
023: import java.util.Map;
024:
025: import org.drools.RuntimeDroolsException;
026: import org.drools.common.BaseNode;
027: import org.drools.common.BetaConstraints;
028: import org.drools.common.DefaultBetaConstraints;
029: import org.drools.common.DoubleBetaConstraints;
030: import org.drools.common.EmptyBetaConstraints;
031: import org.drools.common.QuadroupleBetaConstraints;
032: import org.drools.common.SingleBetaConstraints;
033: import org.drools.common.TripleBetaConstraints;
034: import org.drools.reteoo.ObjectSink;
035: import org.drools.reteoo.ObjectSource;
036: import org.drools.reteoo.ObjectTypeNode;
037: import org.drools.reteoo.TupleSink;
038: import org.drools.reteoo.TupleSource;
039: import org.drools.rule.Declaration;
040: import org.drools.rule.InvalidPatternException;
041: import org.drools.rule.RuleConditionElement;
042: import org.drools.spi.BetaNodeFieldConstraint;
043:
044: /**
045: * Utility functions for reteoo build
046: *
047: * @author etirelli
048: */
049: public class BuildUtils {
050:
051: private final Map componentBuilders = new HashMap();
052:
053: /**
054: * Adds the given builder for the given target to the builders map
055: *
056: * @param target
057: * @param builder
058: */
059: public void addBuilder(final Class target,
060: final ReteooComponentBuilder builder) {
061: this .componentBuilders.put(target, builder);
062: }
063:
064: /**
065: * Returns a builder for the given target from the builders map
066: *
067: * @param target
068: * @return returns null if not found
069: */
070: public ReteooComponentBuilder getBuilderFor(
071: final RuleConditionElement target) {
072: return (ReteooComponentBuilder) this .componentBuilders
073: .get(target.getClass());
074: }
075:
076: /**
077: * Attaches a node into the network. If a node already exists that could
078: * substitute, it is used instead.
079: *
080: * @param context
081: * The current build context
082: * @param candidate
083: * The node to attach.
084: *
085: * @return the actual attached node that may be the one given as parameter
086: * or eventualy one that was already in the cache if sharing is enabled
087: */
088: public BaseNode attachNode(final BuildContext context,
089: final BaseNode candidate) {
090: BaseNode node = null;
091: if (candidate instanceof ObjectTypeNode) {
092: // object type nodes are always shared
093: ObjectTypeNode otn = (ObjectTypeNode) candidate;
094: otn = (ObjectTypeNode) context.getRuleBase().getRete()
095: .getObjectTypeNodes().get(otn.getObjectType());
096: if (otn != null) {
097: node = otn;
098: }
099: } else if (isSharingEnabledForNode(context, candidate)) {
100: if ((context.getTupleSource() != null)
101: && (candidate instanceof TupleSink)) {
102: TupleSink[] sinks = context.getTupleSource()
103: .getSinkPropagator().getSinks();
104: for (int i = 0; i < sinks.length; i++) {
105: if (candidate.equals(sinks[i])) {
106: node = (BaseNode) sinks[i];
107: break;
108: }
109: }
110: } else if ((context.getObjectSource() != null)
111: && (candidate instanceof ObjectSink)) {
112: ObjectSink[] sinks = context.getObjectSource()
113: .getSinkPropagator().getSinks();
114: for (int i = 0; i < sinks.length; i++) {
115: if (candidate.equals(sinks[i])) {
116: node = (BaseNode) sinks[i];
117: break;
118: }
119: }
120: } else {
121: throw new RuntimeDroolsException(
122: "This is a bug on node sharing verification. Please report to development team.");
123: }
124: if (node != null) {
125: // shared node found
126: // undo previous id assignment
127: context.releaseLastId();
128: node.addShare();
129: }
130: }
131:
132: if (node == null) {
133: // only attach() if it is a new node
134: node = candidate;
135: if (context.getWorkingMemories().length == 0) {
136: node.attach();
137: } else {
138: node.attach(context.getWorkingMemories());
139: }
140: }
141: return node;
142:
143: }
144:
145: /**
146: * Utility function to check if sharing is enabled for nodes of the given class
147: *
148: * @param context
149: * @param node
150: * @return
151: */
152: private boolean isSharingEnabledForNode(final BuildContext context,
153: final BaseNode node) {
154: if (node instanceof TupleSource) {
155: return context.getRuleBase().getConfiguration()
156: .isShareBetaNodes();
157: } else if (node instanceof ObjectSource) {
158: return context.getRuleBase().getConfiguration()
159: .isShareAlphaNodes();
160: }
161: return false;
162: }
163:
164: /**
165: * Creates and returns a BetaConstraints object for the given list of constraints
166: *
167: * @param context the current build context
168: * @param list the list of constraints
169: *
170: * @return
171: */
172: public BetaConstraints createBetaNodeConstraint(
173: final BuildContext context, final List list,
174: final boolean disableIndexing) {
175: BetaConstraints constraints;
176: switch (list.size()) {
177: case 0:
178: constraints = EmptyBetaConstraints.getInstance();
179: break;
180: case 1:
181: constraints = new SingleBetaConstraints(
182: (BetaNodeFieldConstraint) list.get(0), context
183: .getRuleBase().getConfiguration(),
184: disableIndexing);
185: break;
186: case 2:
187: constraints = new DoubleBetaConstraints(
188: (BetaNodeFieldConstraint[]) list
189: .toArray(new BetaNodeFieldConstraint[list
190: .size()]), context.getRuleBase()
191: .getConfiguration(), disableIndexing);
192: break;
193: case 3:
194: constraints = new TripleBetaConstraints(
195: (BetaNodeFieldConstraint[]) list
196: .toArray(new BetaNodeFieldConstraint[list
197: .size()]), context.getRuleBase()
198: .getConfiguration(), disableIndexing);
199: break;
200: case 4:
201: constraints = new QuadroupleBetaConstraints(
202: (BetaNodeFieldConstraint[]) list
203: .toArray(new BetaNodeFieldConstraint[list
204: .size()]), context.getRuleBase()
205: .getConfiguration(), disableIndexing);
206: break;
207: default:
208: constraints = new DefaultBetaConstraints(
209: (BetaNodeFieldConstraint[]) list
210: .toArray(new BetaNodeFieldConstraint[list
211: .size()]), context.getRuleBase()
212: .getConfiguration(), disableIndexing);
213: }
214: return constraints;
215: }
216:
217: /**
218: * Make sure the required declarations are previously bound
219: *
220: * @param declarations
221: * @throws InvalidPatternException
222: */
223: public void checkUnboundDeclarations(final BuildContext context,
224: final Declaration[] declarations)
225: throws InvalidPatternException {
226: final List list = new ArrayList();
227: for (int i = 0, length = declarations.length; i < length; i++) {
228: for (final ListIterator it = context.stackIterator(); it
229: .hasPrevious();) {
230: final RuleConditionElement rce = (RuleConditionElement) it
231: .previous();
232: final Declaration decl = rce
233: .resolveDeclaration(declarations[i]
234: .getIdentifier());
235: if (decl == null
236: || decl.getPattern().getOffset() > declarations[i]
237: .getPattern().getOffset()) {
238: list.add(declarations[i].getIdentifier());
239: }
240: }
241: }
242:
243: // Make sure the required declarations
244: if (list.size() != 0) {
245: final StringBuffer buffer = new StringBuffer();
246: buffer.append(list.get(0));
247: for (int i = 1, size = list.size(); i < size; i++) {
248: buffer.append(", " + list.get(i));
249: }
250:
251: throw new InvalidPatternException(
252: "Required Declarations not bound: '" + buffer);
253: }
254: }
255:
256: }
|