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