0

In one of my use case, i have all my route information in a json file and i want to read the file and create the routes accordingly.

for example,

if i have declared route like this in my json config file

{
  "config": [
    {
      "routeSrcSystem": "System1",
      "routes": [
        {
          "fromRoute": {
            "type": "default",
            "typeValue": "direct:CMStart"
            },  
          "toRoute": {
            "type": "http"
            "typeMethod": "POST",
            "typeContent": "application/json",
            "typeValue": "http://localhost:8080/v1/System1/inboundMessage"
            }
        }
      ]
    }
  ]
}

then i able to create the routes as below dynamically. but here though its dynamic,the route definition is not dynamic because i have used one "from" and one "to" definition but parameter for this definition i am passing dynamically.

public class GenerateRouter extends RouteBuilder {

        private RoutesMetadata routesMetadata;

        public GenerateRouter(CamelContext context,RoutesMetadata routesMetadata) {
            super(context);
            this.routesMetadata=routesMetadata;
        }

        @Override
        public void configure() throws Exception {
            from(routesMetadata.getFromRoute().getTypeValue())
            .setHeader(Exchange.HTTP_METHOD, simple(routesMetadata.getToRoute().getTypeMethod()))
            .setHeader(Exchange.CONTENT_TYPE, constant(routesMetadata.getToRoute().getTypeContent()))
            .to(routesMetadata.getToRoute().getTypeValue());
        }
    }

But i would like to do the route definition itself dynamically. for example, i have route config like this,

{
  "config": [
    {
      "routeSrcSystem": "System1",
      "routes": [
        {
          "fromRoute": {
            "type": "default",
            "typeValue": "direct:CMStart"
            },  
          "toRoute1": {
            "type": "http"
            "typeMethod": "POST",
            "typeContent": "application/json",
            "typeValue": "http://localhost:8080/v1/System1/inboundMessage"
            }
         "toRoute2": {
            "type": "http"
            "typeMethod": "POST",
            "typeContent": "application/json",
            "typeValue": "http://localhost:8080/v1/System2/inboundMessage"
            }
        }
      ]
    }
  ]
}

then in my route definition i need to add one more "to" definition dynamically. its just example. it could be more dynamic. for example, configuration can be changed to introduce "process" or "bean" or "class" definition. so based on the config, we need to decide how many "to" to be created and how many "process" to be created and etc. I might need to call the next rest end point after some validation and etc and some times i need to call kafka to put the message in queue. i do see an option to list all routes in a list and execute it but i think we need to have flexibility to add process or to or class definition before we call next end point and this has to be based on configuration.

public class GenerateRouter extends RouteBuilder {

        private RoutesMetadata routesMetadata;

        public GenerateRouter(CamelContext context,RoutesMetadata routesMetadata) {
            super(context);
            this.routesMetadata=routesMetadata;
        }

        @Override
        public void configure() throws Exception {
            from(routesMetadata.getFromRoute().getTypeValue())
            .setHeader(Exchange.HTTP_METHOD, simple(routesMetadata.getToRoute().getTypeMethod()))
            .setHeader(Exchange.CONTENT_TYPE, constant(routesMetadata.getToRoute().getTypeContent()))
            .to(routesMetadata.getToRoute().getTypeValue())
            .setHeader(Exchange.HTTP_METHOD, simple(routesMetadata.getToRoute().getTypeMethod()))
            .setHeader(Exchange.CONTENT_TYPE, constant(routesMetadata.getToRoute().getTypeContent()))
            .to(routesMetadata.getToRoute().getTypeValue());
        }
    }

I saw some information where route definition itself can be defined dynamically and i am doing research on it. but meantime i would like to post this here to get experts opinion. Also, please suggest whether I am using the camel on right way? because in my use case i am thinking to add "to" definition to which pass the class name dynamically based on configuration file, so that application developer can do their logic for transformation, enrich or manipulation in this class on the fly before deliver to target system. please let me know if we have any better approach. also, let me know whether XML way of doing is good way or defining own config file in json format is a good way to create dynamic route.

i am planning to read the json file and create a router definition as a string dynamically. but i would need to load this string as a definition in context it seems. i think i am missing this part.

.to("class:com.xxx.camel.layoutTransform?method=layout()")

if we provide all these configurations in xml file and if camel supports to create the route definition automatically using this file then we can consider this option as well.

Below is the one of the way from another source to create the router definition using XML file. within the XML, we have router information defined and this xml considered as a string and this string is converted as router-definition object and finally added into context.

<routes
  xmlns=\"http://camel.apache.org/schema/spring\">
  <route>
      <from uri='direct:c'/>
      <to uri='mock:d'/>
  </route>
</routes>
CamelContext context = new DefaultCamelContext(); 
context.setTracing(true); 
String xmlString = "<routes  xmlns=\"http://camel.apache.org/schema/spring\"><route><from uri='direct:c'/><to uri='mock:d'/></route></routes>"; 

InputStream is = new ByteArrayInputStream(xmlString.getBytes()); 
RoutesDefinition routes = context.loadRoutesDefinition(is); 
context.addRouteDefinitions(routes.getRoutes()); 

context.start(); 

ProducerTemplate template = null; 
template = context.createProducerTemplate(); 
template.start(); 
template.sendBody("direct:c", "HelloC"); 
Thread.sleep(10000); 
context.stop();

I would like to do the similar concept using java dsl definition as a string.

for example, if i have string as below then can this be converted as a router definition?

String dslString = "from("direct:starting").to("seda:end")";

Here is my use case. Sometime, we want to call 2 http services as below

from("direct:start").to(http://localhost:8080/service1).to("http://localhost:8080/service2")

Somtimes we might need to call 3 services as like below

from("direct:start").to(http://localhost:8080/service1).to("http://localhost:8080/service2").to("http://localhost:8080/service3")

sometimes we need to do transformation before we invoke service2 as like below.

from("direct:start").to(http://localhost:8080/service1).to("class:com.xxx.yyy").to("http://localhost:8080/service2").to("http://localhost:8080/service3")

In the even driven architecture, we will have set of routes must be defined for each event types. so the idea is, if we define these routes in a table for each event type, then at the time of service start up all the routes will be loaded in context and will be started. I am able to do the same in XML DSL way but trying to do the same in java DSL.

Thanks in advance!

James Mark
  • 319
  • 4
  • 15

1 Answers1

2

Camel supports defining all details about routes in a particular XML-based format. This page has links to that (and other) DSLs.

You could definitely come up with your own DSL and build routes dynamically, but that's a lot of work if you want to support all the things a full Camel DSL would support. I would suspect that is not the right solution for whatever your use-case.

If you have certain patterns to your routes, you can create fairly dynamic Camel route-builders that are driven by some configuration. To make this concrete, let's say you have many use cases that follow a very similar pattern... say, consumer data from files in a folder, do a few transformations from a menu of (say) 10-15 transformations, and then sends output to one of many queues.

Since you have various possible combinations, it could make sense to configure those details in file etc. and then build some routes off that. The trade-off is not different from any other place where you have to decide if it is clearer to just code the 10 things you want, or to make something more complex but generic.

Essentially, you would still be creating a DSL or sorts, but one that is closer to your use case.

Darius X.
  • 2,886
  • 4
  • 24
  • 51
  • Thanks for the quick response!. I found a way to dynamically create the router definition using XML file but i would like to do the same using java DSL way. i have updated this information in my post for more information – James Mark May 17 '19 at 18:20
  • 1
    I totally agree to what Darius X. said. The OP is roughly implementing a JSON DSL for Camel and very likely it will lead to [Inner-platform effect](https://en.wikipedia.org/wiki/Inner-platform_effect) – ShellDragon May 18 '19 at 14:30
  • @ShellDragon, Thank you for your suggestions!.. I am still searching to load the route definition dynamically if my route information are defined in DSL format but kept in a string variable because I would like to do all the definition in DSL way rather than XML way. My question is, if i have string like below, can i load as route definition? String dslString = "from(\"direct:starting\").to(\"seda:end\")"; Thanks in advance!. – James Mark May 19 '19 at 21:03
  • So, James... are you saying you want to write the DSL just as if you were coding the DSL in Java, but you want to save this to some file that you read in. Essentially...like dynamic Java code compiled at run-time? – Darius X. May 20 '19 at 19:31
  • Hi Darius - Thanks for the response again!.. yes, you are correct. do we have option for doing it? – James Mark May 25 '19 at 21:58
  • I'm not sure there's a straightforward way. Basically you want interpreted Java code...maybe something along the lines of Groovy. To be honest, I'm having a hard time getting my had around that: I can't image a use-case where that would be a good solution. – Darius X. May 25 '19 at 23:15
  • @DariusX.- I have added additional information now in main post to explain in more detail about the use case. Please review it. – James Mark May 26 '19 at 03:45
  • @James Mark: Thanks for providing further detail. I am not aware of anything that could dynamically produce Java DSL to a running route or a `RouteBuilder`. Reading through your examples, if all those route definitions are known, based on the event type, you may have other options in Camel to implement what you want. For instance 1. three different end points for each of those events 2. Using routing decisions in-flight, using conditionals in Camel (like `.choice()` + `.when()`). They can help you to decide whether to use some processors or not, based on header values you pick. – ShellDragon May 27 '19 at 06:59
  • @JamesMark I don't know how one would do that. But, I still don't understand the real motivation. Basically, you will be adding "code" into a database. How would this be debugged, version-controlled etc. An easier approach seems to be to keep the Routes in class files, let people test them etc. And, when you want to deploy, add them to the deployed app. The database could do the mapping: what route to call for what event You might even want to spin up multiple apps, each handling a basket of events. I think that by moving out of the IDE you will lose value. – Darius X. May 28 '19 at 00:38