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.ModelCamelContext;
029 import org.apache.camel.model.OnCompletionDefinition;
030 import org.apache.camel.model.OnExceptionDefinition;
031 import org.apache.camel.model.RouteDefinition;
032 import org.apache.camel.model.RoutesDefinition;
033
034 import org.slf4j.Logger;
035 import 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 */
043 public 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 }