originalPayload not the same as message.originalPayload in groovy scripts - mule

I found that originalPayload does not do the same as message.originalPayload in groovy expressions. That is, the following transformers do not do the same thing:
with originalPayload:
<expression-transformer evaluator="groovy" expression="originalPayload" />
with message.originalPayload:
<expression-transformer evaluator="groovy" expression="message.originalPayload" />
The following mule configuration and test case can be used to reproduce the issue:
<mule ...>
<flow name="test">
<vm:inbound-endpoint name="test.Name" path="test.Path"
exchange-pattern="request-response" />
<expression-transformer evaluator="string" expression="bar" />
<expression-transformer evaluator="groovy" expression="originalPayload" />
<!-- or alternatively -->
<!-- <expression-transformer evaluator="groovy" expression="message.originalPayload" /> -->
</flow>
</mule>
The test case can be:
#Test
public void transformers() throws MuleException {
final MuleClient client = muleContext.getClient();
final MuleMessage reply = client.send("vm://test.Path", 1, null, RECEIVE_TIMEOUT);
assertEquals(1, reply.getPayload());
}
The alternative with message.originalPayload works as expected. The one with originalPayload does not and the following exception is shown in the logs:
Exception stack is:
1. Expression Evaluator "groovy" with expression "originalPayload" returned null
but a value was required. (org.mule.api.expression.RequiredValue Exception)
What could I be doing wrong?
Thanks.

The problem is that expression-transformer and scripting:transformer use a different set of bindings than the one used by a scripting:component, and this because they call a different method in org.mule.module.scripting.component.Scriptable.
Moreover, when originalPayload gets bound, it is with the wrong value:
bindings.put("originalPayload", event.getMessage().getPayload());
Hence: MULE-6215

Following the Scripting Module Reference, they should be the same.
Also, if you take a look to org.mule.module.scripting.component.Scriptable in the scripting module, you will find that "originalPayload" is message.getPayload.
Can you post a small project reproducing the error?
public void populateBindings(Bindings bindings, MuleMessage message)
{
populateDefaultBindings(bindings);
if (message == null)
{
message = new DefaultMuleMessage(NullPayload.getInstance(), muleContext);
}
bindings.put("message", message);
//This will get overwritten if populateBindings(Bindings bindings, MuleEvent event) is called
//and not this method directly.
bindings.put("payload", message.getPayload());
//For backward compatability
bindings.put("src", message.getPayload());
}
public void populateBindings(Bindings bindings, MuleEvent event)
{
populateBindings(bindings, event.getMessage());
bindings.put("originalPayload", event.getMessage().getPayload());
bindings.put("payload", event.getMessage().getPayload());
bindings.put("eventContext", new DefaultMuleEventContext(event));
bindings.put("id", event.getId());
bindings.put("flowConstruct", event.getFlowConstruct());
if (event.getFlowConstruct() instanceof Service)
{
bindings.put("service", event.getFlowConstruct());
}
}

Related

How can I use dataObject inside serviceTask in a BPMN

I am working on a BPMN file which has a dataObject and and some serviceTasks. I want to check whether the serviceTask variable is present in dataObject or not. If it is present, the service task should be skipped. So, I am using skipExpressions to achieve this.
Here is the sample BPMN:
<process id="TASK_FLOW_TESTING" name="TASK_FLOW_TESTING" isExecutable="true">
<dataObject id="optionalInputList" name="optionalInputList">
<extensionElements>
<flowable:value>
["input1","input2"]
</flowable:value>
</extensionElements>
</dataObject>
<dataObject id="_ACTIVITI_SKIP_EXPRESSION_ENABLED" name="_ACTIVITI_SKIP_EXPRESSION_ENABLED" itemSubjectRef="xsd:boolean">
<extensionElements>
<flowable:value>true</flowable:value>
</extensionElements>
</dataObject>
<serviceTask id="REFRESH_TASK" name="REFRESH_TASK" flowable:async="true" skipExpression="/*something should be here*/" flowable:triggerable="true" flowable:class="com.delegates.customDelegate">
<extensionElements>
<flowable:field name="inputData">
<flowable:string>["input1"]</flowable:string>
</flowable:field>
<flowable:field name="outputDataConfig">
<flowable:string>["output1"]</flowable:string>
</flowable:field>
</extensionElements>
</serviceTask>
I want to skip refresh task if my input1 is present in optionalInputList of dataObject.
Can I achieve this inside BPMN ?
In order to enable skip expressions, you need to set the _ACTIVITI_SKIP_EXPRESSION_ENABLED field to true as a variable. You have correctly done this by defining a dataObject with the variable demonstrated in your bpmn20.xml.
Next, your skip_expression as any other expression in flowable expects a true or false result and is evaluated before your service task's execution expression,DelegateExpression,Class etc..
I have defined the skip_expression to execute a method in a Spring Bean that returns either true(task skipped) or false(task executed)
<serviceTask id="sid-80A94367-049B-4851-BD97-DC1A368DAB9F" name="Some service" flowable:expression="${serviceTaskBean.execute(execution)}" flowable:skipExpression="${serviceTaskBean.skipExpressionLogic(optionalInputList)}"></serviceTask>
where the input to the method is the value of your optionalInputList dataObject
The Service Task Bean :
public class ServiceTaskBean {
public void execute(DelegateExecution execution) {
//some service execution logic executed only if the
//skipExpressionLogic method below returns false
}
public boolean skipExpressionLogic(String optionalInputList) {
try {
//The values set in your dataObject appears in
//optionalInputList
if(optionalInputList.contains("input1")) {
return true; //task skipped
}
else {
return false; //task executed
}
}catch(Exception e) {
e.printStackTrace();
}
return false;
}
}
more info on using expressions here : https://www.flowable.com/open-source/docs/bpmn/ch04-API#expressions

Choice flow control component fails in Mule ESB

i have a choice flow control component that uses an expression as follows:
<choice>
<when expression="${LoggingFlag} == YES">SOME CODE</when>
<otherwise>SOME OTHER CODE</otherwise>
</choice>
Here LoggingFlag used is a key-value pair defined in the app.properties file.
LoggingFlag=NO
when i run the code i see the following error:
Execution of the expression "NO == YES" failed. (org.mule.api.expression.ExpressionRuntimeException). Message payload is of type: String
Exception stack is:
1. [Error: unresolvable property or identifier: NO]
[Near : {... NO == YES ....}]
Can someone tell me what is the reason behind this issue?
This error occurs due to Mule not being able to resolve the type of value, set to LoggingFlag while comparing it in choice.
For this you need to explicitly change the type to string, so that Mule can compare the two easily.
For that you need to use:
<choice>
<when expression="'${LoggingFlag}' == 'YES'">SOME CODE</when>
<otherwise>SOME OTHER CODE</otherwise>
</choice>
You need to enclose the variables in when expression within single quotes ' '
<choice doc:name="Choice">
<when expression="'${LoggingFlag}' == 'YES'"><set-payload value="payload 1" doc:name="Set Payload"/></when>
<otherwise><set-payload value="payload 2" doc:name="Set Payload"/></otherwise>
</choice>
You can even try by reading the property value and storing it in a variable and then comparing the variable value with the string in choice component as follows:
<set-variable variableName="SetLoggingFlag" value="${LoggingFlag}" doc:name="SetLoggingFlag"/>
<choice>
<when expression="#[flowVars.SetLoggingFlag=='YES']">SOME CODE</when>
<otherwise>SOME OTHER CODE</otherwise>
</choice>
Hope this helps you!

Is there a while loop in Camel?

Is there an idea of a while loop in Camel?
We are using Camel for doing batch processing (not really the remit of an ESB I know). I want to keep checking on the status of something else whilst I am processing messages in the ESB. I can only find a loop that loops for a defined number of times, i.e. for testing or a quartz timer that will check every x seconds. Neither of these are really suitable.
Any suggestions, or am I asking for something simply outside of the remit of an ESB?
What about doing something like this:
<camelContext id="myContext">
<route id ="initializer">
<!--This will be created only once -->
<from uri="timer://foo?repeatCount=1"/>
<to uri="seda:mySedaQueue"/>
</route>
<route id ="myRoute">
<from uri="seda:mySedaQueue"/>
<choice>
<when>
<simple>{your condition if you want to continue}</simple>
...
<to uri="seda:mySedaQueue" />
</when>
<otherwise>
...
</otherwise>
</choice>
</route>
</camelContext>
How about the camel timer:?
E.g.
from("timer://foo?fixedRate=true&period=1000")
.to("bean:myBean?method=someMethodName");
Reference: Camel Timer Component
Try using DynamicRouter.
It uses an Expression class to determine the next route to dispatch the exchange. If the expression returns null it means that it will stop routing.
This way you can evaluate the exchange contents and continue routing to the same route until you decide is time to stop, and then return null.
from("direct:start")
.dynamicRouter(new Expression() {
#Override
public <T> T evaluate(Exchange exchange, Class<T> type) {
if (<your condition>) return (T) "direct:whileRoute";
return null;
}
})
.to("mock:finish");
from("direct:whileRoute")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
// Do whatever you want
}
});

ItemUpdating called twice after ItemAdded in event receiver

I've created an event receiver to handle the ItemAdded and ItemUpdating events on a document library in SharePoint 2010.
I've encountered a problem where when I add a document to the library (e.g. by saving it back from Word) the ItemAdded method is correctly called however this is then followed by two calls to ItemUpdating. I have removed all code from my handlers to ensure that it's not something I'm doing inside that is causing the problem. They literally look like:
public override void ItemUpdating(SPItemEventProperties properties)
{
}
public override void ItemAdded(SPItemEventProperties properties)
{
}
Does anyone have a solution to this issue?
Here is my elements.xml file for the event receiver:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Receivers ListTemplateId="101">
<Receiver>
<Name>DocumentsEventReceiverItemUpdating</Name>
<Type>ItemUpdating</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>My.Namespace.DocumentsEventReceiver</Class>
<SequenceNumber>10000</SequenceNumber>
<Synchronization>Synchronous</Synchronization>
</Receiver>
<Receiver>
<Name>DocumentsEventReceiverItemAdded</Name>
<Type>ItemAdded</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>My.Namespace.DocumentsEventReceiver</Class>
<SequenceNumber>10000</SequenceNumber>
<Synchronization>Synchronous</Synchronization>
</Receiver>
</Receivers>
</Elements>
Problem is that In Document library event handlers during Item Updating also checking that Document is it in Check In mode or Check Out. That's why it is called twice.
You should put your code in
public override void ItemUpdating(SPItemEventProperties properties)
{
base.ItemUpdating(properties);
if (properties.AfterProperties["vti_sourcecontrolcheckedoutby"] == null && properties.BeforeProperties["vti_sourcecontrolcheckedoutby"] != null)
{
//do stuff
}
}
For further details Here is good article for describe whole situation of the Document's Events.

Spring Batch: Always looking for files with MultiResourceItemReader

I'm a newbie in Spring Batch. I have inherited a batch process implemented with Spring Batch.
This works well, except for one thing I'll try to describe.
I launch parseJob and, when it's reading XML to process in bean parsingStepReader,
read() method is been invoking always.
The directory *path_to_xml* contains only one XML, invoke read() and return XML parsed, which is processed OK. Then, read() method is invoked again, return a null object, and is invoked again, return null... and so on.
When debugging, MultiResourceItemReader read method try to read, does not read anything (all resources has already been readed), increment currentResources and return null.
I have readed something about the job stops when the reader return a null object, but that read method returns null and reads again and again...
I changed restartable to false, but does not work.
The job is launched in Linux, batch mode, with org.springframework.batch.core.launch.support.CommandLineJobRunner
Because of this problem, the .sh that launch the job does not finish, and resources are busy.
How can I avoid this, or stop the job when resources (XML) input directory have already been processed?
Any help would be very appreciated. Best regards.
Beans file and Java class pieces are attached
<batch:job id="parseJob" restartable="true" incrementer="jobParametersIncrementer">
<batch:flow parent="parseFlow"/>
<batch:flow .../>
<batch:flow .../>
</batch:job>
<batch:flow id="parseFlow">
<batch:step id="parsingStep">
<batch:tasklet start-limit="100" allow-start-if-complete="true" transaction-manager="..." task-executor="taskExecutor" throttle-limit="$...">
<batch:chunk reader="parsingStepReader" writer="..." processor="..." commit-interval="..." skip-limit="10000000">
<batch:skippable-exception-classes>
<batch:include class="java.lang.Exception" />
</batch:skippable-exception-classes>
</batch:chunk>
<batch:listeners>
<batch:listener ref="iwListener" />
<batch:listener ref="mySkipListener" />
<batch:listener ref="myStep1Listener" />
</batch:listeners>
<batch:no-rollback-exception-classes>
<batch:include class="java.lang.Exception" />
</batch:no-rollback-exception-classes>
</batch:tasklet>
</batch:step>
</batch:flow>
<!-- -->
<bean id="bpfReader" class="org.springframework.batch.item.xml.StaxEventItemReader" scope="prototype">
<property name="fragmentRootElementName" value="..." />
<property name="unmarshaller" ref="..." />
<property name="strict" value="false" />
</bean>
<bean id="multiresourceItemReader" class="...SyncMultiResourceItemReader" abstract="true">
<property name="strict" value="false" />
<property name="delegate" ref="bpfReader" />
</bean>
<bean id="parsingStepReader" parent="multiresourceItemReader" scope="step">
<property name="resources" value="<path_to_xml>" />
</bean>
And the reader class is:
public class SyncMultiResourceItemReader<T> extends MultiResourceItemReader<T> {
. . .
#Override
public T read() throws Exception, UnexpectedInputException, ParseException {
synchronized (this) {
return super.read();
}
}
. . .
}
UPDATE: Solution suggested by #vsingh works perfectly. Once an input element is chosen, it must be removed from the input. I don't know why, but class org.springframework.batch.item.file.MultiResourceItemReader does not work as I expected, especially in an input error.
I hope this helps. Best regards
The read method will read the data , store at class level and pass it to the write method.
I will give you an example of how we did it
for eg
#Override
public Long read() throws Exception, UnexpectedInputException,
ParseException, NonTransientResourceException {
synchronized (this.myIds) {
if (!this.myIds.isEmpty()) {
return this.myIds.remove(0);
}
return null;
}
}
myIds is a List at class level
This list is populated at before step method
#Override
public void beforeStep(final StepExecution stepExec) {
this.stepExecution = stepExec;
// read the ids from service and set at class level
}
Solution suggested by #vsingh works perfectly. Once an input element is chosen, it must be removed from the input. I don't know why, but class org.springframework.batch.item.file.MultiResourceItemReader does not work as I expected, especially in an input error.
I hope this helps. Best regards