/*
* 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.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.drools.core.common.ProjectClassLoader;
import org.drools.core.process.instance.WorkItemManagerFactory;
import org.drools.core.time.TimerService;
import org.drools.core.util.ConfFileUtils;
import org.drools.core.util.MVELSafeHelper;
import org.kie.api.runtime.Environment;
import org.kie.api.runtime.ExecutableRunner;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.runtime.conf.BeliefSystemTypeOption;
import org.kie.api.runtime.conf.ClockTypeOption;
import org.kie.api.runtime.conf.KeepReferenceOption;
import org.kie.api.runtime.conf.QueryListenerOption;
import org.kie.api.runtime.conf.TimedRuleExecutionFilter;
import org.kie.api.runtime.conf.TimedRuleExecutionOption;
import org.kie.api.runtime.conf.TimerJobFactoryOption;
import org.kie.api.runtime.process.WorkItemHandler;
import org.kie.internal.KnowledgeBase;
import org.kie.internal.runtime.conf.ForceEagerActivationFilter;
import org.kie.internal.runtime.conf.ForceEagerActivationOption;
import org.kie.internal.utils.ChainedProperties;
/**
* SessionConfiguration
*
* A class to store Session related configuration. It must be used at session 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 sessions, you can simply set the property as
* a System property.
*
* After the Session is created, it makes the configuration immutable and there is no way to make it
* mutable again. This is to avoid inconsistent behavior inside session.
*
* NOTE: This API is under review and may change in the future.
*
*
* drools.keepReference = <true|false>
* drools.clockType = <pseudo|realtime|heartbeat|implicit>
*/
public class SessionConfigurationImpl extends SessionConfiguration {
private static final long serialVersionUID = 510l;
private ChainedProperties chainedProperties;
private volatile boolean immutable;
private boolean keepReference;
private ForceEagerActivationFilter forceEagerActivationFilter;
private TimedRuleExecutionFilter timedRuleExecutionFilter;
private ClockType clockType;
private BeliefSystemType beliefSystemType;
private QueryListenerOption queryListener;
private Map<String, WorkItemHandler> workItemHandlers;
private WorkItemManagerFactory workItemManagerFactory;
private ExecutableRunner runner;
private transient ClassLoader classLoader;
private TimerJobFactoryType timerJobFactoryType;
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject( chainedProperties );
out.writeBoolean(immutable);
out.writeBoolean( keepReference );
out.writeObject(clockType);
out.writeObject( queryListener );
out.writeObject( timerJobFactoryType );
}
@SuppressWarnings("unchecked")
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
chainedProperties = (ChainedProperties) in.readObject();
immutable = in.readBoolean();
keepReference = in.readBoolean();
clockType = (ClockType) in.readObject();
queryListener = (QueryListenerOption) in.readObject();
try {
timerJobFactoryType = (TimerJobFactoryType) in.readObject();
} catch (java.io.InvalidObjectException e) {
// workaround for old typo in TimerJobFactoryType
if (e.getMessage().contains( "DEFUALT" )) {
timerJobFactoryType = TimerJobFactoryType.DEFAULT;
} else {
throw e;
}
}
}
/**
* Creates a new session configuration with default configuration options.
*/
public SessionConfigurationImpl() {
init( null, null, null );
}
/**
* Creates a new session configuration using the provided properties
* as configuration options.
*/
public SessionConfigurationImpl( Properties properties ) {
init( properties, null, null );
}
public SessionConfigurationImpl( Properties properties, ClassLoader classLoader ) {
init( properties, classLoader, null );
}
public SessionConfigurationImpl( Properties properties, ClassLoader classLoader, ChainedProperties chainedProperties ) {
init( properties, classLoader, chainedProperties );
}
private void init(Properties properties, ClassLoader classLoader, ChainedProperties chainedProperties) {
this.classLoader = classLoader instanceof ProjectClassLoader ?
classLoader :
ProjectClassLoader.getClassLoader(classLoader == null ? null : classLoader, getClass(), false);
this.immutable = false;
this.chainedProperties = chainedProperties != null ? chainedProperties : ChainedProperties.getChainedProperties( this.classLoader );
if ( properties != null ) {
this.chainedProperties = this.chainedProperties.clone();
this.chainedProperties.addProperties( properties );
}
setKeepReference(Boolean.valueOf(this.chainedProperties.getProperty(KeepReferenceOption.PROPERTY_NAME, "true")));
setForceEagerActivationFilter(ForceEagerActivationOption.resolve(this.chainedProperties.getProperty(ForceEagerActivationOption.PROPERTY_NAME,
"false")).getFilter());
setTimedRuleExecutionFilter(TimedRuleExecutionOption.resolve(this.chainedProperties.getProperty(TimedRuleExecutionOption.PROPERTY_NAME,
"false")).getFilter());
setBeliefSystemType( BeliefSystemType.resolveBeliefSystemType( this.chainedProperties.getProperty( BeliefSystemTypeOption.PROPERTY_NAME,
BeliefSystemType.SIMPLE.getId())) );
setClockType( ClockType.resolveClockType( this.chainedProperties.getProperty( ClockTypeOption.PROPERTY_NAME,
ClockType.REALTIME_CLOCK.getId() ) ) );
setQueryListenerOption( QueryListenerOption.determineQueryListenerClassOption( this.chainedProperties.getProperty( QueryListenerOption.PROPERTY_NAME,
QueryListenerOption.STANDARD.getAsString() ) ) );
setTimerJobFactoryType(TimerJobFactoryType.resolveTimerJobFactoryType(this.chainedProperties.getProperty(TimerJobFactoryOption.PROPERTY_NAME,
TimerJobFactoryType.TRACKABLE.getId())));
}
public SessionConfigurationImpl addDefaultProperties(Properties properties) {
Properties defaultProperties = new Properties();
for ( Map.Entry<Object, Object> prop : properties.entrySet() ) {
if ( chainedProperties.getProperty( (String) prop.getKey(), null) == null ) {
defaultProperties.put( prop.getKey(), prop.getValue() );
}
}
this.chainedProperties.addProperties(defaultProperties);
return this;
}
/**
* 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.
*/
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 setKeepReference(boolean keepReference) {
checkCanChange(); // throws an exception if a change isn't possible;
this.keepReference = keepReference;
}
public boolean isKeepReference() {
return this.keepReference;
}
public void setForceEagerActivationFilter(ForceEagerActivationFilter forceEagerActivationFilter) {
checkCanChange(); // throws an exception if a change isn't possible;
this.forceEagerActivationFilter = forceEagerActivationFilter;
}
public ForceEagerActivationFilter getForceEagerActivationFilter() {
return this.forceEagerActivationFilter;
}
public void setTimedRuleExecutionFilter(TimedRuleExecutionFilter timedRuleExecutionFilter) {
checkCanChange(); // throws an exception if a change isn't possible;
this.timedRuleExecutionFilter = timedRuleExecutionFilter;
}
public TimedRuleExecutionFilter getTimedRuleExecutionFilter() {
return this.timedRuleExecutionFilter;
}
public BeliefSystemType getBeliefSystemType() {
return this.beliefSystemType;
}
public void setBeliefSystemType(BeliefSystemType beliefSystemType) {
checkCanChange(); // throws an exception if a change isn't possible;
this.beliefSystemType = beliefSystemType;
}
public ClockType getClockType() {
return clockType;
}
public void setClockType(ClockType clockType) {
checkCanChange(); // throws an exception if a change isn't possible;
this.clockType = clockType;
}
public TimerJobFactoryType getTimerJobFactoryType() {
return timerJobFactoryType;
}
public void setTimerJobFactoryType(TimerJobFactoryType timerJobFactoryType) {
checkCanChange(); // throws an exception if a change isn't possible;
this.timerJobFactoryType = timerJobFactoryType;
}
private void setQueryListenerClass(QueryListenerOption option) {
checkCanChange();
this.queryListener = option;
}
public Map<String, WorkItemHandler> getWorkItemHandlers() {
if ( this.workItemHandlers == null ) {
initWorkItemHandlers(new HashMap<String, Object>());
}
return this.workItemHandlers;
}
public Map<String, WorkItemHandler> getWorkItemHandlers(Map<String, Object> params) {
if ( this.workItemHandlers == null ) {
initWorkItemHandlers(params);
}
return this.workItemHandlers;
}
private void initWorkItemHandlers(Map<String, Object> params) {
this.workItemHandlers = new HashMap<String, WorkItemHandler>();
// split on each space
String locations[] = this.chainedProperties.getProperty( "drools.workItemHandlers", "" ).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( "" ) ) {
loadWorkItemHandlers( factoryLocation, params );
}
}
}
@SuppressWarnings("unchecked")
private void loadWorkItemHandlers(String location, Map<String, Object> params) {
String content = ConfFileUtils.URLContentsToString( ConfFileUtils.getURL( location,
null,
RuleBaseConfiguration.class ) );
Map<String, WorkItemHandler> workItemHandlers = (Map<String, WorkItemHandler>) MVELSafeHelper.getEvaluator().eval( content,
params );
this.workItemHandlers.putAll( workItemHandlers );
}
public WorkItemManagerFactory getWorkItemManagerFactory() {
if ( this.workItemManagerFactory == null ) {
initWorkItemManagerFactory();
}
return this.workItemManagerFactory;
}
@SuppressWarnings("unchecked")
private void initWorkItemManagerFactory() {
String className = this.chainedProperties.getProperty( "drools.workItemManagerFactory",
"org.drools.core.process.instance.impl.DefaultWorkItemManagerFactory" );
Class<WorkItemManagerFactory> clazz = null;
try {
clazz = (Class<WorkItemManagerFactory>) this.classLoader.loadClass( className );
} catch ( ClassNotFoundException e ) {
}
if ( clazz != null ) {
try {
this.workItemManagerFactory = clazz.newInstance();
} catch ( Exception e ) {
throw new IllegalArgumentException( "Unable to instantiate work item manager factory '" + className + "'",
e );
}
} else {
throw new IllegalArgumentException( "Work item manager factory '" + className + "' not found" );
}
}
public String getProcessInstanceManagerFactory() {
return this.chainedProperties.getProperty( "drools.processInstanceManagerFactory",
"org.jbpm.process.instance.impl.DefaultProcessInstanceManagerFactory" );
}
public String getSignalManagerFactory() {
return this.chainedProperties.getProperty( "drools.processSignalManagerFactory",
"org.jbpm.process.instance.event.DefaultSignalManagerFactory" );
}
public ExecutableRunner getRunner( KnowledgeBase kbase, Environment environment ) {
if ( this.runner == null ) {
initCommandService( kbase,
environment );
}
return this.runner;
}
@SuppressWarnings("unchecked")
private void initCommandService(KnowledgeBase kbase,
Environment environment) {
String className = this.chainedProperties.getProperty( "drools.commandService",
null );
if ( className == null ) {
return;
}
Class<ExecutableRunner> clazz = null;
try {
clazz = (Class<ExecutableRunner>) this.classLoader.loadClass( className );
} catch ( ClassNotFoundException e ) {
}
if ( clazz != null ) {
try {
this.runner = clazz.getConstructor( KnowledgeBase.class,
KieSessionConfiguration.class,
Environment.class ).newInstance( kbase,
this,
environment );
} catch ( Exception e ) {
throw new IllegalArgumentException( "Unable to instantiate command service '" + className + "'",
e );
}
} else {
throw new IllegalArgumentException( "Command service '" + className + "' not found" );
}
}
public TimerService newTimerService() {
String className = this.chainedProperties.getProperty( "drools.timerService",
"org.drools.core.time.impl.JDKTimerService" );
if ( className == null ) {
return null;
}
Class<TimerService> clazz = null;
try {
clazz = (Class<TimerService>) this.classLoader.loadClass( className );
} catch ( ClassNotFoundException e ) {
}
if ( clazz != null ) {
try {
return clazz.newInstance();
} catch ( Exception e ) {
throw new IllegalArgumentException(
"Unable to instantiate timer service '" + className
+ "'",
e );
}
} else {
try {
return (TimerService) MVELSafeHelper.getEvaluator().eval(className);
} catch (Exception e) {
throw new IllegalArgumentException( "Timer service '" + className
+ "' not found", e );
}
}
}
public QueryListenerOption getQueryListenerOption() {
return this.queryListener;
}
public void setQueryListenerOption( QueryListenerOption queryListener ) {
checkCanChange();
this.queryListener = queryListener;
}
}