001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.builder; 018 019import java.util.concurrent.atomic.AtomicBoolean; 020 021import org.apache.camel.CamelContext; 022import org.apache.camel.Endpoint; 023import org.apache.camel.RoutesBuilder; 024import org.apache.camel.impl.DefaultCamelContext; 025import org.apache.camel.model.InterceptDefinition; 026import org.apache.camel.model.InterceptFromDefinition; 027import org.apache.camel.model.InterceptSendToEndpointDefinition; 028import org.apache.camel.model.ModelCamelContext; 029import org.apache.camel.model.OnCompletionDefinition; 030import org.apache.camel.model.OnExceptionDefinition; 031import org.apache.camel.model.RouteDefinition; 032import org.apache.camel.model.RoutesDefinition; 033 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037/** 038 * A <a href="http://camel.apache.org/dsl.html">Java DSL</a> which is 039 * used to build {@link org.apache.camel.impl.DefaultRoute} instances in a {@link CamelContext} for smart routing. 040 * 041 * @version 042 */ 043public abstract class RouteBuilder extends BuilderSupport implements RoutesBuilder { 044 protected Logger log = LoggerFactory.getLogger(getClass()); 045 private AtomicBoolean initialized = new AtomicBoolean(false); 046 private RoutesDefinition routeCollection = new RoutesDefinition(); 047 048 public RouteBuilder() { 049 this(null); 050 } 051 052 public RouteBuilder(CamelContext context) { 053 super(context); 054 } 055 056 @Override 057 public String toString() { 058 return getRouteCollection().toString(); 059 } 060 061 /** 062 * <b>Called on initialization to build the routes using the fluent builder syntax.</b> 063 * <p/> 064 * This is a central method for RouteBuilder implementations to implement 065 * the routes using the Java fluent builder syntax. 066 * 067 * @throws Exception can be thrown during configuration 068 */ 069 public abstract void configure() throws Exception; 070 071 /** 072 * Creates a new route from the given URI input 073 * 074 * @param uri the from uri 075 * @return the builder 076 */ 077 public RouteDefinition from(String uri) { 078 getRouteCollection().setCamelContext(getContext()); 079 RouteDefinition answer = getRouteCollection().from(uri); 080 configureRoute(answer); 081 return answer; 082 } 083 084 /** 085 * Creates a new route from the given URI input 086 * 087 * @param uri the String formatted from uri 088 * @param args arguments for the string formatting of the uri 089 * @return the builder 090 */ 091 public RouteDefinition fromF(String uri, Object... args) { 092 getRouteCollection().setCamelContext(getContext()); 093 RouteDefinition answer = getRouteCollection().from(String.format(uri, args)); 094 configureRoute(answer); 095 return answer; 096 } 097 098 /** 099 * Creates a new route from the given endpoint 100 * 101 * @param endpoint the from endpoint 102 * @return the builder 103 */ 104 public RouteDefinition from(Endpoint endpoint) { 105 getRouteCollection().setCamelContext(getContext()); 106 RouteDefinition answer = getRouteCollection().from(endpoint); 107 configureRoute(answer); 108 return answer; 109 } 110 111 /** 112 * Creates a new route from the given URIs input 113 * 114 * @param uris the from uris 115 * @return the builder 116 */ 117 public RouteDefinition from(String... uris) { 118 getRouteCollection().setCamelContext(getContext()); 119 RouteDefinition answer = getRouteCollection().from(uris); 120 configureRoute(answer); 121 return answer; 122 } 123 124 /** 125 * Creates a new route from the given endpoint 126 * 127 * @param endpoints the from endpoints 128 * @return the builder 129 */ 130 public RouteDefinition from(Endpoint... endpoints) { 131 getRouteCollection().setCamelContext(getContext()); 132 RouteDefinition answer = getRouteCollection().from(endpoints); 133 configureRoute(answer); 134 return answer; 135 } 136 137 /** 138 * Installs the given <a href="http://camel.apache.org/error-handler.html">error handler</a> builder 139 * 140 * @param errorHandlerBuilder the error handler to be used by default for all child routes 141 */ 142 public void errorHandler(ErrorHandlerBuilder errorHandlerBuilder) { 143 if (!getRouteCollection().getRoutes().isEmpty()) { 144 throw new IllegalArgumentException("errorHandler must be defined before any routes in the RouteBuilder"); 145 } 146 getRouteCollection().setCamelContext(getContext()); 147 setErrorHandlerBuilder(errorHandlerBuilder); 148 } 149 150 /** 151 * Adds a route for an interceptor that intercepts every processing step. 152 * 153 * @return the builder 154 */ 155 public InterceptDefinition intercept() { 156 if (!getRouteCollection().getRoutes().isEmpty()) { 157 throw new IllegalArgumentException("intercept must be defined before any routes in the RouteBuilder"); 158 } 159 getRouteCollection().setCamelContext(getContext()); 160 return getRouteCollection().intercept(); 161 } 162 163 /** 164 * Adds a route for an interceptor that intercepts incoming messages on any inputs in this route 165 * 166 * @return the builder 167 */ 168 public InterceptFromDefinition interceptFrom() { 169 if (!getRouteCollection().getRoutes().isEmpty()) { 170 throw new IllegalArgumentException("interceptFrom must be defined before any routes in the RouteBuilder"); 171 } 172 getRouteCollection().setCamelContext(getContext()); 173 return getRouteCollection().interceptFrom(); 174 } 175 176 /** 177 * Adds a route for an interceptor that intercepts incoming messages on the given endpoint. 178 * 179 * @param uri endpoint uri 180 * @return the builder 181 */ 182 public InterceptFromDefinition interceptFrom(String uri) { 183 if (!getRouteCollection().getRoutes().isEmpty()) { 184 throw new IllegalArgumentException("interceptFrom must be defined before any routes in the RouteBuilder"); 185 } 186 getRouteCollection().setCamelContext(getContext()); 187 return getRouteCollection().interceptFrom(uri); 188 } 189 190 /** 191 * Applies a route for an interceptor if an exchange is send to the given endpoint 192 * 193 * @param uri endpoint uri 194 * @return the builder 195 */ 196 public InterceptSendToEndpointDefinition interceptSendToEndpoint(String uri) { 197 if (!getRouteCollection().getRoutes().isEmpty()) { 198 throw new IllegalArgumentException("interceptSendToEndpoint must be defined before any routes in the RouteBuilder"); 199 } 200 getRouteCollection().setCamelContext(getContext()); 201 return getRouteCollection().interceptSendToEndpoint(uri); 202 } 203 204 /** 205 * <a href="http://camel.apache.org/exception-clause.html">Exception clause</a> 206 * for catching certain exceptions and handling them. 207 * 208 * @param exception exception to catch 209 * @return the builder 210 */ 211 public OnExceptionDefinition onException(Class<? extends Throwable> exception) { 212 // is only allowed at the top currently 213 if (!getRouteCollection().getRoutes().isEmpty()) { 214 throw new IllegalArgumentException("onException must be defined before any routes in the RouteBuilder"); 215 } 216 getRouteCollection().setCamelContext(getContext()); 217 return getRouteCollection().onException(exception); 218 } 219 220 /** 221 * <a href="http://camel.apache.org/exception-clause.html">Exception clause</a> 222 * for catching certain exceptions and handling them. 223 * 224 * @param exceptions list of exceptions to catch 225 * @return the builder 226 */ 227 public OnExceptionDefinition onException(Class<? extends Throwable>... exceptions) { 228 OnExceptionDefinition last = null; 229 for (Class<? extends Throwable> ex : exceptions) { 230 last = last == null ? onException(ex) : last.onException(ex); 231 } 232 return last != null ? last : onException(Exception.class); 233 } 234 235 /** 236 * <a href="http://camel.apache.org/oncompletion.html">On completion</a> 237 * callback for doing custom routing when the {@link org.apache.camel.Exchange} is complete. 238 * 239 * @return the builder 240 */ 241 public OnCompletionDefinition onCompletion() { 242 // is only allowed at the top currently 243 if (!getRouteCollection().getRoutes().isEmpty()) { 244 throw new IllegalArgumentException("onCompletion must be defined before any routes in the RouteBuilder"); 245 } 246 getRouteCollection().setCamelContext(getContext()); 247 return getRouteCollection().onCompletion(); 248 } 249 250 // Properties 251 // ----------------------------------------------------------------------- 252 public ModelCamelContext getContext() { 253 ModelCamelContext context = super.getContext(); 254 if (context == null) { 255 context = createContainer(); 256 setContext(context); 257 } 258 return context; 259 } 260 261 public void addRoutesToCamelContext(CamelContext context) throws Exception { 262 configureRoutes((ModelCamelContext)context); 263 // add routes to Camel by populating them 264 populateRoutes(); 265 } 266 267 /** 268 * Configures the routes 269 * 270 * @param context the Camel context 271 * @return the routes configured 272 * @throws Exception can be thrown during configuration 273 */ 274 public RoutesDefinition configureRoutes(ModelCamelContext context) throws Exception { 275 setContext(context); 276 checkInitialized(); 277 routeCollection.setCamelContext(context); 278 return routeCollection; 279 } 280 281 /** 282 * Includes the routes from the build to this builder. 283 * <p/> 284 * This allows you to use other builds as route templates. 285 * @param routes other builder with routes to include 286 * 287 * @throws Exception can be thrown during configuration 288 */ 289 public void includeRoutes(RoutesBuilder routes) throws Exception { 290 // TODO: We should support including multiple routes so I think invoking configure() 291 // needs to be deferred to later 292 if (routes instanceof RouteBuilder) { 293 // if its a RouteBuilder then let it use my route collection and error handler 294 // then we are integrated seamless 295 RouteBuilder builder = (RouteBuilder) routes; 296 builder.setContext(this.getContext()); 297 builder.setRouteCollection(this.getRouteCollection()); 298 builder.setErrorHandlerBuilder(this.getErrorHandlerBuilder()); 299 // must invoke configure on the original builder so it adds its configuration to me 300 builder.configure(); 301 } else { 302 getContext().addRoutes(routes); 303 } 304 } 305 306 @Override 307 public void setErrorHandlerBuilder(ErrorHandlerBuilder errorHandlerBuilder) { 308 super.setErrorHandlerBuilder(errorHandlerBuilder); 309 getRouteCollection().setErrorHandlerBuilder(getErrorHandlerBuilder()); 310 } 311 312 // Implementation methods 313 // ----------------------------------------------------------------------- 314 @SuppressWarnings("deprecation") 315 protected void checkInitialized() throws Exception { 316 if (initialized.compareAndSet(false, true)) { 317 // Set the CamelContext ErrorHandler here 318 ModelCamelContext camelContext = getContext(); 319 if (camelContext.getErrorHandlerBuilder() != null) { 320 setErrorHandlerBuilder(camelContext.getErrorHandlerBuilder()); 321 } 322 configure(); 323 // mark all route definitions as custom prepared because 324 // a route builder prepares the route definitions correctly already 325 for (RouteDefinition route : getRouteCollection().getRoutes()) { 326 route.markPrepared(); 327 } 328 } 329 } 330 331 protected void populateRoutes() throws Exception { 332 ModelCamelContext camelContext = getContext(); 333 if (camelContext == null) { 334 throw new IllegalArgumentException("CamelContext has not been injected!"); 335 } 336 getRouteCollection().setCamelContext(camelContext); 337 camelContext.addRouteDefinitions(getRouteCollection().getRoutes()); 338 } 339 340 public void setRouteCollection(RoutesDefinition routeCollection) { 341 this.routeCollection = routeCollection; 342 } 343 344 public RoutesDefinition getRouteCollection() { 345 return this.routeCollection; 346 } 347 348 /** 349 * Factory method 350 * 351 * @return the CamelContext 352 */ 353 protected ModelCamelContext createContainer() { 354 return new DefaultCamelContext(); 355 } 356 357 protected void configureRoute(RouteDefinition route) { 358 route.setGroup(getClass().getName()); 359 } 360 361 /** 362 * Adds a collection of routes to this context 363 * 364 * @param routes the routes 365 * @throws Exception if the routes could not be created for whatever reason 366 * @deprecated will be removed in Camel 3.0. Instead use {@link #includeRoutes(org.apache.camel.RoutesBuilder) includeRoutes} instead. 367 */ 368 @Deprecated 369 protected void addRoutes(RoutesBuilder routes) throws Exception { 370 includeRoutes(routes); 371 } 372 373}