Save out response Body into variable with Apache Camel - apache-camel

i have my WSDL file which i built with apache-cxf and i have created my own RouteBuilder to perform a SOAP request. I receive correctly the response using the .log file, so i see into the console, but i do not understand if i can save the response into a variable, so i can perform my operation.
from("timer://start")
.setBody(routeSettings.body)
.log(CxfConstants.OPERATION_NAME+": "+routeSettings.operationName)
.setHeader(CxfConstants.OPERATION_NAME, constant(routeSettings.operationName))
.log(CxfConstants.OPERATION_NAMESPACE+": "+routeSettings.operationNamespace)
.setHeader(CxfConstants.OPERATION_NAMESPACE, constant(routeSettings.operationNamespace))
.to("cxf://"+routeSettings.endpointURL
+ "?serviceClass="+routeSettings.packageURL
+ "&wsdlURL=/wsdl/"+routeSettings.nameWSDL)
.log("Result: ${body.get(0).toString()}")
.to("log:results");
This is my configure() function, i would like to save the body content into a variable.

This allows you to get access to the response to perform operations:
...
.log("Result: ${body.get(0).toString()}")
.to("log:results");
.process(exchange -> {
MyResponseType myResponse = exchange.getIn().getMandatoryBody(MyResponseType.class)
})

Related

REST request fails with URI encoded path parameter

I use AngularJS (client) and a REST interface in my project (server, javax.ws.rs.*). I'm passing data in a path parameter. It may contain special characters, so I call encodeURIComponent() to encode the arguments prior to sending a request.
Client-side:
$http.put('/foo/data/' + encodeURIComponent(data) + '/bar');
The controller will process the request and send a response.
Server-side:
#PUT
#Path("/data/{data}/bar")
public ResultObject handleFooRequest(#PathParam("data") String data) throws Exception {
return handleRequest(data);
}
This works fine on localhost, however, the request fails when I do a request on our production server (Error 400: Bad request). What am I doing wrong and why is it working on one server and fails on the other? In general, is my approach correct? Do I need to tell RESTEasy to decode the arguments? To my understanding (I read the documentation), it does that on default.

Camel rest API for file download

Is there any camel restful web service example to provide file download as below api
#GET
#Path("/jar")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response downloadFile() {
File file = new File("/home/user/Downloads/classes.jar");
ResponseBuilder response = Response.ok((Object) file);
response.header("Content-Disposition", "attachment;filename=classes.jar");
return response.build();
}
You can use a combination of Camel REST DSL and Content Enricher (specifically - pollEnrich).
An example implementation for your case could look like this:
// you can configure it as you want, it's just an example
restConfiguration().component("restlet").host("localhost").port(8081);
rest("/jar")
.get()
.produces(MediaType.APPLICATION_OCTET_STREAM_VALUE)
.route()
.routeId("downloadFile")
.pollEnrich("file:/home/user/Downloads?fileName=classes.jar&noop=true")
.setHeader("Content-Disposition", simple("attachment;filename=classes.jar"));
Please note, that if the file is not found in the specified path, pollEnrich will block until the file arrives. You can set a timeout in milliseconds by providing a second argument of type long to the call to pollEnrich.

How to use / in parameter during rest webservice call from angularjs?

I need to send a value like app/role as parameter through rest webservice url from angularjs
In controller.js
var roleName = 'app/role';
checkRole.check({'roleName': roleName}, function(data){}
In model.js
popModel.factory('checkRole', function ($resource) {
return $resource('./rest/checkRole/:roleName',{roleName:'#roleName'},{
check: {'method':'GET'},
});
});
The rest webservice call in java
#GET
#Path("/checkRole/{roleName}")
#Produces(MediaType.APPLICATION_JSON)
public Response checkRole(#Context HttpServletRequest request, #PathParam("roleName") String roleName);
When i pass it i am getting browser console error as
Bad request response from the server.
For normal parameter values like 'Test', 'Solution', 'Application' etc. If i use with / as a parameter no process is done and i am getting error.
/ is reserved character for GET request. So, you can't use them directly. If you use them, you would get Bad Request Error.
One of the solution can be to encode the URL on client side and decode it on server.
Reference:
Characters allowed in GET parameter
How to handle special characters in url as parameter values?

Apache Camel, FTP consumer: How to take header parameters of the previous route?

I have several camel routes and I set a header in the Exchange object with the name FILE_NAME in the one route while reading the data from a DB. As a next step this route goes further to my FTP route where the file should be downloaded. The problem is that the FTP route does not receive the headers of the previous route with the contentEnricher I am using. This is the official behaviour: http://camel.apache.org/content-enricher.html However, "fileName" parameter of the FTP endpoint could be constructed dynamically to download a particular file.
My FTP route looks like this, with schematic data now:
from("direct:myRoute")
.pollEnrich("ftp://foo#localhost/public/reports?password=secret&binary=true&fileName=data.txt")
.to("mock:result");
How could I download just the file provided in the header value of the previous route? Should I not use content enricher or should I store the fileName in a variable somewhere else? Thanks also in advance for your response.
EDIT1:
Thanks for the posts I got further but I need to come back to the same point as I can access the header values from Java DSL also from the simple expression in pollEnrich() but not in the to(). The process(Exchange exchange) prints the correct header values, the pollEnrich with the sftp consumer fetches the file from the sftp server but neither ${header.FILE_NAME_ONLY} nor ${in.header.FILE_NAME_ONLY} access it in the to(). So the file created will be named "value of obNumber"_ . Could you please have a look what is incorrect in the code snippet below?
from("direct:SFTP").routeId("SFTP")
.log("### SFTP")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
LOGGER.info("### Process SFTP " +
"FILE_NAME_ONLY = " + exchange.getIn().getHeader("FILE_NAME_ONLY" ) +
" FILE_PATH = " + exchange.getIn().getHeader("FILE_PATH") +
" AGG = " + exchange.getIn().getHeader("AGG"));
}
})
.choice()
.when(header("FILE_NAME_ONLY").isEqualTo(""))
.log("### SFTP FILE_NAME_ONLY is null!")
.endChoice()
.otherwise()
.log("### SFTP FILE_NAME_ONLY is NOT null!")
.pollEnrich().simple("sftp:" + ftpUid + "#" + ftpHost + "/" + ftpBasePath + "/${header.FILE_PATH}?password=" +
ftpPwd + "&binary=true&fileName=${header.FILE_NAME_ONLY}")
.to("file:extract?fileName=" + obNumber + "_${header.FILE_NAME_ONLY}")
.end();
Solution:
The final solution was the dynamic router as Jeremie B proposed on 25 Febr. The problem is that pollEnrich() swallows up the previous header variables. So they are available to construct the URI but cannot be accessed afterwards to name the file. I was using camel 2.16.1.
What I did:
created a route with the dynamic router
created a bean that is called for determining the next route to get to
before the pollEnrich I save the necessary header values in a map of the exchange
after the pollEnrich I get the saved header values and set them as headers
then it is routed to a routed where it writes the file. (It can already access the newly set header variables)
Two examples that helped:
http://www.systemmobile.com/?p=427 "[...] To determine the
destination endpoint after each point in the route, we need to use a
Dynamic Router. [...]"
http://camel.apache.org/dynamic-router.html
You can use an expression to build the endpoint uri :
from("direct:myRoute")
.pollEnrich().simple("ftp://foo#localhost/public/reports?password=secret&binary=true&fileName=${header.FILE_NAME}")
.to("mock:result")
As said by Alexey, it's available since v2.16
The manual (http://camel.apache.org/content-enricher.html) says:
From Camel 2.16 onwards both enrich and pollEnrich supports dynamic
endpoints that uses an Expression to compute the uri, which allows to
use data from the current Exchange.
You just have to use Camel 2.16 or newer.
EDIT1:
This should work correctly
.to("file:?fileName=extract/" + obNumber + "_${header.FILE_NAME_ONLY}")
or try this:
.recipientList(simple("file:?fileName=extract/" + obNumber + "_${header.FILE_NAME_ONLY}"))
or try this:
.setHeader("CamelFileName").simple("extract/"+obNumber+"_${header.FILE_NAME_ONLY}")
.to("file:")

CXF wsdl2java, GZip compression, and stub reutilization

I´m using CXF to consume a WebService and, as the responses are quite large, I´m requesting with a gzip "Accept-Encoding" and using GZIPInInterceptor to handle the gziped response. Also my WSDL is very large (360kb) and it takes a long time(+10 seconds) to create the stub, because it has to read and parse the WSDL, so I´m creating the stub once and reusing it.
The problem is, whenever I try to use two different methods the second request gives me an error saying it is expecting the previous request.
To illustrate my problem I created a simple example with this public WebService:
http://www.webservicex.net/BibleWebservice.asmx?WSDL
Without the GZip compression it works fine:
BibleWebserviceSoap bibleService = new BibleWebservice().getBibleWebserviceSoap();
String title = bibleService.getBookTitles();
response.getWriter().write(title);
String johnResponse = bibleService.getBibleWordsbyKeyWord("John");
response.getWriter().write(johnResponse);
I´m able to receive both responses.
Enabling Gzip compression:
BibleWebserviceSoap bibleService = new BibleWebservice().getBibleWebserviceSoap();
//GZIP compression on bibleService
Client client = ClientProxy.getClient(bibleService);
client.getInInterceptors().add(new GZIPInInterceptor());
client.getInFaultInterceptors().add(new GZIPInInterceptor());
// Creating HTTP headers
Map<String, List<String>> headers = new HashMap<String, List<String>>();
headers.put("Accept-Encoding", Arrays.asList("gzip"));
// Add HTTP headers to the web service request
client.getRequestContext().put(Message.PROTOCOL_HEADERS, headers);
String title = bibleService.getBookTitles();
response.getWriter().write(title);
String johnResponse = bibleService.getBibleWordsbyKeyWord("John");
response.getWriter().write(johnResponse);
When I try to receive the second response I´m getting this exception:
org.apache.cxf.interceptor.Fault: Unexpected wrapper element {http://www.webserviceX.NET}GetBookTitlesResponse found. Expected {http://www.webserviceX.NET}GetBibleWordsbyKeyWordResponse.
On my real application I´m getting an exception with the request:
org.apache.cxf.binding.soap.SoapFault: OperationFormatter encountered an invalid Message body. Expected to find node type 'Element' with name 'GetAvailabilityRequest' and namespace 'http://schemas.navitaire.com/WebServices/ServiceContracts/BookingService'. Found node type 'Element' with name 'ns4:PriceItineraryRequest' and namespace 'http://schemas.navitaire.com/WebServices/ServiceContracts/BookingService'
My sample project can be downloaded here:
http://www.sendspace.com/file/plt0m4
Thank you
Instead of setting the protocol headers directly like that, use CXF's GZIPOutInterceptor to handle that.
Either that or reset the PROTOCOL headers for each request. When set like that, the headers map gets updated as the request goes through the chain. In this case, the soapaction gets set. This then gets resent on the second request.

Resources