Package org.drools.workbench.screens.dtablexls.backend.server.conversion.builders

Source Code of org.drools.workbench.screens.dtablexls.backend.server.conversion.builders.GuidedDecisionTableLHSBuilder

/*
* Copyright 2012 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.workbench.screens.dtablexls.backend.server.conversion.builders;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.drools.decisiontable.parser.ActionType;
import org.drools.decisiontable.parser.RuleSheetParserUtil;
import org.drools.workbench.models.commons.shared.oracle.DataType;
import org.drools.workbench.models.commons.shared.rule.FreeFormLine;
import org.drools.workbench.models.guided.dtable.shared.conversion.ConversionMessageType;
import org.drools.workbench.models.guided.dtable.shared.conversion.ConversionResult;
import org.drools.workbench.models.guided.dtable.shared.model.BRLConditionColumn;
import org.drools.workbench.models.guided.dtable.shared.model.BRLConditionVariableColumn;
import org.drools.workbench.models.guided.dtable.shared.model.DTCellValue52;
import org.drools.workbench.models.guided.dtable.shared.model.GuidedDecisionTable52;
import org.drools.template.model.SnippetBuilder;
import org.drools.template.model.SnippetBuilder.SnippetType;
import org.drools.template.parser.DecisionTableParseException;

/**
* Builder for Condition columns
*/
public class GuidedDecisionTableLHSBuilder
        implements
        HasColumnHeadings,
        GuidedDecisionTableSourceBuilder {

    private final int headerRow;
    private final int headerCol;

    //DRL generation parameters
    private String colDefPrefix;
    private String colDefSuffix;
    private boolean hasPattern;
    private String andop;

    //Operators used to detect whether a template contains an operator or implies "=="
    private static Set<String> operators;

    static {
        operators = new HashSet<String>();
        operators.add( "==" );
        operators.add( "=" );
        operators.add( "!=" );
        operators.add( "<" );
        operators.add( ">" );
        operators.add( "<=" );
        operators.add( ">=" );
        operators.add( "contains" );
        operators.add( "matches" );
        operators.add( "memberOf" );
        operators.add( "str[startsWith]" );
        operators.add( "str[endsWith]" );
        operators.add( "str[length]" );
    }

    private static final Pattern patParFrm = Pattern.compile( "\\(\\s*\\)\\s*from\\b" );
    private static final Pattern patFrm = Pattern.compile( "\\s+from\\s+" );
    private static final Pattern patPar = Pattern.compile( "\\(\\s*\\)" );
    private static final Pattern patEval = Pattern.compile( "\\beval\\s*(?:\\(\\s*\\)\\s*)?$" );

    //Map of column headers, keyed on XLS column index
    private final Map<Integer, String> columnHeaders = new HashMap<Integer, String>();

    //Map of column value parsers, keyed on XLS column index
    private final Map<Integer, ParameterizedValueBuilder> valueBuilders = new HashMap<Integer, ParameterizedValueBuilder>();

    //Utility class to convert XLS parameters to BRLFragment Template keys
    private final ParameterUtilities parameterUtilities;

    private ConversionResult conversionResult;

    public GuidedDecisionTableLHSBuilder( final int row,
                                          final int column,
                                          final String colDefinition,
                                          final ParameterUtilities parameterUtilities,
                                          final ConversionResult conversionResult ) {
        this.headerRow = row;
        this.headerCol = column;
        this.parameterUtilities = parameterUtilities;
        this.conversionResult = conversionResult;
        preProcessColumnDefinition( colDefinition );
    }

    private void preProcessColumnDefinition( final String colDefinition ) {

        //Determine DRL generation parameters
        String colDef = colDefinition == null ? "" : colDefinition;
        if ( "".equals( colDef ) ) {
            colDefPrefix = colDefSuffix = "";
            hasPattern = false;
            andop = "";
            return;
        }
        hasPattern = true;

        // ...eval
        final Matcher matEval = patEval.matcher( colDef );
        if ( matEval.find() ) {
            colDefPrefix = colDef.substring( 0,
                                             matEval.start() ) + "eval(";
            colDefSuffix = ")";
            andop = " && ";
            return;
        }
        andop = ", ";

        // ...(<b> ) from...
        final Matcher matParFrm = patParFrm.matcher( colDef );
        if ( matParFrm.find() ) {
            colDefPrefix = colDef.substring( 0,
                                             matParFrm.start() ) + '(';
            colDefSuffix = ") from" + colDef.substring( matParFrm.end() );
            return;
        }

        // ...from...
        final Matcher matFrm = patFrm.matcher( colDef );
        if ( matFrm.find() ) {
            colDefPrefix = colDef.substring( 0,
                                             matFrm.start() ) + "(";
            colDefSuffix = ") from " + colDef.substring( matFrm.end() );
            return;
        }

        // ...(<b> )...
        Matcher matPar = patPar.matcher( colDef );
        if ( matPar.find() ) {
            colDefPrefix = colDef.substring( 0,
                                             matPar.start() ) + '(';
            colDefSuffix = ")" + colDef.substring( matPar.end() );
            return;
        }

        // <a>
        colDefPrefix = colDef + '(';
        colDefSuffix = ")";

    }

    public void populateDecisionTable( final GuidedDecisionTable52 dtable ) {
        if ( !hasPattern ) {
            //Add separate columns for each ValueBuilder
            addExplicitColumns( dtable );
        } else {
            //Add a single column for all ValueBuilders
            addPatternColumn( dtable );
        }
    }

    //An explicit column does not add constraints to a Pattern. It is does not have a value in the OBJECT row
    private void addExplicitColumns( final GuidedDecisionTable52 dtable ) {

        //Sort column builders by column index to ensure Actions are added in the correct sequence
        final Set<Integer> sortedIndexes = new TreeSet<Integer>( this.valueBuilders.keySet() );

        for ( Integer index : sortedIndexes ) {
            final ParameterizedValueBuilder vb = this.valueBuilders.get( index );
            if ( vb instanceof LiteralValueBuilder ) {
                addLiteralColumn( dtable,
                                  (LiteralValueBuilder) vb,
                                  index );
            } else {
                addBRLFragmentColumn( dtable,
                                      vb,
                                      index );
            }
        }
    }

    private void addLiteralColumn( final GuidedDecisionTable52 dtable,
                                   final LiteralValueBuilder vb,
                                   final int index ) {
        //Create column - Everything is a BRL fragment (for now)
        final BRLConditionColumn column = new BRLConditionColumn();
        final FreeFormLine ffl = new FreeFormLine();
        ffl.setText( vb.getTemplate() );
        column.getDefinition().add( ffl );
        final BRLConditionVariableColumn parameterColumn = new BRLConditionVariableColumn( "",
                                                                                           DataType.TYPE_BOOLEAN );
        column.getChildColumns().add( parameterColumn );
        column.setHeader( this.columnHeaders.get( index ) );
        dtable.getConditions().add( column );

        //Add column data
        final List<List<DTCellValue52>> columnData = vb.getColumnData();
        final int iColIndex = dtable.getExpandedColumns().indexOf( column.getChildColumns().get( 0 ) );
        for ( int iRow = 0; iRow < columnData.size(); iRow++ ) {
            final List<DTCellValue52> rowData = dtable.getData().get( iRow );
            rowData.addAll( iColIndex,
                            columnData.get( iRow ) );
        }

    }

    private void addBRLFragmentColumn( final GuidedDecisionTable52 dtable,
                                       final ParameterizedValueBuilder vb,
                                       final int index ) {
        //Create column - Everything is a BRL fragment (for now)
        final BRLConditionColumn column = new BRLConditionColumn();
        final FreeFormLine ffl = new FreeFormLine();
        ffl.setText( vb.getTemplate() );
        column.getDefinition().add( ffl );

        for ( String parameter : vb.getParameters() ) {
            final BRLConditionVariableColumn parameterColumn = new BRLConditionVariableColumn( parameter,
                                                                                               DataType.TYPE_OBJECT );
            column.getChildColumns().add( parameterColumn );
        }
        column.setHeader( this.columnHeaders.get( index ) );
        dtable.getConditions().add( column );

        //Add column data
        final List<List<DTCellValue52>> columnData = vb.getColumnData();

        //We can use the index of the first child column to add all data
        final int iColIndex = dtable.getExpandedColumns().indexOf( column.getChildColumns().get( 0 ) );
        for ( int iRow = 0; iRow < columnData.size(); iRow++ ) {
            final List<DTCellValue52> rowData = dtable.getData().get( iRow );
            rowData.addAll( iColIndex,
                            columnData.get( iRow ) );
        }
    }

    //A Pattern column adds constraints to a Pattern. It has a value in the OBJECT row
    private void addPatternColumn( final GuidedDecisionTable52 dtable ) {

        //Sort column builders by column index to ensure Actions are added in the correct sequence
        final TreeSet<Integer> sortedIndexes = new TreeSet<Integer>( this.valueBuilders.keySet() );

        //If the Pattern spans multiple columns create a column header
        String columnHeader = this.columnHeaders.get( sortedIndexes.first() );
        if ( sortedIndexes.size() > 1 ) {
            columnHeader = "Converted from cell [" +
                    RuleSheetParserUtil.rc2name( this.headerRow + 1,
                                                 this.headerCol ) + "]";
        }

        //Create column - Everything is a BRL fragment (for now)
        final BRLConditionColumn column = new BRLConditionColumn();
        dtable.getConditions().add( column );

        final FreeFormLine ffl = new FreeFormLine();
        column.getDefinition().add( ffl );

        //DRL prefix
        final StringBuffer drl = new StringBuffer();
        drl.append( this.colDefPrefix );
        String sep = "";

        int dataColumnIndex = 0;
        for ( Integer index : sortedIndexes ) {

            final ParameterizedValueBuilder vb = this.valueBuilders.get( index );

            //DRL fragment
            drl.append( sep ).append( vb.getTemplate() );
            sep = this.andop;

            //Add columns for parameters
            for ( String parameter : vb.getParameters() ) {
                final BRLConditionVariableColumn parameterColumn = new BRLConditionVariableColumn( parameter,
                                                                                                   DataType.TYPE_OBJECT );
                column.getChildColumns().add( parameterColumn );
            }

            //Add column data
            final List<List<DTCellValue52>> columnData = vb.getColumnData();
            final int iColIndex = dtable.getExpandedColumns().indexOf( column.getChildColumns().get( dataColumnIndex ) );
            for ( int iRow = 0; iRow < columnData.size(); iRow++ ) {
                final List<DTCellValue52> rowData = dtable.getData().get( iRow );
                rowData.addAll( iColIndex,
                                columnData.get( iRow ) );
            }
            dataColumnIndex = dataColumnIndex + vb.getParameters().size();
        }

        //DRL suffix
        drl.append( this.colDefSuffix );
        ffl.setText( drl.toString() );

        //Set header after children have been added as it's copied into them
        column.setHeader( columnHeader );
    }

    public void addTemplate( final int row,
                             final int column,
                             final String content ) {
        //Validate column template
        if ( valueBuilders.containsKey( column ) ) {
            final String message = "Internal error: Can't have a code snippet added twice to one spreadsheet column.";
            this.conversionResult.addMessage( message,
                                              ConversionMessageType.ERROR );
            return;
        }

        //Add new template
        final String template = content.trim();
        try {
            this.valueBuilders.put( column,
                                    getValueBuilder( template ) );
        } catch ( DecisionTableParseException pe ) {
            this.conversionResult.addMessage( pe.getMessage(),
                                              ConversionMessageType.WARNING );
        }
    }

    @Override
    public void setColumnHeader( final int column,
                                 final String value ) {
        this.columnHeaders.put( column,
                                value.trim() );
    }

    private ParameterizedValueBuilder getValueBuilder( final String content ) {

        // Work out the type of "template":-
        // age                     ---> SnippetType.SINGLE
        // age ==                  ---> SnippetType.SINGLE
        // age == $param           ---> SnippetType.PARAM
        // age == $1 || age == $2  ---> SnippetType.INDEXED
        // forall{age < $}{,}      ---> SnippetType.FORALL
        String template = content.trim();
        SnippetType type = SnippetBuilder.getType( template );
        if ( type == SnippetType.SINGLE ) {
            type = SnippetType.PARAM;
            boolean hasExplicitOperator = false;
            for ( String op : operators ) {
                if ( template.endsWith( op ) ) {
                    hasExplicitOperator = true;
                    break;
                }
            }
            if ( !hasExplicitOperator ) {
                template = template + " ==";
            }
            template = template + " \"";
            template = template + SnippetBuilder.PARAM_STRING + "\"";
        }

        //Make a ValueBuilder for the template
        switch ( type ) {
            case INDEXED:
                return new IndexedParametersValueBuilder( template,
                                                          parameterUtilities );
            case PARAM:
                return new SingleParameterValueBuilder( template,
                                                        parameterUtilities );
            case SINGLE:
                return new LiteralValueBuilder( template );
        }
        throw new DecisionTableParseException( "SnippetBuilder.SnippetType '" + type.toString() + "' is not supported. The column will not be added." );
    }

    public void addCellValue( final int row,
                              final int column,
                              final String value ) {
        //Add new row to column data
        final ParameterizedValueBuilder vb = this.valueBuilders.get( column );
        if ( vb == null ) {
            final String message = "No code snippet for CONDITION, above cell " +
                    RuleSheetParserUtil.rc2name( this.headerRow + 2,
                                                 this.headerCol );
            this.conversionResult.addMessage( message,
                                              ConversionMessageType.ERROR );
            return;
        }
        vb.addCellValue( row,
                         column,
                         value );
    }

    public ActionType.Code getActionTypeCode() {
        return ActionType.Code.CONDITION;
    }

    public String getResult() {
        throw new UnsupportedOperationException( "GuidedDecisionTableLHSBuilder does not return DRL." );
    }

    public void clearValues() {
        throw new UnsupportedOperationException();
    }

    public boolean hasValues() {
        throw new UnsupportedOperationException();
    }

}
TOP

Related Classes of org.drools.workbench.screens.dtablexls.backend.server.conversion.builders.GuidedDecisionTableLHSBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.