Following is the route that I have created -
from("jetty:http://localhost:8181/abc").routeId("abc").choice()
// Authenticate the request
.when(authenticator).endChoice()
// Authorize the request
.when(authorizer).endChoice()
// Validate the request
.when(abcValidator).endChoice()
.otherwise()
.process(abcRequestProcessor).process(storeFeatureRequestDetails).process(featureRequestApproverUpdater).split(body()).process(abcApproverMailer).to("direct:toMail");
The above route is functional but I do not want to add the authenticator and authorizer step to each and every route. Is there a way by which I can configure them to run before each route.
I tried the following -
from("jetty:http://localhost:8181/*").process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("Triggered");
}
});
but it looks for exact match.
you can use the Camel interceptor API for this...
// intercept all incoming routes and log it
interceptFrom().process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("Triggered");
}
});
If you don't want to put your AAA in every to each and every route why don't you extract their functionality and put them in separate routes and call them inside your route? Example code:
from("jetty:http://localhost:8181/abc").routeId("abc").choice()
// Authenticate the request
.to("direct:authenticator")
// Authorize the request
.to("direct:authorizer")
// Validate the request
.to("direct:abcValidator")
.process(abcRequestProcessor).process(storeFeatureRequestDetails).process(featureRequestApproverUpdater).split(body()).process(abcApproverMailer).to("direct:toMail");
Basically the authenticator is now in a separate route. You call it by "direct:authenticator". The same goes for authorize and validate.
This way, if you have other routes that need to use this functionality you just call the AAA routes.
Related
Using camel 3.4.4, I've a route that calls a cxf endpoint with .to(getCxfEndpoint()) and I've a header that's set earlier in the route like process(exchange -> exchange.getIn().setHeader("myKey", "myValue"):
from(someEndpoint)
.process(exchange -> exchange.getIn().setHeader("myKey", "myValue")
.to(getCxfEndpoint())
.process(exchange -> String value = exchange.getIn().getHeader("myKey");
I'm trying to unit test this using the following:
RouteReifer.adviceWith(routeDefinition, mcc, new AdviceWithRouteBuilder() {
#Override
public void configure() {
weaveByString("To[http://myurl.com/xxx").replace()
process(exchange -> {
log.debug("Assume external call is made and I can see the headers in exchange here");
});
}
});
But in the route, when I try to get the header exchange.getIn().getHeader("myKey"), it's null. This only happens in test - it actually works when you run the real route. I'm unable to figure out why the header is lost after I mock the call using weaveByString. Also the headers are still present in the lambda in process above.
Thanks in advance.
I am having this issue in my apache camel code which I am trying to resolve from last two days, but I could not resolve it.
I have two routes. First route is as below:
public class XXXRoute1 extends RouteBuilder {
public void configure() {
String endpointUri = "cxf:/XXX;
String logEndpoint = "log:" + XXX() + "?level=DEBUG";
from(endpointUri)
.to(logEndpoint).to(ROUTE2.ENDPOINT_URI)
.to(logEndpoint);
}
Second Route:(In second route , I am catching some exception through onException)
public class Route2 extends RouteBuilder {
public void configure() throws Exception{
String integrationEndpoint = "xxx.integration";
onException(RuntimeException.class).handled(true).onWhen(exceptionMessage().contains("Invalid")).bean(translator, "translateSomeError(${property.XXX})").end();
from(ENDPOINT_URI)
.
.
. so on
Now , In my case, the object which I am populating through onException
public SomeObjectResponse translateSomeError(Object someObject) throws Exception{
SomeObjectResponse someObjectResponse = new SomeObjectResponse();
someObjectResponse.setError("someError");
return someObjectResponse ;
}
However, In SOAP UI while testing I am getting an empty SOAP envelop
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body/>
</soap:Envelope>
I am using cxf component in apache camel.
Can you post your route completely ? Where you have the onException ?
Also before you use your custom class, can you try this ? Just want to make sure anything set at onException is propagated back to CXF endpoint:
onException(RuntimeException.class).handled(true).setBody().simple("</Unexpected exception> ");
The onException() block appears to be in your second route and is consequently not in scope of your first route.
Make the onException() block global or add it to your CXF route so it's in scope.
In my application I have a generic Camel Route such as the following
from("direct:something").to("direct:outgoing")
and then dynamically in my code I deploy another route:
from("direct:outgoing").process(processor)
When flowing from route 1 to route 2 a new Exchange will be created. Is there an idiomatic way to correlate both? Should I set EXCHANGE.Correlation_ID header on the first route before sending it out?
This should definitely all be processed on the one exchange. Run this test and you'll see the same camel Exchange, with the same properties, etc.
public class CamelExchangeTest {
public static void main(String[] args) throws Exception {
final Processor showExchangeIdProcessor = new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println(exchange.getExchangeId());
}
};
Main camelMain = new Main();
camelMain.addRouteBuilder(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("timer:foo?period=1s&repeatCount=1")
.log("excgabge created!")
.process(showExchangeIdProcessor)
.to("direct:outgoing")
;
from("direct:outgoing")
.log("outgoing!")
.process(showExchangeIdProcessor)
;
}
});
camelMain.run();
}
}
Output:
ID-MYPC-55760-1411129552791-0-2
ID-MYPC-55760-1411129552791-0-2
So something else is going on. When you say "direct:outgoing", do you mean exactly that or is it something different - a different component perhaps?
When you say the route is created dynamically, how exactly is that done, and when (and why?)
From the Camel doc:
Some EIP patterns will spin off a sub message, and in those cases, Camel will add a correlation id on the Exchange as a property with they key Exchange.CORRELATION_ID, which links back to the source Exchange. For example the Splitter, Multicast, Recipient List, and Wire Tap EIP does this.
Thus, Exchange.CORRELATION_ID is set by Camel and should not be set by your application. But feel free to set a custom header or property if you need to such as:
exchange.getIn().setProperty("myProperty", myIdentifier);
Hi i am having a JMS consumer route in camel, my requirement is to stop/suspend that route at certain incident(based on the some field value) and then resume that route using a scheduler.
For this i have created two routes, one is my original jms consumer route and one is scheduler route, that resume the jms consumer routes, although i am able to suspend the route but second route is not resuming the suspended route and its showing the state as started.
below are my two routes
original consumer route
from("activeMQ:demo.audit.event1?testConnectionOnStartup=true&acknowledgementModeName=CLIENT_ACKNOWLEDGE")
.routeId("javadslconsumer")
.log("before stopping==="+new Date().toString())
.process(new Processor() {
#Override
public void process(final Exchange exchange) throws Exception {
try {
Route route = exchange.getContext().getRoute("javadslconsumer");
System.out.println("route.supportsSuspension()"+route.supportsSuspension());
exchange.getContext().suspendRoute("javadslconsumer",1l,TimeUnit.SECONDS);
// create another helper route, using which we can start or resume this route based
// on the current life cycle phase of this route.
} catch (Exception e) {
// ignore
e.printStackTrace();
}
}
})
.log("after stopping logs==="+new Date().toString())
.unmarshal(dataFormat)
.beanRef("auditProcessor", "getErrorAuditDTO")
.beanRef("auditProcessor", "processCreateAudit");
scheduler route
from("timer:dlqscheduler?period=6000&fixedRate=true")
.process(new Processor(){
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("timer process started");
try {
exchange.getContext().resumeRoute("javadslconsumer");
//exchange.getContext().startRoute("javadslconsumer");
} catch (Exception e) {
System.out.println("-----d-d-d-d-"+e.getMessage());
}
ServiceStatus serviceStatus = getContext().getRouteStatus("javadslconsumer");
System.out.println("serviceStatus.isStopped()"+serviceStatus.isStopped()); // showing false instead of true
System.out.println("serviceStatus.isSuspended()"+serviceStatus.isSuspended()); // showing false instead of true
System.out.println("serviceStatus"+serviceStatus);// showing started
}
})
.log("after resuming the route javadslconsumer");
Please help me how i can implement the above scenario.
You need to give it more time than 1 second. That is a fallback timeout, so if the suspension could not happen within 1 sec it let the route run instead. eg read the javadoc documentation of the API you use, and you can see that information.
Also btw there is a controlbus component so you can just send a message to an endpoint to suspend/resume a route.
http://camel.apache.org/controlbus
I would like to set up a Camel CXF endpont, and have the SOAP response asynchronous to much of my Camel Route. The route will have a lot of processing steps, and I do not want to have the response generated at the very end.
An example endpoint:
<cxf:cxfEndpoint id="someEndpoint"
address="/Service"
serviceClass="com.SomeImpl" />
An example route:
public class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
from("cxf:bean:someEndpoint")
to("bean:processingStep1")
to("bean:replyToSOAP") // I would like to respond to cxf:cxfEndpoint here!
to("bean:processingStep2")
to("bean:processingStep3")
to("bean:processingStep4");
// The response to cxf:cxfEndpoint actually happens here.
}
}
I have tried many options in MyRouteBuilder to "fork" the process (i.e. bean:replyToSOAP):
.multicast().parallelProcessing()
In-memory Asynchronous messaging ("seda" and "vm")
I have NOT tried JMS. It could be overkill for what I want to do.
I can get the route steps to process in parallel, but all steps must be completed before the response is generated.
In addition to the answer Claus gives below, I'd like to add that the placement of wireTap is important. Using:
.wireTap("bean:replyToSOAP")
will not get the desired behavior. What will is:
public class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
from("cxf:bean:someEndpoint")
to("bean:processingStep1")
.wireTap("direct:furtherProcessing")
to("bean:replyToSOAP") // respond to cxf:cxfEndpoint here
from("direct:furtherProcessing") // steps happen independantly of beann:replyToSOAP
to("bean:processingStep2")
to("bean:processingStep3")
to("bean:processingStep4");
}
}
There is the WireTap EIP which can spin of a copy of the message to be processed independently from the current route: http://camel.apache.org/wire-tap