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.List;
021: import java.util.Map;
022:
023: import org.drools.InitialFact;
024: import org.drools.RuleIntegrationException;
025: import org.drools.base.ClassFieldExtractor;
026: import org.drools.base.ClassObjectType;
027: import org.drools.base.DroolsQuery;
028: import org.drools.base.FieldFactory;
029: import org.drools.base.ValueType;
030: import org.drools.base.evaluators.Operator;
031: import org.drools.common.BaseNode;
032: import org.drools.common.InternalRuleBase;
033: import org.drools.reteoo.QueryTerminalNode;
034: import org.drools.reteoo.ReteooBuilder;
035: import org.drools.reteoo.ReteooRuleBase;
036: import org.drools.reteoo.RuleTerminalNode;
037: import org.drools.reteoo.TerminalNode;
038: import org.drools.rule.Accumulate;
039: import org.drools.rule.Collect;
040: import org.drools.rule.Pattern;
041: import org.drools.rule.EvalCondition;
042: import org.drools.rule.Forall;
043: import org.drools.rule.From;
044: import org.drools.rule.GroupElement;
045: import org.drools.rule.InvalidPatternException;
046: import org.drools.rule.LiteralConstraint;
047: import org.drools.rule.Query;
048: import org.drools.rule.Rule;
049: import org.drools.spi.FieldValue;
050:
051: /**
052: * @author etirelli
053: *
054: */
055: public class ReteooRuleBuilder {
056:
057: private BuildUtils utils;
058:
059: public ReteooRuleBuilder() {
060: this .utils = new BuildUtils();
061:
062: this .utils.addBuilder(GroupElement.class,
063: new GroupElementBuilder());
064: this .utils.addBuilder(Pattern.class, new PatternBuilder());
065: this .utils.addBuilder(EvalCondition.class, new EvalBuilder());
066: this .utils.addBuilder(From.class, new FromBuilder());
067: this .utils.addBuilder(Collect.class, new CollectBuilder());
068: this .utils
069: .addBuilder(Accumulate.class, new AccumulateBuilder());
070: this .utils.addBuilder(Forall.class, new ForallBuilder());
071: }
072:
073: /**
074: * Creates the corresponting Rete network for the given <code>Rule</code> and adds it to
075: * the given rule base.
076: *
077: * @param rule
078: * The rule to add.
079: * @param rulebase
080: * The rulebase to add the rule to.
081: *
082: * @return a List<BaseNode> of terminal nodes for the rule
083: *
084: * @throws RuleIntegrationException
085: * if an error prevents complete construction of the network for
086: * the <code>Rule</code>.
087: * @throws InvalidPatternException
088: */
089: public List addRule(final Rule rule,
090: final InternalRuleBase rulebase,
091: final ReteooBuilder.IdGenerator idGenerator)
092: throws InvalidPatternException {
093:
094: // the list of terminal nodes
095: final List nodes = new ArrayList();
096:
097: // transform rule and gets the array of subrules
098: final GroupElement[] subrules = rule.getTransformedLhs();
099:
100: for (int i = 0; i < subrules.length; i++) {
101: // creates a clean build context for each subrule
102: final BuildContext context = new BuildContext(rulebase,
103: idGenerator);
104: // adds subrule
105: final TerminalNode node = this .addSubRule(context,
106: subrules[i], rule);
107:
108: // adds the terminal node to the list of terminal nodes
109: nodes.add(node);
110:
111: }
112:
113: return nodes;
114: }
115:
116: private TerminalNode addSubRule(final BuildContext context,
117: final GroupElement subrule, final Rule rule)
118: throws InvalidPatternException {
119: // gets the appropriate builder
120: final ReteooComponentBuilder builder = this .utils
121: .getBuilderFor(subrule);
122:
123: // checks if an initial-fact is needed
124: if (builder.requiresLeftActivation(this .utils, subrule)) {
125: this .addInitialFactPattern(context, subrule, rule);
126: }
127:
128: // builds and attach
129: builder.build(context, this .utils, subrule);
130:
131: TerminalNode terminal = null;
132:
133: if (!(rule instanceof Query)) {
134: // Check a consequence is set
135: if (rule.getConsequence() == null) {
136: throw new InvalidPatternException("Rule '"
137: + rule.getName() + "' has no Consequence");
138: }
139: terminal = new RuleTerminalNode(context.getNextId(),
140: context.getTupleSource(), rule, subrule);
141: } else {
142: // Check there is no consequence
143: if (rule.getConsequence() != null) {
144: throw new InvalidPatternException("Query '"
145: + rule.getName()
146: + "' should have no Consequence");
147: }
148: terminal = new QueryTerminalNode(context.getNextId(),
149: context.getTupleSource(), rule, subrule);
150: }
151: if (context.getWorkingMemories().length == 0) {
152: ((BaseNode) terminal).attach();
153: } else {
154: ((BaseNode) terminal).attach(context.getWorkingMemories());
155: }
156:
157: return terminal;
158: }
159:
160: /**
161: * Adds a query pattern to the given subrule
162: *
163: * @param context
164: * @param subrule
165: * @param query
166: */
167: private void addInitialFactPattern(final BuildContext context,
168: final GroupElement subrule, final Rule rule) {
169:
170: // creates a pattern for initial fact
171: final Pattern pattern = new Pattern(0, new ClassObjectType(
172: InitialFact.class));
173:
174: // adds the pattern as the first child of the given AND group element
175: subrule.addChild(0, pattern);
176: }
177:
178: }
|