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.Route;
026    import org.apache.camel.Routes;
027    import org.apache.camel.impl.DefaultCamelContext;
028    import org.apache.camel.model.InterceptDefinition;
029    import org.apache.camel.model.InterceptFromDefinition;
030    import org.apache.camel.model.InterceptSendToEndpointDefinition;
031    import org.apache.camel.model.OnCompletionDefinition;
032    import org.apache.camel.model.OnExceptionDefinition;
033    import org.apache.camel.model.RouteDefinition;
034    import org.apache.camel.model.RoutesDefinition;
035    
036    /**
037     * A <a href="http://camel.apache.org/dsl.html">Java DSL</a> which is
038     * used to build {@link org.apache.camel.impl.DefaultRoute} instances in a {@link CamelContext} for smart routing.
039     *
040     * @version $Revision: 775057 $
041     */
042    public abstract class RouteBuilder extends BuilderSupport implements Routes {
043        private AtomicBoolean initialized = new AtomicBoolean(false);
044        private RoutesDefinition routeCollection = new RoutesDefinition();
045        private List<Route> routes = new ArrayList<Route>();
046    
047        public RouteBuilder() {
048            this(null);
049        }
050    
051        public RouteBuilder(CamelContext context) {
052            super(context);
053        }
054    
055        @Override
056        public String toString() {
057            return routeCollection.toString();
058        }
059    
060        /**
061         * <b>Called on initialization to build the routes using the fluent builder syntax.</b>
062         * <p/>
063         * This is a central method for RouteBuilder implementations to implement
064         * the routes using the Java fluent builder syntax.
065         *
066         * @throws Exception can be thrown during configuration
067         */
068        public abstract void configure() throws Exception;
069    
070        /**
071         * Creates a new route from the given URI input
072         *
073         * @param uri  the from uri
074         * @return the builder
075         */
076        public RouteDefinition from(String uri) {
077            routeCollection.setCamelContext(getContext());
078            RouteDefinition answer = routeCollection.from(uri);
079            configureRoute(answer);
080            return answer;
081        }
082    
083        /**
084         * Creates a new route from the given URI input
085         *
086         * @param uri  the String formatted from uri
087         * @param args arguments for the string formatting of the uri
088         * @return the builder
089         */
090        public RouteDefinition fromF(String uri, Object... args) {
091            routeCollection.setCamelContext(getContext());
092            RouteDefinition answer = routeCollection.from(String.format(uri, args));
093            configureRoute(answer);
094            return answer;
095        }
096    
097        /**
098         * Creates a new route from the given endpoint
099         *
100         * @param endpoint  the from endpoint
101         * @return the builder
102         */
103        public RouteDefinition from(Endpoint endpoint) {
104            routeCollection.setCamelContext(getContext());
105            RouteDefinition answer = routeCollection.from(endpoint);
106            configureRoute(answer);
107            return answer;
108        }
109    
110        /**
111         * Creates a new route from the given URIs input
112         *
113         * @param uris  the from uris
114         * @return the builder
115         */
116        public RouteDefinition from(String... uris) {
117            routeCollection.setCamelContext(getContext());
118            RouteDefinition answer = routeCollection.from(uris);
119            configureRoute(answer);
120            return answer;
121        }
122    
123        /**
124         * Creates a new route from the given endpoint
125         *
126         * @param endpoints  the from endpoints
127         * @return the builder
128         */
129        public RouteDefinition from(Endpoint... endpoints) {
130            routeCollection.setCamelContext(getContext());
131            RouteDefinition answer = routeCollection.from(endpoints);
132            configureRoute(answer);
133            return answer;
134        }
135    
136        /**
137         * Installs the given <a href="http://camel.apache.org/error-handler.html">error handler</a> builder
138         *
139         * @param errorHandlerBuilder  the error handler to be used by default for all child routes
140         * @return the current builder with the error handler configured
141         */
142        public RouteBuilder errorHandler(ErrorHandlerBuilder errorHandlerBuilder) {
143            routeCollection.setCamelContext(getContext());
144            setErrorHandlerBuilder(errorHandlerBuilder);
145            return this;
146        }
147    
148        /**
149         * Adds a route for an interceptor that intercepts every processing step.
150         *
151         * @return the builder
152         */
153        public InterceptDefinition intercept() {
154            routeCollection.setCamelContext(getContext());
155            return routeCollection.intercept();
156        }
157    
158        /**
159         * Adds a route for an interceptor that intercepts incoming messages on any inputs in this route
160         *
161         * @return the builder
162         */
163        public InterceptFromDefinition interceptFrom() {
164            routeCollection.setCamelContext(getContext());
165            return routeCollection.interceptFrom();
166        }
167    
168        /**
169         * Adds a route for an interceptor that intercepts incoming messages on the given endpoint.
170         *
171         * @param uri  endpoint uri
172         * @return the builder
173         */
174        public InterceptFromDefinition interceptFrom(String uri) {
175            routeCollection.setCamelContext(getContext());
176            return routeCollection.interceptFrom(uri);
177        }
178    
179        /**
180         * Applies a route for an interceptor if an exchange is send to the given endpoint
181         *
182         * @param uri  endpoint uri
183         * @return the builder
184         */
185        public InterceptSendToEndpointDefinition interceptSendToEndpoint(String uri) {
186            routeCollection.setCamelContext(getContext());
187            return routeCollection.interceptSendToEndpoint(uri);
188        }
189    
190        /**
191         * <a href="http://camel.apache.org/exception-clause.html">Exception clause</a>
192         * for catching certain exceptions and handling them.
193         *
194         * @param exception exception to catch
195         * @return the builder
196         */
197        public OnExceptionDefinition onException(Class exception) {
198            routeCollection.setCamelContext(getContext());
199            return routeCollection.onException(exception);
200        }
201    
202        /**
203         * <a href="http://camel.apache.org/exception-clause.html">Exception clause</a>
204         * for catching certain exceptions and handling them.
205         *
206         * @param exceptions list of exceptions to catch
207         * @return the builder
208         */
209        public OnExceptionDefinition onException(Class... exceptions) {
210            OnExceptionDefinition last = null;
211            for (Class ex : exceptions) {
212                last = last == null ? onException(ex) : last.onException(ex);
213            }
214            return last != null ? last : onException(Exception.class);
215        }
216    
217        /**
218         * <a href="http://camel.apache.org/oncompletion.html">On completion</a>
219         * callback for doing custom routing when the {@link org.apache.camel.Exchange} is complete.
220         *
221         * @return the builder
222         */
223        public OnCompletionDefinition onCompletion() {
224            routeCollection.setCamelContext(getContext());
225            return routeCollection.onCompletion();
226        }
227        
228        // Properties
229        // -----------------------------------------------------------------------
230        public CamelContext getContext() {
231            CamelContext context = super.getContext();
232            if (context == null) {
233                context = createContainer();
234                setContext(context);
235            }
236            return context;
237        }
238    
239        /**
240         * Uses {@link org.apache.camel.CamelContext#getRoutes()} to return the routes in the context.
241         */
242        public List<Route> getRouteList() throws Exception {
243            checkInitialized();
244            return routes;
245        }
246    
247        @Override
248        public void setErrorHandlerBuilder(ErrorHandlerBuilder errorHandlerBuilder) {
249            super.setErrorHandlerBuilder(errorHandlerBuilder);
250            routeCollection.setErrorHandlerBuilder(getErrorHandlerBuilder());
251        }
252    
253        // Implementation methods
254        // -----------------------------------------------------------------------
255        protected void checkInitialized() throws Exception {
256            if (initialized.compareAndSet(false, true)) {
257                // Set the CamelContext ErrorHandler here
258                CamelContext camelContext = getContext();
259                if (camelContext.getErrorHandlerBuilder() != null) {
260                    setErrorHandlerBuilder(camelContext.getErrorHandlerBuilder());
261                }
262                configure();
263                populateRoutes(routes);
264            }
265        }
266    
267        protected void populateRoutes(List<Route> routes) throws Exception {
268            CamelContext camelContext = getContext();
269            if (camelContext == null) {
270                throw new IllegalArgumentException("CamelContext has not been injected!");
271            }
272            routeCollection.setCamelContext(camelContext);
273            camelContext.addRouteDefinitions(routeCollection.getRoutes());
274        }
275    
276        public void setRouteCollection(RoutesDefinition routeCollection) {
277            this.routeCollection = routeCollection;
278        }
279    
280        public RoutesDefinition getRouteCollection() {
281            return this.routeCollection;
282        }
283    
284        /**
285         * Factory method
286         */
287        protected CamelContext createContainer() {
288            return new DefaultCamelContext();
289        }
290    
291        protected void configureRoute(RouteDefinition route) {
292            route.setGroup(getClass().getName());
293        }
294    
295        /**
296         * Adds a collection of routes to this context
297         *
298         * @throws Exception if the routes could not be created for whatever reason
299         */
300        protected void addRoutes(Routes routes) throws Exception {
301            getContext().addRoutes(routes);
302        }
303    }