001: package org.drools.reteoo;
002:
003: /*
004: * Copyright 2005 JBoss Inc
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: import java.io.IOException;
020: import java.io.ObjectInputStream;
021: import java.io.Serializable;
022: import java.util.ArrayList;
023: import java.util.Collections;
024: import java.util.Comparator;
025: import java.util.HashMap;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Map;
029: import java.util.Map.Entry;
030:
031: import org.drools.RuleIntegrationException;
032: import org.drools.base.SalienceInteger;
033: import org.drools.common.BaseNode;
034: import org.drools.common.DroolsObjectInputStream;
035: import org.drools.common.InternalRuleBase;
036: import org.drools.common.InternalWorkingMemory;
037: import org.drools.reteoo.builder.ReteooRuleBuilder;
038: import org.drools.rule.InvalidPatternException;
039: import org.drools.rule.Rule;
040: import org.drools.spi.AgendaGroup;
041: import org.drools.spi.Salience;
042:
043: /**
044: * Builds the Rete-OO network for a <code>Package</code>.
045: *
046: * @see org.drools.rule.Package
047: *
048: * @author <a href="mailto:mark.proctor@jboss.com">Mark Proctor</a>
049: * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
050: *
051: */
052: public class ReteooBuilder implements Serializable {
053: // ------------------------------------------------------------
054: // Instance members
055: // ------------------------------------------------------------
056:
057: /**
058: *
059: */
060: private static final long serialVersionUID = 400L;
061:
062: /** The RuleBase */
063: private transient InternalRuleBase ruleBase;
064:
065: private transient InternalWorkingMemory[] workingMemories;
066:
067: private Map rules;
068:
069: private transient ReteooRuleBuilder ruleBuilder;
070:
071: private IdGenerator idGenerator;
072:
073: private boolean ordered;
074:
075: // ------------------------------------------------------------
076: // Constructors
077: // ------------------------------------------------------------
078:
079: /**
080: * Construct a <code>Builder</code> against an existing <code>Rete</code>
081: * network.
082: */
083: ReteooBuilder(final InternalRuleBase ruleBase) {
084: this .ruleBase = ruleBase;
085: this .rules = new HashMap();
086:
087: //Set to 1 as Rete node is set to 0
088: this .idGenerator = new IdGenerator(1);
089: this .ruleBuilder = new ReteooRuleBuilder();
090: }
091:
092: private void readObject(ObjectInputStream stream)
093: throws IOException, ClassNotFoundException {
094: stream.defaultReadObject();
095: this .ruleBase = ((DroolsObjectInputStream) stream)
096: .getRuleBase();
097: }
098:
099: // ------------------------------------------------------------
100: // Instance methods
101: // ------------------------------------------------------------
102:
103: /**
104: * Add a <code>Rule</code> to the network.
105: *
106: * @param rule
107: * The rule to add.
108: *
109: * @throws RuleIntegrationException
110: * if an error prevents complete construction of the network for
111: * the <code>Rule</code>.
112: * @throws InvalidPatternException
113: */
114: void addRule(final Rule rule) throws InvalidPatternException {
115: final List terminals = this .ruleBuilder.addRule(rule,
116: this .ruleBase, this .idGenerator);
117:
118: this .rules.put(rule, terminals.toArray(new BaseNode[terminals
119: .size()]));
120: }
121:
122: public IdGenerator getIdGenerator() {
123: return this .idGenerator;
124: }
125:
126: public void order() {
127: if (ordered) {
128: // we should only do this on first call, its expected the RuleBase should not change afterwards.
129: return;
130: }
131: Map map = new HashMap();
132:
133: for (Iterator it = this .rules.values().iterator(); it.hasNext();) {
134: BaseNode[] nodes = (BaseNode[]) it.next();
135: for (int i = 0; i < nodes.length; i++) {
136: if (nodes[i] instanceof RuleTerminalNode) {
137: RuleTerminalNode node = (RuleTerminalNode) nodes[i];
138: String agendaGroup = node.getRule()
139: .getAgendaGroup();
140: if (agendaGroup == null || agendaGroup.equals("")) {
141: agendaGroup = "MAIN";
142: }
143: List rules = (List) map.get(agendaGroup);
144: if (rules == null) {
145: rules = new ArrayList();
146: map.put(agendaGroup, rules);
147: }
148: rules.add(node);
149: }
150: }
151: }
152:
153: for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
154: Entry entry = (Entry) it.next();
155: String agendaGroup = (String) entry.getKey();
156: List rules = (List) entry.getValue();
157: Collections.sort(rules, RuleSequenceComparator.INSTANCE);
158:
159: int i = 0;
160: for (Iterator listIter = rules.iterator(); listIter
161: .hasNext();) {
162: RuleTerminalNode node = (RuleTerminalNode) listIter
163: .next();
164: node.setSequence(i++);
165: }
166:
167: ruleBase.getAgendaGroupRuleTotals().put(agendaGroup,
168: new Integer(i));
169: }
170: ordered = true;
171: }
172:
173: public static class RuleSequenceComparator implements Comparator {
174: public final static RuleSequenceComparator INSTANCE = new RuleSequenceComparator();
175:
176: public int compare(Object o1, Object o2) {
177: RuleTerminalNode r1 = (RuleTerminalNode) o1;
178: RuleTerminalNode r2 = (RuleTerminalNode) o2;
179:
180: Salience so1 = r1.getRule().getSalience();
181: if (so1 != null && !(so1 instanceof SalienceInteger)) {
182: throw new RuntimeException(r1.getRule().getName()
183: + "must not have a dynamic salience");
184: }
185: Salience so2 = r2.getRule().getSalience();
186: if (so2 != null && !(so2 instanceof SalienceInteger)) {
187: throw new RuntimeException(r2.getRule().getName()
188: + "must not have a dynamic salience");
189: }
190:
191: int s1 = so1.getValue(null, null);
192: int s2 = so2.getValue(null, null);
193:
194: if (s1 > s2) {
195: return -1;
196: } else if (s1 < s2) {
197: return 1;
198: }
199:
200: int id1 = r1.getId();
201: int id2 = r2.getId();
202:
203: if (id1 < id2) {
204: return -1;
205: } else if (id1 > id2) {
206: return 1;
207: } else {
208: return 0;
209: }
210: }
211:
212: }
213:
214: public BaseNode[] getTerminalNodes(final Rule rule) {
215: return (BaseNode[]) this .rules.get(rule);
216: }
217:
218: public void removeRule(final Rule rule) {
219: // reset working memories for potential propagation
220: this .workingMemories = (InternalWorkingMemory[]) this .ruleBase
221: .getWorkingMemories();
222:
223: final Object object = this .rules.remove(rule);
224:
225: final BaseNode[] nodes = (BaseNode[]) object;
226: for (int i = 0, length = nodes.length; i < length; i++) {
227: final BaseNode node = nodes[i];
228: node.remove(null, this .workingMemories);
229: }
230: }
231:
232: public static class IdGenerator implements Serializable {
233:
234: private static final long serialVersionUID = 400L;
235:
236: private int nextId;
237:
238: public IdGenerator(final int firstId) {
239: this .nextId = firstId;
240: }
241:
242: public int getNextId() {
243: return this .nextId++;
244: }
245:
246: public void releaseLastId() {
247: this.nextId--;
248: }
249:
250: }
251:
252: }
|