java - Camel: failure to add routes dynamically -
i'm using apache-camel 2.15.2.
i trying add routes camelcontext
dynamically, came across problem baffles me.
as far can tell, add routes correct camelcontext
, , seems configure()
called without throwing exceptions. when try execute main route, run time exception telling me route added dynamically not exist.
here simplified version of code:
public class mainroutebuilder extends routebuilder { public static camelcontext camelcontext; public static boolean returnlabel = true; public static routebuilder nestedroutebuilder; @override public void configure() throws exception { system.out.println("building main route!"); system.out.println("context: " + getcontext()); camelcontext = getcontext(); from("direct:mainroute") //3. not want instantiate routecontainer each time call route. //i want reuse reference instance created outside of configure()... .to(new routecontainer().getmyroute(2)) ; returnlabel = false; //configure direct:myroute.2 includeroutes(nestedroutebuilder); } } public class routecontainer extends routebuilder { public route route; routecontainer() { super(mainroutebuilder.camelcontext); } string getmyroute(final int n) { if (mainroutebuilder.returnlabel && route == null) { route = new route() { @override public void configure() { system.out.println("building nested route!"); system.out.println("context: " + getcontext()); from("direct:myroute." + n) .transform() .simple("number: " + n) .to("stream:out") .process(new processor() { @override public void process(exchange exchange) throws exception { response response = new response(); response.setstatus(status.success); exchange.getout().setbody(response); } }); } }; } //1. works: mainroutebuilder.nestedroutebuilder = this; //2. not work: // routecontainer routecontainer = new routecontainer(); // routecontainer.route = this.route; // mainroutebuilder.nestedroutebuilder = routecontainer; return "direct:myroute." + n; } @override public void configure() throws exception { if (route != null) { route.configure(); } } public abstract static class route { abstract public void configure(); } }
requests sent direct:mainroute
work. during camel startup see in console:
building main route! context: springcamelcontext(camel-1) spring id org.springframework.web.context.webapplicationcontext:/sample-route building nested route! context: springcamelcontext(camel-1) spring id org.springframework.web.context.webapplicationcontext:/sample-route
and when send request direct:mainroute
, output is:
{"status":"success"}
however, if comment out (1) above, , uncomment (2), camel starts same output console, when send request direct:mainroute
, execution of route fails exception:
org.apache.camel.component.direct.directconsumernotavailableexception: no consumers available on endpoint: endpoint[direct://myroute.2].
to clarify: problem because not instantiate routecontainer
each time call route, in (3). why instantiate them @ point (2) , plug route
instance it...
so mainroutebuilder
this:
public class mainroutebuilder extends routebuilder { public static camelcontext camelcontext; public static boolean returnlabel = true; public static routebuilder nestedroutebuilder; routecontainer routecontainer = new routecontainer(); @override public void configure() throws exception { system.out.println("building main route!"); system.out.println("context: " + getcontext()); camelcontext = getcontext(); from("direct:mainroute") .to(routecontainer.getmyroute(2)) //i may want call again this: //.to(routecontainer.getmyroute(3)) ; returnlabel = false; //configure direct:myroute.2 includeroutes(nestedroutebuilder); } }
my assumption maybe nested route direct:myroute.2
created in wrong camelcontext
, console output tells me not so.
any idea doing wrong here?
route configuration != route execution
it seems confusing route configuration route execution. we've been there ;-)
when configure routebuilder in mainroutebuilder#configure()
, method only executed once when camel app bootstraps, in order set routing logic. dsl creates plumbing route (processors, interceptors, etc.) , that's route runtime be.
point bring home: dsl not executed on , on again every exchange.
in other words, camel not point out in (3). doesn't execute new routecontainer().getmyroute(2)
every single exchange. think it: bytecode configure()
executed when configuring camel, , bytecode instantiates object of class routecontainer
, invokes getmyroute
argument 2
. resulting object fed sendprocessor
to()
dsl generates.
analysis of code
now, regards why code doesn't yield result expect.
you have problem state-keeping of routecontainer
. every time call getmyroute
overwrite instance variable route
. it's impossible current code call getmyroute
several times (with different n
s) , call includeroutes
once @ end, because generated route added.
i don't masking camel route
class class of own, act placeholder, brings different discussion didn't ask for.
simpler solution
instead of routecontainer
class, here's routegenerator
class creates routes , returns direct:
endpoint caller. keeps track of routes in internal set
.
public class routegenerator { private set<routebuilder> routebuilders = new hashset<>(); public string generateroute(final int n) { routebuilders.add(new routebuilder() { @override public void configure() throws exception { system.out.println("building nested route!"); system.out.println("context: " + getcontext()); from("direct:myroute." + n) .transform() .simple("number: " + n) .to("stream:out") .process(new processor() { @override public void process(exchange exchange) throws exception { response response = new response(); response.setstatus(status.success); exchange.getout().setbody(response); } }); } }); return "direct:myroute." + n; } public set<routebuilder> getroutebuilders() { return routebuilders; } }
and here mainroutebuilder
, instantiates routegenerator
once, , can generate many routes wish.
once finish configuring routes, iterate on accumulated routebuilders
, include them:
public class mainroutebuilder extends routebuilder { public static camelcontext camelcontext; public static routegenerator routegenerator = new routegenerator(); @override public void configure() throws exception { system.out.println("building main route!"); system.out.println("context: " + getcontext()); camelcontext = getcontext(); from("direct:mainroute") .to(routegenerator.generateroute(2)); (routebuilder routebuilder : routegenerator.getroutebuilders()) { includeroutes(routebuilder); } } }
edit: why doesn't option (2) work?
after debugging time, realised why you're seeing effect.
extracted the java tutorial:
as instance methods , variables, inner class associated instance of enclosing class , has direct access object's methods , fields.
in (2), create instance of route
within scope of initial routecontainer
object, acting outer object. route
object retains outer routecontainer
outer object. from()
, subsequent methods therefore being invoked on initial routecontainer
(routebuilder
) object, not on new routecontainer
create later, 1 provide upper routebuilder (which associated camelcontext).
that's why direct:myroute.2
not being added camel context, because it's being created in different route builder.
also note console output of (2):
building main route! context: camelcontext(camel-1) building nested route! context: camelcontext(camel-2) added!
the second route being added different context camel-2
. new context created camel lazily when adds route old routebuilder, hasn't been associated camel context yet.
note the camel context of initial routecontainer (created in instance variable initialization) null
, because assign mainroutebuilder.camelcontext
property later on.
you can see how 2 different route builders being used adding following println
statements:
inside route#configure:
system.out.println("routecontainer route added: " + routecontainer.this.hashcode());
inside mainroutebuilder#configure, before includeroutes
:
system.out.println("routecontainer loaded camel: " + nestedroutebuilder.hashcode());
with (1), hashcode is same. (2), hashcode is different, showing there 2 different routebuilders in play (one contains route, , 1 that's loaded context, not include route).
source: i'm apache camel pmc member , committer.
Comments
Post a Comment