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 }