/*
* Copyright 2010 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;
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.core.common.AgendaGroupFactory;
import org.drools.core.common.ProjectClassLoader;
import org.drools.core.conflict.DepthConflictResolver;
import org.drools.core.reteoo.KieComponentFactory;
import org.drools.core.runtime.rule.impl.DefaultConsequenceExceptionHandler;
import org.drools.core.spi.ConflictResolver;
import org.drools.core.util.ConfFileUtils;
import org.drools.core.util.MVELSafeHelper;
import org.drools.core.util.StringUtils;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.conf.DeclarativeAgendaOption;
import org.kie.api.conf.EqualityBehaviorOption;
import org.kie.api.conf.EventProcessingOption;
import org.kie.api.conf.KieBaseOption;
import org.kie.api.conf.MBeansOption;
import org.kie.api.conf.MultiValueKieBaseOption;
import org.kie.api.conf.RemoveIdentitiesOption;
import org.kie.api.conf.SingleValueKieBaseOption;
import org.kie.api.runtime.rule.ConsequenceExceptionHandler;
import org.kie.internal.builder.conf.ClassLoaderCacheOption;
import org.kie.internal.builder.conf.SessionCacheOption;
import org.kie.internal.conf.AlphaThresholdOption;
import org.kie.internal.conf.CompositeKeyDepthOption;
import org.kie.internal.conf.ConsequenceExceptionHandlerOption;
import org.kie.internal.conf.ConstraintJittingThresholdOption;
import org.kie.internal.conf.IndexLeftBetaMemoryOption;
import org.kie.internal.conf.IndexPrecedenceOption;
import org.kie.internal.conf.IndexRightBetaMemoryOption;
import org.kie.internal.conf.MaxThreadsOption;
import org.kie.internal.conf.MultithreadEvaluationOption;
import org.kie.internal.conf.PermGenThresholdOption;
import org.kie.internal.conf.SequentialAgendaOption;
import org.kie.internal.conf.SequentialOption;
import org.kie.internal.conf.ShareAlphaNodesOption;
import org.kie.internal.conf.ShareBetaNodesOption;
import org.kie.internal.utils.ChainedProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.drools.core.util.Drools.isJmxAvailable;
import static org.drools.core.util.MemoryUtil.hasPermGen;
/**
* 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.equalityBehavior = <identity|equality>
* drools.conflictResolver = <qualified class name>
* drools.consequenceExceptionHandler = <qualified class name>
* drools.ruleBaseUpdateHandler = <qualified class name>
* drools.sessionClock = <qualified class name>
* drools.mbeans = <enabled|disabled>
* drools.classLoaderCacheEnabled = <true|false>
* drools.phreakEnabled = <true|false>
* drools.declarativeAgendaEnabled = <true|false>
* drools.permgenThreshold = <1...n>
* drools.jittingThreshold = <1...n>
* </pre>
*/
public class RuleBaseConfiguration
implements
KieBaseConfiguration,
Externalizable {
private static final long serialVersionUID = 510l;
public static final boolean DEFAULT_PHREAK = true;
public static final boolean DEFAULT_SESSION_CACHE = true;
public static final String DEFAULT_SIGN_ON_SERIALIZATION = "false";
protected static final transient Logger logger = LoggerFactory.getLogger(RuleBaseConfiguration.class);
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 permGenThreshold;
private int jittingThreshold;
private int alphaNodeHashingThreshold;
private int compositeKeyDepth;
private boolean indexLeftBetaMemory;
private boolean indexRightBetaMemory;
private AssertBehaviour assertBehaviour;
private String consequenceExceptionHandler;
private String ruleBaseUpdateHandler;
private boolean classLoaderCacheEnabled;
private boolean phreakEnabled;
private boolean declarativeAgenda;
private EventProcessingOption eventProcessingMode;
private IndexPrecedenceOption indexPrecedenceOption;
private SessionCacheOption sessionCacheOption;
// 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 Map<String, ActivationListenerFactory> activationListeners;
private List<Map<String, Object>> workDefinitions;
private boolean advancedProcessRuleIntegration;
private transient ClassLoader classLoader;
private KieComponentFactory componentFactory;
private static class DefaultRuleBaseConfigurationHolder {
private static final RuleBaseConfiguration defaultConf = new RuleBaseConfiguration();
}
public static RuleBaseConfiguration getDefaultInstance() {
return DefaultRuleBaseConfigurationHolder.defaultConf;
}
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(permGenThreshold);
out.writeInt(jittingThreshold);
out.writeInt(alphaNodeHashingThreshold);
out.writeInt(compositeKeyDepth);
out.writeBoolean(indexLeftBetaMemory);
out.writeBoolean(indexRightBetaMemory);
out.writeObject(indexPrecedenceOption);
out.writeObject(assertBehaviour);
out.writeObject(consequenceExceptionHandler);
out.writeObject(ruleBaseUpdateHandler);
out.writeObject(conflictResolver);
out.writeBoolean(advancedProcessRuleIntegration);
out.writeBoolean(multithread);
out.writeInt(maxThreads);
out.writeObject(eventProcessingMode);
out.writeBoolean(classLoaderCacheEnabled);
out.writeBoolean(phreakEnabled);
out.writeBoolean(declarativeAgenda);
out.writeObject(componentFactory);
out.writeObject(sessionCacheOption);
}
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();
permGenThreshold = in.readInt();
jittingThreshold = in.readInt();
alphaNodeHashingThreshold = in.readInt();
compositeKeyDepth = in.readInt();
indexLeftBetaMemory = in.readBoolean();
indexRightBetaMemory = in.readBoolean();
indexPrecedenceOption = (IndexPrecedenceOption) in.readObject();
assertBehaviour = (AssertBehaviour) 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();
phreakEnabled = in.readBoolean();
declarativeAgenda = in.readBoolean();
componentFactory = (KieComponentFactory) in.readObject();
sessionCacheOption = (SessionCacheOption) in.readObject();
}
/**
* 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 classLoaders
*/
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(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( PermGenThresholdOption.PROPERTY_NAME ) ) {
setPermGenThreshold(StringUtils.isEmpty(value) ? PermGenThresholdOption.DEFAULT_VALUE : Integer.parseInt(value));
} else if ( name.equals( ConstraintJittingThresholdOption.PROPERTY_NAME ) ) {
setJittingThreshold( StringUtils.isEmpty( value ) ? ConstraintJittingThresholdOption.DEFAULT_VALUE : Integer.parseInt( 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( IndexPrecedenceOption.PROPERTY_NAME ) ) {
setIndexPrecedenceOption( StringUtils.isEmpty( value ) ? IndexPrecedenceOption.EQUALITY_PRIORITY : IndexPrecedenceOption.determineIndexPrecedence(value));
} else if ( name.equals( EqualityBehaviorOption.PROPERTY_NAME ) ) {
setAssertBehaviour( AssertBehaviour.determineAssertBehaviour( StringUtils.isEmpty( value ) ? "identity" : 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));
} else if ( name.equals( SessionCacheOption.PROPERTY_NAME ) ) {
setSessionCacheOption(SessionCacheOption.determineOption(StringUtils.isEmpty(value) ? "none" : 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( 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( PermGenThresholdOption.PROPERTY_NAME ) ) {
return Integer.toString( getPermGenThreshold() );
} else if ( name.equals( ConstraintJittingThresholdOption.PROPERTY_NAME ) ) {
return Integer.toString( getJittingThreshold() );
} 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( IndexPrecedenceOption.PROPERTY_NAME ) ) {
return getIndexPrecedenceOption().getValue();
} else if ( name.equals( EqualityBehaviorOption.PROPERTY_NAME ) ) {
return getAssertBehaviour().toExternalForm();
} 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 classLoaders
* @param properties
*/
public RuleBaseConfiguration(Properties properties,
ClassLoader... classLoaders) {
init( properties,
classLoaders );
}
private void init(Properties properties, ClassLoader... classLoaders) {
if (classLoaders != null && classLoaders.length > 1) {
throw new RuntimeException("Multiple classloaders are no longer supported");
}
setClassLoader( classLoaders == null || classLoaders.length == 0 ? null : classLoaders[0] );
init(properties);
}
private void init(Properties properties) {
this.componentFactory = new KieComponentFactory();
this.immutable = false;
this.chainedProperties = ChainedProperties.getChainedProperties( this.classLoader );
if ( properties != null ) {
this.chainedProperties.addProperties( properties );
}
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());
setPermGenThreshold(Integer.parseInt(this.chainedProperties.getProperty(PermGenThresholdOption.PROPERTY_NAME, "" + PermGenThresholdOption.DEFAULT_VALUE)));
setJittingThreshold( Integer.parseInt( this.chainedProperties.getProperty( ConstraintJittingThresholdOption.PROPERTY_NAME, "" + ConstraintJittingThresholdOption.DEFAULT_VALUE)));
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());
setIndexPrecedenceOption(IndexPrecedenceOption.determineIndexPrecedence(this.chainedProperties.getProperty(IndexPrecedenceOption.PROPERTY_NAME, "equality")));
setAssertBehaviour(AssertBehaviour.determineAssertBehaviour(this.chainedProperties.getProperty(EqualityBehaviorOption.PROPERTY_NAME, "identity")));
setConsequenceExceptionHandler(this.chainedProperties.getProperty(ConsequenceExceptionHandlerOption.PROPERTY_NAME, "org.drools.core.runtime.rule.impl.DefaultConsequenceExceptionHandler"));
setRuleBaseUpdateHandler(this.chainedProperties.getProperty("drools.ruleBaseUpdateHandler", ""));
setSequentialAgenda(SequentialAgenda.determineSequentialAgenda(this.chainedProperties.getProperty(SequentialAgendaOption.PROPERTY_NAME, "sequential")));
setSequential(Boolean.valueOf(this.chainedProperties.getProperty(SequentialOption.PROPERTY_NAME, "false")).booleanValue());
setConflictResolver( determineConflictResolver( this.chainedProperties.getProperty( "drools.conflictResolver", "org.drools.core.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" ) ) );
setSessionCacheOption(SessionCacheOption.determineOption(this.chainedProperties.getProperty(SessionCacheOption.PROPERTY_NAME, "none")));
setDeclarativeAgendaEnabled( Boolean.valueOf( this.chainedProperties.getProperty( DeclarativeAgendaOption.PROPERTY_NAME,
"false" ) ) );
}
/**
* 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 getPermGenThreshold() {
return this.permGenThreshold;
}
public void setPermGenThreshold(final int permGenThreshold) {
checkCanChange(); // throws an exception if a change isn't possible;
if (permGenThreshold < 0 || permGenThreshold > 100) {
throw new UnsupportedOperationException( "The PermGen threshold should be a number between 0 and 100" );
}
if (isJmxAvailable() && !hasPermGen()) {
if (permGenThreshold != PermGenThresholdOption.DEFAULT_VALUE) {
logger.warn( "JVM version " + System.getProperty("java.version") + " has no PermGen space. " +
"Attempt to set the permgenThreshold to " + permGenThreshold + " will be ignored");
}
this.permGenThreshold = 100;
return;
}
this.permGenThreshold = permGenThreshold;
}
public int getJittingThreshold() {
return jittingThreshold;
}
public void setJittingThreshold( int jittingThreshold ) {
checkCanChange(); // throws an exception if a change isn't possible;
this.jittingThreshold = jittingThreshold;
}
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 IndexPrecedenceOption getIndexPrecedenceOption() {
return this.indexPrecedenceOption;
}
public void setIndexPrecedenceOption(final IndexPrecedenceOption precedence) {
checkCanChange(); // throws an exception if a change isn't possible;
this.indexPrecedenceOption = precedence;
}
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() {
return getComponentFactory().getAgendaGroupFactory();
}
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;
}
public void enforceSingleThreadEvaluation() {
this.multithread = false;
}
/**
* 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;
}
public SessionCacheOption getSessionCacheOption() {
return this.sessionCacheOption;
}
public void setSessionCacheOption(SessionCacheOption sessionCacheOption) {
checkCanChange(); // throws an exception if a change isn't possible;
this.sessionCacheOption = sessionCacheOption;
}
public boolean isDeclarativeAgenda() {
return this.declarativeAgenda;
}
/**
* Enable declarative agenda
* @param enabled
*/
public void setDeclarativeAgendaEnabled(boolean enabled) {
checkCanChange(); // throws an exception if a change isn't possible;
this.declarativeAgenda = enabled;
}
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>>) MVELSafeHelper.getEvaluator().eval( content, new HashMap() ) );
} catch ( Throwable t ) {
logger.error("Error occurred while loading work definitions " + location
+ "\nContinuing without reading these work definitions", t);
throw new RuntimeException( "Could not parse work definitions " + location + ": " + t.getMessage() );
}
}
public boolean isAdvancedProcessRuleIntegration() {
return advancedProcessRuleIntegration;
}
public void setAdvancedProcessRuleIntegration(boolean advancedProcessRuleIntegration) {
this.advancedProcessRuleIntegration = advancedProcessRuleIntegration;
}
public void addActivationListener(String name, ActivationListenerFactory factory) {
if ( this.activationListeners == null ) {
this.activationListeners = new HashMap<String, ActivationListenerFactory>();
}
this.activationListeners.put( name, factory );
}
public ActivationListenerFactory getActivationListenerFactory(String name) {
ActivationListenerFactory factory = null;
if ( this.activationListeners != null ) {
factory = this.activationListeners.get( name );
}
if ( factory != null ) {
return factory;
} else {
if ( "query".equals( name )) {
return QueryActivationListenerFactory.INSTANCE;
} else if ( "agenda".equals( name ) || "direct".equals( name ) ) {
return RuleActivationListenerFactory.INSTANCE;
}
}
throw new IllegalArgumentException( "ActivationListenerFactory not found for '" + name + "'" );
}
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 ClassLoader getClassLoader() {
return this.classLoader;
}
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = ProjectClassLoader.getClassLoader( classLoader,
getClass(),
isClassLoaderCacheEnabled());
}
public KieComponentFactory getComponentFactory() {
return componentFactory;
}
public void setComponentFactory(KieComponentFactory componentFactory) {
this.componentFactory = componentFactory;
}
/**
* Defines if the RuleBase should expose management and monitoring MBeans
*
* @param mbeansEnabled 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 SingleValueKieBaseOption> T getOption(Class<T> option) {
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 (IndexPrecedenceOption.class.equals(option)) {
return (T) getIndexPrecedenceOption();
} else if (EqualityBehaviorOption.class.equals(option)) {
return (T) ((this.assertBehaviour == AssertBehaviour.IDENTITY) ? EqualityBehaviorOption.IDENTITY : EqualityBehaviorOption.EQUALITY);
} else if (SequentialAgendaOption.class.equals(option)) {
return (T) ((this.sequentialAgenda == SequentialAgenda.SEQUENTIAL) ? SequentialAgendaOption.SEQUENTIAL : SequentialAgendaOption.DYNAMIC);
} else if (PermGenThresholdOption.class.equals(option)) {
return (T) PermGenThresholdOption.get(permGenThreshold);
} else if (ConstraintJittingThresholdOption.class.equals(option)) {
return (T) ConstraintJittingThresholdOption.get(jittingThreshold);
} 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 RuntimeException("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);
} else if (DeclarativeAgendaOption.class.equals(option)) {
return (T) (this.isDeclarativeAgenda() ? DeclarativeAgendaOption.ENABLED : DeclarativeAgendaOption.DISABLED);
}
return null;
}
public <T extends KieBaseOption> void setOption(T option) {
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 IndexPrecedenceOption) {
setIndexPrecedenceOption((IndexPrecedenceOption) option);
} else if (option instanceof EqualityBehaviorOption) {
setAssertBehaviour((option == EqualityBehaviorOption.IDENTITY) ? AssertBehaviour.IDENTITY : AssertBehaviour.EQUALITY);
} else if (option instanceof SequentialAgendaOption) {
setSequentialAgenda((option == SequentialAgendaOption.SEQUENTIAL) ? SequentialAgenda.SEQUENTIAL : SequentialAgenda.DYNAMIC);
} else if (option instanceof PermGenThresholdOption) {
setPermGenThreshold(((PermGenThresholdOption) option).getThreshold());
} else if (option instanceof ConstraintJittingThresholdOption) {
setJittingThreshold( ( (ConstraintJittingThresholdOption) option ).getThreshold());
} 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());
} else if (option instanceof SessionCacheOption) {
setSessionCacheOption( (SessionCacheOption) option);
} else if (option instanceof DeclarativeAgendaOption) {
setDeclarativeAgendaEnabled(((DeclarativeAgendaOption) option).isDeclarativeAgendaEnabled());
}
}
public <T extends MultiValueKieBaseOption> T getOption(Class<T> option,
String key) {
return null;
}
public ChainedProperties getChainedProperties() {
return chainedProperties;
}
}