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.model;
018    
019    import java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.List;
022    
023    import javax.xml.bind.annotation.XmlAccessType;
024    import javax.xml.bind.annotation.XmlAccessorType;
025    import javax.xml.bind.annotation.XmlAttribute;
026    import javax.xml.bind.annotation.XmlElementRef;
027    import javax.xml.bind.annotation.XmlRootElement;
028    import javax.xml.bind.annotation.XmlTransient;
029    import javax.xml.bind.annotation.XmlType;
030    
031    import org.apache.camel.CamelContext;
032    import org.apache.camel.CamelContextAware;
033    import org.apache.camel.Endpoint;
034    import org.apache.camel.NoSuchEndpointException;
035    import org.apache.camel.Route;
036    import org.apache.camel.ServiceStatus;
037    import org.apache.camel.builder.ErrorHandlerBuilder;
038    import org.apache.camel.impl.DefaultRouteContext;
039    import org.apache.camel.processor.interceptor.StreamCachingInterceptor;
040    import org.apache.camel.spi.RouteContext;
041    import org.apache.camel.util.CamelContextHelper;
042    import org.apache.commons.logging.Log;
043    import org.apache.commons.logging.LogFactory;
044    
045    /**
046     * Represents an XML <route/> element
047     *
048     * @version $Revision: 751357 $
049     */
050    @XmlRootElement(name = "route")
051    @XmlType(propOrder = {"inputs", "outputs" })
052    @XmlAccessorType(XmlAccessType.PROPERTY)
053    public class RouteDefinition extends ProcessorDefinition<ProcessorDefinition> implements CamelContextAware {
054        private static final transient Log LOG = LogFactory.getLog(RouteDefinition.class);
055        private List<AbstractInterceptorDefinition> interceptors = new ArrayList<AbstractInterceptorDefinition>();
056        private List<FromDefinition> inputs = new ArrayList<FromDefinition>();
057        private List<ProcessorDefinition> outputs = new ArrayList<ProcessorDefinition>();
058        private String group;
059        private CamelContext camelContext;
060        private Boolean streamCaching;
061    
062        public RouteDefinition() {
063        }
064    
065        public RouteDefinition(String uri) {
066            from(uri);
067        }
068    
069        public RouteDefinition(Endpoint endpoint) {
070            from(endpoint);
071        }
072    
073        @Override
074        public String toString() {
075            return "Route[" + inputs + " -> " + outputs + "]";
076        }
077    
078    
079        /**
080         * Returns the status of the route if it has been registered with a {@link CamelContext}
081         */
082        public ServiceStatus getStatus() {
083            if (camelContext != null) {
084                ServiceStatus answer = camelContext.getRouteStatus(this);
085                if (answer == null) {
086                    answer = ServiceStatus.Stopped;
087                }
088                return answer;
089            }
090            return null;
091        }
092    
093        public boolean isStartable() {
094            ServiceStatus status = getStatus();
095            if (status == null) {
096                return true;
097            } else {
098                return status.isStartable();
099            }
100        }
101    
102        public boolean isStoppable() {
103            ServiceStatus status = getStatus();
104            if (status == null) {
105                return false;
106            } else {
107                return status.isStoppable();
108            }
109        }
110        
111        public List<RouteContext> addRoutes(CamelContext context, Collection<Route> routes) throws Exception {
112            List<RouteContext> answer = new ArrayList<RouteContext>();
113            setCamelContext(context);
114    
115            ErrorHandlerBuilder handler = context.getErrorHandlerBuilder();
116            if (handler != null) {
117                setErrorHandlerBuilderIfNull(handler);
118            }
119    
120            for (FromDefinition fromType : inputs) {
121                RouteContext routeContext = addRoutes(routes, fromType);
122                answer.add(routeContext);
123            }
124            return answer;
125        }
126    
127    
128        public Endpoint resolveEndpoint(String uri) throws NoSuchEndpointException {
129            CamelContext context = getCamelContext();
130            if (context == null) {
131                throw new IllegalArgumentException("CamelContext has not been injected!");
132            }
133            return CamelContextHelper.getMandatoryEndpoint(context, uri);
134        }
135    
136        // Fluent API
137        // -----------------------------------------------------------------------
138    
139        /**
140         * Creates an input to the route
141         *
142         * @param uri  the from uri
143         * @return the builder
144         */
145        public RouteDefinition from(String uri) {
146            getInputs().add(new FromDefinition(uri));
147            return this;
148        }
149    
150        /**
151         * Creates an input to the route
152         *
153         * @param endpoint  the from endpoint
154         * @return the builder
155         */
156        public RouteDefinition from(Endpoint endpoint) {
157            getInputs().add(new FromDefinition(endpoint));
158            return this;
159        }
160    
161        /**
162         * Creates inputs to the route
163         *
164         * @param uris  the from uris
165         * @return the builder
166         */
167        public RouteDefinition from(String... uris) {
168            for (String uri : uris) {
169                getInputs().add(new FromDefinition(uri));
170            }
171            return this;
172        }
173    
174        /**
175         * Creates inputs to the route
176         *
177         * @param endpoints  the from endpoints
178         * @return the builder
179         */
180        public RouteDefinition from(Endpoint... endpoints) {
181            for (Endpoint endpoint : endpoints) {
182                getInputs().add(new FromDefinition(endpoint));
183            }
184            return this;
185        }
186    
187        /**
188         * Set the group name for this route
189         *
190         * @param name  the group name
191         * @return the builder
192         */
193        public RouteDefinition group(String name) {
194            setGroup(name);
195            return this;
196        }
197    
198        /**
199         * Disable stream caching for this route
200         *
201         * @return the builder
202         */
203        public RouteDefinition noStreamCaching() {
204            StreamCachingInterceptor.noStreamCaching(interceptors);
205            return this;
206        }
207    
208        /**
209         * Enable stream caching for this route
210         *
211         * @return the builder
212         */
213        public RouteDefinition streamCaching() {
214            addInterceptor(new StreamCachingInterceptor());
215            return this;
216        }
217    
218        // Properties
219        // -----------------------------------------------------------------------
220    
221        public List<AbstractInterceptorDefinition> getInterceptors() {
222            return interceptors;
223        }
224    
225        @XmlTransient
226        public void setInterceptors(List<AbstractInterceptorDefinition> interceptors) {
227            this.interceptors = interceptors;
228        }
229    
230        public List<FromDefinition> getInputs() {
231            return inputs;
232        }
233    
234        @XmlElementRef
235        public void setInputs(List<FromDefinition> inputs) {
236            this.inputs = inputs;
237        }
238    
239        public List<ProcessorDefinition> getOutputs() {
240            return outputs;
241        }
242    
243        @XmlElementRef
244        public void setOutputs(List<ProcessorDefinition> outputs) {
245            this.outputs = outputs;
246    
247            // TODO I don't think this is called when using JAXB!
248            if (outputs != null) {
249                for (ProcessorDefinition output : outputs) {
250                    configureChild(output);
251                }
252            }
253        }
254    
255        public CamelContext getCamelContext() {
256            return camelContext;
257        }
258    
259        @XmlTransient
260        public void setCamelContext(CamelContext camelContext) {
261            this.camelContext = camelContext;
262        }
263    
264        /**
265         * The group that this route belongs to; could be the name of the RouteBuilder class
266         * or be explicitly configured in the XML.
267         *
268         * May be null.
269         */
270        public String getGroup() {
271            return group;
272        }
273    
274        @XmlAttribute
275        public void setGroup(String group) {
276            this.group = group;
277        }
278    
279        public Boolean getStreamCaching() {
280            return streamCaching;
281        }
282    
283        /**
284         * Enable stream caching on this route
285         * @param streamCaching <code>true</code> for enabling stream caching
286         */
287        @XmlAttribute(required = false)
288        public void setStreamCaching(Boolean streamCaching) {
289            this.streamCaching = streamCaching;
290            if (streamCaching != null && streamCaching) {
291                streamCaching();
292            } else {
293                noStreamCaching();
294            }
295        }
296    
297    
298        // Implementation methods
299        // -------------------------------------------------------------------------
300        protected RouteContext addRoutes(Collection<Route> routes, FromDefinition fromType) throws Exception {
301            RouteContext routeContext = new DefaultRouteContext(this, fromType, routes);
302            routeContext.getEndpoint(); // force endpoint resolution
303            if (camelContext != null) {
304                camelContext.getLifecycleStrategy().onRouteContextCreate(routeContext);
305            }
306    
307            List<ProcessorDefinition> list = new ArrayList<ProcessorDefinition>(outputs);
308            for (ProcessorDefinition output : list) {
309                output.addRoutes(routeContext, routes);
310            }
311    
312            routeContext.commit();
313            return routeContext;
314        }
315    
316        @Override
317        protected void configureChild(ProcessorDefinition output) {
318            super.configureChild(output);
319    
320            if (isInheritErrorHandler()) {
321                output.setErrorHandlerBuilder(getErrorHandlerBuilder());
322            }
323    
324            List<AbstractInterceptorDefinition> interceptors = getInterceptors();
325            for (AbstractInterceptorDefinition interceptor : interceptors) {
326                output.addInterceptor(interceptor);
327            }
328        }
329    
330        @Override
331        public void addInterceptor(AbstractInterceptorDefinition interceptor) {
332            getInterceptors().add(interceptor);
333        }
334    
335    }