/* * Copyright 2015 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. * * 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.compiler.rule.builder.dialect.mvel; import java.util.HashMap; import java.util.Map; import org.drools.compiler.Person; import org.drools.compiler.builder.impl.KnowledgeBuilderImpl; import org.drools.compiler.compiler.DialectCompiletimeRegistry; import org.drools.compiler.lang.descr.AttributeDescr; import org.drools.compiler.lang.descr.RuleDescr; import org.drools.compiler.rule.builder.RuleBuildContext; import org.drools.compiler.rule.builder.SalienceBuilder; import org.drools.core.WorkingMemory; import org.drools.core.base.ClassObjectType; import org.drools.core.base.DefaultKnowledgeHelper; import org.drools.core.base.mvel.MVELSalienceExpression; import org.drools.core.common.AgendaItem; import org.drools.core.common.AgendaItemImpl; import org.drools.core.common.InternalFactHandle; import org.drools.core.definitions.InternalKnowledgePackage; import org.drools.core.definitions.impl.KnowledgePackageImpl; import org.drools.core.impl.InternalKnowledgeBase; import org.drools.core.impl.KnowledgeBaseFactory; import org.drools.core.impl.StatefulKnowledgeSessionImpl; import org.drools.core.reteoo.LeftTupleImpl; import org.drools.core.reteoo.RuleTerminalNode; import org.drools.core.rule.Declaration; import org.drools.core.rule.MVELDialectRuntimeData; import org.drools.core.rule.Pattern; import org.drools.core.spi.ObjectType; import org.drools.core.spi.PatternExtractor; import org.drools.core.spi.Salience; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.kie.api.definition.rule.Rule; import static org.junit.jupiter.api.Assertions.assertEquals; public class MVELSalienceBuilderTest { private RuleBuildContext context; private InternalKnowledgeBase kBase ; @BeforeEach public void setUp() throws Exception { InternalKnowledgePackage pkg = new KnowledgePackageImpl( "pkg1" ); final RuleDescr ruleDescr = new RuleDescr( "rule 1" ); ruleDescr.addAttribute( new AttributeDescr( "salience", "(p.age + 20)/2" ) ); ruleDescr.setConsequence( "" ); KnowledgeBuilderImpl pkgBuilder = new KnowledgeBuilderImpl( pkg ); DialectCompiletimeRegistry dialectRegistry = pkgBuilder.getPackageRegistry( pkg.getName() ).getDialectCompiletimeRegistry(); MVELDialect mvelDialect = (MVELDialect) dialectRegistry.getDialect( "mvel" ); context = new RuleBuildContext( pkgBuilder, ruleDescr, dialectRegistry, pkg, mvelDialect ); final InstrumentedDeclarationScopeResolver declarationResolver = new InstrumentedDeclarationScopeResolver(); final ObjectType personObjeectType = new ClassObjectType( Person.class ); final Pattern pattern = new Pattern( 0, personObjeectType ); final PatternExtractor extractor = new PatternExtractor( personObjeectType ); final Declaration declaration = new Declaration( "p", extractor, pattern ); final Map<String, Declaration> map = new HashMap<String, Declaration>(); map.put( "p", declaration ); declarationResolver.setDeclarations( map ); context.setDeclarationResolver( declarationResolver ); kBase = KnowledgeBaseFactory.newKnowledgeBase(); SalienceBuilder salienceBuilder = new MVELSalienceBuilder(); salienceBuilder.build( context ); ((MVELSalienceExpression) context.getRule().getSalience()).compile( (MVELDialectRuntimeData) context.getPkg().getDialectRuntimeRegistry().getDialectData( "mvel" ) ); } @Test public void testSimpleExpression() { StatefulKnowledgeSessionImpl ksession = (StatefulKnowledgeSessionImpl)kBase.newKieSession(); final Person p = new Person( "mark", "", 31 ); final InternalFactHandle f0 = (InternalFactHandle) ksession.insert( p ); final LeftTupleImpl tuple = new LeftTupleImpl( f0, null, true ); RuleTerminalNode rtn = new RuleTerminalNode(); rtn.setSalienceDeclarations( context.getDeclarationResolver().getDeclarations( context.getRule() ).values().toArray( new Declaration[1] ) ); AgendaItem item = new AgendaItemImpl(0, tuple, 0, null, rtn, null); assertEquals( 25, context.getRule().getSalience().getValue( new DefaultKnowledgeHelper( item, ksession ), context.getRule(), ksession ) ); } @Test public void testMultithreadSalienceExpression() { final int tcount = 10; final SalienceEvaluator[] evals = new SalienceEvaluator[tcount]; final Thread[] threads = new Thread[tcount]; for ( int i = 0; i < evals.length; i++ ) { evals[i] = new SalienceEvaluator( kBase, context, context.getRule(), context.getRule().getSalience(), new Person( "bob" + i, 30 + (i * 3) ) ); threads[i] = new Thread( evals[i] ); } for ( int i = 0; i < threads.length; i++ ) { threads[i].start(); } for ( int i = 0; i < threads.length; i++ ) { try { threads[i].join(); } catch ( InterruptedException e ) { e.printStackTrace(); } } int errors = 0; for ( int i = 0; i < evals.length; i++ ) { if ( evals[i].isError() ) { errors++; } } assertEquals( 0, errors, "There shouldn't be any threads in error: "); } public static class SalienceEvaluator implements Runnable { public static final int iterations = 1000; private Salience salience; private Rule rule; private LeftTupleImpl tuple; private WorkingMemory wm; private final int result; private transient boolean halt; private RuleBuildContext context; private AgendaItem item; private boolean error; public SalienceEvaluator(InternalKnowledgeBase kBase, RuleBuildContext context, Rule rule, Salience salience, Person person) { wm = ((StatefulKnowledgeSessionImpl)kBase.newKieSession()); this.context = context; final InternalFactHandle f0 = (InternalFactHandle) wm.insert( person ); tuple = new LeftTupleImpl( f0, null, true ); this.salience = salience; this.halt = false; this.error = false; this.result = (person.getAge() + 20) / 2; RuleTerminalNode rtn = new RuleTerminalNode(); rtn.setSalienceDeclarations( context.getDeclarationResolver().getDeclarations( context.getRule() ).values().toArray( new Declaration[1] ) ); item = new AgendaItemImpl(0, tuple, 0, null, rtn, null); } public void run() { try { Thread.sleep( 1000 ); for ( int i = 0; i < iterations && !halt; i++ ) { assertEquals( result, salience.getValue( new DefaultKnowledgeHelper( item, wm ), rule, wm ) ); Thread.currentThread().yield(); } } catch ( Throwable e ) { e.printStackTrace(); this.error = true; } } public void halt() { this.halt = true; } public boolean isError() { return error; } public void setError(boolean error) { this.error = error; } } }