Camel send modified body to AMQ without modifying route's body - java

I have a rest-api which create a resource and send it on a AMQ queue.
I am using camel rest dsl and created the something like that :
rest("/api")
.consumes("application/json").produces("application/json")
.post("/test").type(Test.class)
.route()
.to(ExchangePattern.InOnly, "direct:sendTestAmq")
.endRest()
from("direct:sendTestAmq")
.convertBodyTo(TestProtos.Test.class)
.marshal().protobuf()
.to(ExchangePattern.InOnly, "amq:queue:test.queue");
When I call the endpoint, I get a base64 response corresponding to the protobuf binary.
I would like to get the Test.class json response.
I thought using "to(ExchangePattern.InOnly,...)" would permit that by not modifying the body.
This is another example, the response is "After" and I wanted it to be "Before".
Does anybody knows how I could do it ?
Thanks

Based on #ClausIbsen answer I found that multicast() also use a copy of the exchange for each route but instead of wiretap, it is not parallele per default.
I could achieve my goal by replacing .to(ExchangePattern.InOnly, "direct:sendTestAmq") by multicast().to(ExchangePattern.InOnly, "direct:sendTestAmq", "direct:mock").end().
Since multicast takes as an output the last route exchange, "direct:mock" is a route which does nothing but preserves the original body.

Related

Sending Java/Kotlin objects to RSocket route

I've set up #MessageMapping endpoint using Spring's RSocket support and tested it with RSocketRequester. This flow is working perfectly since Spring handles bunch of low-level stuff for us.
Now, I'd like to have some sort of UI to show whatever data I'm working with and do any UI updates on that data through mentioned #MessageMapping endpoint. The problem is that I have no idea how to send full Java/Kotlin object (as JSON) to my endpoint using either rsocket-java or rsocket-kotlin libraries. Since I have to send both data and metadata and metadata is encoded as ByteBuf I had to encode JSON to ByteBuf, but it comes to endpoint all messed up and it cannot be deserialized.
I've also tried sending raw string value and it also comes to endpoint all messed up (bunch of non-UTF chars). I've tried both APPLICATION_JSON and TEXT_PLAIN for data mime type, but it didn't work for either.
Also, I guess whatever I'm doing wrong is not strictly related to Java/Kotlin libraries, but can be applied to any other existing RSocket library (Go, Rust, JS, etc.)
If you are using an rsocket-kotlin client (not building on spring-boot) then you can copy the code from https://github.com/rsocket/rsocket-cli/blob/master/src/main/kotlin/io/rsocket/cli/Main.kt
It builds metadata for the route with
this.route != null -> {
CompositeMetadata(RoutingMetadata(route!!)).toPacket().readBytes()
}
I guess I've figured it out.
I've scratched that binary encoded metadata and borrowed what I found on the internet for RSocket in JavaScript and it worked :)
So, the solution is to use routing metadata mime type (I was using composite since example I found was using it) and the payload then can be created like this:
val json = "{}"
val route = "myawesomeroute"
DefaultPayload.create(<json>, "${route.length.toChar()}$route")

Apache Camel Rest - How to send request and response from previous endpoint to next

I wanted to implement a camel DSL logic where e.g I have two routes where the request received for first route should be passed to second route along with the response from first route. How do I achieve this?
`.to("direct:validatePayload")
.to("bean:fundService?method=depositFund(${exchange})")
.to("bean:rparticipantService?method=notifyParticipant(${exchange})");`
In the above code, after validating the request payload, the exchange which has the Fund body is passed as request to depositFund. After this, I wanted to pass the request to notifyParticipant which will be combination of response from depositFund along with the request that depositFund received. How do I achieve this through camel DSL code.
Take a look at Message History: https://cwiki.apache.org/confluence/display/CAMEL/Message+History
In the rparticipantService#notifyParticipant you should be able to lookup history and get results of fundService#depositFund.
List<MessageHistory> list = exchange.getProperty(Exchange.MESSAGE_HISTORY, List.class);
Also you will need to tune MessageHistoryFactory to be able to access the message + body:
camelContext.getMessageHistoryFactory().setCopyMessage(true);

REST API Single Request - Multiple responses

I am writing a REST API in JAX-RS 2.0, JDK 8 for the below requirement
POST API /server/fileUpload/ (Multipart Form data) where I need to send a Big .AI (Adobe Illustrator) File in this.
The Server, takes the file and return Status 202 (Accepted), Acknowledging that file transfer happened Successfully. (From endpoint to Server)
Now at the Server, I am using Java + Imagemagik to convert .AI File (20-25 MB File) to small JPG Thumbnail, place on a Apache HTTP Server and share the location (like http://happyplace/thumbnail0987.jpg)
Now the Second Response should come from Server with Status 200 OK and Thumbnail URL
is it feasible with one REST API? (Async/similar)
or should I split it to 2 API calls, Please suggest
No. In http, one request gets one response. The client must send a second request to get a second response.
You can use WebSockets for that.
If you are calling from script the call will be async you can handle the Thumbnail URL when you get a response. When you are calling from java program i suggest to run it on a different thread, If the execution is not sequential i.e ( Remaining lines can be executed without getting URL). If url is needed for the remaining section of code you can make one call and wait for the response then execute remaining code.
You need to make different APIs for both scenarios. One for showing file upload status and another for all file conversion and manipulation.
On the client side second request must be callback of first request.
The best way to handle these kind of scenario is to use Java Reactive (Project Reactor, WebFlux).
You can return two response using custom middlewares in asp.net (however not recommended).
Return response from one middleware and subsequently you can invoke next middleware and return second response from second middleware

How can I pass JSON as well as File to REST API in JAVA?

My main question is how can I pass JSON as well as File to post request to REST API? What needs in Spring framework to work as client and wait for response by passing post with JSON and File?
Options:
Do I need to use FileRepresentation with ClientResource? But how can I pass file as well as JSON?
By using RestTemplate for passing both JSON as well as File? How it can be used for posting JSON as well as File?
Any other option is available?
Sounds like an awful resource you're trying to expose. My suggestion is to separate them into 2 different requests. Maybe the JSON has the URI for the file to then be requested…
From a REST(ish) perspective, it sounds like the resource you are passing is a multipart/mixed content-type. One subtype will be application/json, and one will be whatever type the file is. Either or both could be base64 encoded.
You may need to write specific providers to serialize/deserialize this data. Depending on the particular REST framework, this article may help.
An alternative is to create a single class that encapsulates both the json and the file data. Then, write a provider specific to that class. You could optionally create a new content-type for it, such as "application/x-combo-file-json".
You basically have three choices:
Base64 encode the file, at the expense of increasing the data size
by around 33%.
Send the file first in a multipart/form-data POST,
and return an ID to the client. The client then sends the metadata
with the ID, and the server re-associates the file and the metadata.
Send the metadata first, and return an ID to the client. The client
then sends the file with the ID, and the server re-associates the
file and the metadata.

MTOM Request / Non-MTOM Response

We have a pretty simple WS, implemented using annotations. We would like to be able to call this from clients both supporting MTOM/XOP and not.
Right now, it is annotated simply #MTOM.
It takes a request containing (amongst others) a base64Binary element, and serves a response containing a single boolean element.
Calling it is no problem, either with our without MTOM - it works. Only, the response, even though it doesn't contain any MTOM:able elements has headers declaring it a MTOM message, which chokes the non-MTOM client.
<tran:headers xsi:type="http:HttpResponseHeaders" xmlns:http="http://www.bea.com/wli/sb/transports/http" xmlns:tran="http://www.bea.com/wli/sb/transports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<tran:user-header name="X-Powered-By" value="Servlet/2.5 JSP/2.1"/>
<http:Content-Type>
multipart/related;start="<rootpart*c3e56707-113c-47f9-b02c-2a3234766dc4#example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:c3e56707-113c-47f9-b02c-2a3234766dc4";start-info="text/xml"
</http:Content-Type>
<http:Date>Tue, 11 May 2010 07:27:51 GMT</http:Date>
<http:Transfer-Encoding>chunked</http:Transfer-Encoding>
</tran:headers>
Does anyone know how to get the service to always respond with a non-MTOM response while still accepting both MTOM and non-MTOM requests?
The service runs on a WebLogic 10.3 server...
Kind regards,
Lars
Actually what I found odd was if I don't put an #MTOM the resulting message never returns a mutli-part message. However, the web service still accepts the MTOM data in WebSphere.

Categories

Resources