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 org.apache.camel.Endpoint;
020    import org.apache.camel.Exchange;
021    import org.apache.camel.Expression;
022    import org.apache.camel.Predicate;
023    import org.apache.camel.Processor;
024    import org.apache.camel.Route;
025    import org.apache.camel.impl.EventDrivenConsumerRoute;
026    import org.apache.camel.processor.CompositeProcessor;
027    import org.apache.camel.processor.DelegateProcessor;
028    import org.apache.camel.processor.MulticastProcessor;
029    import org.apache.camel.processor.Pipeline;
030    import org.apache.camel.processor.RecipientList;
031    import org.apache.camel.processor.idempotent.IdempotentConsumer;
032    import org.apache.camel.processor.idempotent.MessageIdRepository;
033    import org.apache.camel.spi.Policy;
034    import org.apache.commons.logging.Log;
035    import org.apache.commons.logging.LogFactory;
036    
037    import java.util.ArrayList;
038    import java.util.Collection;
039    import java.util.Collections;
040    import java.util.List;
041    
042    /**
043     * @version $Revision: 548618 $
044     */
045    public class FromBuilder extends BuilderSupport implements ProcessorFactory {
046        public static final String DEFAULT_TRACE_CATEGORY = "org.apache.camel.TRACE";
047        private RouteBuilder builder;
048        private Endpoint from;
049        private List<Processor> processors = new ArrayList<Processor>();
050        private List<ProcessorFactory> processFactories = new ArrayList<ProcessorFactory>();
051        private FromBuilder routeBuilder;
052    
053        public FromBuilder(RouteBuilder builder, Endpoint from) {
054            super(builder);
055            this.builder = builder;
056            this.from = from;
057        }
058    
059        public FromBuilder(FromBuilder parent) {
060            super(parent);
061            this.builder = parent.getBuilder();
062            this.from = parent.getFrom();
063        }
064    
065        /**
066         * Sends the exchange to the given endpoint URI
067         */
068        @Fluent
069        public ProcessorFactory to(@FluentArg("uri")String uri) {
070            return to(endpoint(uri));
071        }
072    
073        /**
074         * Sends the exchange to the given endpoint
075         */
076        @Fluent
077        public ProcessorFactory to(@FluentArg("ref")Endpoint endpoint) {
078            ToBuilder answer = new ToBuilder(this, endpoint);
079            addProcessBuilder(answer);
080            return answer;
081        }
082    
083        /**
084         * Sends the exchange to a list of endpoints using the {@link MulticastProcessor} pattern
085         */
086        @Fluent
087        public ProcessorFactory to(String... uris) {
088            return to(endpoints(uris));
089        }
090    
091        /**
092         * Sends the exchange to a list of endpoints using the {@link MulticastProcessor} pattern
093         */
094        @Fluent
095        public ProcessorFactory to(
096                @FluentArg(value = "endpoint", attribute = false, element = true)
097                Endpoint... endpoints) {
098            return to(endpoints(endpoints));
099        }
100    
101        /**
102         * Sends the exchange to a list of endpoint using the {@link MulticastProcessor} pattern
103         */
104        @Fluent
105        public ProcessorFactory to(@FluentArg(value = "endpoint", attribute = false, element = true)
106        Collection<Endpoint> endpoints) {
107            return addProcessBuilder(new MulticastBuilder(this, endpoints));
108        }
109    
110        /**
111         * Creates a {@link Pipeline} of the list of endpoints so that the message will get processed by each endpoint in turn
112         * and for request/response the output of one endpoint will be the input of the next endpoint
113         */
114        @Fluent
115        public ProcessorFactory pipeline(@FluentArg("uris")String... uris) {
116            return pipeline(endpoints(uris));
117        }
118    
119        /**
120         * Creates a {@link Pipeline} of the list of endpoints so that the message will get processed by each endpoint in turn
121         * and for request/response the output of one endpoint will be the input of the next endpoint
122         */
123        @Fluent
124        public ProcessorFactory pipeline(@FluentArg("endpoints")Endpoint... endpoints) {
125            return pipeline(endpoints(endpoints));
126        }
127    
128        /**
129         * Creates a {@link Pipeline} of the list of endpoints so that the message will get processed by each endpoint in turn
130         * and for request/response the output of one endpoint will be the input of the next endpoint
131         */
132        @Fluent
133        public ProcessorFactory pipeline(@FluentArg("endpoints")Collection<Endpoint> endpoints) {
134            return addProcessBuilder(new PipelineBuilder(this, endpoints));
135        }
136    
137        /**
138         * Creates an {@link IdempotentConsumer} to avoid duplicate messages
139         */
140        @Fluent
141        public IdempotentConsumerBuilder idempotentConsumer(
142                @FluentArg("messageIdExpression")Expression messageIdExpression,
143                @FluentArg("MessageIdRepository")MessageIdRepository messageIdRepository) {
144            return (IdempotentConsumerBuilder) addProcessBuilder(new IdempotentConsumerBuilder(this, messageIdExpression, messageIdRepository));
145        }
146    
147        /**
148         * Creates a predicate which is applied and only if it is true then
149         * the exchange is forwarded to the destination
150         *
151         * @return the builder for a predicate
152         */
153        @Fluent
154        public FilterBuilder filter(
155                @FluentArg(value = "predicate", element = true)
156                Predicate predicate) {
157            FilterBuilder answer = new FilterBuilder(this, predicate);
158            addProcessBuilder(answer);
159            return answer;
160        }
161    
162        /**
163         * Creates a choice of one or more predicates with an otherwise clause
164         *
165         * @return the builder for a choice expression
166         */
167        @Fluent(nestedActions = true)
168        public ChoiceBuilder choice() {
169            ChoiceBuilder answer = new ChoiceBuilder(this);
170            addProcessBuilder(answer);
171            return answer;
172        }
173    
174        /**
175         * Creates a dynamic <a href="http://activemq.apache.org/camel/recipient-list.html">Recipient List</a> pattern.
176         *
177         * @param receipients is the builder of the expression used in the {@link RecipientList} to decide the destinations
178         */
179        @Fluent
180        public RecipientListBuilder recipientList(
181                @FluentArg(value = "recipients", element = true)
182                Expression receipients) {
183            RecipientListBuilder answer = new RecipientListBuilder(this, receipients);
184            addProcessBuilder(answer);
185            return answer;
186        }
187    
188        /**
189         * A builder for the <a href="http://activemq.apache.org/camel/splitter.html">Splitter</a> pattern
190         * where an expression is evaluated to iterate through each of the parts of a message and then each part is then send to some endpoint.
191         *
192         * @param receipients the expression on which to split
193         * @return the builder
194         */
195        @Fluent
196        public SplitterBuilder splitter(@FluentArg(value = "recipients", element = true)Expression receipients) {
197            SplitterBuilder answer = new SplitterBuilder(this, receipients);
198            addProcessBuilder(answer);
199            return answer;
200        }
201    
202        /**
203         * A builder for the <a href="http://activemq.apache.org/camel/resequencer.html">Resequencer</a> pattern
204         * where an expression is evaluated to be able to compare the message exchanges to reorder them. e.g. you
205         * may wish to sort by some header
206         *
207         * @param expression the expression on which to compare messages in order
208         * @return the builder
209         */
210        public ResequencerBuilder resequencer(Expression<Exchange> expression) {
211            return resequencer(Collections.<Expression<Exchange>>singletonList(expression));
212        }
213    
214        /**
215         * A builder for the <a href="http://activemq.apache.org/camel/resequencer.html">Resequencer</a> pattern
216         * where a list of expressions are evaluated to be able to compare the message exchanges to reorder them. e.g. you
217         * may wish to sort by some headers
218         *
219         * @param expressions the expressions on which to compare messages in order
220         * @return the builder
221         */
222        @Fluent
223        public ResequencerBuilder resequencer(@FluentArg(value = "expressions")List<Expression<Exchange>> expressions) {
224            ResequencerBuilder answer = new ResequencerBuilder(this, expressions);
225            setRouteBuilder(answer);
226            return answer;
227        }
228    
229        /**
230         * A builder for the <a href="http://activemq.apache.org/camel/resequencer.html">Resequencer</a> pattern
231         * where a list of expressions are evaluated to be able to compare the message exchanges to reorder them. e.g. you
232         * may wish to sort by some headers
233         *
234         * @param expressions the expressions on which to compare messages in order
235         * @return the builder
236         */
237        @Fluent
238        public ResequencerBuilder resequencer(Expression<Exchange>... expressions) {
239            List<Expression<Exchange>> list = new ArrayList<Expression<Exchange>>();
240            for (Expression<Exchange> expression : expressions) {
241                list.add(expression);
242            }
243            return resequencer(list);
244        }
245    
246        /**
247         * Installs the given error handler builder
248         *
249         * @param errorHandlerBuilder the error handler to be used by default for all child routes
250         * @return the current builder with the error handler configured
251         */
252        @Fluent
253        public FromBuilder errorHandler(@FluentArg("handler")ErrorHandlerBuilder errorHandlerBuilder) {
254            setErrorHandlerBuilder(errorHandlerBuilder);
255            return this;
256        }
257    
258        /**
259         * Configures whether or not the error handler is inherited by every processing node (or just the top most one)
260         *
261         * @param condition the falg as to whether error handlers should be inherited or not
262         * @return the current builder
263         */
264        @Fluent
265        public FromBuilder inheritErrorHandler(@FluentArg("condition")boolean condition) {
266            setInheritErrorHandler(condition);
267            return this;
268        }
269    
270        @Fluent(nestedActions = true)
271        public InterceptorBuilder intercept() {
272            InterceptorBuilder answer = new InterceptorBuilder(this);
273            addProcessBuilder(answer);
274            return answer;
275        }
276    
277        /**
278         * Trace logs the exchange before it goes to the next processing step using the {@link #DEFAULT_TRACE_CATEGORY} logging
279         * category.
280         *
281         * @return
282         */
283        @Fluent
284        public FromBuilder trace() {
285            return trace(DEFAULT_TRACE_CATEGORY);
286        }
287    
288        /**
289         * Trace logs the exchange before it goes to the next processing step using the specified logging
290         * category.
291         *
292         * @param category the logging category trace messages will sent to.
293         * @return
294         */
295        @Fluent
296        public FromBuilder trace(@FluentArg("category")String category) {
297            final Log log = LogFactory.getLog(category);
298            return intercept(new DelegateProcessor() {
299                @Override
300                public void process(Exchange exchange) throws Exception {
301                    log.trace(exchange);
302                    processNext(exchange);
303                }
304            });
305        }
306    
307        @Fluent
308        public FromBuilder intercept(@FluentArg("interceptor")DelegateProcessor interceptor) {
309            InterceptorBuilder answer = new InterceptorBuilder(this);
310            answer.add(interceptor);
311            addProcessBuilder(answer);
312            return answer.target();
313        }
314    
315        @Fluent(nestedActions = true)
316        public PolicyBuilder policies() {
317            PolicyBuilder answer = new PolicyBuilder(this);
318            addProcessBuilder(answer);
319            return answer;
320        }
321    
322        @Fluent
323        public FromBuilder policy(@FluentArg("policy")Policy policy) {
324            PolicyBuilder answer = new PolicyBuilder(this);
325            answer.add(policy);
326            addProcessBuilder(answer);
327            return answer.target();
328        }
329    
330        // Transformers
331        //-------------------------------------------------------------------------
332    
333        /**
334         * Adds the custom processor to this destination which could be a final destination, or could be a transformation in a pipeline
335         */
336        @Fluent
337        public FromBuilder process(@FluentArg("ref")Processor processor) {
338            addProcessorBuilder(processor);
339            return this;
340        }
341    
342        /**
343         * Adds a processor which sets the body on the IN message
344         */
345        @Fluent
346        public FromBuilder setBody(Expression expression) {
347            addProcessorBuilder(ProcessorBuilder.setBody(expression));
348            return this;
349        }
350    
351        /**
352         * Adds a processor which sets the body on the OUT message
353         */
354        @Fluent
355        public FromBuilder setOutBody(Expression expression) {
356            addProcessorBuilder(ProcessorBuilder.setOutBody(expression));
357            return this;
358        }
359    
360        /**
361         * Adds a processor which sets the header on the IN message
362         */
363        @Fluent
364        public FromBuilder setHeader(String name, Expression expression) {
365            addProcessorBuilder(ProcessorBuilder.setHeader(name, expression));
366            return this;
367        }
368    
369        /**
370         * Adds a processor which sets the header on the OUT message
371         */
372        @Fluent
373        public FromBuilder setOutHeader(String name, Expression expression) {
374            addProcessorBuilder(ProcessorBuilder.setOutHeader(name, expression));
375            return this;
376        }
377    
378        /**
379         * Adds a processor which sets the exchange property
380         */
381        @Fluent
382        public FromBuilder setProperty(String name, Expression expression) {
383            addProcessorBuilder(ProcessorBuilder.setProperty(name, expression));
384            return this;
385        }
386    
387        /**
388         * Converts the IN message body to the specified type
389         */
390        @Fluent
391        public FromBuilder convertBodyTo(Class type) {
392            addProcessorBuilder(ProcessorBuilder.setBody(Builder.body().convertTo(type)));
393            return this;
394        }
395    
396        /**
397         * Converts the OUT message body to the specified type
398         */
399        @Fluent
400        public FromBuilder convertOutBodyTo(Class type) {
401            addProcessorBuilder(ProcessorBuilder.setOutBody(Builder.outBody().convertTo(type)));
402            return this;
403        }
404    
405        // Properties
406        //-------------------------------------------------------------------------
407        public RouteBuilder getBuilder() {
408            return builder;
409        }
410    
411        public Endpoint getFrom() {
412            return from;
413        }
414    
415        public List<Processor> getProcessors() {
416            return processors;
417        }
418    
419        public ProcessorFactory addProcessBuilder(ProcessorFactory processFactory) {
420            processFactories.add(processFactory);
421            return processFactory;
422        }
423    
424        protected void addProcessorBuilder(Processor processor) {
425            addProcessBuilder(new ConstantProcessorBuilder(processor));
426        }
427    
428        public void addProcessor(Processor processor) {
429            processors.add(processor);
430        }
431    
432        public Route createRoute() throws Exception {
433            if (routeBuilder != null) {
434                return routeBuilder.createRoute();
435            }
436            Processor processor = createProcessor();
437            if (processor == null) {
438                throw new IllegalArgumentException("No processor created for: " + this);
439            }
440            return new EventDrivenConsumerRoute(getFrom(), processor);
441        }
442    
443        public Processor createProcessor() throws Exception {
444            List<Processor> answer = new ArrayList<Processor>();
445    
446            for (ProcessorFactory processFactory : processFactories) {
447                Processor processor = makeProcessor(processFactory);
448                if (processor == null) {
449                    throw new IllegalArgumentException("No processor created for processBuilder: " + processFactory);
450                }
451                answer.add(processor);
452            }
453            if (answer.size() == 0) {
454                return null;
455            }
456            Processor processor = null;
457            if (answer.size() == 1) {
458                processor = answer.get(0);
459            }
460            else {
461                processor = new CompositeProcessor(answer);
462            }
463            return processor;
464        }
465    
466        /**
467         * Creates the processor and wraps it in any necessary interceptors and error handlers
468         */
469        protected Processor makeProcessor(ProcessorFactory processFactory) throws Exception {
470            Processor processor = processFactory.createProcessor();
471            processor = wrapProcessor(processor);
472            return wrapInErrorHandler(processor);
473        }
474    
475        /**
476         * A strategy method to allow newly created processors to be wrapped in an error handler. This feature
477         * could be disabled for child builders such as {@link IdempotentConsumerBuilder} which will rely on the
478         * {@link FromBuilder} to perform the error handling to avoid doubly-wrapped processors with 2 nested error handlers
479         */
480        protected Processor wrapInErrorHandler(Processor processor) throws Exception {
481            return getErrorHandlerBuilder().createErrorHandler(processor);
482        }
483    
484        /**
485         * A strategy method which allows derived classes to wrap the child processor in some kind of interceptor such as
486         * a filter for the {@link IdempotentConsumerBuilder}.
487         *
488         * @param processor the processor which can be wrapped
489         * @return the original processor or a new wrapped interceptor
490         */
491        protected Processor wrapProcessor(Processor processor) {
492            return processor;
493        }
494    
495        protected FromBuilder getRouteBuilder() {
496            return routeBuilder;
497        }
498    
499        protected void setRouteBuilder(FromBuilder routeBuilder) {
500            this.routeBuilder = routeBuilder;
501        }
502    }