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.ArrayList;
020    import java.util.List;
021    import java.util.concurrent.atomic.AtomicBoolean;
022    
023    import org.apache.camel.CamelContext;
024    import org.apache.camel.Endpoint;
025    import org.apache.camel.Predicate;
026    import org.apache.camel.Route;
027    import org.apache.camel.Routes;
028    import org.apache.camel.impl.DefaultCamelContext;
029    import org.apache.camel.model.ChoiceDefinition;
030    import org.apache.camel.model.InterceptDefinition;
031    import org.apache.camel.model.OnExceptionDefinition;
032    import org.apache.camel.model.RouteDefinition;
033    import org.apache.camel.model.RoutesDefinition;
034    import org.apache.camel.processor.DelegateProcessor;
035    import org.apache.camel.processor.interceptor.StreamCachingInterceptor;
036    
037    /**
038     * A <a href="http://camel.apache.org/dsl.html">Java DSL</a> which is
039     * used to build {@link Route} instances in a {@link CamelContext} for smart routing.
040     *
041     * @version $Revision: 751655 $
042     */
043    public abstract class RouteBuilder extends BuilderSupport implements Routes {
044        private AtomicBoolean initialized = new AtomicBoolean(false);
045        private RoutesDefinition routeCollection = new RoutesDefinition();
046        private List<Route> routes = new ArrayList<Route>();
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 routeCollection.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            RouteDefinition answer = routeCollection.from(uri);
079            configureRoute(answer);
080            return answer;
081        }
082    
083        /**
084         * Creates a new route from the given endpoint
085         *
086         * @param endpoint  the from endpoint
087         * @return the builder
088         */
089        public RouteDefinition from(Endpoint endpoint) {
090            RouteDefinition answer = routeCollection.from(endpoint);
091            configureRoute(answer);
092            return answer;
093        }
094    
095        /**
096         * Creates a new route from the given URIs input
097         *
098         * @param uris  the from uris
099         * @return the builder
100         */
101        public RouteDefinition from(String... uris) {
102            RouteDefinition answer = routeCollection.from(uris);
103            configureRoute(answer);
104            return answer;
105        }
106    
107        /**
108         * Creates a new route from the given endpoint
109         *
110         * @param endpoints  the from endpoints
111         * @return the builder
112         */
113        public RouteDefinition from(Endpoint... endpoints) {
114            RouteDefinition answer = routeCollection.from(endpoints);
115            configureRoute(answer);
116            return answer;
117        }
118    
119        /**
120         * Installs the given <a href="http://camel.apache.org/error-handler.html">error handler</a> builder
121         *
122         * @param errorHandlerBuilder  the error handler to be used by default for all child routes
123         * @return the current builder with the error handler configured
124         */
125        public RouteBuilder errorHandler(ErrorHandlerBuilder errorHandlerBuilder) {
126            setErrorHandlerBuilder(errorHandlerBuilder);
127            return this;
128        }
129    
130        /**
131         * Configures whether or not the <a href="http://camel.apache.org/error-handler.html">error handler</a>
132         * is inherited by every processing node (or just the top most one)
133         *
134         * @param inherit  whether error handlers should be inherited or not
135         * @return the current builder
136         */
137        public RouteBuilder inheritErrorHandler(boolean inherit) {
138            routeCollection.setInheritErrorHandlerFlag(inherit);
139            return this;
140        }
141    
142        /**
143         * Adds the given interceptor to this route
144         *
145         * @param interceptor  the interceptor
146         * @return the builder
147         */
148        public RouteBuilder intercept(DelegateProcessor interceptor) {
149            routeCollection.intercept(interceptor);
150            return this;
151        }
152    
153        /**
154         * Adds a route for an interceptor; use the {@link org.apache.camel.model.ProcessorDefinition#proceed()} method
155         * to continue processing the underlying route being intercepted.
156         * @return the builder
157         */
158        public InterceptDefinition intercept() {
159            return routeCollection.intercept();
160        }
161    
162        /**
163         * Applies a route for an interceptor if the given predicate is true
164         * otherwise the interceptor route is not applied
165         *
166         * @param predicate  the predicate
167         * @return the builder
168         */
169        public ChoiceDefinition intercept(Predicate predicate) {
170            return routeCollection.intercept(predicate);
171        }
172    
173        /**
174         * <a href="http://camel.apache.org/exception-clause.html">Exception clause</a>
175         * for catching certain exceptions and handling them.
176         *
177         * @param exception exception to catch
178         * @return the builder
179         */
180        public OnExceptionDefinition onException(Class exception) {
181            return routeCollection.onException(exception);
182        }
183    
184        /**
185         * <a href="http://camel.apache.org/exception-clause.html">Exception clause</a>
186         * for catching certain exceptions and handling them.
187         *
188         * @param exceptions list of exceptions to catch
189         * @return the builder
190         */
191        public OnExceptionDefinition onException(Class... exceptions) {
192            OnExceptionDefinition last = null;
193            for (Class ex : exceptions) {
194                last = last == null ? onException(ex) : last.onException(ex);
195            }
196            return last != null ? last : onException(Exception.class);
197        }
198        
199        // Properties
200        // -----------------------------------------------------------------------
201        public CamelContext getContext() {
202            CamelContext context = super.getContext();
203            if (context == null) {
204                context = createContainer();
205                setContext(context);
206            }
207            return context;
208        }
209    
210        /**
211         * Uses {@link org.apache.camel.CamelContext#getRoutes()} to return the routes in the context.
212         */
213        public List<Route> getRouteList() throws Exception {
214            checkInitialized();
215            return routes;
216        }
217    
218        @Override
219        public void setInheritErrorHandler(boolean inheritErrorHandler) {
220            super.setInheritErrorHandler(inheritErrorHandler);
221            routeCollection.setInheritErrorHandlerFlag(inheritErrorHandler);
222    
223        }
224    
225        @Override
226        public void setErrorHandlerBuilder(ErrorHandlerBuilder errorHandlerBuilder) {
227            super.setErrorHandlerBuilder(errorHandlerBuilder);
228            routeCollection.setErrorHandlerBuilder(getErrorHandlerBuilder());
229        }
230    
231        // Implementation methods
232        // -----------------------------------------------------------------------
233        protected void checkInitialized() throws Exception {
234            if (initialized.compareAndSet(false, true)) {
235                // Set the CamelContext ErrorHandler here
236                CamelContext camelContext = getContext();
237                if (camelContext.getErrorHandlerBuilder() != null) {
238                    setErrorHandlerBuilder(camelContext.getErrorHandlerBuilder());
239                }
240                configure();
241                populateRoutes(routes);
242            }
243        }
244    
245        protected void populateRoutes(List<Route> routes) throws Exception {
246            CamelContext camelContext = getContext();
247            if (camelContext == null) {
248                throw new IllegalArgumentException("CamelContext has not been injected!");
249            }
250            routeCollection.setCamelContext(camelContext);
251            camelContext.addRouteDefinitions(routeCollection.getRoutes());
252        }
253    
254        public void setRouteCollection(RoutesDefinition routeCollection) {
255            this.routeCollection = routeCollection;
256        }
257    
258        public RoutesDefinition getRouteCollection() {
259            return this.routeCollection;
260        }
261    
262        /**
263         * Completely disable stream caching for all routes being defined in the same RouteBuilder after this.
264         */
265        public void noStreamCaching() {
266            StreamCachingInterceptor.noStreamCaching(routeCollection.getInterceptors());
267        }
268    
269        /**
270         * Enable stream caching for all routes being defined in the same RouteBuilder after this call.
271         */
272        public void streamCaching() {
273            routeCollection.intercept(new StreamCachingInterceptor());
274        }
275    
276        /**
277         * Factory method
278         */
279        protected CamelContext createContainer() {
280            return new DefaultCamelContext();
281        }
282    
283        protected void configureRoute(RouteDefinition route) {
284            route.setGroup(getClass().getName());
285        }
286    
287        /**
288         * Adds a collection of routes to this context
289         *
290         * @throws Exception if the routes could not be created for whatever reason
291         */
292        protected void addRoutes(Routes routes) throws Exception {
293            getContext().addRoutes(routes);
294        }
295    }