skip to Main Content

I want to have a base RouteBuilder class that would allow using an optional Custom Processor. If a child class has it specified, then add it to the route otherwise don’t.

I have been trying to use the choice() when() otherwise() construct, but needless to say without success. I am new using Apache Camel so I am not sure how to interpret/fix the error message. If the custom processor is defined, it works fine but if it is null I get the error message below.

package test;

import org.apache.camel.CamelContext;
import org.apache.camel.LoggingLevel;
import org.apache.camel.Predicate;
import org.apache.camel.Processor;
import org.apache.camel.builder.PredicateBuilder;
import org.apache.camel.impl.DefaultCamelContext;

public class SimpleApp {
  public static final long FIVE_MINUTES = 5 * 60 * 1000;

  public SimpleApp() {
    try {
      CamelContext ctx = new DefaultCamelContext();
      ctx.addRoutes( new SimpleRouteBuilder() );
      ctx.addRoutes(new org.apache.camel.builder.RouteBuilder() {
        @Override
        public void configure() throws Exception {
          Processor proc = new SimpleProcessor();
          // proc = null;
          Predicate useProc = PredicateBuilder.isNotNull( constant( proc ) );

          from("timer://myTimer?period=3000")
          .setBody()
            .simple("Creating a new message at ${header.firedTime}")
          .log(LoggingLevel.WARN,  "Message Generated at ${header.firedTime}")
          .to("stream:out")
          .choice()
            .when(useProc)
              .log(LoggingLevel.WARN, "Using Custom Processor (is not null)")
              .process( proc )
              .to("stream:out")
              .endChoice()
            .otherwise()
              .log(LoggingLevel.WARN, "Skipping Custom Processor (is null)")
              .endChoice()
          .end()
          .log(LoggingLevel.WARN, "Ended choice construct")
          .to("stream:out");
        }
      });
      ctx.start();
      System.out.println("Started....");
      Thread.sleep( FIVE_MINUTES );
      System.out.println("Done waiting, exiting");
      ctx.stop();
    }
    catch( Exception e) {
      e.printStackTrace();
    }
  }

  public static void main(String[] args) {
    new SimpleApp();
  }

}

The Processor is a dummy place holder, but here is the code anyway.

package test;

import org.apache.camel.Exchange;
import org.apache.camel.Processor;

public class SimpleProcessor implements Processor {

  public SimpleProcessor() {
    System.out.println("Running Simple Processor");
  }

  @Override
  public void process(Exchange exchange) throws Exception {
    System.out.println("Processing Exchange");
  }

}

I expected to work even if I set the proc = null, but instead I am getting the following error message:

19-10-08 11:30:15.710] test.SimpleProcessor:14 [INFO  ] => Running Simple Processor
org.apache.camel.FailedToCreateRouteException: Failed to create route route2 at: >>> Choice[[When[{null is not null} -> [Log[Using Custom Processor (is not null)], process[Processor@0x0], To[stream:out]]]] Otherwise[[Log[Skipping Custom Processor (is null)]]]] <<< in route: Route(route2)[[From[timer://myTimer?period=3000]] -> [SetBod... because of ref must be specified on: process[Processor@0x0]
    at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:1352)
    at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:212)
    at org.apache.camel.impl.DefaultCamelContext.startRoute(DefaultCamelContext.java:1140)
    at org.apache.camel.impl.DefaultCamelContext.startRouteDefinitions(DefaultCamelContext.java:3735)
    at org.apache.camel.impl.DefaultCamelContext.doStartCamel(DefaultCamelContext.java:3440)
    at org.apache.camel.impl.DefaultCamelContext$4.call(DefaultCamelContext.java:3248)
    at org.apache.camel.impl.DefaultCamelContext$4.call(DefaultCamelContext.java:3244)
    at org.apache.camel.impl.DefaultCamelContext.doWithDefinedClassLoader(DefaultCamelContext.java:3267)
    at org.apache.camel.impl.DefaultCamelContext.doStart(DefaultCamelContext.java:3244)
    at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:72)
    at org.apache.camel.impl.DefaultCamelContext.start(DefaultCamelContext.java:3160)
    at test.SimpleApp.<init>(SimpleApp.java:47)
    at test.SimpleApp.main(SimpleApp.java:61)
Caused by: java.lang.IllegalArgumentException: ref must be specified on: process[Processor@0x0]

2

Answers


  1. Chosen as BEST ANSWER

    The comment from @hk6279 was valid, but not the approach I needed because if I want/need more than one processor then it would involved having too many if conditions to define the different methods.

    I changed the application and is using an XML file and Spring to hook provide all the components. It uses named components and the application gets them by name. In my RouteBuilder configure method I get the object and create the Predicate;

    Processor reqProc = 
           this.getContext().getRegistry().lookupByNameAndType("requestProcessor", Processor.class);
    Predicate useReqProc = PredicateBuilder.isNotNull( constant( reqProc ) );
    

    For whatever reason if I get the processor from a bean defined in the XML I can use the choice() when() otherwise() construct I need. If I try it directly as show in the question I cannot. Once I got the Predicate from above I was able to do the following:

    from( sources.toArray(new String[0]) )
          .split().method(RequestSplitter.class, "splitMessage")
          .choice()
            .when(useReqProc)
              .log(LoggingLevel.INFO, "Found the request processor using it")
              .to("bean:" + "requestProcessor")
            .endChoice()
            .otherwise()
              .log(LoggingLevel.ERROR, "requestProcessor not found, stopping route")
              .stop()
            .endChoice()
          .end()
          .log("Sending the request the ARES URI")
          .recipientList(header(Constants.HDR_TARGET_URI));
    

    I hope this is useful for someone else.


  2. For processor component, it requires a java instance of class implementing the java interface Processor when route is being created. Obviously, null does not meet the requirement.

    To workaround it, create two functions to return RouteBuilder, one without processor and one with processor (pass by variable). And then has a function to choose which RouteBuilder for use.

    // Sample code - function with processor (pass by variable)
    protected static RouteBuilder createRouteBuilder(final Processor myProcessor) throws Exception{
    
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("timer://myTimer?period=3000")
                    // omit steps
                    .process(myProcessor)
                    // omit steps
                    .to("stream:out");
            }
        };
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search