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: 982303 $
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            routeCollection.setCamelContext(getContext());
140            setErrorHandlerBuilder(errorHandlerBuilder);
141            return this;
142        }
143    
144        /**
145         * Adds a route for an interceptor that intercepts every processing step.
146         *
147         * @return the builder
148         */
149        public InterceptDefinition intercept() {
150            routeCollection.setCamelContext(getContext());
151            return routeCollection.intercept();
152        }
153    
154        /**
155         * Adds a route for an interceptor that intercepts incoming messages on any inputs in this route
156         *
157         * @return the builder
158         */
159        public InterceptFromDefinition interceptFrom() {
160            routeCollection.setCamelContext(getContext());
161            return routeCollection.interceptFrom();
162        }
163    
164        /**
165         * Adds a route for an interceptor that intercepts incoming messages on the given endpoint.
166         *
167         * @param uri  endpoint uri
168         * @return the builder
169         */
170        public InterceptFromDefinition interceptFrom(String uri) {
171            routeCollection.setCamelContext(getContext());
172            return routeCollection.interceptFrom(uri);
173        }
174    
175        /**
176         * Applies a route for an interceptor if an exchange is send to the given endpoint
177         *
178         * @param uri  endpoint uri
179         * @return the builder
180         */
181        public InterceptSendToEndpointDefinition interceptSendToEndpoint(String uri) {
182            routeCollection.setCamelContext(getContext());
183            return routeCollection.interceptSendToEndpoint(uri);
184        }
185    
186        /**
187         * <a href="http://camel.apache.org/exception-clause.html">Exception clause</a>
188         * for catching certain exceptions and handling them.
189         *
190         * @param exception exception to catch
191         * @return the builder
192         */
193        public OnExceptionDefinition onException(Class exception) {
194            routeCollection.setCamelContext(getContext());
195            return routeCollection.onException(exception);
196        }
197    
198        /**
199         * <a href="http://camel.apache.org/exception-clause.html">Exception clause</a>
200         * for catching certain exceptions and handling them.
201         *
202         * @param exceptions list of exceptions to catch
203         * @return the builder
204         */
205        public OnExceptionDefinition onException(Class... exceptions) {
206            OnExceptionDefinition last = null;
207            for (Class ex : exceptions) {
208                last = last == null ? onException(ex) : last.onException(ex);
209            }
210            return last != null ? last : onException(Exception.class);
211        }
212    
213        /**
214         * <a href="http://camel.apache.org/oncompletion.html">On completion</a>
215         * callback for doing custom routing when the {@link org.apache.camel.Exchange} is complete.
216         *
217         * @return the builder
218         */
219        public OnCompletionDefinition onCompletion() {
220            routeCollection.setCamelContext(getContext());
221            return routeCollection.onCompletion();
222        }
223        
224        // Properties
225        // -----------------------------------------------------------------------
226        public CamelContext getContext() {
227            CamelContext context = super.getContext();
228            if (context == null) {
229                context = createContainer();
230                setContext(context);
231            }
232            return context;
233        }
234    
235        public void addRoutesToCamelContext(CamelContext context) throws Exception {
236            configureRoutes(context);
237            // add routes to Camel by populating them
238            populateRoutes();
239        }
240    
241        /**
242         * Configures the routes
243         *
244         * @param context the Camel context
245         * @return the routes configured
246         * @throws Exception can be thrown during configuration
247         */
248        public RoutesDefinition configureRoutes(CamelContext context) throws Exception {
249            setContext(context);
250            checkInitialized();
251            routeCollection.setCamelContext(context);
252            return routeCollection;
253        }
254    
255        /**
256         * Includes the routes from the build to this builder.
257         * <p/>
258         * This allows you to use other builds as route templates.
259         * @param routes other builder with routes to include
260         *
261         * @throws Exception can be thrown during configuration
262         */
263        public void includeRoutes(RoutesBuilder routes) throws Exception {
264            // TODO: We should support including multiple routes so I think invoking configure()
265            // needs to be deferred to later
266            if (routes instanceof RouteBuilder) {
267                // if its a RouteBuilder then let it use my route collection and error handler
268                // then we are integrated seamless
269                RouteBuilder builder = (RouteBuilder) routes;
270                builder.setContext(this.getContext());
271                builder.setRouteCollection(this.getRouteCollection());
272                builder.setErrorHandlerBuilder(this.getErrorHandlerBuilder());
273                // must invoke configure on the original builder so it adds its configuration to me
274                builder.configure();
275            } else {
276                getContext().addRoutes(routes);
277            }
278        }
279    
280        @Override
281        public void setErrorHandlerBuilder(ErrorHandlerBuilder errorHandlerBuilder) {
282            super.setErrorHandlerBuilder(errorHandlerBuilder);
283            routeCollection.setErrorHandlerBuilder(getErrorHandlerBuilder());
284        }
285    
286        // Implementation methods
287        // -----------------------------------------------------------------------
288        protected void checkInitialized() throws Exception {
289            if (initialized.compareAndSet(false, true)) {
290                // Set the CamelContext ErrorHandler here
291                CamelContext camelContext = getContext();
292                if (camelContext.getErrorHandlerBuilder() != null) {
293                    setErrorHandlerBuilder(camelContext.getErrorHandlerBuilder());
294                }
295                configure();
296                // mark all route definitions as custom prepared because
297                // a route builder prepares the route definitions correctly already
298                for (RouteDefinition route : getRouteCollection().getRoutes()) {
299                    route.customPrepared();
300                }
301            }
302        }
303    
304        protected void populateRoutes() throws Exception {
305            CamelContext camelContext = getContext();
306            if (camelContext == null) {
307                throw new IllegalArgumentException("CamelContext has not been injected!");
308            }
309            routeCollection.setCamelContext(camelContext);
310            camelContext.addRouteDefinitions(routeCollection.getRoutes());
311        }
312    
313        public void setRouteCollection(RoutesDefinition routeCollection) {
314            this.routeCollection = routeCollection;
315        }
316    
317        public RoutesDefinition getRouteCollection() {
318            return this.routeCollection;
319        }
320    
321        /**
322         * Factory method
323         */
324        protected CamelContext createContainer() {
325            return new DefaultCamelContext();
326        }
327    
328        protected void configureRoute(RouteDefinition route) {
329            route.setGroup(getClass().getName());
330        }
331    
332        /**
333         * Adds a collection of routes to this context
334         *
335         * @throws Exception if the routes could not be created for whatever reason
336         * @deprecated use {@link #includeRoutes(org.apache.camel.RoutesBuilder) includeRoutes} instead.
337         */
338        @Deprecated
339        protected void addRoutes(RoutesBuilder routes) throws Exception {
340            includeRoutes(routes);
341        }
342    
343    }