org.drools.runtime.help.BatchExecutionHelper Maven / Gradle / Ivy
/**
* 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.runtime.help;
import com.thoughtworks.xstream.XStream;
/**
*
* Provides a configured XStream instance to support the marshalling of BatchExecutions, where the resulting
* xml can be used as a message format. Configured converters only exist for the commands supported via the
* CommandFactory. The user may add other converters for their user objects.
*
*
*
* This is very useful for scripting stateless of stateful knowledge sessions, especially when services are involved.
*
*
*
* There is current no xsd for schema validation, however we will try to outline the basic format here and the drools-transformer-xstream module
* has an illustrative unit test in the XStreamBatchExecutionTest unit test. The root element is <batch-execution> and it can contain zero or more
* commands elements.
*
*
* <batch-execution>
* ...
* </batch-execution>
*
*
*
* This contains a list of elements that represent commands, the supported commands is limited to those Commands provided by the CommandFactory. The
* most basic of these is the <insert> element, which inserts objects. The contents of the insert element is the user object, as dictated by XStream.
*
*
* <batch-execution>
* <insert>
* ....
* </insert>
* </batch-execution>
*
*
* The insert element supports an 'out-identifier' attribute, this means the inserted object's FactHandle will be returned
* and optionally the object itself as part of the payload. To return the object use the attribute 'return-object' which takes a boolean
* 'true'|'false' value, by default this is true.
* The
*
*
* <batch-execution >
* <insert out-identifier='userVar' >
* ....
* </insert>
* </batch-execution>
*
*
*
* It's also possible to insert a collection of objects using the <insert-elements> element, here each element is inserted in turn. This command also support's an
* 'out-identifier' attribute which returns the FactHandle's in a Collection, of the same order that the objects where inserted. 'return-object' is also supported to optionally
* return the inserted objects, again they will be in a collection of the same order they where inserted.
* The org.domain.UserClass is just an illustrative user object that xstream would serialise.
*
*
* <batch-execution>
* <insert-elements>
* <org.domain.UserClass>
* ...
* </org.domain.UserClass>
* <org.domain.UserClass>
* ...
* </org.domain.UserClass>
* <org.domain.UserClass>
* ...
* </org.domain.UserClass>
* </insert-elements>
* </batch-execution>
*
*
*
* Next there is the <set-global> element, which sets a global for the session.
*
*
* <batch-execution>
* <set-global identifier='userVar'>
* <org.domain.UserClass>
* ...
* </org.domain.UserClass>
* </set-global>
* </batch-execution>
*
*
* <set-global> also supports two other optional attributes 'out' and 'out-identifier'. 'out' is a boolean and when set the global will be added to the
* <batch-execution-results&g; payload using the name from the 'identifier' attribute. 'out-identifier' works like 'out' but additionally allows you to
* override the identifier used in the <batch-execution-results&g; payload.
*
*
* <batch-execution>
* <set-global identifier='userVar1' out='true'>
* <org.domain.UserClass>
* ...
* </org.domain.UserClass>
* </set-global>
* <set-global identifier='userVar2' out-identifier='alternativeUserVar2'>
* <org.domain.UserClass>
* ...
* </org.domain.UserClass>
* </set-global>
* </batch-execution>
*
*
* There is also a <get-global> element, which has no contents but does support an 'out-identifier' attribute, there is no need for an 'out' attribute
* as we assume that a <get-global> is always an 'out'.
*
*
* <batch-execution>
* <get-global identifier='userVar1' />
* <get-global identifier='userVar2' out-identifier='alternativeUserVar2'/>
* </batch-execution>
*
*
* Specific objects can be retrieved using the FactHandle:
*
* <batch-execution>
* <get-object out-identifier='outStilton' factHandle='" + factHandle.toExternalForm() + "' />
* </batch-execution>
*
*
*
* While the 'out' attribute is useful in returning specific instances as a result payload, we often wish to run actual querries. Both parameter
* and parameterless querries are supported. The 'name' attribute is the name of the query to be called, and the 'out-identifier' is the identifier
* to be used for the query results in the <batch-execution-results> payload.
*
*
* <batch-execution>
* <query out-identifier='cheeses' name='cheeses'/>
* <query out-identifier='cheeses2' name='cheesesWithParams'>
* <string>stilton</string>
* <string>cheddar</string>
* </query>;
* </batch-execution>
*
*
*
* The <start-process> command is also supported and accepts optional parameters:
*
*
* <batch-execution>
* <startProcess processId='org.drools.actions'>
* <parameter identifier='person'>
* <org.drools.TestVariable>
* <name>John Doe</name>
* </org.drools.TestVariable>
* </parameter>
* </startProcess>
* </batch-execution>
*
*
* SignelEvent
*
* <signal-event process-instance-id='1' event-type='MyEvent'>
* <string>MyValue</string>
* </signal-event>
*
*
* CompleteWorkItem
*
* <complete-work-item id='" + workItem.getId() + "' >
* <result identifier='Result'>
* <string>SomeOtherString</string>
* </result>
* </complete-work-item>
*
*
* AbortWorkItem
*
* <abort-work-item id='21' />
*
*
*
* Support for more commands will be added over time.
*
*
*
* The following is a simple insert batch-execution command:
*
*
* <batch-execution>
* <insert out-identifier='outStilton'>
* <org.drools.Cheese>
* <type>stilton</type>
* <price>25</price>
* <oldPrice>0</oldPrice>
* </org.drools.Cheese>
* </insert>
* </batch-execution>
*
*
*
* The pipeline can be used to handle this end to end, notice the part where the configured XStream instance is passed "BatchExecutionHelper.newXStreamMarshaller()".
* This will take a given xml, transform it and then execute it as a BatchExecution Command. Notice the Pipeline also handles the marshalling
* of the ExecutionResults back out to XML.
*
*
* Action executeResultHandler = PipelineFactory.newExecuteResultHandler();
*
* Action assignResult = PipelineFactory.newAssignObjectAsResult();
* assignResult.setReceiver( executeResultHandler );
*
* Transformer outTransformer = PipelineFactory.newXStreamToXmlTransformer( BatchExecutionHelper.newXStreamMarshaller() );
* outTransformer.setReceiver( assignResult );
*
* KnowledgeRuntimeCommand batchExecution = PipelineFactory.newBatchExecutor();
* batchExecution.setReceiver( outTransformer );
*
*
* Transformer inTransformer = PipelineFactory.newXStreamFromXmlTransformer( BatchExecutionHelper.newXStreamMarshaller() );
* inTransformer.setReceiver( batchExecution );
*
* Pipeline pipeline = PipelineFactory.newStatelessKnowledgeSessionPipeline( ksession );
* pipeline.setReceiver( inTransformer );
*
*
*
* The results would look like following xml:
*
*
* <execution-results>
* <result identifier='outStilton'>
* <org.drools.Cheese>
* <type>stilton</type>
* <oldPrice>0</oldPrice>
* <price>30</price>
* </org.drools.Cheese>
* </result>
* </execution-results>
*
*
* This api is experimental and thus the classes and the interfaces returned are subject to change.
*
*/
public class BatchExecutionHelper {
private static volatile BatchExecutionHelperProvider provider;
public static XStream newXStreamMarshaller() {
return getBatchExecutionHelperProvider().newXStreamMarshaller();
}
public static XStream newJSonMarshaller() {
return getBatchExecutionHelperProvider().newJSonMarshaller();
}
private static synchronized void setBatchExecutionHelperProvider(BatchExecutionHelperProvider provider) {
BatchExecutionHelper.provider = provider;
}
private static synchronized BatchExecutionHelperProvider getBatchExecutionHelperProvider() {
if ( provider == null ) {
loadProvider();
}
return provider;
}
private static void loadProvider() {
try {
Class cls = (Class) Class.forName( "org.drools.runtime.help.impl.BatchExecutionHelperProviderImpl" );
setBatchExecutionHelperProvider( cls.newInstance() );
} catch ( Exception e2 ) {
throw new RuntimeException( "Provider org.drools.runtime.help.impl.BatchExecutionHelperProviderImpl could not be set.",
e2 );
}
}
}