/*
* Copyright 2005 Red Hat, Inc. and/or its affiliates.
*
* 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.EnumSet;
import java.util.HashMap;
import java.util.Map;
import org.drools.template.parser.DecisionTableParseException;
/**
* Simple holder class identifying a condition, action or attribute column, also
* including the rule name and a comment (called "description").
* Its objects are stored in a map in the main listener class, to track what type of values
* you can expect to see in the rows directly below the column header, identified
* by an ActionType.Code.
*/
public class ActionType {
public enum Code {
CONDITION( "CONDITION", "C" ),
ACTION( "ACTION", "A" ),
NAME( "NAME", "N", 1 ),
DESCRIPTION( "DESCRIPTION", "I" ),
SALIENCE( "PRIORITY", "P", 1 ),
DURATION( "DURATION", "D", 1 ),
TIMER( "TIMER", "T", 1 ),
ENABLED( "ENABLED", "B", 1 ),
CALENDARS( "CALENDARS", "E", 1 ),
NOLOOP( "NO-LOOP", "U", 1 ),
LOCKONACTIVE( "LOCK-ON-ACTIVE", "L", 1 ),
AUTOFOCUS( "AUTO-FOCUS", "F", 1 ),
ACTIVATIONGROUP( "ACTIVATION-GROUP", "X", 1 ),
AGENDAGROUP( "AGENDA-GROUP", "G", 1 ),
RULEFLOWGROUP( "RULEFLOW-GROUP", "R", 1 ),
DATEEFFECTIVE( "DATE-EFFECTIVE", "V", 1 ),
DATEEXPIRES( "DATE-EXPIRES", "Z", 1 ),
METADATA( "METADATA", "@" );
private String colHeader;
private String colShort;
private int maxCount;
/**
* Constructor.
* @param colHeader the column header
* @param colShort a single letter, recognized as initial
* @param maxCount maximum number of permitted columns
*/
Code( String colHeader,
String colShort,
int maxCount ) {
this.colHeader = colHeader;
this.colShort = colShort;
this.maxCount = maxCount;
}
Code( String colHeader,
String colShort ) {
this( colHeader, colShort, Integer.MAX_VALUE );
}
public String getColHeader() {
return colHeader;
}
public String getColShort() {
return colShort;
}
public int getMaxCount() {
return maxCount;
}
}
public static final EnumSet<Code> ATTRIBUTE_CODE_SET = EnumSet.range( Code.SALIENCE, Code.DATEEXPIRES );
private static final Map<String, Code> tag2code = new HashMap<String, Code>();
static {
for ( Code code : EnumSet.allOf( Code.class ) ) {
tag2code.put( code.colHeader, code );
tag2code.put( code.colShort, code );
}
}
private Code code;
private SourceBuilder sourceBuilder = null;
/**
* Constructor.
* @param actionTypeCode code identifying the column
*/
ActionType( Code actionTypeCode ) {
this.code = actionTypeCode;
}
public static EnumSet<Code> getAttributeCodeSet() {
return ATTRIBUTE_CODE_SET;
}
public static Map<String, Code> getTag2code() {
return tag2code;
}
/**
* Retrieves the code.
* @return an enum Code value
*/
public Code getCode() {
return this.code;
}
/**
* This is only set for LHS or RHS building.
*/
public void setSourceBuilder( SourceBuilder src ) {
this.sourceBuilder = src;
}
public SourceBuilder getSourceBuilder() {
return this.sourceBuilder;
}
/**
* Create a new action type that matches this cell, and add it to the map,
* keyed on that column.
*/
public static void addNewActionType( final Map<Integer, ActionType> actionTypeMap,
final String value,
final int column,
final int row ) {
final String ucValue = value.toUpperCase();
Code code = tag2code.get( ucValue );
if ( code == null ) {
code = tag2code.get( ucValue.substring( 0, 1 ) );
}
if ( code != null ) {
int count = 0;
for ( ActionType at : actionTypeMap.values() ) {
if ( at.getCode() == code ) {
count++;
}
}
if ( count >= code.getMaxCount() ) {
throw new DecisionTableParseException( "Maximum number of " +
code.getColHeader() + "/" + code.getColShort() + " columns is " +
code.getMaxCount() + ", in cell " + RuleSheetParserUtil.rc2name( row, column ) );
}
actionTypeMap.put( new Integer( column ), new ActionType( code ) );
} else {
throw new DecisionTableParseException(
"Invalid column header: " + value + ", should be CONDITION, ACTION or attribute, " +
"in cell " + RuleSheetParserUtil.rc2name( row, column ) );
}
}
/**
* This is where a code snippet template is added.
*/
public void addTemplate( int row,
int column,
String content ) {
if ( this.sourceBuilder == null ) {
throw new DecisionTableParseException(
"Unexpected content \"" + content + "\" in cell " +
RuleSheetParserUtil.rc2name( row, column ) + ", leave this cell blank" );
}
this.sourceBuilder.addTemplate( row, column, content );
}
/**
* Values are added to populate the template.
* The source builder contained needs to be "cleared" when the resultant snippet is extracted.
*/
public void addCellValue( int row,
int column,
String content,
boolean _escapeQuotesFlag ) {
if ( _escapeQuotesFlag ) {
//Michael Neale:
// For single standard quotes we escape them - eg they may mean "inches"
// as in "I want a Stonehenge replica 19" tall"
int idx = content.indexOf( "\"" );
if ( idx > 0 && content.indexOf( "\"", idx ) > -1 ) {
content = content.replace( "\"", "\\\"" );
}
}
this.sourceBuilder.addCellValue( row, column, content );
}
}