001: package org.drools.decisiontable.parser;
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.util.ArrayList;
020: import java.util.List;
021:
022: import org.drools.decisiontable.model.Condition;
023: import org.drools.decisiontable.model.Consequence;
024: import org.drools.decisiontable.model.Rule;
025: import org.drools.decisiontable.model.SnippetBuilder;
026: import org.drools.decisiontable.parser.DefaultRuleSheetListener;
027: import org.drools.util.StringUtils;
028:
029: /**
030: * @author <a href="mailto:stevearoonie@gmail.com"> Steven Williams </a><a
031: * href="mailto:michael.neale@gmail.com"> Michael Neale </a>
032: *
033: * Define a ruleset spreadsheet which contains a matrix style decision tables.
034: *
035: * This is an example of a custom RuleSheetListener. It differs from the standard
036: * decision table in the following ways:
037: * - AgendaGroup property so that all rules fall within the same agenda-group
038: * - Precondition property which specifies a condition that is always included
039: * if a rule is being generated
040: * - Action property. Each cell within the decision table causes this action
041: * to be triggered
042: * - HorizontalCondition property. Each column header in the matrix
043: * applies this condition
044: * - VerticalCondition property. Each row header in the matrix applies this
045: * condition
046: *
047: * A table is identifed by a cell beginning with the text "RuleTable".
048: * The cells after RuleTable in the same row identify the Horizontal Conditions.
049: * The cells after RuleTable in the same column identify the Vertical Conditions.
050: * The cells with the matrix identify the actions.
051: * Wherever an action cell exists for a Vertical/Horizontal condition intersection
052: * the following rule is created:
053: * rule "rule_row_col"
054: * agenda-group AgendaGroup
055: * when
056: * Precondition
057: * VerticalCondition
058: * HorizontalCondition
059: * then
060: * Action
061: * end
062: */
063: public class RuleMatrixSheetListener extends DefaultRuleSheetListener {
064:
065: //keywords
066: public static final String AGENDAGROUP_TAG = "AgendaGroup";
067: public static final String PRECONDITION_TAG = "Precondition";
068: public static final String ACTION_TAG = "Action";
069: public static final String HORIZONTALCONDITION_TAG = "HorizontalCondition";
070: public static final String VERTICALCONDITION_TAG = "VerticalCondition";
071:
072: //state machine variables for this parser
073: private int ruleTableRow;
074: private int ruleTableColumn;
075: private String _currentAgendaGroup;
076: private Condition _currentPrecondition;
077: private String _action;
078: private String _horizontalCondition;
079: private String _verticalCondition;
080: private List _horizontalConditions = new ArrayList();
081: private Condition _currentVerticalCondition;
082: private boolean isInRuleTable;
083: private Rule firstRule;
084:
085: public void newCell(final int row, final int column,
086: final String value, final int mergedColStart) {
087: // if we aren't in the rule table just use the default handling
088: // (add a property)
089: if (!isInRuleTable) {
090: super .newCell(row, column, value, mergedColStart);
091: return;
092: }
093: // ignore empty cells
094: if (StringUtils.isEmpty(value)) {
095: return;
096: }
097:
098: //Horizontal header column
099: //Create a new condition using HorizontalCondition as the template
100: //and save it for later use
101: if (row == (ruleTableRow) && column > ruleTableColumn) {
102: _horizontalConditions.add(createCondition(value,
103: _horizontalCondition));
104: }
105: //Vertical header column
106: //Create a new condition using VerticalCondition as the template
107: //and set it as the current condition
108: else if (row > (ruleTableRow) && column == ruleTableColumn) {
109: _currentVerticalCondition = createCondition(value,
110: _verticalCondition);
111: }
112: //Intersection column
113: //Create a new Consequence
114: else if (row > (ruleTableRow) && column > ruleTableColumn) {
115: createRule(row, column, value);
116: }
117: }
118:
119: private void createRule(final int row, final int column,
120: final String value) {
121: final Consequence consequence = createConsequence(value);
122:
123: Rule rule = firstRule;
124: if (rule == null) {
125: rule = new Rule("rule_" + row + "_" + column, null, row);
126: addRule(rule);
127: } else {
128: firstRule = null;
129: rule.setName("rule_" + row + "_" + column);
130: }
131: rule.setAgendaGroup(this ._currentAgendaGroup);
132: rule.addCondition(this ._currentPrecondition);
133: rule.addCondition(_currentVerticalCondition);
134: rule.addCondition((Condition) _horizontalConditions.get(column
135: - (ruleTableColumn + 1)));
136: rule.addConsequence(consequence);
137: }
138:
139: private Consequence createConsequence(final String value) {
140: final SnippetBuilder snip = new SnippetBuilder(_action);
141: final String result = snip.build(value);
142: final Consequence consequence = new Consequence();
143: consequence.setSnippet(result);
144: return consequence;
145: }
146:
147: private Condition createCondition(final String value,
148: final String conditionTemplate) {
149: SnippetBuilder snip = new SnippetBuilder(conditionTemplate);
150: String result = snip.build(value);
151: Condition condition = new Condition();
152: condition.setSnippet(result);
153: return condition;
154: }
155:
156: public void newRow(int rowNumber, int columns) {
157: // nothing to do here
158: }
159:
160: public void finishSheet() {
161: // nothing to do here
162: }
163:
164: protected void postInitRuleTable(int row, int column, String value) {
165: this .firstRule = getCurrentRule();
166: }
167:
168: /**
169: * This gets called each time a "new" rule table is found.
170: */
171: protected void preInitRuleTable(final int row, final int column,
172: final String value) {
173: this .ruleTableColumn = column;
174: this .ruleTableRow = row;
175: this .isInRuleTable = true;
176: this ._currentAgendaGroup = getProperties().getProperty(
177: AGENDAGROUP_TAG, null);
178: this ._action = getProperties().getProperty(ACTION_TAG);
179: this ._horizontalCondition = getProperties().getProperty(
180: HORIZONTALCONDITION_TAG);
181: this ._verticalCondition = getProperties().getProperty(
182: VERTICALCONDITION_TAG);
183: String precondition = getProperties().getProperty(
184: PRECONDITION_TAG, null);
185: if (precondition != null) {
186: this ._currentPrecondition = new Condition();
187: this._currentPrecondition.setSnippet(precondition);
188: }
189: }
190:
191: }
|