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.ChoiceType;
030    import org.apache.camel.model.ExceptionType;
031    import org.apache.camel.model.InterceptType;
032    import org.apache.camel.model.ProcessorType;
033    import org.apache.camel.model.RouteType;
034    import org.apache.camel.model.RoutesType;
035    import org.apache.camel.processor.DelegateProcessor;
036    import org.apache.camel.processor.interceptor.StreamCachingInterceptor;
037    
038    /**
039     * A <a href="http://activemq.apache.org/camel/dsl.html">Java DSL</a> which is
040     * used to build {@link Route} instances in a {@link CamelContext} for smart routing.
041     *
042     * @version $Revision: 61064 $
043     */
044    public abstract class RouteBuilder extends BuilderSupport implements Routes {
045        private AtomicBoolean initialized = new AtomicBoolean(false);
046        private RoutesType routeCollection = new RoutesType();
047        private List<Route> routes = new ArrayList<Route>();
048    
049        public RouteBuilder() {
050            this(null);
051        }
052    
053        public RouteBuilder(CamelContext context) {
054            super(context);
055        }
056    
057        @Override
058        public String toString() {
059            return routeCollection.toString();
060        }
061    
062        /**
063         * Called on initialization to to build the required destinationBuilders
064         */
065        public abstract void configure() throws Exception;
066    
067        /**
068         * Creates a new route from the given URI input
069         */
070        public RouteType from(String uri) {
071            RouteType answer = routeCollection.from(uri);
072            configureRoute(answer);
073            return answer;
074        }
075    
076        /**
077         * Creates a new route from the given endpoint
078         */
079        public RouteType from(Endpoint endpoint) {
080            RouteType answer = routeCollection.from(endpoint);
081            configureRoute(answer);
082            return answer;
083        }
084    
085        /**
086         * Installs the given error handler builder
087         *
088         * @param errorHandlerBuilder the error handler to be used by default for
089         *                all child routes
090         * @return the current builder with the error handler configured
091         */
092        public RouteBuilder errorHandler(ErrorHandlerBuilder errorHandlerBuilder) {
093            setErrorHandlerBuilder(errorHandlerBuilder);
094            return this;
095        }
096    
097        /**
098         * Configures whether or not the error handler is inherited by every
099         * processing node (or just the top most one)
100         *
101         * @param value the flag as to whether error handlers should be inherited or not
102         * @return the current builder
103         */
104        public RouteBuilder inheritErrorHandler(boolean value) {
105            routeCollection.setInheritErrorHandlerFlag(value);
106            return this;
107        }
108    
109        /**
110         * Adds the given interceptor to this route
111         */
112        public RouteBuilder intercept(DelegateProcessor interceptor) {
113            routeCollection.intercept(interceptor);
114            return this;
115        }
116    
117        /**
118         * Adds a route for an interceptor; use the {@link ProcessorType#proceed()} method
119         * to continue processing the underlying route being intercepted.
120         */
121        public InterceptType intercept() {
122            return routeCollection.intercept();
123        }
124    
125        /**
126         * Applies a route for an interceptor if the given predicate is true
127         * otherwise the interceptor route is not applied
128         */
129        public ChoiceType intercept(Predicate predicate) {
130            return routeCollection.intercept(predicate);
131        }
132    
133        /**
134         * Adds an exception handler route for the given exception type
135         */
136        public ExceptionType onException(Class exceptionType) {
137            return routeCollection.onException(exceptionType);
138        }
139    
140        /**
141         * Adds an exception handler route for the given exception types
142         */
143        public ExceptionType onException(Class... exceptions) {
144            ExceptionType last = null;
145            for (Class ex : exceptions) {
146                last = last == null ? onException(ex) : last.onException(ex);
147            }
148            return last != null ? last : onException(Exception.class);
149        }
150    
151        /**
152         * Adds an exception handler route for the given exception type
153         *
154         * @deprecated Please use {@link #onException(Class)} instead. Will be removed in Camel 2.0.
155         */
156        public ExceptionType exception(Class exceptionType) {
157            return onException(exceptionType);
158        }    
159        
160        // Properties
161        // -----------------------------------------------------------------------
162        public CamelContext getContext() {
163            CamelContext context = super.getContext();
164            if (context == null) {
165                context = createContainer();
166                setContext(context);
167            }
168            return context;
169        }
170    
171        /**
172         * Uses {@link org.apache.camel.CamelContext#getRoutes()} to return the routes in the context.
173         */
174        public List<Route> getRouteList() throws Exception {
175            checkInitialized();
176            return routes;
177        }
178    
179        @Override
180        public void setInheritErrorHandler(boolean inheritErrorHandler) {
181            super.setInheritErrorHandler(inheritErrorHandler);
182            routeCollection.setInheritErrorHandlerFlag(inheritErrorHandler);
183    
184        }
185    
186        @Override
187        public void setErrorHandlerBuilder(ErrorHandlerBuilder errorHandlerBuilder) {
188            super.setErrorHandlerBuilder(errorHandlerBuilder);
189            routeCollection.setErrorHandlerBuilder(getErrorHandlerBuilder());
190        }
191    
192        // Implementation methods
193        // -----------------------------------------------------------------------
194        protected void checkInitialized() throws Exception {
195            if (initialized.compareAndSet(false, true)) {
196                // Set the CamelContext ErrorHandler here
197                CamelContext camelContext = getContext();
198                if (camelContext.getErrorHandlerBuilder() != null) {
199                    setErrorHandlerBuilder(camelContext.getErrorHandlerBuilder());
200                }
201                configure();
202                populateRoutes(routes);
203            }
204        }
205    
206        protected void populateRoutes(List<Route> routes) throws Exception {
207            CamelContext camelContext = getContext();
208            if (camelContext == null) {
209                throw new IllegalArgumentException("No CamelContext has been injected!");
210            }
211            routeCollection.setCamelContext(camelContext);
212            camelContext.addRouteDefinitions(routeCollection.getRoutes());
213        }
214    
215        public void setRouteCollection(RoutesType routeCollection) {
216            this.routeCollection = routeCollection;
217        }
218    
219        public RoutesType getRouteCollection() {
220            return this.routeCollection;
221        }
222    
223        /**
224         * Completely disable stream caching for all routes being defined in the same RouteBuilder after this.
225         */
226        public void noStreamCaching() {
227            StreamCachingInterceptor.noStreamCaching(routeCollection.getInterceptors());
228        }
229    
230        /**
231         * Enable stream caching for all routes being defined in the same RouteBuilder after this call.
232         */
233        public void streamCaching() {
234            routeCollection.intercept(new StreamCachingInterceptor());
235        }
236    
237        /**
238         * Factory method
239         */
240        protected CamelContext createContainer() {
241            return new DefaultCamelContext();
242        }
243    
244        protected void configureRoute(RouteType route) {
245            route.setGroup(getClass().getName());
246        }
247    
248        protected void addRoutes(Routes routes) throws Exception {
249            getContext().addRoutes(routes);
250        }
251    }