/* * Copyright 2016 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.core.impl; import java.util.Collection; import java.util.concurrent.atomic.AtomicBoolean; import org.drools.core.SessionConfiguration; import org.drools.core.SessionConfigurationImpl; import org.drools.core.common.DynamicEntryPoint; import org.drools.core.common.InternalAgenda; import org.drools.core.datasources.CursoredDataSource; import org.drools.core.datasources.InternalDataSource; import org.drools.core.event.AgendaEventSupport; import org.drools.core.event.RuleEventListenerSupport; import org.drools.core.event.RuleRuntimeEventSupport; import org.drools.core.rule.EntryPointId; import org.drools.core.ruleunit.RuleUnitDescr; import org.drools.core.ruleunit.RuleUnitFactory; import org.drools.core.ruleunit.RuleUnitGuardSystem; import org.drools.core.ruleunit.RuleUnitsNodeMemories; import org.drools.core.spi.Activation; import org.drools.core.spi.FactHandleFactory; import org.kie.api.KieBase; import org.kie.api.runtime.Environment; import org.kie.api.runtime.Globals; import org.kie.api.runtime.rule.DataSource; import org.kie.api.runtime.rule.RuleUnit; import org.kie.api.runtime.rule.RuleUnitExecutor; public class RuleUnitExecutorSession implements InternalRuleUnitExecutor { private final StatefulKnowledgeSessionImpl session; private RuleUnitGuardSystem ruleUnitGuardSystem; private RuleUnitFactory ruleUnitFactory; private RuleUnit currentRuleUnit; private AtomicBoolean suspended = new AtomicBoolean( false ); public RuleUnitExecutorSession() { session = new StatefulKnowledgeSessionImpl(); initSession(new SessionConfigurationImpl(), EnvironmentFactory.newEnvironment()); session.agendaEventSupport = new AgendaEventSupport(); session.ruleRuntimeEventSupport = new RuleRuntimeEventSupport(); session.ruleEventListenerSupport = new RuleEventListenerSupport(); } public RuleUnitExecutorSession( final long id, boolean initInitFactHandle, final SessionConfiguration config, final Environment environment ) { session = new StatefulKnowledgeSessionImpl(id, null, initInitFactHandle, config, environment); initSession(config, environment); } public RuleUnitExecutorSession( final long id, final FactHandleFactory handleFactory, final long propagationContext, final SessionConfiguration config, final InternalAgenda agenda, final Environment environment ) { session = new StatefulKnowledgeSessionImpl(id, null, handleFactory, propagationContext, config, agenda, environment); initSession(config, environment); } private void initSession(SessionConfiguration config, Environment environment) { session.init(config, environment); session.ruleUnitExecutor = this; } @Override public RuleUnitExecutor bind( KieBase kiebase ) { InternalKnowledgeBase kbase = (InternalKnowledgeBase) kiebase; if (!kbase.hasUnits()) { throw new IllegalStateException( "Cannot create a RuleUnitExecutor against a KieBase without units" ); } session.handleFactory = kbase.newFactHandleFactory(); session.bindRuleBase( kbase, null, false, false ); session.nodeMemories = new RuleUnitsNodeMemories(kbase); DynamicEntryPoint defaultEp = new DynamicEntryPoint( EntryPointId.DEFAULT, session ); session.defaultEntryPoint = defaultEp; defaultEp.bindRuleBase( kbase ); this.ruleUnitGuardSystem = new RuleUnitGuardSystem( this ); return this; } @Override public <T> DataSource<T> newDataSource( String name, T... items ) { DataSource<T> dataSource = new CursoredDataSource( session ); for (T item : items) { dataSource.insert( item ); } getRuleUnitFactory().bindVariable( name, dataSource ); return dataSource; } public int run( Class<? extends RuleUnit> ruleUnitClass ) { return internalRun( getRuleUnitFactory().getOrCreateRuleUnit( this, ruleUnitClass ) ); } public int run( RuleUnit ruleUnit ) { return internalRun( getRuleUnitFactory().injectUnitVariables( this, ruleUnit ) ); } private int internalRun( RuleUnit ruleUnit ) { return internalExecuteUnit( ruleUnit ) + ruleUnitGuardSystem.fireActiveUnits(ruleUnit); } public int internalExecuteUnit( RuleUnit ruleUnit ) { RuleUnitDescr ruDescr = bindRuleUnit( ruleUnit ); try { return session.fireAllRules(); } finally { unbindRuleUnit(ruDescr); } } public void runUntilHalt( Class<? extends RuleUnit> ruleUnitClass ) { runUntilHalt( getRuleUnitFactory().getOrCreateRuleUnit( this, ruleUnitClass ) ); } public void runUntilHalt( RuleUnit ruleUnit ) { bindRuleUnit( ruleUnit ); session.fireUntilHalt(); } @Override public void halt() { session.halt(); unbindRuleUnit(session.kBase.getRuleUnitRegistry().getRuleUnitDescr( currentRuleUnit )); } @Override public RuleUnitDescr switchToRuleUnit( Class<? extends RuleUnit> ruleUnitClass ) { return switchToRuleUnit( getRuleUnitFactory().getOrCreateRuleUnit( this, ruleUnitClass ) ); } @Override public RuleUnitDescr switchToRuleUnit( RuleUnit ruleUnit ) { if (currentRuleUnit != null) { currentRuleUnit.onYield( ruleUnit ); } session.getPropagationList().flush(); return bindRuleUnit( ruleUnit ); } @Override public void guardRuleUnit( Class<? extends RuleUnit> ruleUnitClass, Activation activation) { ruleUnitGuardSystem.registerGuard( getRuleUnitFactory().getOrCreateRuleUnit( this, ruleUnitClass ), activation ); } @Override public void guardRuleUnit( RuleUnit ruleUnit, Activation activation ) { ruleUnitGuardSystem.registerGuard( getRuleUnitFactory().registerUnit( this, ruleUnit ), activation ); } @Override public void cancelActivation( Activation activation ) { ruleUnitGuardSystem.removeActivation( activation ); } private RuleUnitDescr bindRuleUnit( RuleUnit ruleUnit ) { suspended.set( false ); currentRuleUnit = ruleUnit; currentRuleUnit.onStart(); getNodeMemories().bindRuleUnit( session, ruleUnit ); RuleUnitDescr ruDescr = session.kBase.getRuleUnitRegistry().getRuleUnitDescr( ruleUnit ); ruDescr.bindDataSources( session, ruleUnit ); ( (Globals) session.getGlobalResolver() ).setDelegate( new RuleUnitGlobals( ruDescr, ruleUnit ) ); return ruDescr; } private void unbindRuleUnit( RuleUnitDescr ruDescr ) { getNodeMemories().unbindRuleUnit(); ruDescr.unbindDataSources( session, currentRuleUnit ); ( (Globals) session.getGlobalResolver() ).setDelegate( null ); currentRuleUnit.onEnd(); currentRuleUnit = null; suspended.set( true ); } private RuleUnitsNodeMemories getNodeMemories() { return ( (RuleUnitsNodeMemories) session.nodeMemories ); } public RuleUnit getCurrentRuleUnit() { return currentRuleUnit; } public RuleUnitFactory getRuleUnitFactory() { if (ruleUnitFactory == null) { ruleUnitFactory = new RuleUnitFactory(); } return ruleUnitFactory; } @Override public RuleUnitExecutor bindVariable( String name, Object value ) { getRuleUnitFactory().bindVariable( name, value ); if (value instanceof InternalDataSource) { bindDataSource( (InternalDataSource) value ); } return this; } @Override public void bindDataSource(InternalDataSource dataSource) { dataSource.setWorkingMemory( session ); } @Override public void onSuspend() { if (!suspended.getAndSet( true )) { if ( currentRuleUnit != null ) { currentRuleUnit.onSuspend(); } } } @Override public void onResume() { if (suspended.getAndSet( false )) { if ( currentRuleUnit != null ) { currentRuleUnit.onResume(); } } } @Override public void dispose() { session.dispose(); ruleUnitGuardSystem = null; ruleUnitFactory = null; currentRuleUnit = null; } public static class RuleUnitGlobals implements Globals { private final RuleUnitDescr ruDescr; private final RuleUnit ruleUnit; private RuleUnitGlobals( RuleUnitDescr ruDescr, RuleUnit ruleUnit ) { this.ruDescr = ruDescr; this.ruleUnit = ruleUnit; } @Override public Object get( String identifier ) { return ruDescr.getValue( ruleUnit, identifier ); } @Override public void set( String identifier, Object value ) { throw new UnsupportedOperationException(); } @Override public void setDelegate( Globals delegate ) { throw new UnsupportedOperationException(); } @Override public Collection<String> getGlobalKeys() { throw new UnsupportedOperationException(); } } }