Camel ActiveMQ replyTo Issues - apache-camel

Getting a exception when trying to use replyTo. Requirement is to receive reply from external queue . Not sure why I am getting timeout error, do I have to make any configuration changes or any code changes . Tried different ways, but it’s not working . Any help will be appreciated
I am reading file from folder, split the file and sending results to req queue and expecting a reply on req2
from("file://C:/pkuma1?fileName=request464.txt").routeId(messageType+"sasasas")
.split()
.tokenize("\\n")
.log(INFO,"i am initial")
.setHeader("JMSReplyTo", simple("req2"))
.inOut("amq://queue:req?replyTo=req2&preserveMessageQos=true&replyToType=Shared&receiveTimeout=250")
// .inOut("amq://queue:req")
.transform(constant("Bye Camel"))
.log(INFO,"msg id initial = ${in.header.JMSMessageId}")
.log(INFO,"corr id initial = ${in.header.JMSCorrelationID}")
.to("stream:out");
from("amq://queue:req")
.log(INFO,"i am second route")
.log(INFO,"msg id second route = ${in.header.JMSMessageId}")
.log(INFO,"corr id second route = ${in.header.JMSCorrelationID}");
.setHeader("JMSCorrelationID", simple("${in.header.JMSCorrelationID}"));
.transform(simple("Hello in second route ${in.body}"))
.process(exchange -> {
System.out.println(exchange);
System.out.println("route2");
});
//.end();
//.to("amq://queue:req2");
from("amq://queue:req2?disableReplyTo=true")
.log(INFO,"i am third route")
.log(INFO,"msg id third route = ${in.header.JMSMessageId}")
.log(INFO,"corr id third route = ${in.header.JMSCorrelationID}")
.setHeader("JMSCorrelationID", simple("${in.header.JMSCorrelationID}"))
.transform(simple("Hello ${in.body}"))
.process(exchange -> {
System.out.println(exchange);
System.out.println("route3");
System.out.println(exchange.getIn().getHeader("JMSCorrelationID"));
exchange.getIn().setBody("Hello ${in.body}");
exchange.getIn().setHeader(JmsConstants.JMS_DESTINATION, "");
exchange.getIn().setHeader("JMSReplyTo","");
exchange.getIn().setHeader("JmsDestination","");
exchange.getIn().setHeader("CamelJmsDestination","");
})
.to("stream:out")
.end();
Getting following error Timeout occurred after 120000 millis waiting for reply message with correlationID

Related

Apache Camel message exchange does not wait for the response

I have following code for publishing message to activeMQ and reading response via exchange. But code seem to be returning instantaneously and not waiting for the response. Could you please point what is wrong with the following Scala code.
def sendAndReceiveExtractionDetails(request:String, header: String) : String = {
val exchange: DefaultExchange = new DefaultExchange(camel, ExchangePattern.InOut)
exchange.getIn.setBody(request)
exchange.getIn.setHeader("meshId", header)
producer.send("activemq:queue:extractor-jobs?requestTimeout=1400000", exchange)
val out: apache.camel.Message = exchange.getOut()
out.getBody().toString
}
It seems to ignore the ExchangePattern you set. Have you tried to set it on your JMS URI as activemq:queue:...&exchangePattern=InOut?
I am not sure if you also need to define the JMSReplyTo header on the message or if this is done automatically when the exchangePattern is InOut.
Use the request method on the producer as that is for InOut
Following code works for me:
def sendAndReceiveExtractionDetails(request:String, header: String) : String = {
camel.createProducerTemplate()
.sendBody("activemq:queue:extractor-jobs?requestTimeout=1400000", ExchangePattern.InOut, request).toString
}

AppEngine channel API: duplicate messages client side

I am trying to use the Channel API to push updates from server to the client. The flow is the user presses a button which triggers a server side action that generates a lot of logs. I want to display the logs to the user "in real time".
When I first load the page it I get all the messages, no problem. If I trigger the action a second time without refreshing the page in my browser, then all messages appear twice. Here is the set up portion of the channel that is tied to the page onLoad event. With resulting console logs I gathered that the onMessage() method is being invoked more than once when the page is not refreshed. Looks like I need to "kill" earlier sockets in some way, but could not find a way in the official documentation. Can someone point me in the right direction to get rid of the spurious messages?
// First fetch a token for the async communication channel and
// create the socket
$.post("/app/channels", {'op':'fetch', 'id' : nonce},
function (data, status, xhr) {
if (status == "success") {
data = JSON.parse(data);
token = data["token"];
console.log("Cookie: " + get_mp_did() + "; token: " + token);
var channel = new goog.appengine.Channel(token);
var handler = {
'onopen': onOpened,
'onmessage': onMessage,
'onerror': function() {
$("#cmd_output").append('Channel error.<br/>');
},
'onclose': function() {
$("#cmd_output").append('The end.<br/>');
$.post("/app/channels", {'op':'clear'});
}
};
var socket = channel.open(handler);
socket.onopen = onOpened;
socket.onmessage = onMessage;
}
});
onOpened = function() {
$("#cmd_output").empty();
};
onMessage = function(data) {
message = JSON.parse(data.data)['message'];
$("#cmd_output").append(message);
console.log('Got this sucker: ' + message);
}
If I understand your post and code correctly, the user clicks on a button which calls the $.post() function. The server code is responsible to create the channel in GAE as response to a /app/channels request. I think that your server in fact creates a new channel client ID / token with every subsequent request. Since the page is not reloaded, any subsequent request would add a new channel to this client. And all these channels would be still connected (hence, no page refresh).
I assume your server code has all channels associated to a user, and you send the message to a user utilizing all channels? Such pattern would result in this behavior. You can verify my assumption by clicking 3 or four times on the button with-out page refresh. The log output would be multiplied by the factor of 3 or 4.
I suggest, that you store the token in the client and on the server. Then make a modification to your client JS. If a channel is already created store the token value and provide it to any subsequent request to /app/channels. Modify the server so it will not create a new channel, if a token is provided with the request. If the token links to an existing valid channel, re-use the channel and return the same token in the response. You may need to add some more details for disconnected or expired channels, maybe also a cron-job to delete all expired channels after a while.

Apache Camel EIP route - How to stop split()

I have some problems with a following route:
// from("cxf:....")...
from("direct:start").process(startRequestProcessor) // STEP 1
.choice()
.when(body().isNull())
.to("direct:finish")
.otherwise()
.split(body()) // STEP 2
.bean(TypeMapper.class) // STEP 3
.log("Goes to DynamicRouter:: routeByTypeHeader with header: ${headers.type}")
.recipientList().method(Endpoint1DynamicRouter.class, "routeByTypeHeader") // STEP 4
.ignoreInvalidEndpoints();
from("direct:endpoint2") // STEP 6
.log("Goes to DynamicRouter::routeByCollectionHeader with header: ${headers.collection}")
.recipientList().method(Endpoint2DynamicRouter.class, "routeByCollectionHeader")
.ignoreInvalidEndpoints();
from("direct:endpoint1.1") // STEP 5
.process(new DateRangeProcessor())
.to("direct:collections");
from("direct:endpoint1.2") // STEP 5
.process(new SingleProcessor())
.to("direct:collections");
from("direct:endpoint2.2") // STEP 7
.aggregate(header("collection" /** endpoint2.2 */), CollectionAggregationStrategy)
.completionSize(exchangeProperty("endpoint22"))
.process(new QueryBuilderProcessor())
.bean(MyService, "getDbCriteria")
.setHeader("collection", constant("endpoint2.1"))
.to("direct:endpoint2.1").end();
from("direct:endpoint2.1") // STEP 8
.aggregate(header("collection" /** endpoint2.1 */), CollectionAggregationStrategy)
.completionSize(exchangeProperty("CamelSplitSize"))
.to("direct:finish").end();
from("direct:finish")
.process(new QueryBuilderProcessor())
.bean(MyRepository, "findAll")
.log("ResponseData: ${body}").
marshal().json(JsonLibrary.Gson).end();
The route
Receives json string an converts it to list (HashSet) of JSONObjects.
split the received list to json objects.
Set corresponding headers according to object content
Routes the messages according to headers to endpoint1.1 or endpoint1.2
Convert messages to mongodb Criteria and send to endpoint2
Endpoint2 routes messages according to another header to endpoint2.1 or endpoint2.2.
Endpoint2.2 aggregates all received messages, processes it to get mongodb Criteria and sends it to endpoint2.1 (completionSize is calculated at step 2 and saved in property "endpoint22").
Enpoint2.1 aggregates ALL messages (CamelSplitSize) converts aggregated messages to Query object and sends it to Repository to retrieve the data.
I can see valid response object in debugger but anyway I get an error:
No message body writer has been found for class java.util.HashSet, ContentType: application/json
The problem is not in response object as it works with other routes and it does not contain HashSets.
My guess is that route sends to the output the HashSet created tat STEP 1...
My questions are:
what is wrong in the route output?
both recipientList() try to forward
messages to invalid endpoint ( I have to use .ignoreInvalidEndpoints() to avoid exception):
org.apache.camel.NoSuchEndpointException: No endpoint could be found for:
org.springframework.data.mongodb.core.query.Criteria#20f55e70, please
check your classpath contains the needed Camel component jar.
Any help would be much appreciated!
Thanks.
I find it very strange, but .aggregate() function does not reply exchange. It uses you aggregation strategy but always reply incoming exchange. This is not clear when reading documentation, but you have to use aggregation strategy along with split() to be able to return exchange.

Camel Apache: can I use a retryWhile to re-send a request?

I would like to achieve the following kind of orchestration with CAMEL:
Client sends a HTTP POST request to CAMEL
CAMEL sends HTTP POST request to external endpoint (server)
External server replies with a 200 OK
CAMEL sends HTTP GET request to external endpoint (server)
External server replies
After step 5, I want to check the reply: if the reply is a 200 OK and state = INPROGRESS (this state can be retrieved from the received XML body), I want to re-transmit the HTTP GET to the external endpoint until the state is different from INPROGRESS.
I was thinking to use the retryWhile statement, but I am not sure how to build the routine within the route.
Eg, for checking whether the reply is a 200 OK and state = INPROGRESS, I can easily introduce a Predicate. So the retryWhile already becomes like:
.retryWhile(Is200OKandINPROGRESS)
but where should I place it in the route so that the HTTP GET will be re-transmitted ?
Eg: (only taking step 4 and 5 into account)
from("...")
// here format the message to be sent out
.to("external_server")
// what code should I write here ??
// something like:
// .onException(alwaysDo.class)
// .retryWhile(Is200OKandINPROGRESS)
// .delay(2000)
// .end ()
// or maybe it should not be here ??
I am also a bit confused how the "alwaysDo.class" should look like ??
Or ... should I use something completely different to solve this orchestration ?
(I just want to re-transmit as long as I get a 200 OK with INPROGRESS state ...)
Thanks in advance for your help.
On CAMEL Nabble, someone replied my question. Check out:
http://camel.465427.n5.nabble.com/Camel-Apache-can-I-use-a-retryWhile-to-re-send-a-request-td5498382.html
By using a loop statement, I could re-transmit the HTTP GET request until I received a state different from INPROGRESS. The check on the state needs to be put inside the loop statement using a choice statement. So something like:
.loop(60)
.choice()
.when(not(Is200OKandINPROGRESS)).stop() // if state is not INPROGRESS, then stop the loop
.end() // choice
.log("Received an INPROGRESS reply on QueryTransaction ... retrying in 5 seconds")
.delay(5000)
.to(httpendpoint")
.end() //loop
I never experimented what you are trying to do but it seems does not seem right.
In the code you are showing, the retry will only occur when an alwaysDo Exception is thrown.
The alwaysDo.class you are refering to should be the name of the Java Exception class you are expecting to handle. See http://camel.apache.org/exception-clause.html for more details.
The idea should be to make the call and inspect the response content then do a CBR based on the state attribute. Either call the GET again or terminate/continue the route.
You probably should write a message to the Apache Camel mailing list (or via Nabble) . Commiters are watching it and are very reactive.

how can I get more error messages out of solrj SolrException

When I send queries to Solr using solrj, I sometimes get SolrException's thrown. When I dig through the exception, it just says "Bad Request", and gives the HTTP return code (which is 400).
When I take the request URL and put it in my browser, I was able to see a richer error message. The browser displays an error message saying one of the fields names is not valid.
I would like to be able to capture this inside my log file. I was able to capture this by copying all the parameters to an Apache HTTP Client POST request (I'm using POST and not GET because GET made the URL too long) and re-executing the request, but this is inefficient. Is there a way to get error message out of SolrException directly?
Here's what I'm doing:
catch (SolrServerException e) {
if(e.getRootCause() instanceof SolrException) {
SolrException ee = (SolrException) e.getRootCause();
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(SOLR_URL);
// copy params over
Iterator<String> iter = request.getParams().getParameterNamesIterator();
while(iter.hasNext()) {
String p = iter.next();
method.setParameter(p, request.getParams().get(p));
}
int statusCode;
try {
// re execute and display the error message
statusCode = client.executeMethod(method);
logger.error(method.getResponseBodyAsString());
} catch (Exception e1) {
// TODO Auto-generated catch block
}
}
These messages aren't available via SolrJ. You can see them in solr's log file, but there is no way to capture them in your client, since solr only returns the 400 error status with a generic message to the client :(

Resources