Using Spring EL to decide which outbound gateway to use - spring

My application can use one of two web services, lets call them WS A and WS B. Both contain the same interface.
I want to perform some logic on the HTTP headers and request channel. WS B should only used on certain request channels. To decide which channel is used I have created a Java class that takes the request channel as a String parameter.
<http:outbound-gateway request-channel="XXXXX"
url-expression="'${EL EXP}'" http-method="GET"
extract-request-payload="true" expected-response-type="java.lang.String"
charset="UTF-8" reply-timeout="3000" reply-channel="XXXXX">
</http:outbound-gateway>
I then read that the url-expression is evaluated when the context is initialised.
source : http://forum.springsource.org/showthread.php?113446-Usage-of-expressions-in-http-namespace-element-url
<int-http:outbound-gateway request-channel="requestChannel"
url="dummy"
http-method="GET" extract-request-payload="true" expected-response-type="java.lang.String"
charset="UTF-8" reply-timeout="3000" reply-channel="sysLoggerRequestChannel">
<int-http:uri-variable name="teststring" expression="test"/>
<int-http:uri-variable name="url" expression="evalClass.getDestinationForChannel(teststring)"/>
</int-http:outbound-gateway>
The problem with this approach is that the expressions in int-http:uri-variable do not seem to be evaluation.
All this makes me believe I am taking the wrong approach. Any help would be very appreciated.

If you have two separate web service end points and a way to determine which one to use per message then a Spring Integration router would be better suited to directing your messages around. This has the added advantage that you can do further processing on your messages specific to the endpoint prior to sending.
There are many many ways to configure a router, including writing an entirely custom one, so I suggest reading through that whole section to see what will work best for you.
A quick example based on message type:
<int:payload-type-router input-channel="requests">
<int:mapping type="my.business.WebServiceARequest" channel="wsA" />
<int:mapping type="my.business.WebServiceBRequest" channel="wsB" />
</int:payload-type-router>
<int-http:outbound-gateway request-channel="wsA" url="http://wsA.com/whatever"
... />
<int-http:outbound-gateway request-channel="wsB" url="http://wsB.com/foo"
... />

To refer to a Spring Bean you should use #. So instead of expression="evalClass.getDestinationForChannel(teststring)" it will be expression="#evalClass.getDestinationForChannel(teststring)".

Related

Consuming XML response from a REST call in Spring Integration

Seems to be a simple task but I cannot get my head around it.
I have a Spring integration chain which calls an external Webservice, which returns an XML. I would like to use that XML response in a downstream XpathRouter.
What expected-response-type should I use?
<int:chain input-channel="filesChannel">
<!-- ... some previous components in the chain -->
<int-http:outbound-gateway
http-method="POST"
url="http://web/service/url"
expected-response-type="java.lang.String" />
<int-xml:xpath-router default-output-channel="resultChannel">
<int-xml:xpath-expression expression="/order/status" />
<int-xml:mapping value="Error" channel="importErrorChannel" />
</int-xml:xpath-router>
</int:chain>
It doesn't seem like the xpath-router can consume the XML returned by the webservice. When I debug the router with a breakpoint on the following line:
Node node = this.converter.convertToNode(message.getPayload());
The node is null, although the message does contain valid XML.
Is it because I am not setting the right expected-response-type?
Here is the response XML I receive from the service:
<apiResponse version="1.0">
<orders>
<order>
<orderReference>test_2_3045342</orderReference>
<status>Error</status>
<errors>
<error>
<errorCode>1100</errorCode>
<errorMessage><![CDATA[ "Field is required: dropWindow" ]]></errorMessage>
</error>
</errors>
</order>
</orders>
</apiResponse>
Ok, I found my mistake - it was actually in the XPATH expression. It should have been //order/status to enable deep search.
The java.lang.String expected-response-type works just fine with XML XpathRouter.
Thanks

JMSExpiration vs TimeToLive

I'm trying to set message expiration within a Blueprint XML Camel route. The value I want to set as the expiration is held within the message body (a protobuf).
Here's my code:-
<setHeader headerName="AMQ_SCHEDULED_DELAY">
<method bean="NotificationScheduler" method="postponeSending" />
</setHeader>
<setHeader headerName="JMSExpiration">
<method bean="NotificationScheduler" method="getExpiry" />
</setHeader>
<setHeader headerName="ExpirationTest">
<method bean="NotificationScheduler" method="getExpiry" />
</setHeader>
<to uri="activemq:notifications.splitter" />
As you can see from the screen shot below, I'm successfully setting two of the three headers but the setting for "JMSExpiration" (as per this thread) has had no effect.
I know I could alternatively use the Recipient List pattern to dynamically set the uri - i.e. pull the expiry out of the message data and append the ?timeToLive=... option. However, this seems a little clunky to me.
Is there a way to set expiration via setHeader within the XML?
Thanks,
J.
Change your uri to: activemq:notifications.splitter?preserveMessageQos=true and you should be fine.
Some JMS headers can be "manually" overriden like you are trying to by using this option.
Please note that you might want to take some precausion, since if you are listening on one JMS endpoint, the arriving messages will have JMS headers populated, and when you send the message out in your "to", the message will keep JMSDeliveryMode, JMSExpiration and JMSPriority. This might or might not be what you want.

Re-marshalling protobuf within Camel route

I'm hoping someone can explain a bit more about how to configure Camel to marshal and unmarshal data. I have a route that calls a bean in order to determine a recipientList. This is based on the contents of the message (a protobuf).
The route config looks like:-
<route id="Splitter">
<from uri="activemq:notification.splitter" />
<unmarshal ref="notificationProto" />
<recipientList>
<method bean="NotificationSplitter" method="splitNotification" />
</recipientList>
</route>
The bean works fine, but the downstream routes complain that:-
org.apache.camel.RuntimeCamelException: java.lang.RuntimeException: Unable to find proto buffer class
The downstream routes have exactly the same protobuf dataFormat config as the route above. If I route directly to the downstream queues (i.e. bypass the bean and hardcode the "to" queues), which means I can also skip the unmarshalling step, it works fine.
I guess that I need to re-marshal the data before Camel puts the messages onto the destination queues but I don't know how to configure this within the XML. I've tried simply adding...
<marshal ref="notificationProto" />
...after the recipientList has been determined but it doesn't do it (I assume because Camel has already dispatched the messages by then).
An alternative could be to do the unmarshalling from within the bean as then the data on the exchange will presumably remain unaltered. I'm not quite sure how to do this. Would it work?
Thanks for any tips.
J.
Yeah the data formats are not an endpoint that's easy to send a message to, as otherwise you can use the Routing Slip EIP pattern instead, and send the message to the data format first, and then the destination. http://camel.apache.org/routing-slip.html
Though you could have a little route
<route>
<from uri="direct:marshalMe"/>
<marshal ref="notificationProto" />
</route>
And then use the routing slip, to set to "direct:marshalMe,whereYouWannaGoNext".
An alternative is to use an interceptor, and intercept sending to endpoints (you can filter by wildcards, or reg exps), and then do the marshal first. http://camel.apache.org/intercept
See that link for more details.

Can we provide multiple patterns for a single filter-chain in filterChainProxy

I have two patterns for which same filters are to be applied.
<security:filter-chain pattern="/home.do*" filters="a,b,c,d" />
<security:filter-chain pattern="/login.do*" filters="a,b,c,d" />
Along with the above two there are many other unique patterns and a generic pattern /**/*.do*/** as well.
Can I specify comma separated multiple patterns in the pattern attribute like below:
<security:filter-chain pattern="/home.do*, /login.do*" filters="a,b,c,d" />
Yes you can, but the implementation depends on Spring Security version you are using.
In 3.0 you can use path-type attribute:
<security:filter-chain-map path-type="regex">
<security:filter-chain pattern="^/(test|home)\.do$" filters="a,b,c,d" />
<!-- other patterns -->
<security:filter-chain-map path-type="regex">
In 3.1 you can either use request-matcher attribute (which deprecates path-type, just change path-type to request matcher in previous example), or you can use multiple http elements with request-matcher-ref bean and do this:
<http pattern="test.do,home.do" security="none" <!-- 'none' as example -->
request-matcher-ref="requestMatcher" />
<bean id="requestMatcher" class="com.example.CommaSeparatedRequestMatcher" />
with your custom implementation of CommaSeparatedRequestMatcher (which splits URL created from request and triest to match any string), based on, for example, RegexRequestMatcher.

Apache Camel: how store variable for later use

while 'playing around' with Camel using Spring DSL, I came across the following problem. Suppose the expected message flow looks like this:
client sends HTTP POST message with XML body to CAMEL
CAMEL proxies HTTP POST message towards server, with the URI slightly adapted using
info from the received XML body (eg: use XPATH to filter out a certain parameter)
after CAMEL has received a reply, CAMEL sends HTTP PUT message towards server, using parameters out of the XML body received in 1
So something like:
<route>
<from uri="...">
<to uri="...">
<to uri="...">
</route>
Question: how do I store the parameters in Spring DSL in step 1, so that I can use them later in step 3 ?
So, I would like to extract XML parameters out of the XML body of the message received in step 1 and put them into variables, which I then later on can use to compose the message to be sent in step 3.
For extracting the parameters, I was thinking of using XPATH. That looks ok, but I just don't see how to put the output of the XPATH into a variable and then use that variable later on ... (syntax ??)
Note: as you can see, my development knowledge is rather limited ... sorry for that. But it would still be great if someone could help with this :).
you can set store data in the Exchange properties or message headers like this...
.setHeader("ID", XPathBuilder.xpath("/order/#id", String.class))
.setProperty("ID", XPathBuilder.xpath("/order/#id", String.class))
and then retrieve them in a bean/processor from the Exchange like this...
String propId = (String) exchange.getProperty("ID");
String headerId = (String) exchange.getIn().getHeader("ID"); }
I leave you some examples:
<setHeader headerName="token">
<constant>someValue</constant>
</setHeader>
<setHeader headerName="userName">
<simple>${properties:userName}</simple> //from config
</setHeader>
<setProperty propertyName="bodyBkp">
<simple>${in.body}</simple>
</setProperty>
<setProperty propertyName="orderNumber">
<xpath resultType="String">//item[1]/orderNumber/text()</xpath>
</setProperty>
Getter
${exchangeProperty[orderNumber]}
${in.headers.token}
Documentation
Check the simple expression language:
http://camel.apache.org/simple.html
Sometimes looking at the test cases of Camel can be helpful as well, in particular for Spring DSL:
setProperty with Spring DSL
setHeader using XPATH with Spring DSL
simple expression language test

Resources