Is there a while loop in Camel? - while-loop

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
}
});

Related

RabbitMQ messages are not recieved in order by the listener

I have a scenario where the order of messages received at the receiving end is some times not in order.
My scenario:
MACHINE A:
I am sending a series of messages(around 12 messages) from machine A to machine B over rabbitMQ shovel.
The messages are are of different sizes. The over all size of 12 messages is close to 8mb.
Once the 12 messages are sent, i am also sending "complete message" in the end to MACHINE B.
MACHINE B:
This is the recieving machine. This machine has a single listener. It recieves all the messages sent by MACHINE A. Once it recieves "sending complete", its obvious that this is the last message from MACHINE A and MACHINE B starts processing all the messages that were recieved.
MACHINE B Configiration
<rabbit:listener-container
connection-factory="connectionFactory">
<rabbit:listener ref="onMessageCommand"
queue-names="CommandQueue" />
</rabbit:listener-container>
<bean id="onMessageCommand"
class="com.mypackage.command.messaging.OnMessageListner">
<property name="callBackObject" ref="callbackDisEvent" />
<property name="template" ref="amqpTemplate" />
</bean>
<bean id="callbackDisEvent" class="com.mypackage.command.OperationSettingsListener"></bean>
MACHINE A CODE
public void sendMessage(String messageToSend,String machineBID)
{
Message sendMessage = new Message(messageToSend, new MessageProperties());
RabbitTemplate rabbitTemplate =
messagingApplContext.getBean(RabbitTemplate.class);
rabbitTemplate.send(message, machineBID + ".command");
}
ISSUE:
Some times i am observing that one "sending complete" is recived by the MACHINE B just before some setting. Ideally "sending complete" should always be the last message recived by the MACHINE B.
May i please know what can be the issue here.
Make sure you are using message acknowledgements. More info here https://www.rabbitmq.com/confirms.html
Can you please provide some links for sample programs to implement scoped operations in the right manner. or a sample code will also suffice
The link I provided you has this example:
Collection<?> messages = getMessagesToSend();
Boolean result = this.template.invoke(t -> {
messages.forEach(m -> t.convertAndSend(ROUTE, m));
t.waitForConfirmsOrDie(10_000);
return true;
});
You just have to make sure all the sends are performed within the scope of an invoke call...
Boolean result = this.template.invoke(t -> {
...
t.send(...)
...
t.send(...)
...
return true;
}
And they will all go on the same channel. The return doesn't have to be boolean, it can be anything you want, even null.
this.template.invoke(t -> {
...
t.send(...)
...
t.send(...)
...
return null;
}

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!

originalPayload not the same as message.originalPayload in groovy scripts

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());
}
}

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