Package org.drools.workbench.models.guided.template.backend

Source Code of org.drools.workbench.models.guided.template.backend.RuleTemplateModelDRLPersistenceImpl$RHSActionVisitor

/*
* 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.models.guided.template.backend;

import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.drools.core.util.IoUtils;
import org.drools.template.DataProvider;
import org.drools.template.DataProviderCompiler;
import org.drools.template.objects.ArrayDataProvider;
import org.drools.workbench.models.commons.backend.rule.RuleModelDRLPersistenceImpl;
import org.drools.workbench.models.commons.backend.rule.RuleModelPersistence;
import org.drools.workbench.models.commons.backend.rule.context.LHSGeneratorContext;
import org.drools.workbench.models.commons.backend.rule.context.LHSGeneratorContextFactory;
import org.drools.workbench.models.commons.backend.rule.context.RHSGeneratorContext;
import org.drools.workbench.models.commons.backend.rule.context.RHSGeneratorContextFactory;
import org.drools.workbench.models.datamodel.rule.ActionFieldValue;
import org.drools.workbench.models.datamodel.rule.BaseSingleFieldConstraint;
import org.drools.workbench.models.datamodel.rule.CompositeFieldConstraint;
import org.drools.workbench.models.datamodel.rule.ConnectiveConstraint;
import org.drools.workbench.models.datamodel.rule.ExpressionFormLine;
import org.drools.workbench.models.datamodel.rule.FieldConstraint;
import org.drools.workbench.models.datamodel.rule.FieldNatureType;
import org.drools.workbench.models.datamodel.rule.FreeFormLine;
import org.drools.workbench.models.datamodel.rule.FromCollectCompositeFactPattern;
import org.drools.workbench.models.datamodel.rule.IFactPattern;
import org.drools.workbench.models.datamodel.rule.InterpolationVariable;
import org.drools.workbench.models.datamodel.rule.RuleModel;
import org.drools.workbench.models.datamodel.rule.SingleFieldConstraint;
import org.drools.workbench.models.datamodel.rule.builder.DRLConstraintValueBuilder;
import org.drools.workbench.models.guided.template.shared.TemplateModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* This class persists a {@link TemplateModel} to DRL template
*/
public class RuleTemplateModelDRLPersistenceImpl
        extends RuleModelDRLPersistenceImpl {

    private static final Pattern patternTemplateKey = Pattern.compile( "@\\{(.+?)\\}" );

    private static final Logger log = LoggerFactory.getLogger( RuleTemplateModelDRLPersistenceImpl.class );
    private static final RuleModelPersistence INSTANCE = new RuleTemplateModelDRLPersistenceImpl();

    private RuleTemplateModelDRLPersistenceImpl() {
        super();
    }

    public static RuleModelPersistence getInstance() {
        return INSTANCE;
    }

    @Override
    protected LHSPatternVisitor getLHSPatternVisitor( final boolean isDSLEnhanced,
                                                      final StringBuilder buf,
                                                      final String nestedIndentation,
                                                      final boolean isNegated,
                                                      final LHSGeneratorContextFactory generatorContextFactory ) {
        return new LHSPatternVisitor( isDSLEnhanced,
                                      bindingsPatterns,
                                      bindingsFields,
                                      constraintValueBuilder,
                                      generatorContextFactory,
                                      buf,
                                      nestedIndentation,
                                      isNegated );
    }

    @Override
    protected RHSActionVisitor getRHSActionVisitor( final boolean isDSLEnhanced,
                                                    final StringBuilder buf,
                                                    final String indentation,
                                                    final RHSGeneratorContextFactory generatorContextFactory ) {
        return new RHSActionVisitor( isDSLEnhanced,
                                     bindingsPatterns,
                                     bindingsFields,
                                     constraintValueBuilder,
                                     generatorContextFactory,
                                     buf,
                                     indentation );
    }

    public static class LHSPatternVisitor extends RuleModelDRLPersistenceImpl.LHSPatternVisitor {

        public LHSPatternVisitor( final boolean isDSLEnhanced,
                                  final Map<String, IFactPattern> bindingsPatterns,
                                  final Map<String, FieldConstraint> bindingsFields,
                                  final DRLConstraintValueBuilder constraintValueBuilder,
                                  final LHSGeneratorContextFactory generatorContextFactory,
                                  final StringBuilder b,
                                  final String indentation,
                                  final boolean isPatternNegated ) {
            super( isDSLEnhanced,
                   bindingsPatterns,
                   bindingsFields,
                   constraintValueBuilder,
                   generatorContextFactory,
                   b,
                   indentation,
                   isPatternNegated );
        }

        @Override
        public void preGenerateConstraints( LHSGeneratorContext gctx ) {
            buf.append( "@code{hasOutput" + gctx.getDepth() + "_" + gctx.getOffset() + " = false}" );
        }

        @Override
        public void preGenerateNestedConnector( LHSGeneratorContext gctx ) {
            if ( gctx.getVarsInScope().size() > 0 ) {
                buf.append( "@if{(" );
                for ( String var : gctx.getVarsInScope() ) {
                    buf.append( var + " != empty || " );
                }
                buf.delete( buf.length() - 4, buf.length() );

                LHSGeneratorContext parentContext = gctx.getParent();
                if ( parentContext != null ) {
                    Set<String> parentVarsInScope = new HashSet<String>( parentContext.getVarsInScope() );
                    parentVarsInScope.removeAll( gctx.getVarsInScope() );
                    if ( parentVarsInScope.size() > 0 ) {
                        buf.append( ") && !(" );
                        for ( String var : parentVarsInScope ) {
                            buf.append( var + " == empty && " );
                        }
                        buf.delete( buf.length() - 4, buf.length() );
                    }
                }
                buf.append( ") || hasNonTemplateOutput" ).append( gctx.getDepth() + "_" + gctx.getOffset() ).append( "}" );
            } else {
                LHSGeneratorContext parentContext = gctx.getParent();
                if ( parentContext != null ) {
                    Set<String> parentVarsInScope = new HashSet<String>( parentContext.getVarsInScope() );
                    parentVarsInScope.removeAll( gctx.getVarsInScope() );
                    if ( parentVarsInScope.size() > 0 ) {
                        buf.append( "@if{!(" );
                        for ( String var : parentVarsInScope ) {
                            buf.append( var + " == empty || " );
                        }
                        buf.delete( buf.length() - 4, buf.length() );
                        buf.append( ")}" );
                    }
                }
            }
        }

        @Override
        public void postGenerateNestedConnector( LHSGeneratorContext gctx ) {
            if ( gctx.getVarsInScope().size() > 0 ) {
                buf.append( "@end{}" );
            } else {
                LHSGeneratorContext parentContext = gctx.getParent();
                if ( parentContext != null ) {
                    Set<String> parentVarsInScope = new HashSet<String>( parentContext.getVarsInScope() );
                    parentVarsInScope.removeAll( gctx.getVarsInScope() );
                    if ( parentVarsInScope.size() > 0 ) {
                        buf.append( "@end{}" );
                    }
                }
            }
        }

        @Override
        public void preGenerateNestedConstraint( LHSGeneratorContext gctx ) {
            if ( gctx.getVarsInScope().size() > 0 ) {
                buf.append( "@if{!(" );
                for ( String var : gctx.getVarsInScope() ) {
                    buf.append( var + " == empty && " );
                }
                buf.delete( buf.length() - 4, buf.length() );
                buf.append( ") || hasNonTemplateOutput" ).append( gctx.getDepth() + "_" + gctx.getOffset() ).append( "}" );
            }
        }

        @Override
        public void postGenerateNestedConstraint( LHSGeneratorContext gctx ) {
            if ( gctx.getVarsInScope().size() > 0 ) {
                buf.append( "@end{}" );
            }
        }

        @Override
        protected void generateConstraint( final FieldConstraint constr,
                                           LHSGeneratorContext gctx ) {
            boolean generateTemplateCheck = isTemplateKey( constr );

            if ( generateTemplateCheck ) {
                if ( constr instanceof SingleFieldConstraint && ( (SingleFieldConstraint) constr ).getConnectives() != null ) {
                    // if there are connectives, and the first is a template key, then all templates keys must be checked up front
                    // individual connectives, that have template keys, will still need to be checked too.
                    SingleFieldConstraint sconstr = (SingleFieldConstraint) constr;
                    buf.append( "@if{" + ( (SingleFieldConstraint) constr ).getValue() + " != empty" );
                    for ( int j = 0; j < sconstr.getConnectives().length; j++ ) {
                        final ConnectiveConstraint conn = sconstr.getConnectives()[ j ];
                        if ( conn.getConstraintValueType() == BaseSingleFieldConstraint.TYPE_TEMPLATE ) {
                            buf.append( " || " + conn.getValue() + " != empty" );
                        }
                    }
                    buf.append( "}" );
                } else {
                    buf.append( "@if{" + ( (SingleFieldConstraint) constr ).getValue() + " != empty}" );
                }
            }
            super.generateConstraint( constr,
                                      gctx );
            buf.append( "@code{hasOutput" + gctx.getDepth() + "_" + gctx.getOffset() + " = true}" );
            if ( generateTemplateCheck ) {
                buf.append( "@end{}" );
            }
        }

        private boolean isTemplateKey( FieldConstraint nestedConstr ) {
            return nestedConstr instanceof BaseSingleFieldConstraint && ( (BaseSingleFieldConstraint) nestedConstr ).getConstraintValueType() == BaseSingleFieldConstraint.TYPE_TEMPLATE;
        }

        public void generateSeparator( FieldConstraint constr,
                                       LHSGeneratorContext gctx ) {
            if ( !gctx.isHasOutput() ) {
                return;
            }

            boolean generateTemplateCheck = isTemplateKey( constr );
            if ( generateTemplateCheck ) {
                buf.append( "@if{ hasOutput" + gctx.getDepth() + "_" + gctx.getOffset() + "}" );
            }

            preGenerateNestedConnector( gctx );
            if ( gctx.getDepth() == 0 ) {
                buf.append( ", " );
            } else {
                CompositeFieldConstraint cconstr = (CompositeFieldConstraint) gctx.getParent().getFieldConstraint();
                buf.append( cconstr.getCompositeJunctionType() + " " );
            }
            postGenerateNestedConnector( gctx );
            if ( generateTemplateCheck ) {
                buf.append( "@end{}" );
            }
        }

        @Override
        protected void addConnectiveFieldRestriction( final StringBuilder buf,
                                                      final int type,
                                                      final String fieldType,
                                                      String operator,
                                                      final Map<String, String> parameters,
                                                      final String value,
                                                      final ExpressionFormLine expression,
                                                      final LHSGeneratorContext gctx,
                                                      boolean spaceBeforeOperator ) {
            boolean generateTemplateCheck = type == BaseSingleFieldConstraint.TYPE_TEMPLATE;
            if ( generateTemplateCheck ) {
                buf.append( "@if{" + value + " != empty}" );
            }

            if ( generateTemplateCheck && operator.startsWith( "||" ) || operator.startsWith( "&&" ) ) {
                spaceBeforeOperator = false;
                buf.append( "@if{ hasOutput" + gctx.getDepth() + "_" + gctx.getOffset() + "} " );// add space here, due to split operator
                buf.append( operator.substring( 0, 2 ) );
                buf.append( "@end{}" );
                operator = operator.substring( 2 );
            }

            super.addConnectiveFieldRestriction( buf, type, fieldType, operator, parameters, value, expression, gctx, spaceBeforeOperator );

            if ( generateTemplateCheck ) {
                buf.append( "@code{hasOutput" + gctx.getDepth() + "_" + gctx.getOffset() + " = true}" );
                buf.append( "@end{}" );
            }
        }

        @Override
        public void visitFreeFormLine( final FreeFormLine ffl ) {
            if ( ffl.getText() == null ) {
                return;
            }
            final Matcher matcherTemplateKey = patternTemplateKey.matcher( ffl.getText() );
            boolean found = matcherTemplateKey.find();
            if ( found ) {
                buf.append( "@if{" );
                boolean addAnd = false;
                while ( found ) {
                    String varName = matcherTemplateKey.group( 1 );
                    if ( addAnd ) {
                        buf.append( " && " );
                    }
                    buf.append( varName + " != empty" );
                    addAnd = true;
                    found = matcherTemplateKey.find();
                }
                buf.append( "}" );
                super.visitFreeFormLine( ffl );
                buf.append( "@end{}" );
            } else {
                // no variables found
                super.visitFreeFormLine( ffl );
            }
        }

        @Override
        public void visitFromCollectCompositeFactPattern( final FromCollectCompositeFactPattern pattern,
                                                          final boolean isSubPattern ) {

            if ( pattern.getRightPattern() instanceof FreeFormLine ) {
                // this allows MVEL to skip the collect, if any vars are empty
                // note this actually duplicates another inner check for the FFL itself
                // @TODO the FFL should get a reference to the parent, so it can avoid this duplication.
                final FreeFormLine ffl = (FreeFormLine) pattern.getRightPattern();
                if ( ffl.getText() == null ) {
                    return;
                }
                final Matcher matcherTemplateKey = patternTemplateKey.matcher( ffl.getText() );
                boolean found = matcherTemplateKey.find();
                if ( found ) {
                    buf.append( "@if{" );
                    boolean addAnd = false;
                    while ( found ) {
                        String varName = matcherTemplateKey.group( 1 );
                        if ( addAnd ) {
                            buf.append( " && " );
                        }
                        buf.append( varName + " != empty" );
                        addAnd = true;
                        found = matcherTemplateKey.find();
                    }
                    buf.append( "}" );
                    super.visitFromCollectCompositeFactPattern( pattern,
                                                                isSubPattern );
                    buf.append( "@end{}" );
                    found = matcherTemplateKey.find();
                } else {
                    // no variables found
                    super.visitFromCollectCompositeFactPattern( pattern,
                                                                isSubPattern );
                }
            } else {
                super.visitFromCollectCompositeFactPattern( pattern,
                                                            isSubPattern );
            }
        }
    }

    public static class RHSActionVisitor extends RuleModelDRLPersistenceImpl.RHSActionVisitor {

        public RHSActionVisitor( final boolean isDSLEnhanced,
                                 final Map<String, IFactPattern> bindingsPatterns,
                                 final Map<String, FieldConstraint> bindingsFields,
                                 final DRLConstraintValueBuilder constraintValueBuilder,
                                 final RHSGeneratorContextFactory generatorContextFactory,
                                 final StringBuilder b,
                                 final String indentation ) {
            super( isDSLEnhanced,
                   bindingsPatterns,
                   bindingsFields,
                   constraintValueBuilder,
                   generatorContextFactory,
                   b,
                   indentation );
        }

        @Override
        protected void generateSetMethodCall( final String variableName,
                                              final ActionFieldValue fieldValue ) {
            if ( fieldValue.getNature() == FieldNatureType.TYPE_TEMPLATE ) {
                buf.append( "@if{" + fieldValue.getValue() + " != empty}" );
                super.generateSetMethodCall( variableName,
                                             fieldValue );
                buf.append( "@end{}" );
            } else {
                super.generateSetMethodCall( variableName,
                                             fieldValue );

            }
        }

        @Override
        protected void preGenerateSetMethodCallParameterValue( final ActionFieldValue fieldValue,
                                                               final RHSGeneratorContext gctx ) {
            if ( fieldValue.getNature() == FieldNatureType.TYPE_TEMPLATE ) {
                buf.append( "@if{" + fieldValue.getValue() + " != empty}" );
                buf.append( "@code{hasOutput" + gctx.getOffset() + " = true}" );
                super.preGenerateSetMethodCallParameterValue( fieldValue,
                                                              gctx );
                buf.append( "@end{}" );
            } else {
                buf.append( "@code{hasOutput" + gctx.getOffset() + " = true}" );
                super.preGenerateSetMethodCallParameterValue( fieldValue,
                                                              gctx );
            }
        }

        @Override
        protected void generateModifyMethodCall( final RHSGeneratorContext gctx,
                                                 final ActionFieldValue fieldValue ) {
            if ( fieldValue.getNature() == FieldNatureType.TYPE_TEMPLATE ) {
                buf.append( "@if{" + fieldValue.getValue() + " != empty}" );
                super.generateModifyMethodCall( gctx,
                                                fieldValue );
                buf.append( "@end{}" );

            } else {
                super.generateModifyMethodCall( gctx,
                                                fieldValue );
            }
        }

        @Override
        protected void generateModifyMethodSeparator( final RHSGeneratorContext gctx,
                                                      final ActionFieldValue fieldValue ) {
            if ( gctx.getParent() == null ) {
                return;
            }
            buf.append( "@if{hasOutput" + gctx.getOffset() + " && (" );
            RHSGeneratorContext parent = gctx.getParent();
            while ( parent != null ) {
                buf.append( "hasOutput" + parent.getOffset() + ( parent.getParent() != null ? " || " : "" ) );
                parent = parent.getParent();
            }
            buf.append( ")}" );
            buf.append( ", \n" );
            buf.append( "@end{}" );
        }

        @Override
        public void visitFreeFormLine( FreeFormLine ffl ) {
            if ( ffl.getText() == null ) {
                return;
            }
            final Matcher matcherTemplateKey = patternTemplateKey.matcher( ffl.getText() );
            boolean found = matcherTemplateKey.find();
            if ( found ) {
                buf.append( "@if{" );
                boolean addAnd = false;
                while ( found ) {
                    String varName = matcherTemplateKey.group( 1 );
                    if ( addAnd ) {
                        buf.append( " && " );
                    }
                    buf.append( varName + " != empty" );
                    addAnd = true;
                    found = matcherTemplateKey.find();
                }
                buf.append( "}" );
                super.visitFreeFormLine( ffl );
                buf.append( "@end{}" );
            } else {
                // no variables found
                super.visitFreeFormLine( ffl );
            }
        }
    }

    @Override
    public String marshal( final RuleModel model ) {

        //Build rule
        final String ruleTemplate = marshalRule( model );
        log.debug( "ruleTemplate:\n{}",
                   ruleTemplate );

        log.debug( "generated template:\n{}", ruleTemplate );

        final DataProvider dataProvider = chooseDataProvider( model );
        final DataProviderCompiler tplCompiler = new DataProviderCompiler();
        final String generatedDrl = tplCompiler.compile( dataProvider,
                                                         new ByteArrayInputStream( ruleTemplate.getBytes( IoUtils.UTF8_CHARSET ) ),
                                                         false );

        log.debug( "generated drl:\n{}", generatedDrl );

        return generatedDrl;
    }

    @Override
    protected String marshalRule( final RuleModel model ) {
        boolean isDSLEnhanced = model.hasDSLSentences();
        bindingsPatterns = new HashMap<String, IFactPattern>();
        bindingsFields = new HashMap<String, FieldConstraint>();

        fixActionInsertFactBindings( model.rhs );

        StringBuilder buf = new StringBuilder();
        StringBuilder header = new StringBuilder();
        LHSGeneratorContextFactory lhsGeneratorContextFactory = new LHSGeneratorContextFactory();
        RHSGeneratorContextFactory rhsGeneratorContextFactory = new RHSGeneratorContextFactory();

        //Build rule
        this.marshalRuleHeader( model,
                                header );
        super.marshalMetadata( buf,
                               model );
        super.marshalAttributes( buf,
                                 model );

        buf.append( "\twhen\n" );

        super.marshalLHS( buf,
                          model,
                          isDSLEnhanced,
                          lhsGeneratorContextFactory );
        buf.append( "\tthen\n" );
        super.marshalRHS( buf,
                          model,
                          isDSLEnhanced,
                          rhsGeneratorContextFactory );
        this.marshalFooter( buf );

        for ( LHSGeneratorContext gc : lhsGeneratorContextFactory.getGeneratorContexts() ) {
            header.append( "@code{hasNonTemplateOutput" + gc.getDepth() + "_" + gc.getOffset() + " = " + gc.hasNonTemplateOutput() + "}" );
        }
        for ( RHSGeneratorContext gc : rhsGeneratorContextFactory.getGeneratorContexts() ) {
            header.append( "@code{hasOutput" + gc.getOffset() + " = false}" );
        }

        return header.append( buf ).toString();
    }

    private DataProvider chooseDataProvider( final RuleModel model ) {
        DataProvider dataProvider;
        TemplateModel tplModel = (TemplateModel) model;
        if ( tplModel.getRowsCount() > 0 ) {
            dataProvider = new ArrayDataProvider( tplModel.getTableAsArray() );
        } else {
            dataProvider = generateEmptyIterator();
        }
        return dataProvider;
    }

    private DataProvider generateEmptyIterator() {
        return new DataProvider() {

            public boolean hasNext() {
                return false;
            }

            public String[] next() {
                return new String[ 0 ];
            }
        };
    }

    @Override
    protected void marshalRuleHeader( final RuleModel model,
                                      final StringBuilder buf ) {
        //Append Template header
        TemplateModel templateModel = (TemplateModel) model;
        buf.append( "template header\n" );

        InterpolationVariable[] interpolationVariables = templateModel.getInterpolationVariablesList();
        if ( interpolationVariables.length == 0 ) {
            buf.append( "test_var" ).append( '\n' );
        } else {
            for ( InterpolationVariable var : interpolationVariables ) {
                buf.append( var.getVarName() ).append( '\n' );
            }
        }
        buf.append( "\n" );

        //Append Package header
        super.marshalPackageHeader( model,
                                    buf );

        //Append Template definition
        buf.append( "\ntemplate \"" ).append( super.marshalRuleName( templateModel ) ).append( "\"\n\n" );
        super.marshalRuleHeader( model,
                                 buf );
    }

    @Override
    protected String marshalRuleName( final RuleModel model ) {
        return super.marshalRuleName( model ) + "_@{row.rowNumber}";
    }

    @Override
    protected void marshalFooter( final StringBuilder buf ) {
        super.marshalFooter( buf );
        buf.append( "\nend template" );
    }

}
TOP

Related Classes of org.drools.workbench.models.guided.template.backend.RuleTemplateModelDRLPersistenceImpl$RHSActionVisitor

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.