/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2013 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * 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.pentaho.di.trans.steps.rules; import java.io.StringReader; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.drools.KnowledgeBase; import org.drools.KnowledgeBaseFactory; import org.drools.builder.KnowledgeBuilder; import org.drools.builder.KnowledgeBuilderFactory; import org.drools.builder.ResourceType; import org.drools.definition.KnowledgePackage; import org.drools.io.Resource; import org.drools.io.ResourceFactory; import org.drools.runtime.ObjectFilter; import org.drools.runtime.StatefulKnowledgeSession; import org.pentaho.di.core.row.RowMetaInterface; import org.pentaho.di.core.row.ValueMetaInterface; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.trans.step.BaseStepData; import org.pentaho.di.trans.step.StepDataInterface; import org.pentaho.di.trans.steps.rules.Rules.Column; /** * This Transformation Step allows a user to execute a rule set against an individual rule or a collection of rules. * * Additional columns can be added to the output from the rules and these (of course) can be used for routing if * desired. * * @author cboyden * */ public class RulesExecutorData extends BaseStepData implements StepDataInterface { private static Class<?> PKG = RulesExecutor.class; // for i18n purposes private RowMetaInterface outputRowMeta; private KnowledgeBuilder kbuilder; private KnowledgeBase kbase; private Column[] columnList; private Map<String, Column> resultMap = new HashMap<String, Column>(); private String ruleString; public String getRuleString() { return ruleString; } public void setRuleString( String ruleString ) { this.ruleString = ruleString; } public String getRuleFilePath() { return ruleFilePath; } public void setRuleFilePath( String ruleFilePath ) { this.ruleFilePath = ruleFilePath; } private String ruleFilePath; public void setOutputRowMeta( RowMetaInterface outputRowMeta ) { this.outputRowMeta = outputRowMeta; } public RowMetaInterface getOutputRowMeta() { return outputRowMeta; } public void initializeRules() { // To ensure the plugin classloader use for dependency resolution ClassLoader orig = Thread.currentThread().getContextClassLoader(); ClassLoader loader = getClass().getClassLoader(); Thread.currentThread().setContextClassLoader( loader ); Resource ruleSet = null; if ( ruleString != null ) { ruleSet = ResourceFactory.newReaderResource( new StringReader( ruleString ) ); } else { ruleSet = ResourceFactory.newFileResource( ruleFilePath ); } kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.add( ruleSet, ResourceType.DRL ); if ( kbuilder.hasErrors() ) { System.out.println( kbuilder.getErrors().toString() ); throw new RuntimeException( BaseMessages.getString( PKG, "RulesData.Error.CompileDRL" ) ); } Collection<KnowledgePackage> pkgs = kbuilder.getKnowledgePackages(); kbase = KnowledgeBaseFactory.newKnowledgeBase(); // Cache the knowledge base as its creation is intensive kbase.addKnowledgePackages( pkgs ); // reset classloader back to original Thread.currentThread().setContextClassLoader( orig ); } public void initializeColumns( RowMetaInterface inputRowMeta ) { if ( inputRowMeta == null ) { BaseMessages.getString( PKG, "RulesData.InitializeColumns.InputRowMetaIsNull" ); return; } // Create objects for insertion into the rules engine List<ValueMetaInterface> columns = inputRowMeta.getValueMetaList(); // This array must 1-1 match the row[] feteched by getRow() columnList = new Column[columns.size()]; for ( int i = 0; i < columns.size(); i++ ) { ValueMetaInterface column = columns.get( i ); Column c = new Column( true ); c.setName( column.getName() ); c.setType( column.getTypeDesc() ); c.setPayload( null ); columnList[i] = c; } } public void loadRow( Object[] r ) { for ( int i = 0; i < columnList.length; i++ ) { columnList[i].setPayload( r[i] ); } resultMap.clear(); } public void execute() { StatefulKnowledgeSession session = initNewKnowledgeSession(); Collection<Object> oList = fetchColumns( session ); for ( Object o : oList ) { resultMap.put( ( (Column) o ).getName(), (Column) o ); } session.dispose(); } protected StatefulKnowledgeSession initNewKnowledgeSession() { StatefulKnowledgeSession session = kbase.newStatefulKnowledgeSession(); for ( int i = 0; i < columnList.length; i++ ) { session.insert( columnList[i] ); } session.fireAllRules(); return session; } protected Collection<Object> fetchColumns( StatefulKnowledgeSession session ) { Collection<Object> oList = session.getObjects( new ObjectFilter() { @Override public boolean accept( Object o ) { if ( o instanceof Column && !( (Column) o ).isExternalSource() ) { return true; } return false; } } ); return oList; } /** * * @param columnName * Column.payload associated with the result, or null if not found * @return */ public Object fetchResult( String columnName ) { return resultMap.get( columnName ); } public void shutdown() { } }