/** * Copyright 2010 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; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import org.drools.builder.conf.ClassLoaderCacheOption; import org.drools.common.AgendaGroupFactory; import org.drools.common.ArrayAgendaGroupFactory; import org.drools.common.PriorityQueueAgendaGroupFactory; import org.drools.concurrent.DefaultExecutorService; import org.drools.conf.AlphaThresholdOption; import org.drools.conf.AssertBehaviorOption; import org.drools.conf.CompositeKeyDepthOption; import org.drools.conf.ConsequenceExceptionHandlerOption; import org.drools.conf.EventProcessingOption; import org.drools.conf.IndexLeftBetaMemoryOption; import org.drools.conf.IndexRightBetaMemoryOption; import org.drools.conf.KnowledgeBaseOption; import org.drools.conf.LogicalOverrideOption; import org.drools.conf.MBeansOption; import org.drools.conf.MaintainTMSOption; import org.drools.conf.MaxThreadsOption; import org.drools.conf.MultiValueKnowledgeBaseOption; import org.drools.conf.MultithreadEvaluationOption; import org.drools.conf.RemoveIdentitiesOption; import org.drools.conf.SequentialAgendaOption; import org.drools.conf.SequentialOption; import org.drools.conf.ShareAlphaNodesOption; import org.drools.conf.ShareBetaNodesOption; import org.drools.conf.SingleValueKnowledgeBaseOption; import org.drools.conflict.DepthConflictResolver; import org.drools.core.util.ConfFileUtils; import org.drools.core.util.StringUtils; import org.drools.runtime.rule.ConsequenceExceptionHandler; import org.drools.runtime.rule.impl.DefaultConsequenceExceptionHandler; import org.drools.spi.ConflictResolver; import org.drools.util.ChainedProperties; import org.drools.util.ClassLoaderUtil; import org.drools.util.CompositeClassLoader; import org.mvel2.MVEL; /** * RuleBaseConfiguration * * A class to store RuleBase related configuration. It must be used at rule base instantiation time * or not used at all. * This class will automatically load default values from system properties, so if you want to set * a default configuration value for all your new rule bases, you can simply set the property as * a System property. * * After RuleBase is created, it makes the configuration immutable and there is no way to make it * mutable again. This is to avoid inconsistent behavior inside rulebase. * * NOTE: This API is under review and may change in the future. */ /** * Available configuration options: * <pre> * drools.maintainTms = <true|false> * drools.sequential = <true|false> * drools.sequential.agenda = <sequential|dynamic> * drools.removeIdentities = <true|false> * drools.shareAlphaNodes = <true|false> * drools.shareBetaNodes = <true|false> * drools.alphaNodeHashingThreshold = <1...n> * drools.compositeKeyDepth =<1..3> * drools.indexLeftBetaMemory = <true/false> * drools.indexRightBetaMemory = <true/false> * drools.assertBehaviour = <identity|equality> * drools.logicalOverride = <discard|preserve> * drools.executorService = <qualified class name> * drools.conflictResolver = <qualified class name> * drools.consequenceExceptionHandler = <qualified class name> * drools.ruleBaseUpdateHandler = <qualified class name> * drools.sessionClock = <qualified class name> * drools.maxThreads = <-1|1..n> * drools.multithreadEvaluation = <true|false> * drools.mbeans = <enabled|disabled> * drools.classLoaderCacheEnabled = <true|false> * </pre> */ public class RuleBaseConfiguration implements KnowledgeBaseConfiguration, Externalizable { private static final long serialVersionUID = 510l; public static final String DEFAULT_SIGN_ON_SERIALIZATION = "false"; private ChainedProperties chainedProperties; private boolean immutable; private boolean sequential; private SequentialAgenda sequentialAgenda; private boolean maintainTms; private boolean removeIdentities; private boolean shareAlphaNodes; private boolean shareBetaNodes; private int alphaNodeHashingThreshold; private int compositeKeyDepth; private boolean indexLeftBetaMemory; private boolean indexRightBetaMemory; private AssertBehaviour assertBehaviour; private LogicalOverride logicalOverride; private String executorService; private String consequenceExceptionHandler; private String ruleBaseUpdateHandler; private boolean classLoaderCacheEnabled; private EventProcessingOption eventProcessingMode; // if "true", rulebase builder will try to split // the rulebase into multiple partitions that can be evaluated // in parallel by using multiple internal threads private boolean multithread; private int maxThreads; // this property activates MBean monitoring and management private boolean mbeansEnabled; private ConflictResolver conflictResolver; private List<Map<String, Object>> workDefinitions; private boolean advancedProcessRuleIntegration; private transient CompositeClassLoader classLoader; public void writeExternal(ObjectOutput out) throws IOException { out.writeObject( chainedProperties ); out.writeBoolean( immutable ); out.writeBoolean( sequential ); out.writeObject( sequentialAgenda ); out.writeBoolean( maintainTms ); out.writeBoolean( removeIdentities ); out.writeBoolean( shareAlphaNodes ); out.writeBoolean( shareBetaNodes ); out.writeInt( alphaNodeHashingThreshold ); out.writeInt( compositeKeyDepth ); out.writeBoolean( indexLeftBetaMemory ); out.writeBoolean( indexRightBetaMemory ); out.writeObject( assertBehaviour ); out.writeObject( logicalOverride ); out.writeObject( executorService ); out.writeObject( consequenceExceptionHandler ); out.writeObject( ruleBaseUpdateHandler ); out.writeObject( conflictResolver ); out.writeBoolean( advancedProcessRuleIntegration ); out.writeBoolean( multithread ); out.writeInt( maxThreads ); out.writeObject( eventProcessingMode ); out.writeBoolean( classLoaderCacheEnabled ); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { chainedProperties = (ChainedProperties) in.readObject(); immutable = in.readBoolean(); sequential = in.readBoolean(); sequentialAgenda = (SequentialAgenda) in.readObject(); maintainTms = in.readBoolean(); removeIdentities = in.readBoolean(); shareAlphaNodes = in.readBoolean(); shareBetaNodes = in.readBoolean(); alphaNodeHashingThreshold = in.readInt(); compositeKeyDepth = in.readInt(); indexLeftBetaMemory = in.readBoolean(); indexRightBetaMemory = in.readBoolean(); assertBehaviour = (AssertBehaviour) in.readObject(); logicalOverride = (LogicalOverride) in.readObject(); executorService = (String) in.readObject(); consequenceExceptionHandler = (String) in.readObject(); ruleBaseUpdateHandler = (String) in.readObject(); conflictResolver = (ConflictResolver) in.readObject(); advancedProcessRuleIntegration = in.readBoolean(); multithread = in.readBoolean(); maxThreads = in.readInt(); eventProcessingMode = (EventProcessingOption) in.readObject(); classLoaderCacheEnabled = in.readBoolean(); } /** * Creates a new rulebase configuration using the provided properties * as configuration options. Also, if a Thread.currentThread().getContextClassLoader() * returns a non-null class loader, it will be used as the parent classloader * for this rulebase class loaders, otherwise, the RuleBaseConfiguration.class.getClassLoader() * class loader will be used. * * @param properties */ public RuleBaseConfiguration(Properties properties) { init( properties, null ); } /** * Creates a new rulebase with a default parent class loader set according * to the following algorithm: * * If a Thread.currentThread().getContextClassLoader() returns a non-null class loader, * it will be used as the parent class loader for this rulebase class loaders, otherwise, * the RuleBaseConfiguration.class.getClassLoader() class loader will be used. * */ public RuleBaseConfiguration() { init( null, null ); } /** * A constructor that sets the parent classloader to be used * while dealing with this rule base * * @param classLoader */ public RuleBaseConfiguration(ClassLoader... classLoaders) { init( null, classLoaders ); } public void setProperty(String name, String value) { name = name.trim(); if ( StringUtils.isEmpty( name ) ) { return; } if ( name.equals( SequentialAgendaOption.PROPERTY_NAME ) ) { setSequentialAgenda( SequentialAgenda.determineSequentialAgenda( StringUtils.isEmpty( value ) ? "sequential" : value ) ); } else if ( name.equals( SequentialOption.PROPERTY_NAME ) ) { setSequential( StringUtils.isEmpty( value ) ? false : Boolean.valueOf( value ) ); } else if ( name.equals( MaintainTMSOption.PROPERTY_NAME ) ) { setMaintainTms( StringUtils.isEmpty( value ) ? false : Boolean.valueOf( value ) ); } else if ( name.equals( RemoveIdentitiesOption.PROPERTY_NAME ) ) { setRemoveIdentities( StringUtils.isEmpty( value ) ? false : Boolean.valueOf( value ) ); } else if ( name.equals( ShareAlphaNodesOption.PROPERTY_NAME ) ) { setShareAlphaNodes( StringUtils.isEmpty( value ) ? false : Boolean.valueOf( value ) ); } else if ( name.equals( ShareBetaNodesOption.PROPERTY_NAME ) ) { setShareBetaNodes( StringUtils.isEmpty( value ) ? false : Boolean.valueOf( value ) ); } else if ( name.equals( AlphaThresholdOption.PROPERTY_NAME ) ) { setAlphaNodeHashingThreshold( StringUtils.isEmpty( value ) ? 3 : Integer.parseInt( value ) ); } else if ( name.equals( CompositeKeyDepthOption.PROPERTY_NAME ) ) { setCompositeKeyDepth( StringUtils.isEmpty( value ) ? 3 : Integer.parseInt( value ) ); } else if ( name.equals( IndexLeftBetaMemoryOption.PROPERTY_NAME ) ) { setIndexLeftBetaMemory( StringUtils.isEmpty( value ) ? true : Boolean.valueOf( value ) ); } else if ( name.equals( IndexRightBetaMemoryOption.PROPERTY_NAME ) ) { setIndexRightBetaMemory( StringUtils.isEmpty( value ) ? true : Boolean.valueOf( value ) ); } else if ( name.equals( AssertBehaviorOption.PROPERTY_NAME ) ) { setAssertBehaviour( AssertBehaviour.determineAssertBehaviour( StringUtils.isEmpty( value ) ? "identity" : value ) ); } else if ( name.equals( LogicalOverrideOption.PROPERTY_NAME ) ) { setLogicalOverride( LogicalOverride.determineLogicalOverride( StringUtils.isEmpty( value ) ? "discard" : value ) ); } else if ( name.equals( "drools.executorService" ) ) { setExecutorService( StringUtils.isEmpty( value ) ? DefaultExecutorService.class.getName() : value ); } else if ( name.equals( ConsequenceExceptionHandlerOption.PROPERTY_NAME ) ) { setConsequenceExceptionHandler( StringUtils.isEmpty( value ) ? DefaultConsequenceExceptionHandler.class.getName() : value ); } else if ( name.equals( "drools.ruleBaseUpdateHandler" ) ) { setRuleBaseUpdateHandler( StringUtils.isEmpty( value ) ? "" : value ); } else if ( name.equals( "drools.conflictResolver" ) ) { setConflictResolver( determineConflictResolver( StringUtils.isEmpty( value ) ? DepthConflictResolver.class.getName() : value ) ); } else if ( name.equals( "drools.advancedProcessRuleIntegration" ) ) { setAdvancedProcessRuleIntegration( StringUtils.isEmpty( value ) ? false : Boolean.valueOf( value ) ); } else if ( name.equals( MultithreadEvaluationOption.PROPERTY_NAME ) ) { setMultithreadEvaluation( StringUtils.isEmpty( value ) ? false : Boolean.valueOf( value ) ); } else if ( name.equals( MaxThreadsOption.PROPERTY_NAME ) ) { setMaxThreads( StringUtils.isEmpty( value ) ? 3 : Integer.parseInt( value ) ); } else if ( name.equals( EventProcessingOption.PROPERTY_NAME ) ) { setEventProcessingMode( EventProcessingOption.determineEventProcessingMode( StringUtils.isEmpty( value ) ? "cloud" : value ) ); } else if ( name.equals( MBeansOption.PROPERTY_NAME ) ) { setMBeansEnabled( MBeansOption.isEnabled( value ) ); } else if ( name.equals( ClassLoaderCacheOption.PROPERTY_NAME ) ) { setClassLoaderCacheEnabled( StringUtils.isEmpty( value ) ? true : Boolean.valueOf( value ) ); } } public String getProperty(String name) { name = name.trim(); if ( StringUtils.isEmpty( name ) ) { return null; } if ( name.equals( SequentialAgendaOption.PROPERTY_NAME ) ) { return getSequentialAgenda().toExternalForm(); } else if ( name.equals( SequentialOption.PROPERTY_NAME ) ) { return Boolean.toString( isSequential() ); } else if ( name.equals( MaintainTMSOption.PROPERTY_NAME ) ) { return Boolean.toString( isMaintainTms() ); } else if ( name.equals( RemoveIdentitiesOption.PROPERTY_NAME ) ) { return Boolean.toString( isRemoveIdentities() ); } else if ( name.equals( ShareAlphaNodesOption.PROPERTY_NAME ) ) { return Boolean.toString( isShareAlphaNodes() ); } else if ( name.equals( ShareBetaNodesOption.PROPERTY_NAME ) ) { return Boolean.toString( isShareBetaNodes() ); } else if ( name.equals( AlphaThresholdOption.PROPERTY_NAME ) ) { return Integer.toString( getAlphaNodeHashingThreshold() ); } else if ( name.equals( CompositeKeyDepthOption.PROPERTY_NAME ) ) { return Integer.toString( getCompositeKeyDepth() ); } else if ( name.equals( IndexLeftBetaMemoryOption.PROPERTY_NAME ) ) { return Boolean.toString( isIndexLeftBetaMemory() ); } else if ( name.equals( IndexRightBetaMemoryOption.PROPERTY_NAME ) ) { return Boolean.toString( isIndexRightBetaMemory() ); } else if ( name.equals( AssertBehaviorOption.PROPERTY_NAME ) ) { return getAssertBehaviour().toExternalForm(); } else if ( name.equals( "drools.logicalOverride" ) ) { return getLogicalOverride().toExternalForm(); } else if ( name.equals( "drools.executorService" ) ) { return getExecutorService(); } else if ( name.equals( ConsequenceExceptionHandlerOption.PROPERTY_NAME ) ) { return getConsequenceExceptionHandler(); } else if ( name.equals( "drools.ruleBaseUpdateHandler" ) ) { return getRuleBaseUpdateHandler(); } else if ( name.equals( "drools.conflictResolver" ) ) { return getConflictResolver().getClass().getName(); } else if ( name.equals( "drools.advancedProcessRuleIntegration" ) ) { return Boolean.toString( isAdvancedProcessRuleIntegration() ); } else if ( name.equals( MultithreadEvaluationOption.PROPERTY_NAME ) ) { return Boolean.toString( isMultithreadEvaluation() ); } else if ( name.equals( MaxThreadsOption.PROPERTY_NAME ) ) { return Integer.toString( getMaxThreads() ); } else if ( name.equals( EventProcessingOption.PROPERTY_NAME ) ) { return getEventProcessingMode().getMode(); } else if ( name.equals( MBeansOption.PROPERTY_NAME ) ) { return isMBeansEnabled() ? "enabled" : "disabled"; } else if ( name.equals( ClassLoaderCacheOption.PROPERTY_NAME ) ) { return Boolean.toString( isClassLoaderCacheEnabled() ); } return null; } /** * A constructor that sets the classloader to be used as the parent classloader * of this rule base classloaders, and the properties to be used * as base configuration options * * @param classLoder * @param properties */ public RuleBaseConfiguration(Properties properties, ClassLoader... classLoaders) { init( properties, classLoaders ); } private void init(Properties properties, ClassLoader... classLoaders) { this.immutable = false; setClassLoader( classLoaders ); this.chainedProperties = new ChainedProperties( "rulebase.conf", this.classLoader, true ); if ( properties != null ) { this.chainedProperties.addProperties( properties ); } setSequentialAgenda( SequentialAgenda.determineSequentialAgenda( this.chainedProperties.getProperty( SequentialAgendaOption.PROPERTY_NAME, "sequential" ) ) ); setSequential( Boolean.valueOf( this.chainedProperties.getProperty( SequentialOption.PROPERTY_NAME, "false" ) ).booleanValue() ); setMaintainTms( Boolean.valueOf( this.chainedProperties.getProperty( MaintainTMSOption.PROPERTY_NAME, "true" ) ).booleanValue() ); setRemoveIdentities( Boolean.valueOf( this.chainedProperties.getProperty( "drools.removeIdentities", "false" ) ).booleanValue() ); setShareAlphaNodes( Boolean.valueOf( this.chainedProperties.getProperty( ShareAlphaNodesOption.PROPERTY_NAME, "true" ) ).booleanValue() ); setShareBetaNodes( Boolean.valueOf( this.chainedProperties.getProperty( ShareBetaNodesOption.PROPERTY_NAME, "true" ) ).booleanValue() ); setAlphaNodeHashingThreshold( Integer.parseInt( this.chainedProperties.getProperty( AlphaThresholdOption.PROPERTY_NAME, "3" ) ) ); setCompositeKeyDepth( Integer.parseInt( this.chainedProperties.getProperty( CompositeKeyDepthOption.PROPERTY_NAME, "3" ) ) ); setIndexLeftBetaMemory( Boolean.valueOf( this.chainedProperties.getProperty( IndexLeftBetaMemoryOption.PROPERTY_NAME, "true" ) ).booleanValue() ); setIndexRightBetaMemory( Boolean.valueOf( this.chainedProperties.getProperty( IndexRightBetaMemoryOption.PROPERTY_NAME, "true" ) ).booleanValue() ); setAssertBehaviour( AssertBehaviour.determineAssertBehaviour( this.chainedProperties.getProperty( AssertBehaviorOption.PROPERTY_NAME, "identity" ) ) ); setLogicalOverride( LogicalOverride.determineLogicalOverride( this.chainedProperties.getProperty( "drools.logicalOverride", "discard" ) ) ); setExecutorService( this.chainedProperties.getProperty( "drools.executorService", "org.drools.concurrent.DefaultExecutorService" ) ); setConsequenceExceptionHandler( this.chainedProperties.getProperty( ConsequenceExceptionHandlerOption.PROPERTY_NAME, "org.drools.runtime.rule.impl.DefaultConsequenceExceptionHandler" ) ); setRuleBaseUpdateHandler( this.chainedProperties.getProperty( "drools.ruleBaseUpdateHandler", "" ) ); setConflictResolver( determineConflictResolver( this.chainedProperties.getProperty( "drools.conflictResolver", "org.drools.conflict.DepthConflictResolver" ) ) ); setAdvancedProcessRuleIntegration( Boolean.valueOf( this.chainedProperties.getProperty( "drools.advancedProcessRuleIntegration", "false" ) ).booleanValue() ); setMultithreadEvaluation( Boolean.valueOf( this.chainedProperties.getProperty( MultithreadEvaluationOption.PROPERTY_NAME, "false" ) ).booleanValue() ); setMaxThreads( Integer.parseInt( this.chainedProperties.getProperty( MaxThreadsOption.PROPERTY_NAME, "3" ) ) ); setEventProcessingMode( EventProcessingOption.determineEventProcessingMode( this.chainedProperties.getProperty( EventProcessingOption.PROPERTY_NAME, "cloud" ) ) ); setMBeansEnabled( MBeansOption.isEnabled( this.chainedProperties.getProperty( MBeansOption.PROPERTY_NAME, "disabled" ) ) ); setClassLoaderCacheEnabled( Boolean.valueOf( this.chainedProperties.getProperty( ClassLoaderCacheOption.PROPERTY_NAME, "true" ) ) ); } /** * Makes the configuration object immutable. Once it becomes immutable, * there is no way to make it mutable again. * This is done to keep consistency. */ public void makeImmutable() { this.immutable = true; } /** * Returns true if this configuration object is immutable or false otherwise. * @return */ public boolean isImmutable() { return this.immutable; } private void checkCanChange() { if ( this.immutable ) { throw new UnsupportedOperationException( "Can't set a property after configuration becomes immutable" ); } } public void setSequential(boolean sequential) { this.sequential = sequential; } public boolean isSequential() { return this.sequential; } public boolean isMaintainTms() { return this.maintainTms; } public void setMaintainTms(final boolean maintainTms) { checkCanChange(); // throws an exception if a change isn't possible; this.maintainTms = maintainTms; } public boolean isRemoveIdentities() { return this.removeIdentities; } public void setRemoveIdentities(final boolean removeIdentities) { checkCanChange(); // throws an exception if a change isn't possible; this.removeIdentities = removeIdentities; } public boolean isShareAlphaNodes() { return this.shareAlphaNodes; } public void setShareAlphaNodes(final boolean shareAlphaNodes) { checkCanChange(); // throws an exception if a change isn't possible; this.shareAlphaNodes = shareAlphaNodes; } public boolean isShareBetaNodes() { return this.shareBetaNodes; } public void setShareBetaNodes(final boolean shareBetaNodes) { checkCanChange(); // throws an exception if a change isn't possible; this.shareBetaNodes = shareBetaNodes; } public int getAlphaNodeHashingThreshold() { return this.alphaNodeHashingThreshold; } public void setAlphaNodeHashingThreshold(final int alphaNodeHashingThreshold) { checkCanChange(); // throws an exception if a change isn't possible; this.alphaNodeHashingThreshold = alphaNodeHashingThreshold; } public AssertBehaviour getAssertBehaviour() { return this.assertBehaviour; } public void setAssertBehaviour(final AssertBehaviour assertBehaviour) { checkCanChange(); // throws an exception if a change isn't possible; this.assertBehaviour = assertBehaviour; } public EventProcessingOption getEventProcessingMode() { return this.eventProcessingMode; } public void setEventProcessingMode(final EventProcessingOption mode) { checkCanChange(); // throws an exception if a change isn't possible; this.eventProcessingMode = mode; } public int getCompositeKeyDepth() { return this.compositeKeyDepth; } public void setCompositeKeyDepth(final int compositeKeyDepth) { if ( !this.immutable ) { if ( compositeKeyDepth > 3 ) { throw new UnsupportedOperationException( "compositeKeyDepth cannot be greater than 3" ); } this.compositeKeyDepth = compositeKeyDepth; } else { throw new UnsupportedOperationException( "Can't set a property after configuration becomes immutable" ); } } public boolean isIndexLeftBetaMemory() { return this.indexLeftBetaMemory; } public void setIndexLeftBetaMemory(final boolean indexLeftBetaMemory) { checkCanChange(); // throws an exception if a change isn't possible; this.indexLeftBetaMemory = indexLeftBetaMemory; } public boolean isIndexRightBetaMemory() { return this.indexRightBetaMemory; } public void setIndexRightBetaMemory(final boolean indexRightBetaMemory) { checkCanChange(); // throws an exception if a change isn't possible; this.indexRightBetaMemory = indexRightBetaMemory; } public LogicalOverride getLogicalOverride() { return this.logicalOverride; } public void setLogicalOverride(final LogicalOverride logicalOverride) { checkCanChange(); // throws an exception if a change isn't possible; this.logicalOverride = logicalOverride; } public String getExecutorService() { return executorService; } public void setExecutorService(String executorService) { checkCanChange(); // throws an exception if a change isn't possible; this.executorService = executorService; } public String getConsequenceExceptionHandler() { return consequenceExceptionHandler; } public void setConsequenceExceptionHandler(String consequenceExceptionHandler) { checkCanChange(); // throws an exception if a change isn't possible; this.consequenceExceptionHandler = consequenceExceptionHandler; } public String getRuleBaseUpdateHandler() { return ruleBaseUpdateHandler; } public void setRuleBaseUpdateHandler(String ruleBaseUpdateHandler) { checkCanChange(); // throws an exception if a change isn't possible; this.ruleBaseUpdateHandler = ruleBaseUpdateHandler; } public AgendaGroupFactory getAgendaGroupFactory() { if ( isSequential() ) { if ( this.sequentialAgenda == SequentialAgenda.SEQUENTIAL ) { return ArrayAgendaGroupFactory.getInstance(); } else { return PriorityQueueAgendaGroupFactory.getInstance(); } } else { return PriorityQueueAgendaGroupFactory.getInstance(); } } public SequentialAgenda getSequentialAgenda() { return this.sequentialAgenda; } public void setSequentialAgenda(final SequentialAgenda sequentialAgenda) { checkCanChange(); // throws an exception if a change isn't possible; this.sequentialAgenda = sequentialAgenda; } /** * Defines if the RuleBase should be executed using a pool of * threads for evaluating the rules ("true"), or if the rulebase * should work in classic single thread mode ("false"). * * @param enableMultithread true for multi-thread or * false for single-thread. Default is false. */ public void setMultithreadEvaluation(boolean enableMultithread) { checkCanChange(); this.multithread = enableMultithread; } /** * Returns true if the partitioning of the rulebase is enabled * and false otherwise. Default is false. * * @return */ public boolean isMultithreadEvaluation() { return this.multithread; } /** * If multi-thread evaluation is enabled, this parameter configures the * maximum number of threads each session can use for concurrent Rete * propagation. * * @param maxThreads the maximum number of threads to use. If 0 or a * negative number is set, the engine will use number * of threads equal to the number of partitions in the * rule base. Default number of threads is 0. */ public void setMaxThreads(final int maxThreads) { this.maxThreads = maxThreads; } /** * Returns the configured number of maximum threads to use for concurrent * propagation when multi-thread evaluation is enabled. Default is zero. * * @return */ public int getMaxThreads() { return this.maxThreads; } public boolean isClassLoaderCacheEnabled() { return this.classLoaderCacheEnabled; } public void setClassLoaderCacheEnabled(final boolean classLoaderCacheEnabled) { checkCanChange(); // throws an exception if a change isn't possible; this.classLoaderCacheEnabled = classLoaderCacheEnabled; this.classLoader.setCachingEnabled( this.classLoaderCacheEnabled ); } public List<Map<String, Object>> getWorkDefinitions() { if ( this.workDefinitions == null ) { initWorkDefinitions(); } return this.workDefinitions; } private void initWorkDefinitions() { this.workDefinitions = new ArrayList<Map<String, Object>>(); // split on each space String locations[] = this.chainedProperties.getProperty( "drools.workDefinitions", "" ).split( "\\s" ); // load each SemanticModule for ( String factoryLocation : locations ) { // trim leading/trailing spaces and quotes factoryLocation = factoryLocation.trim(); if ( factoryLocation.startsWith( "\"" ) ) { factoryLocation = factoryLocation.substring( 1 ); } if ( factoryLocation.endsWith( "\"" ) ) { factoryLocation = factoryLocation.substring( 0, factoryLocation.length() - 1 ); } if ( !factoryLocation.equals( "" ) ) { loadWorkItems( factoryLocation ); } } } private void loadWorkItems(String location) { String content = ConfFileUtils.URLContentsToString( ConfFileUtils.getURL( location, null, RuleBaseConfiguration.class ) ); try { this.workDefinitions.addAll( (List<Map<String, Object>>) MVEL.eval( content, new HashMap() ) ); } catch ( Throwable t ) { System.err.println( "Error occured while loading work definitions " + location ); System.err.println( "Continuing without reading these work definitions" ); t.printStackTrace(); throw new RuntimeException( "Could not parse work definitions " + location + ": " + t.getMessage() ); } } public boolean isAdvancedProcessRuleIntegration() { return advancedProcessRuleIntegration; } public void setAdvancedProcessRuleIntegration(boolean advancedProcessRuleIntegration) { this.advancedProcessRuleIntegration = advancedProcessRuleIntegration; } private boolean determineShadowProxy(String userValue) { if ( this.isSequential() ) { // sequential never needs shadowing, so always override return false; } if ( userValue != null ) { return Boolean.valueOf( userValue ).booleanValue(); } else { return true; } } private ConflictResolver determineConflictResolver(String className) { Class clazz = null; try { clazz = this.classLoader.loadClass( className ); } catch ( ClassNotFoundException e ) { throw new IllegalArgumentException( "conflict Resolver '" + className + "' not found" ); } try { return (ConflictResolver) clazz.getMethod( "getInstance", null ).invoke( null, null ); } catch ( Exception e ) { throw new IllegalArgumentException( "Unable to set Conflict Resolver '" + className + "'" ); } } public void setConflictResolver(ConflictResolver conflictResolver) { checkCanChange(); // throws an exception if a change isn't possible; this.conflictResolver = conflictResolver; } public ConflictResolver getConflictResolver() { return this.conflictResolver; } public CompositeClassLoader getClassLoader() { return this.classLoader.clone(); } public void setClassLoader(ClassLoader... classLoaders) { this.classLoader = ClassLoaderUtil.getClassLoader( classLoaders, getClass(), isClassLoaderCacheEnabled() ); } /** * Defines if the RuleBase should expose management and monitoring MBeans * * @param enableMultithread true for multi-thread or * false for single-thread. Default is false. */ public void setMBeansEnabled(boolean mbeansEnabled) { checkCanChange(); this.mbeansEnabled = mbeansEnabled; } /** * Returns true if the management and monitoring through MBeans is active * * @return */ public boolean isMBeansEnabled() { return this.mbeansEnabled; } public static class AssertBehaviour implements Externalizable { private static final long serialVersionUID = 510l; public static final AssertBehaviour IDENTITY = new AssertBehaviour( 0 ); public static final AssertBehaviour EQUALITY = new AssertBehaviour( 1 ); private int value; public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { value = in.readInt(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeInt( value ); } public AssertBehaviour() { } private AssertBehaviour(final int value) { this.value = value; } public boolean equals(Object obj) { if ( obj == this ) return true; else if ( obj instanceof AssertBehaviour ) { AssertBehaviour that = (AssertBehaviour) obj; return value == that.value; } return false; } public static AssertBehaviour determineAssertBehaviour(final String value) { if ( "IDENTITY".equalsIgnoreCase( value ) ) { return IDENTITY; } else if ( "EQUALITY".equalsIgnoreCase( value ) ) { return EQUALITY; } else { throw new IllegalArgumentException( "Illegal enum value '" + value + "' for AssertBehaviour" ); } } private Object readResolve() throws java.io.ObjectStreamException { switch ( this.value ) { case 0 : return IDENTITY; case 1 : return EQUALITY; default : throw new IllegalArgumentException( "Illegal enum value '" + this.value + "' for AssertBehaviour" ); } } public String toExternalForm() { return (this.value == 0) ? "identity" : "equality"; } public String toString() { return "AssertBehaviour : " + ((this.value == 0) ? "identity" : "equality"); } } public static class LogicalOverride implements Externalizable { private static final long serialVersionUID = 510l; public static final LogicalOverride PRESERVE = new LogicalOverride( 0 ); public static final LogicalOverride DISCARD = new LogicalOverride( 1 ); private int value; public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { value = in.readInt(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeInt( value ); } public LogicalOverride() { } private LogicalOverride(final int value) { this.value = value; } public static LogicalOverride determineLogicalOverride(final String value) { if ( "PRESERVE".equalsIgnoreCase( value ) ) { return PRESERVE; } else if ( "DISCARD".equalsIgnoreCase( value ) ) { return DISCARD; } else { throw new IllegalArgumentException( "Illegal enum value '" + value + "' for LogicalOverride" ); } } private Object readResolve() throws java.io.ObjectStreamException { switch ( this.value ) { case 0 : return PRESERVE; case 1 : return DISCARD; default : throw new IllegalArgumentException( "Illegal enum value '" + this.value + "' for LogicalOverride" ); } } public boolean equals(Object obj) { if ( obj == this ) { return true; } else if ( obj instanceof LogicalOverride ) { return value == ((LogicalOverride) obj).value; } return false; } public String toExternalForm() { return (this.value == 0) ? "preserve" : "discard"; } public String toString() { return "LogicalOverride : " + ((this.value == 0) ? "preserve" : "discard"); } } public static class SequentialAgenda implements Externalizable { private static final long serialVersionUID = 510l; public static final SequentialAgenda SEQUENTIAL = new SequentialAgenda( 0 ); public static final SequentialAgenda DYNAMIC = new SequentialAgenda( 1 ); private int value; public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { value = in.readInt(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeInt( value ); } public SequentialAgenda() { } private SequentialAgenda(final int value) { this.value = value; } public static SequentialAgenda determineSequentialAgenda(final String value) { if ( "sequential".equalsIgnoreCase( value ) ) { return SEQUENTIAL; } else if ( "dynamic".equalsIgnoreCase( value ) ) { return DYNAMIC; } else { throw new IllegalArgumentException( "Illegal enum value '" + value + "' for SequentialAgenda" ); } } private Object readResolve() throws java.io.ObjectStreamException { switch ( this.value ) { case 0 : return SEQUENTIAL; case 1 : return DYNAMIC; default : throw new IllegalArgumentException( "Illegal enum value '" + this.value + "' for SequentialAgenda" ); } } public String toExternalForm() { return (this.value == 0) ? "sequential" : "dynamic"; } public String toString() { return "SequentialAgenda : " + ((this.value == 0) ? "sequential" : "dynamic"); } } @SuppressWarnings("unchecked") public <T extends SingleValueKnowledgeBaseOption> T getOption(Class<T> option) { if ( MaintainTMSOption.class.equals( option ) ) { return (T) (this.maintainTms ? MaintainTMSOption.YES : MaintainTMSOption.NO); } else if ( SequentialOption.class.equals( option ) ) { return (T) (this.sequential ? SequentialOption.YES : SequentialOption.NO); } else if ( RemoveIdentitiesOption.class.equals( option ) ) { return (T) (this.removeIdentities ? RemoveIdentitiesOption.YES : RemoveIdentitiesOption.NO); } else if ( ShareAlphaNodesOption.class.equals( option ) ) { return (T) (this.shareAlphaNodes ? ShareAlphaNodesOption.YES : ShareAlphaNodesOption.NO); } else if ( ShareBetaNodesOption.class.equals( option ) ) { return (T) (this.shareBetaNodes ? ShareBetaNodesOption.YES : ShareBetaNodesOption.NO); } else if ( IndexLeftBetaMemoryOption.class.equals( option ) ) { return (T) (this.indexLeftBetaMemory ? IndexLeftBetaMemoryOption.YES : IndexLeftBetaMemoryOption.NO); } else if ( IndexRightBetaMemoryOption.class.equals( option ) ) { return (T) (this.indexRightBetaMemory ? IndexRightBetaMemoryOption.YES : IndexRightBetaMemoryOption.NO); } else if ( AssertBehaviorOption.class.equals( option ) ) { return (T) ((this.assertBehaviour == AssertBehaviour.IDENTITY) ? AssertBehaviorOption.IDENTITY : AssertBehaviorOption.EQUALITY); } else if ( LogicalOverrideOption.class.equals( option ) ) { return (T) ((this.logicalOverride == LogicalOverride.DISCARD) ? LogicalOverrideOption.DISCARD : LogicalOverrideOption.PRESERVE); } else if ( SequentialAgendaOption.class.equals( option ) ) { return (T) ((this.sequentialAgenda == SequentialAgenda.SEQUENTIAL) ? SequentialAgendaOption.SEQUENTIAL : SequentialAgendaOption.DYNAMIC); } else if ( AlphaThresholdOption.class.equals( option ) ) { return (T) AlphaThresholdOption.get( alphaNodeHashingThreshold ); } else if ( CompositeKeyDepthOption.class.equals( option ) ) { return (T) CompositeKeyDepthOption.get( compositeKeyDepth ); } else if ( ConsequenceExceptionHandlerOption.class.equals( option ) ) { Class< ? extends ConsequenceExceptionHandler> handler; try { handler = (Class< ? extends ConsequenceExceptionHandler>) Class.forName( consequenceExceptionHandler ); } catch ( ClassNotFoundException e ) { throw new RuntimeDroolsException( "Unable to resolve ConsequenceExceptionHandler class: " + consequenceExceptionHandler, e ); } return (T) ConsequenceExceptionHandlerOption.get( handler ); } else if ( EventProcessingOption.class.equals( option ) ) { return (T) getEventProcessingMode(); } else if ( MaxThreadsOption.class.equals( option ) ) { return (T) MaxThreadsOption.get( getMaxThreads() ); } else if ( MultithreadEvaluationOption.class.equals( option ) ) { return (T) (this.multithread ? MultithreadEvaluationOption.YES : MultithreadEvaluationOption.NO); } else if ( MBeansOption.class.equals( option ) ) { return (T) (this.isMBeansEnabled() ? MBeansOption.ENABLED : MBeansOption.DISABLED); } else if ( ClassLoaderCacheOption.class.equals( option ) ) { return (T) (this.isClassLoaderCacheEnabled() ? ClassLoaderCacheOption.ENABLED : ClassLoaderCacheOption.DISABLED); } return null; } public <T extends KnowledgeBaseOption> void setOption(T option) { if ( option instanceof MaintainTMSOption ) { setMaintainTms( ((MaintainTMSOption) option).isMaintainTMS() ); } else if ( option instanceof SequentialOption ) { setSequential( ((SequentialOption) option).isSequential() ); } else if ( option instanceof RemoveIdentitiesOption ) { setRemoveIdentities( ((RemoveIdentitiesOption) option).isRemoveIdentities() ); } else if ( option instanceof ShareAlphaNodesOption ) { setShareAlphaNodes( ((ShareAlphaNodesOption) option).isShareAlphaNodes() ); } else if ( option instanceof ShareBetaNodesOption ) { setShareBetaNodes( ((ShareBetaNodesOption) option).isShareBetaNodes() ); } else if ( option instanceof IndexLeftBetaMemoryOption ) { setIndexLeftBetaMemory( ((IndexLeftBetaMemoryOption) option).isIndexLeftBetaMemory() ); } else if ( option instanceof IndexRightBetaMemoryOption ) { setIndexRightBetaMemory( ((IndexRightBetaMemoryOption) option).isIndexRightBetaMemory() ); } else if ( option instanceof AssertBehaviorOption ) { setAssertBehaviour( (option == AssertBehaviorOption.IDENTITY) ? AssertBehaviour.IDENTITY : AssertBehaviour.EQUALITY ); } else if ( option instanceof LogicalOverrideOption ) { setLogicalOverride( (option == LogicalOverrideOption.DISCARD) ? LogicalOverride.DISCARD : LogicalOverride.PRESERVE ); } else if ( option instanceof SequentialAgendaOption ) { setSequentialAgenda( (option == SequentialAgendaOption.SEQUENTIAL) ? SequentialAgenda.SEQUENTIAL : SequentialAgenda.DYNAMIC ); } else if ( option instanceof AlphaThresholdOption ) { setAlphaNodeHashingThreshold( ((AlphaThresholdOption) option).getThreshold() ); } else if ( option instanceof CompositeKeyDepthOption ) { setCompositeKeyDepth( ((CompositeKeyDepthOption) option).getDepth() ); } else if ( option instanceof ConsequenceExceptionHandlerOption ) { setConsequenceExceptionHandler( ((ConsequenceExceptionHandlerOption) option).getHandler().getName() ); } else if ( option instanceof EventProcessingOption ) { setEventProcessingMode( (EventProcessingOption) option ); } else if ( option instanceof MaxThreadsOption ) { setMaxThreads( ((MaxThreadsOption) option).getMaxThreads() ); } else if ( option instanceof MultithreadEvaluationOption ) { setMultithreadEvaluation( ((MultithreadEvaluationOption) option).isMultithreadEvaluation() ); } else if ( option instanceof MBeansOption ) { setMBeansEnabled( ((MBeansOption) option).isEnabled() ); } else if ( option instanceof ClassLoaderCacheOption ) { setClassLoaderCacheEnabled( ((ClassLoaderCacheOption) option).isClassLoaderCacheEnabled() ); } } public <T extends MultiValueKnowledgeBaseOption> T getOption(Class<T> option, String key) { return null; } }