/* * Copyright 2005 JBoss Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.drools.decisiontable.parser; import java.util.ArrayList; import java.util.List; import org.drools.core.util.StringUtils; import org.drools.decisiontable.parser.DefaultRuleSheetListener; import org.drools.template.model.Condition; import org.drools.template.model.Consequence; import org.drools.template.model.Rule; import org.drools.template.model.SnippetBuilder; /** * @author <a href="mailto:stevearoonie@gmail.com"> Steven Williams </a><a * href="mailto:michael.neale@gmail.com"> Michael Neale </a> * * Define a ruleset spreadsheet which contains a matrix style decision tables. * * This is an example of a custom RuleSheetListener. It differs from the standard * decision table in the following ways: * - AgendaGroup property so that all rules fall within the same agenda-group * - Precondition property which specifies a condition that is always included * if a rule is being generated * - Action property. Each cell within the decision table causes this action * to be triggered * - HorizontalCondition property. Each column header in the matrix * applies this condition * - VerticalCondition property. Each row header in the matrix applies this * condition * * A table is identifed by a cell beginning with the text "RuleTable". * The cells after RuleTable in the same row identify the Horizontal Conditions. * The cells after RuleTable in the same column identify the Vertical Conditions. * The cells with the matrix identify the actions. * Wherever an action cell exists for a Vertical/Horizontal condition intersection * the following rule is created: * rule "rule_row_col" * agenda-group AgendaGroup * when * Precondition * VerticalCondition * HorizontalCondition * then * Action * end */ public class RuleMatrixSheetListener extends DefaultRuleSheetListener { //keywords public static final String AGENDAGROUP_TAG = "AgendaGroup"; public static final String PRECONDITION_TAG = "Precondition"; public static final String ACTION_TAG = "Action"; public static final String HORIZONTALCONDITION_TAG = "HorizontalCondition"; public static final String VERTICALCONDITION_TAG = "VerticalCondition"; //state machine variables for this parser private int ruleTableRow; private int ruleTableColumn; private String _currentAgendaGroup; private Condition _currentPrecondition; private String _action; private String _horizontalCondition; private String _verticalCondition; private List<Condition> _horizontalConditions = new ArrayList<Condition>(); private Condition _currentVerticalCondition; private boolean isInRuleTable; private Rule firstRule; public void newCell(final int row, final int column, final String value, final int mergedColStart) { // if we aren't in the rule table just use the default handling // (add a property) if ( !isInRuleTable ) { super.newCell( row, column, value, mergedColStart ); return; } // ignore empty cells if ( StringUtils.isEmpty( value ) ) { return; } //Horizontal header column //Create a new condition using HorizontalCondition as the template //and save it for later use if ( row == (ruleTableRow) && column > ruleTableColumn ) { _horizontalConditions.add( createCondition( value, _horizontalCondition ) ); } //Vertical header column //Create a new condition using VerticalCondition as the template //and set it as the current condition else if ( row > (ruleTableRow) && column == ruleTableColumn ) { _currentVerticalCondition = createCondition( value, _verticalCondition ); } //Intersection column //Create a new Consequence else if ( row > (ruleTableRow) && column > ruleTableColumn ) { createRule( row, column, value ); } } private void createRule(final int row, final int column, final String value) { final Consequence consequence = createConsequence( value ); Rule rule = firstRule; if ( rule == null ) { rule = new Rule( "rule_" + row + "_" + column, null, row ); addRule( rule ); } else { firstRule = null; rule.setName( "rule_" + row + "_" + column ); } rule.setAgendaGroup( this._currentAgendaGroup ); rule.addCondition( this._currentPrecondition ); rule.addCondition( _currentVerticalCondition ); rule.addCondition( (Condition) _horizontalConditions.get( column - (ruleTableColumn + 1) ) ); rule.addConsequence( consequence ); } private Consequence createConsequence(final String value) { final SnippetBuilder snip = new SnippetBuilder( _action ); final String result = snip.build( value ); final Consequence consequence = new Consequence(); consequence.setSnippet( result ); return consequence; } private Condition createCondition(final String value, final String conditionTemplate) { SnippetBuilder snip = new SnippetBuilder( conditionTemplate ); String result = snip.build( value ); Condition condition = new Condition(); condition.setSnippet( result ); return condition; } public void newRow(int rowNumber, int columns) { // nothing to do here } public void finishSheet() { // nothing to do here } protected void postInitRuleTable(int row, int column, String value) { this.firstRule = getCurrentRule(); } /** * This gets called each time a "new" rule table is found. */ protected void preInitRuleTable(final int row, final int column, final String value) { this.ruleTableColumn = column; this.ruleTableRow = row; this.isInRuleTable = true; this._currentAgendaGroup = getProperties().getProperty( AGENDAGROUP_TAG, null ); this._action = getProperties().getProperty( ACTION_TAG ); this._horizontalCondition = getProperties().getProperty( HORIZONTALCONDITION_TAG ); this._verticalCondition = getProperties().getProperty( VERTICALCONDITION_TAG ); String precondition = getProperties().getProperty( PRECONDITION_TAG, null ); if ( precondition != null ) { this._currentPrecondition = new Condition(); this._currentPrecondition.setSnippet( precondition ); } } }