How to invoke a method in restful web service using camel-cxf? - rest

I want to invoke a rest service using apache camel. Currently i am using the cxfrs component to configure my endpoint. My route looks like below:
from("cxfrs://http://127.0.0.1:8080/RestServiceApp/?resourceClasses="com.sample.Server.HelloWorld").log("Route Started");
My problem is that i want to invoke a method present in the server class (HelloWorld in my case). Can you please tell me how do i call a particular method?

Camel doesn't call resource class methods. From the documentation on the Camel web-site http://camel.apache.org/cxfrs.html:
This class is used to configure the JAXRS properties ONLY. The methods
will NOT be executed during the routing of messages to the endpoint,
the route itself is responsible for ALL processing instead.
You need to write a custom processing logic, for example as following:
<from uri="cxfrs://http://127.0.0.1:8080/RestServiceApp/?resourceClasses="com.sample.Server.HelloWorld">
<choice>
<when>
<simple>${header.operationName} == 'operation1'</simple>
<to uri="direct:operation1" />
</when>
<when>
<simple>${header.operationName} == 'operation2'</simple>
<to uri="direct:operation2" />
</when>
....
</choice>

Related

Camel REST service problem in parallel calls

I have created a REST service with Apache Camel (REST DSL) running on Karaf container that accepts a list of items and returns the availabilities of those them. The problem is that if the service is called in parallel it doesn’t return the correct results. For example, let’s assume that we have the following two calls:
Call 1: item1, item2
Call 2: item3, item4
I would expect the following two answers
Response 1: availabilityOfItem1, availabilityOfItem2
Response 2: availabilityOfItem3, availabilityOfItem4
But instead of that I am getting the two answers with mixed availabilities
Response 1: availabilityOfItem1, availabilityOfItem2, availabilityOfItem3, availabilityOfItem4
Response 2: availabilityOfItem1, availabilityOfItem2, availabilityOfItem3, availabilityOfItem4
Probably this problem occurs due to the related bean that I have for the service, but let me give you an overview of what I did in my Camel context.
<camelContext>
<restConfiguration ... />
<rest path="/" consumes="application/json" produces="application/json">
<post uri="/availabilities" type="com.xxx.ArticleListReq">
<to uri="direct:availabilities"/>
</post
</rest>
<route id="route.Availabilities">
<from uri="direct:availabilities"/>
<bean ref="availabilitiesBean" method="init"/>
<split parallelProcessing="true">
<simple>${body.articles}</simple>
...
SQL calls for each item
<bean ref="availabilitiesBean" method="buildResponse"/>
</split>
<bean ref="availabilitiesBean" method="getResponse"/>
</route>
</camelContext>
As you can notice when the service is called it goes to the direct:availabilities route that does the job. I am using availabilitiesBean in order to initialize the response object (List), then for each request item I am getting availability from db and put the result to the response object that was previously initialized (buildResponse) and at the end I am returning that object with method getResponse.
The problem is that bean has a singleton scope and that means that for both calls the same bean is used. So, call 1 writes the answer for item1 and item2 but the same time call 2 adds also item3 and item 4 in the response.
Is there a possibility to create a request scope bean? Or follow another approach in order to overcome this issue?
Thanks a lot!

Camel cxfrs RESTful client / ProducerTemplate ConnectionTimeout

I am trying to set the 'connectionTimeout' for a Camel CXF-RS component here which produces a RESTful requests on a 3rd party service. The default 30000 miliseconds is to long.
Exchange exchange = template.send("cxfrs://" + url, new Processor() {
public void process(Exchange exchange) throws Exception {
exchange.setPattern(ExchangePattern.InOut);
Message inMessage = exchange.getIn();
setupDestinationURL(inMessage);
// using the http central client API
inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_USING_HTTP_API, Boolean.TRUE);
// set the Http method
inMessage.setHeader(Exchange.HTTP_METHOD, "PUT");
// set the relative path
inMessage.setHeader(Exchange.HTTP_PATH, url);
// Specify the response class , cxfrs will use InputStream as the response object type
inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_RESPONSE_CLASS, Customer.class);
// set a customer header
inMessage.setHeader("key", "value");
// since we use the Get method, so we don't need to set the message body
inMessage.setBody(null);
}
});
I have tried adding this to our application-context as many have suggested, but cannot see it modifying the default values when debugging through the HTTPConduit and HTTPClientPolicy classes:
<http-conf:conduit name="*.http-conduit">
<http-conf:client ConnectionTimeout="5000"/>
</http-conf:conduit>
and I have tried appending
"?httpClientAPI=true&connectionTimeout=5000"
as options to the url string.
Any help or guidance would be much appreciated.
Adding the http-conf:conduit element in application-context as you did is the way to go and should work. What makes you say it does not?
Quite often a backend server take too long to answer, after the connection is made; in this case setting ReceiveTimeout is as important as ConnectionTimeout.
This is a sample camel Route which consumes RS requests and calls a third-party RS server; the ReceiveTimeout and ConnectionTimeout parameters work as expected.
<cxf:rsServer id="rsFrontServer" address="..." serviceClass="..."/>
<cxf:rsClient id="rsBackendClient" address=".../" serviceClass="..."/>
<http-conf:conduit name="*.http-conduit">
<http-conf:client ReceiveTimeout="5000" ConnectionTimeout="5000"/>
</http-conf:conduit>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route id="front">
<from uri="cxfrs:bean:rsFrontServer"/>
<!-- do stuff -->
<to uri="cxfrs:bean:rsBackendClient"/>
</route>
</camelContext>

Spring integration XMPP and Google Cloud Messaging

I'm using the spring integration xmpp module to write a custom implementation of a 3rd party Server connecting to GCM cloud services, as in GCM Cloud Connection Server (XMPP).
So far I've successfully connected to the GCM server, however when I send a message to the server I end up with something like:
<message id="m-1366082849205" to="REGISTRATION_ID">
<body>{"hello":"world"}</body>
</message>
, but I need to send something like this:
<message id="">
<gcm xmlns="google:mobile:data">
{
"to":"REGISTRATION_ID",
"message_id":"m-1366082849205"
"data":
{
"hello":"world",
}
}
</gcm>
</message>
I use the latest SI version, 4.0.4, this is my configuration in the xml:
<int-xmpp:outbound-channel-adapter
id="gcmOutboundAdapter" channel="gcmOutboundNotificationChannel"
xmpp-connection="gcmConnection" auto-startup="true"/>
I'm sending messages with the usual MessageBuilder like this:
Message<String> xmppOutboundMsg = MessageBuilder.withPayload(xmppPayload)
.setHeader(XmppHeaders.TO, REGISTRATION_ID)
.build();
where xmppPayload is a json string.
I need to configure/override the way the xmpp message is composed, what is the best practice to achieve the result? Should I override the class implementing int-xmpp:outbound-channel-adapter with a custom service activator, is there anyway to configure the way the xmpp message is composed?
Thanks for any help.
<gcm xmlns="google:mobile:data"> is a extended content element (see RFC 6120 8.4), which is modelled as PacketExtension in Smack. Do not subclass message, instead create a GCMPacketExtension class and add a instance of it to your message
message.addPacketExtension(gcmPackExtension)
The format of the message is hard-coded in the Smack Message.toXML() method (we use the smack library underneath).
See #Flow's answer.
Then, subclass ChatMessageSendingMessageHandler, overriding handleMessageInternal() - pretty much copy the code and set the extension after the message is created.
The easiest way to configure your custom handler is probably to put it in a chain...
<chain input-channel="gcmOutboundNotificationChannel">
<bean class="foo.MyChatMessageSendingMessageHandler">
<constructor-arg ref="gcmConnection" />
</bean>
</chain>
Or you can wire it up as a top level bean and inject it into a ConsumerEndpointFactoryBean.
Feel free to open a New Feature JIRA Issue and we'll consider adding an extension point to make this a bit easier.
Until we introduce the PackExtension injection, you can overcome it with custom <transformer ref="">, because the <int-xmpp:outbound-channel-adapter> can accept org.jivesoftware.smack.packet.Message as a Message payload:
<transformer ref="toGcmTransformer" output-channel="gcmOutboundNotificationChannel"/>
<int-xmpp:outbound-channel-adapter
id="gcmOutboundAdapter" channel="gcmOutboundNotificationChannel"
xmpp-connection="gcmConnection" auto-startup="true"/>
public class ToGcmTransformer extends AbstractTransformer {
protected Object doTransform(Message<String> message) throws Exception {
String to = message.getHeaders().get(XmppHeaders.TO, String.class);
xmppMessage = new org.jivesoftware.smack.packet.Message(to);
xmppMessage.setBody(message.getPayload());
xmppMessage.addPacketExtension(gcmPackExtension);
return xmppMessage;
}
}
Please, raise an issue about PackExtension support.
-->
<int:chain input-channel="gcmOutboundNotificationChannel">
<!--<int:transformer ref="toGcmTransformer" output-channel="gcmOutboundNotificationChannel"/>-->
<bean class="com.payumoney.cardhash.service.MyMessageSendingMessageHandler">
<constructor-arg ref="gcmConnection" />
</bean>
</int:chain>
<int:transformer id="testTransformer" ref="toGcmTransformer" input-channel="gcmInboundNotificationChannel"
method="doTransform" output-channel="gcmOutboundNotificationChannel"/>
<!--<int:transformer ref="toGcmTransformer" output-channel="gcmOutboundNotificationChannel"/>-->
<int-xmpp:outbound-channel-adapter
id="gcmOutboundAdapter" channel="gcmOutboundNotificationChannel"
xmpp-connection="gcmConnection" auto-startup="true"/>
<int:chain input-channel="gcmInboundNotificationChannel">
<bean class="com.payumoney.cardhash.service.PayumoneyNotificationListeningEndpoint">
<constructor-arg ref="gcmConnection" />
<property name="outputChannel" ref="gcmOutboundNotificationChannel" />
</bean>
</int:chain>
<int-xmpp:inbound-channel-adapter
id="gcmInboundAdapter" channel="gcmInboundNotificationChannel"
xmpp-connection="gcmConnection" extract-payload="true" auto-startup="true" />

Saving WS payload into database in Camel

I'm absolutely newbie in Apache Camel. I'd like to create a very simple app in which it would accept WS calls and save the payload into a database using JPA.
The payload's structure is quite simple. The root is a Marriage object. It contain some String and int and Date fields, a wife, a husband and a list of children (Person objects).
My goal is to save these data into two tables of a database: MARRIAGE, PERSON.
I've successfully created a jaxws:endpoint in which I listen and respond a dummy response.
I've created the tables and JPA entities.
I don't know how to "connect" the WS implementation with the spring configured JpaTemplate. Should I solve this problem with Camel routing using somehow a #Converter class or #Injet it into the WS implementing class by Spring. I'm confused.
Should I use cxf endpoint instead of jaxws endpoint?
You need to use camle-cxf endpoint if you want to use camel. What I would do is expose the endpoint as a camle-cxf endpoint. Something like this:
<camel-cxf:cxfEndpoint id="listenerEndpoint"
address="http://0.0.0.0:8022/Dummy/services/Dummy"
wsdlURL="wsdl/DummyService.wsdl"
xmlns:tns="http://dummy.com/ws/Dummy"
serviceName="tns:Dummy"
endpointName="tns:DummyService">
<camel-cxf:properties>
<entry key="schema-validation-enabled" value="true"/>
<entry key="dataFormat" value="PAYLOAD"/>
</camel-cxf:properties>
</camel-cxf:cxfEndpoint>
Then I would have a simple Spring bean like this:
<bean id="processor" class="com.dummy.DummyProcessor">
<property name="..." value="..."/> //there goes your data source of jdbc template or whatever...
</bean>
If you want to use JPA just configure all the configuration and inject your entity manager into this bean.
The actual class would look something like this:
public class DummyProcessor {
#Trancational //If you need transaction to be at this level...
public void processRequest(Exchange exchange) {
YourPayloadObject object = exchange.getIn().getBody(YourPayloadObject.class);
//object - is your object from SOAP request, now you can get all the data and store it in the database.
}
}
The camel route would be like this:
<camel:camelContext trace="true" id="camelContext" >
<camel:route id="listenerEndpointRoute">
<camel:from uri="cxf:bean:listenerEndpoint?dataFormat=POJO&synchronous=true" />
<camel:log message="Got message. The expected operation is :: ${headers.operationName}"/>
<camel:choice>
<camel:when>
<camel:simple>${headers.operationName} == 'YourPayloadObject'</camel:simple>
<camel:bean ref="processor" method="processRequest"/>
</camel:when>
</camel:choice>
<camel:log message="Got message before sending to target: ${headers.operationName}"/>
<camel:to uri="cxf:bean:someTargetEndpointOrSomethingElse"/>
<camel:log message="Got message received from target ${headers.operationName}"/>
</camel:route>
</camel:camelContext>
Hope this helps.

Do not resolve view in RESTful Application

I am building a web application with RESTful web services using Spring MVC 3. The web services will be used by applications, so should never really resolve any requests to a view. Is there any way to specify in the servlet context that no requests should resolve to any view?
At the moment, I have:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
which I know tries to resolve any request to a correspondingly named view in the jsp folder. However, if I remove this, the application just tries to use a default view resolver.
The reason I am concerned about this is that my application logs are going to be full of the following messages (even though it works fine):
SEVERE: Servlet.service() for servlet [DispatcherServlet] in context with path [/vouchd] threw exception [Circular view path [signup]: would dispatch back to the current handler URL [/vouchd/signup] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)] with root cause
javax.servlet.ServletException: Circular view path [signup]: would dispatch back to the current handler URL [/vouchd/signup] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
or with the InternalViewResolver:
WARN [http-bio-8080-exec-4] (DispatcherServlet.java:1057) - No mapping found for HTTP request with URI [/app/WEB-INF/jsp/call.jsp] in DispatcherServlet with name 'DispatcherServlet'
which I guess is the better of the two evils. I don't want to turn off logging WARN level.
Try with #ResponseStatus. This code returns 204 with no content and view resolving skipped:
#ResponseStatus(NO_CONTENT)
void noView() {
//...
}
If you want to return raw data and simply serialize it to JSON or XML, use #ResponseBody:
#ResponseBody
MyPojo noView() {
return new MyPojo();
}