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.Iterator;
022: import java.util.List;
023: import java.util.Map;
024:
025: import org.drools.RuntimeDroolsException;
026: import org.drools.common.BetaConstraints;
027: import org.drools.common.TupleStartEqualsConstraint;
028: import org.drools.reteoo.ExistsNode;
029: import org.drools.reteoo.JoinNode;
030: import org.drools.reteoo.LeftInputAdapterNode;
031: import org.drools.reteoo.NotNode;
032: import org.drools.reteoo.ObjectSource;
033: import org.drools.reteoo.RightInputAdapterNode;
034: import org.drools.reteoo.TupleSource;
035: import org.drools.rule.GroupElement;
036: import org.drools.rule.RuleConditionElement;
037:
038: /**
039: * @author etirelli
040: *
041: */
042: public class GroupElementBuilder implements ReteooComponentBuilder {
043:
044: private final Map geBuilders = new HashMap();
045:
046: public GroupElementBuilder() {
047: this .geBuilders.put(GroupElement.AND, new AndBuilder());
048: this .geBuilders.put(GroupElement.OR, new OrBuilder());
049: this .geBuilders.put(GroupElement.NOT, new NotBuilder());
050: this .geBuilders.put(GroupElement.EXISTS, new ExistsBuilder());
051: }
052:
053: /**
054: * @inheritDoc
055: */
056: public void build(final BuildContext context,
057: final BuildUtils utils, final RuleConditionElement rce) {
058: final GroupElement ge = (GroupElement) rce;
059:
060: final ReteooComponentBuilder builder = (ReteooComponentBuilder) this .geBuilders
061: .get(ge.getType());
062:
063: builder.build(context, utils, rce);
064: }
065:
066: /**
067: * @inheritDoc
068: */
069: public boolean requiresLeftActivation(final BuildUtils utils,
070: final RuleConditionElement rce) {
071: final GroupElement ge = (GroupElement) rce;
072:
073: final ReteooComponentBuilder builder = (ReteooComponentBuilder) this .geBuilders
074: .get(ge.getType());
075:
076: return builder.requiresLeftActivation(utils, rce);
077: }
078:
079: private static class AndBuilder implements ReteooComponentBuilder {
080:
081: /**
082: * @inheritDoc
083: *
084: * And group elements just iterate over their children
085: * selecting and calling the build procedure for each one
086: *
087: */
088: public void build(final BuildContext context,
089: final BuildUtils utils, final RuleConditionElement rce) {
090:
091: final GroupElement ge = (GroupElement) rce;
092:
093: // iterate over each child and build it
094: for (final Iterator it = ge.getChildren().iterator(); it
095: .hasNext();) {
096:
097: final RuleConditionElement child = (RuleConditionElement) it
098: .next();
099:
100: final ReteooComponentBuilder builder = utils
101: .getBuilderFor(child);
102:
103: builder.build(context, utils, child);
104:
105: // if a previous object source was bound, but no tuple source
106: if (context.getObjectSource() != null
107: && context.getTupleSource() == null) {
108: // adapt it to a Tuple source
109: context.setTupleSource((TupleSource) utils
110: .attachNode(context,
111: new LeftInputAdapterNode(context
112: .getNextId(), context
113: .getObjectSource())));
114:
115: context.setObjectSource(null);
116: }
117:
118: // if there was a previous tuple source, then a join node is needed
119: if (context.getObjectSource() != null
120: && context.getTupleSource() != null) {
121: // so, create the tuple source and clean up the constraints and object source
122: final BetaConstraints betaConstraints = utils
123: .createBetaNodeConstraint(context, context
124: .getBetaconstraints(), false);
125: context.setTupleSource((TupleSource) utils
126: .attachNode(context,
127: new JoinNode(context.getNextId(),
128: context.getTupleSource(),
129: context.getObjectSource(),
130: betaConstraints)));
131: context.setBetaconstraints(null);
132: context.setObjectSource(null);
133: }
134: }
135: }
136:
137: public boolean requiresLeftActivation(final BuildUtils utils,
138: final RuleConditionElement rce) {
139: final GroupElement and = (GroupElement) rce;
140:
141: // need to check this because in the case of an empty rule, the root AND
142: // will have no child
143: if (and.getChildren().isEmpty()) {
144: return true;
145: }
146:
147: final RuleConditionElement child = (RuleConditionElement) and
148: .getChildren().get(0);
149: final ReteooComponentBuilder builder = utils
150: .getBuilderFor(child);
151:
152: return builder.requiresLeftActivation(utils, child);
153: }
154: }
155:
156: private static class OrBuilder implements ReteooComponentBuilder {
157:
158: /**
159: * @inheritDoc
160: */
161: public void build(final BuildContext context,
162: final BuildUtils utils, final RuleConditionElement rce) {
163: throw new RuntimeDroolsException(
164: "BUG: Can't build a rete network with an inner OR group element");
165: }
166:
167: public boolean requiresLeftActivation(final BuildUtils utils,
168: final RuleConditionElement rce) {
169: throw new RuntimeDroolsException(
170: "BUG: Can't build a rete network with an inner OR group element");
171: }
172: }
173:
174: private static class NotBuilder implements ReteooComponentBuilder {
175:
176: /**
177: * @inheritDoc
178: *
179: * Not must verify what is the class of its child:
180: *
181: * If it is a pattern, a simple NotNode is added to the rulebase
182: * If it is a group element, than a subnetwork must be created
183: */
184: public void build(final BuildContext context,
185: final BuildUtils utils, final RuleConditionElement rce) {
186: final GroupElement not = (GroupElement) rce;
187:
188: // NOT must save some context info to restore it later
189: final int currentPatternIndex = context
190: .getCurrentPatternOffset();
191: final TupleSource tupleSource = context.getTupleSource();
192:
193: // get child
194: final RuleConditionElement child = (RuleConditionElement) not
195: .getChildren().get(0);
196:
197: // get builder for child
198: final ReteooComponentBuilder builder = utils
199: .getBuilderFor(child);
200:
201: // builds the child
202: builder.build(context, utils, child);
203:
204: // if it is a subnetwork
205: if (context.getObjectSource() == null
206: && context.getTupleSource() != null) {
207:
208: // attach right input adapter node to convert tuple source into an object source
209: context.setObjectSource((ObjectSource) utils
210: .attachNode(context, new RightInputAdapterNode(
211: context.getNextId(), context
212: .getTupleSource())));
213:
214: // restore tuple source from before the start of the sub network
215: context.setTupleSource(tupleSource);
216:
217: // create a tuple start equals constraint and set it in the context
218: final TupleStartEqualsConstraint constraint = TupleStartEqualsConstraint
219: .getInstance();
220: final List predicates = new ArrayList();
221: predicates.add(constraint);
222: context.setBetaconstraints(predicates);
223:
224: }
225:
226: final BetaConstraints betaConstraints = utils
227: .createBetaNodeConstraint(context, context
228: .getBetaconstraints(), false);
229: // then attach the NOT node. It will work both as a simple not node
230: // or as subnetwork join node as the context was set appropriatelly
231: // in each case
232: context.setTupleSource((TupleSource) utils.attachNode(
233: context, new NotNode(context.getNextId(), context
234: .getTupleSource(), context
235: .getObjectSource(), betaConstraints)));
236: context.setBetaconstraints(null);
237: context.setObjectSource(null);
238:
239: // restore pattern index
240: context.setCurrentPatternOffset(currentPatternIndex);
241: }
242:
243: public boolean requiresLeftActivation(final BuildUtils utils,
244: final RuleConditionElement rce) {
245: return true;
246: }
247: }
248:
249: private static class ExistsBuilder implements
250: ReteooComponentBuilder {
251:
252: /**
253: * @inheritDoc
254: *
255: * Exists must verify what is the class of its child:
256: *
257: * If it is a pattern, a simple ExistsNode is added to the rulebase
258: * If it is a group element, than a subnetwork must be created
259: */
260: public void build(final BuildContext context,
261: final BuildUtils utils, final RuleConditionElement rce) {
262: final GroupElement exists = (GroupElement) rce;
263:
264: // EXISTS must save some context info to restore it later
265: final int currentPatternIndex = context
266: .getCurrentPatternOffset();
267: final TupleSource tupleSource = context.getTupleSource();
268:
269: // get child
270: final RuleConditionElement child = (RuleConditionElement) exists
271: .getChildren().get(0);
272:
273: // get builder for child
274: final ReteooComponentBuilder builder = utils
275: .getBuilderFor(child);
276:
277: // builds the child
278: builder.build(context, utils, child);
279:
280: // if it is a subnetwork
281: if (context.getObjectSource() == null
282: && context.getTupleSource() != null) {
283:
284: // attach right input adapter node to convert tuple source into an object source
285: context.setObjectSource((ObjectSource) utils
286: .attachNode(context, new RightInputAdapterNode(
287: context.getNextId(), context
288: .getTupleSource())));
289:
290: // restore tuple source from before the start of the sub network
291: context.setTupleSource(tupleSource);
292:
293: // create a tuple start equals constraint and set it in the context
294: final TupleStartEqualsConstraint constraint = TupleStartEqualsConstraint
295: .getInstance();
296: final List predicates = new ArrayList();
297: predicates.add(constraint);
298: context.setBetaconstraints(predicates);
299:
300: }
301:
302: final BetaConstraints betaConstraints = utils
303: .createBetaNodeConstraint(context, context
304: .getBetaconstraints(), false);
305:
306: // then attach the EXISTS node. It will work both as a simple exists node
307: // or as subnetwork join node as the context was set appropriatelly
308: // in each case
309: context.setTupleSource((TupleSource) utils.attachNode(
310: context,
311: new ExistsNode(context.getNextId(), context
312: .getTupleSource(), context
313: .getObjectSource(), betaConstraints)));
314: context.setBetaconstraints(null);
315: context.setObjectSource(null);
316:
317: // restore pattern index
318: context.setCurrentPatternOffset(currentPatternIndex);
319: }
320:
321: /**
322: * @inheritDoc
323: */
324: public boolean requiresLeftActivation(final BuildUtils utils,
325: final RuleConditionElement rce) {
326: return true;
327: }
328: }
329:
330: }
|