Hi guys I have the following situation when I need to have "composite" process for the XML request. This is snippet from my spring route definition:
<route id="request1">
<from uri="activemq:request1" />
<unmarshal ref="integrationServerJaxb" />
<bean ref="createTINValidationMessage" />
<bean ref="switchComponent" />
<bean ref="createCreateTINMessage" />
<bean ref="switchComponent" />
<bean ref="createResponse1" />
<marshal ref="integrationServerJaxb" />
</route>
Basically what I want to achieve is:
grab a message from request1 message queue
create TIN VALIDATION message from it
send TIN VALIDATION message to the switch
wait for the switch response
with the switch response from step 4 AND initial request 1 XML message, create CREATE TIN message
send message (from step 5) to the switch
create response XML based on response from switch (from step 6)
So in other words, I need to get hold of initial message during processing. In the CreateCreateTINMessage bean I can change the method parameter to Message type, then it will be mapped to the actual Camel Message (from the previous step though), not the very first message in the exchange. Inspecting the message's exchange, I could trace the initial JMS message with request1 xml payload but getting that deep does not seem right. My question is, is it possible to somehow perform integration with intermediary result and initial message from the route? Thank you.
sure, just preserve it explicitly in an exchange property (or message header)...
from(...)
.setProperty("ORIG_EXCH",body())
...
.process(new Processor() {
public void process(Exchange exch) throws Exception {
Object orig = exch.getProperty("ORIG_EXCH");
...
}
})
...
or you can use this API to retrieve it from your route...
exchange.getUnitOfWork().getOriginalInMessage();
Related
I have a route that calls an external rest service. I have configured my error handler as shown below.
errorHandler(deadLetterChannel("jms:dlc").maximumRedeliveries(3));
What i want to do:
If connection to external api fails, i want to retry 3 times and then send to deadLetterChannel
If api call is fine, i want to check the status code, log the response and then send the message to deadLetterChannel.
For that i set throwExceptionOnFailure to false.
In my route i have a bean as the last endpoint. This bean receives the response from the external end point and checks for the status.
void process(Exchange exchange){
//check http status code
//if not success
exchange.setProperty(Exchange.ROUTE_STOP,true);
//sendToDeadLetterQueue;
}
My problem is that redelivery happens even when i am able to connect to API. I expect the redelivery to happen on error. But i am handling the response and also setting the exchange to stop.
Can i stop the redelivery from my bean?
You can use onException as follows:
<onException>
<exception>SomeException</exception>
<handled><constant>true</constant></handled>
<process ref="failureResponse"/>
</onException
Use onException tag handled as true
Java DSL
onException(ExceptionClass).handled(true)
.to(deadLetterChannel);
Spring DSL :
<onException>
<exception>SomeException</exception>
<handled><constant>true</constant></handled>
<to uri=deadLetterChannel/>
</onException>
For More Clarification click here
I have already created a simple tcp server with spring integration which keeps a connection alive and responses to each request during the connection.
In that requestMethod, I'm also able to read the MessageHeder to get the connectionId.
Now I want to send messages from the server to the client.
As far as i understood the documentation i need to put the connectionid in the MessageHeader and then send the message. But I can't figure out how to do the latter one. I have the Message ready but how do i send/push it out?
Here is my xml-configuration:
<bean id="lfSerializer" class="org.springframework.integration.ip.tcp.serializer.ByteArrayLfSerializer"/>
<int-ip:tcp-connection-factory
id="socketserver"
type="server"
port="30124"
using-nio="true"
deserializer="lfSerializer"
serializer="lfSerializer"
single-use="false"/>
<int-ip:tcp-inbound-channel-adapter id="inboundServer"
channel="inputChannel"
connection-factory="socketserver"/>
<int-ip:tcp-outbound-channel-adapter id="outboundServer"
channel="outputChannel"
connection-factory="socketserver"
/>
<int:channel id="inputChannel">
<int:interceptors>
<int:wire-tap channel="logger"/>
</int:interceptors>
</int:channel>
<int:channel id="outputChannel">
<int:interceptors>
<int:wire-tap channel="logger"/>
</int:interceptors>
</int:channel>
<int:logging-channel-adapter id="logger" level="DEBUG" log-full-message="true"/>
<int:service-activator input-channel="inputChannel"
output-channel="outputChannel"
ref="echoService"
method="test"/>
<bean id="echoService"
class="com.examples.EchoService" />
I also tried to create a bean and another serviceactivator for output, then autowired that bean and called it's "send" method, but I don't know what to implement in that send-method to send out a message.
If it's a simple request/response scenario use an inbound gateway instead of channel adapters and the framework will take care of the correlation for you. This is used in the sample app. Simply have your POJO method return the reply payload.
If you want to send arbitrary messages to the client (i.e. NOT request/reply but, say, in, out, out, in, out, out, out etc) then, yes, you need to build the messages yourself, inserting the ip_connectionId header.
To send them, there are several options:
Inject outputChannel into your code
#Autowired
private MessageChannel outputChannel;
Use a MessagingTemplate to send to the channel (or simply call its send(Message<?> message) method directly).
Or
Use a MessagingGateway with a void return method and inject the gateway into your code.
EDIT:
Note, that if you want to start sending messages before receiving anything, you can obtain the connection id via the connection opened event.
I am using Spring Integration 4.1.2.
In the program flow, at the end of a process I need to send an email. I am using the following:
<int:payload-type-router input-channel="response.in">
<int:mapping type="java.lang.String" channel="response.out"/>
<int:mapping type="org.springframework.mail.SimpleMailMessage" channel="mail.out"/>
</int:payload-type-router>
<mail:outbound-channel-adapter channel="mail.out" mail-sender="mailSender"/>
This is working fine.
I want to also handle the situation when the mail server is down.
I've tried the following solution but it does not work.
<int:chain input-channel="errorChannel" output-channel="emailErrorChannel">
<int:transformer ref="errorUnwrapper" />
</int:chain>
And the unwrapper:
#MessageEndpoint
public class ErrorUnwrapper {
#Transformer
public Message<?> transform(final ErrorMessage errorMessage) {
Message<?> failedMessage = ((MessagingException) errorMessage.getPayload()).getFailedMessage();
return failedMessage;
}
}
But this is not working. I want to catch the exception and send a meaningful response back to the user instead of a stacktrace. And I want to do this within Spring Integration. Otherwise I'll have to write a Java mail service call with a service-activator instead of the SI mail extension.
Or is it a one-way component? I've just found this blog post doing the same. I've also read this but got nowhere.
You likely need to add the errorChannel to whatever starts you flow; you need to show us the rest of your configuration.
Alternatively, you can add an ExpressionEvaluatingAdvice to the mail adapter; see this sample for an example of using the advice.
I'm trying to send a simple POST request to a REST endpoint. I have a simple pojo that I would like to send in the payload as JSON. Here is the pojo (note I'm using Spring Integration with grails so the pojo/service are in Groovy):
class Person implements Serializable {
String name
}
Here is my gateway:
public interface PersonGateway {
Person savePerson(Person person)
}
Here are the important parts of the wiring:
<int:channel id="requestChannel" />
<int:channel id="responseChannel" />
<int:header-enricher input-channel="requestChannel">
<int:header name="Content-Type" value="application/json" />
</int:header-enricher>
<int:gateway id="PersonGateway"
service-interface="com.example.PersonGateway"
default-request-channel="requestChannel"
default-reply-channel="responseChannel">
<int:method name="savePerson" />
</int:gateway>
<int-http:outbound-gateway url="http://127.0.0.1:8000/person"
http-method="POST"
message-converters="jsonConverter"
expected-response-type="com.example.Person"
request-channel="requestChannel"
extract-request-payload="false"/>
This POST request never reaches that service but doesn't throw any exceptions. When I log all levels the only thing I get that looks like a clue is:
2014-03-30 16:35:07,313 [main] DEBUG
outbound.HttpRequestExecutingMessageHandler - Unable to attempt
conversion of Message payload types. Component
'org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler#0'
has no explicit ConversionService reference, and there is no
'integrationConversionService' bean within the context.
Other than that it doesn't give me much. I've been trying little things all day and can't seem to get anywhere. Anyone see what I am missing? Thanks!
Unable to attempt conversion of Message payload types.
Don't worry: it doesn't have value for you. In most cases we can live in our application without that integrationConversionService. Here it is needed for expressions. Since you don't use any expression, that WARN doesn't hurt you.
You say that you are going to send POJO as JSON, then you shouldn't use extract-request-payload="false". With false the <int-http:outbound-gateway> places to the request body entire Message<?> and changes content-type to application/x-java-serialized-object
Hope your jsonConverterdoes the correct stuff around POJO <-> JSON
I receive a SOAP message to a CXF endpoint, with a Long and String value.
eg. [5, 'test']
The camel route receiving messages is already using dataformat=POJO
I need to send these parameters on ActiveMQ to another application.
If I use:
<convertBodyTo type="java.lang.String"/>
The logs show the body contains 5 only. 'test' is not sent.
I tried converting to a POJO before converting to a String, but I can't find proper documentation on making TypeConverters, (seriously, who can read this and figure out actual code from it?)
eg.
<convertBodyTo type="com.company.InfoPojo"/>
<convertBodyTo type="java.lang.String"/>
If I try to just forward the CXF data to the queue without any converting, I get:
Failed to extract body due to: javax.jms.JMSException: Failed to
build body from content. Serializable class not available to broker.
Reason: java.lang.ClassNotFoundException: Forbidden class
org.apache.cxf.message.MessageContentsList! This class is not allowed
to be serialized. Add package with
'org.apache.activemq.SERIALIZABLE_PACKAGES' system property..
Anyone know what the best option here is?
Thanks
You should marshal the parameters to XML or JSON (or any other format that takes your fancy) before sending them to the queue. The consumer will then need to unmarshal them.
No need to mess around with type converters. Camel's data formats make this really easy: https://github.com/apache/camel/blob/master/components/readme.adoc#data-formats
JSON: https://github.com/apache/camel/blob/master/docs/user-manual/en/json.adoc
JAXB: https://github.com/apache/camel/blob/master/components/camel-jaxb/src/main/docs/jaxb-dataformat.adoc
Made a bean and sent to the bean:
public void process(Exchange exchange) throws Exception {
log.info("Converting CXF values for queue.");
Object[] args = exchange.getIn().getBody(Object[].class);
patientKey = String.valueOf((Long)args[0]);
destinationUrl = (String)args[1];
exchange.getOut().setBody(new String(patientKey + "|" + destinationUrl));
}