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 }