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 */ 017package org.apache.camel.model; 018 019import java.util.ArrayList; 020import java.util.List; 021import java.util.concurrent.ExecutorService; 022import java.util.concurrent.ScheduledExecutorService; 023import java.util.function.Supplier; 024 025import javax.xml.bind.annotation.XmlAccessType; 026import javax.xml.bind.annotation.XmlAccessorType; 027import javax.xml.bind.annotation.XmlAttribute; 028import javax.xml.bind.annotation.XmlElement; 029import javax.xml.bind.annotation.XmlElementRef; 030import javax.xml.bind.annotation.XmlRootElement; 031import javax.xml.bind.annotation.XmlTransient; 032 033import org.apache.camel.AggregationStrategy; 034import org.apache.camel.Expression; 035import org.apache.camel.ExpressionFactory; 036import org.apache.camel.Predicate; 037import org.apache.camel.builder.AggregationStrategyClause; 038import org.apache.camel.builder.ExpressionClause; 039import org.apache.camel.builder.PredicateClause; 040import org.apache.camel.model.language.ExpressionDefinition; 041import org.apache.camel.processor.aggregate.AggregateController; 042import org.apache.camel.processor.aggregate.OptimisticLockRetryPolicy; 043import org.apache.camel.spi.AggregationRepository; 044import org.apache.camel.spi.AsPredicate; 045import org.apache.camel.spi.Metadata; 046 047/** 048 * Aggregates many messages into a single message 049 */ 050@Metadata(label = "eip,routing") 051@XmlRootElement(name = "aggregate") 052@XmlAccessorType(XmlAccessType.FIELD) 053public class AggregateDefinition extends ProcessorDefinition<AggregateDefinition> implements OutputNode, ExecutorServiceAwareDefinition<AggregateDefinition> { 054 @XmlElement(name = "correlationExpression", required = true) 055 private ExpressionSubElementDefinition correlationExpression; 056 @XmlElement(name = "completionPredicate") 057 @AsPredicate 058 private ExpressionSubElementDefinition completionPredicate; 059 @XmlElement(name = "completionTimeoutExpression") 060 private ExpressionSubElementDefinition completionTimeoutExpression; 061 @XmlElement(name = "completionSizeExpression") 062 private ExpressionSubElementDefinition completionSizeExpression; 063 @XmlElement(name = "optimisticLockRetryPolicy") 064 private OptimisticLockRetryPolicyDefinition optimisticLockRetryPolicyDefinition; 065 @XmlTransient 066 private ExpressionDefinition expression; 067 @XmlTransient 068 private AggregationStrategy aggregationStrategy; 069 @XmlTransient 070 private ExecutorService executorService; 071 @XmlTransient 072 private ScheduledExecutorService timeoutCheckerExecutorService; 073 @XmlTransient 074 private AggregationRepository aggregationRepository; 075 @XmlTransient 076 private OptimisticLockRetryPolicy optimisticLockRetryPolicy; 077 @XmlAttribute 078 private Boolean parallelProcessing; 079 @XmlAttribute 080 private Boolean optimisticLocking; 081 @XmlAttribute 082 private String executorServiceRef; 083 @XmlAttribute 084 private String timeoutCheckerExecutorServiceRef; 085 @XmlAttribute 086 private String aggregationRepositoryRef; 087 @XmlAttribute 088 private String strategyRef; 089 @XmlAttribute 090 private String strategyMethodName; 091 @XmlAttribute 092 private Boolean strategyMethodAllowNull; 093 @XmlAttribute 094 private Integer completionSize; 095 @XmlAttribute 096 private Long completionInterval; 097 @XmlAttribute 098 private Long completionTimeout; 099 @XmlAttribute 100 @Metadata(defaultValue = "1000") 101 private Long completionTimeoutCheckerInterval = 1000L; 102 @XmlAttribute 103 private Boolean completionFromBatchConsumer; 104 @XmlAttribute 105 private Boolean completionOnNewCorrelationGroup; 106 @XmlAttribute 107 private Boolean eagerCheckCompletion; 108 @XmlAttribute 109 private Boolean ignoreInvalidCorrelationKeys; 110 @XmlAttribute 111 private Integer closeCorrelationKeyOnCompletion; 112 @XmlAttribute 113 private Boolean discardOnCompletionTimeout; 114 @XmlAttribute 115 private Boolean discardOnAggregationFailure; 116 @XmlAttribute 117 private Boolean forceCompletionOnStop; 118 @XmlAttribute 119 private Boolean completeAllOnStop; 120 @XmlTransient 121 private AggregateController aggregateController; 122 @XmlAttribute 123 private String aggregateControllerRef; 124 @XmlElementRef 125 private List<ProcessorDefinition<?>> outputs = new ArrayList<>(); 126 127 public AggregateDefinition() { 128 } 129 130 public AggregateDefinition(@AsPredicate Predicate predicate) { 131 this(ExpressionNodeHelper.toExpressionDefinition(predicate)); 132 } 133 134 public AggregateDefinition(Expression expression) { 135 this(ExpressionNodeHelper.toExpressionDefinition(expression)); 136 } 137 138 public AggregateDefinition(ExpressionDefinition correlationExpression) { 139 setExpression(correlationExpression); 140 141 ExpressionSubElementDefinition cor = new ExpressionSubElementDefinition(); 142 cor.setExpressionType(correlationExpression); 143 setCorrelationExpression(cor); 144 } 145 146 public AggregateDefinition(Expression correlationExpression, AggregationStrategy aggregationStrategy) { 147 this(correlationExpression); 148 this.aggregationStrategy = aggregationStrategy; 149 } 150 151 @Override 152 public String toString() { 153 return "Aggregate[" + description() + " -> " + getOutputs() + "]"; 154 } 155 156 protected String description() { 157 return getExpression() != null ? getExpression().getLabel() : ""; 158 } 159 160 @Override 161 public String getShortName() { 162 return "aggregate"; 163 } 164 165 @Override 166 public String getLabel() { 167 return "aggregate[" + description() + "]"; 168 } 169 170 @Override 171 public void configureChild(ProcessorDefinition<?> output) { 172 Expression exp = getExpression(); 173 if (getExpression() != null && getExpression().getExpressionValue() != null) { 174 exp = getExpression().getExpressionValue(); 175 } 176 177 if (exp instanceof ExpressionClause) { 178 ExpressionClause<?> clause = (ExpressionClause<?>)exp; 179 if (clause.getExpressionType() != null) { 180 // if using the Java DSL then the expression may have been set 181 // using the 182 // ExpressionClause which is a fancy builder to define 183 // expressions and predicates 184 // using fluent builders in the DSL. However we need afterwards 185 // a callback to 186 // reset the expression to the expression type the 187 // ExpressionClause did build for us 188 ExpressionFactory model = clause.getExpressionType(); 189 if (model instanceof ExpressionDefinition) { 190 correlationExpression = new ExpressionSubElementDefinition(); 191 correlationExpression.setExpressionType((ExpressionDefinition)model); 192 } 193 } 194 } 195 } 196 197 public AggregationStrategy getAggregationStrategy() { 198 return aggregationStrategy; 199 } 200 201 /** 202 * The AggregationStrategy to use. 203 * <p/> 204 * Configuring an AggregationStrategy is required, and is used to merge the 205 * incoming Exchange with the existing already merged exchanges. At first 206 * call the oldExchange parameter is null. On subsequent invocations the 207 * oldExchange contains the merged exchanges and newExchange is of course 208 * the new incoming Exchange. 209 */ 210 public void setAggregationStrategy(AggregationStrategy aggregationStrategy) { 211 this.aggregationStrategy = aggregationStrategy; 212 } 213 214 public String getAggregationStrategyRef() { 215 return strategyRef; 216 } 217 218 /** 219 * A reference to lookup the AggregationStrategy in the Registry. 220 * <p/> 221 * Configuring an AggregationStrategy is required, and is used to merge the 222 * incoming Exchange with the existing already merged exchanges. At first 223 * call the oldExchange parameter is null. On subsequent invocations the 224 * oldExchange contains the merged exchanges and newExchange is of course 225 * the new incoming Exchange. 226 */ 227 public void setAggregationStrategyRef(String aggregationStrategyRef) { 228 this.strategyRef = aggregationStrategyRef; 229 } 230 231 public String getStrategyRef() { 232 return strategyRef; 233 } 234 235 /** 236 * A reference to lookup the AggregationStrategy in the Registry. 237 * <p/> 238 * Configuring an AggregationStrategy is required, and is used to merge the 239 * incoming Exchange with the existing already merged exchanges. At first 240 * call the oldExchange parameter is null. On subsequent invocations the 241 * oldExchange contains the merged exchanges and newExchange is of course 242 * the new incoming Exchange. 243 */ 244 public void setStrategyRef(String strategyRef) { 245 this.strategyRef = strategyRef; 246 } 247 248 public String getAggregationStrategyMethodName() { 249 return strategyMethodName; 250 } 251 252 /** 253 * This option can be used to explicit declare the method name to use, when 254 * using POJOs as the AggregationStrategy. 255 */ 256 public void setAggregationStrategyMethodName(String strategyMethodName) { 257 this.strategyMethodName = strategyMethodName; 258 } 259 260 public Boolean getStrategyMethodAllowNull() { 261 return strategyMethodAllowNull; 262 } 263 264 public String getStrategyMethodName() { 265 return strategyMethodName; 266 } 267 268 /** 269 * This option can be used to explicit declare the method name to use, when 270 * using POJOs as the AggregationStrategy. 271 */ 272 public void setStrategyMethodName(String strategyMethodName) { 273 this.strategyMethodName = strategyMethodName; 274 } 275 276 /** 277 * If this option is false then the aggregate method is not used for the 278 * very first aggregation. If this option is true then null values is used 279 * as the oldExchange (at the very first aggregation), when using POJOs as 280 * the AggregationStrategy. 281 */ 282 public void setStrategyMethodAllowNull(Boolean strategyMethodAllowNull) { 283 this.strategyMethodAllowNull = strategyMethodAllowNull; 284 } 285 286 /** 287 * The expression used to calculate the correlation key to use for 288 * aggregation. The Exchange which has the same correlation key is 289 * aggregated together. If the correlation key could not be evaluated an 290 * Exception is thrown. You can disable this by using the 291 * ignoreBadCorrelationKeys option. 292 */ 293 public void setCorrelationExpression(ExpressionSubElementDefinition correlationExpression) { 294 this.correlationExpression = correlationExpression; 295 } 296 297 public ExpressionSubElementDefinition getCorrelationExpression() { 298 return correlationExpression; 299 } 300 301 public Integer getCompletionSize() { 302 return completionSize; 303 } 304 305 public void setCompletionSize(Integer completionSize) { 306 this.completionSize = completionSize; 307 } 308 309 public OptimisticLockRetryPolicyDefinition getOptimisticLockRetryPolicyDefinition() { 310 return optimisticLockRetryPolicyDefinition; 311 } 312 313 public void setOptimisticLockRetryPolicyDefinition(OptimisticLockRetryPolicyDefinition optimisticLockRetryPolicyDefinition) { 314 this.optimisticLockRetryPolicyDefinition = optimisticLockRetryPolicyDefinition; 315 } 316 317 public OptimisticLockRetryPolicy getOptimisticLockRetryPolicy() { 318 return optimisticLockRetryPolicy; 319 } 320 321 public void setOptimisticLockRetryPolicy(OptimisticLockRetryPolicy optimisticLockRetryPolicy) { 322 this.optimisticLockRetryPolicy = optimisticLockRetryPolicy; 323 } 324 325 public Long getCompletionInterval() { 326 return completionInterval; 327 } 328 329 public void setCompletionInterval(Long completionInterval) { 330 this.completionInterval = completionInterval; 331 } 332 333 public Long getCompletionTimeout() { 334 return completionTimeout; 335 } 336 337 public void setCompletionTimeout(Long completionTimeout) { 338 this.completionTimeout = completionTimeout; 339 } 340 341 public Long getCompletionTimeoutCheckerInterval() { 342 return completionTimeoutCheckerInterval; 343 } 344 345 public void setCompletionTimeoutCheckerInterval(Long completionTimeoutCheckerInterval) { 346 this.completionTimeoutCheckerInterval = completionTimeoutCheckerInterval; 347 } 348 349 public ExpressionSubElementDefinition getCompletionPredicate() { 350 return completionPredicate; 351 } 352 353 public void setCompletionPredicate(ExpressionSubElementDefinition completionPredicate) { 354 this.completionPredicate = completionPredicate; 355 } 356 357 public ExpressionSubElementDefinition getCompletionTimeoutExpression() { 358 return completionTimeoutExpression; 359 } 360 361 /** 362 * Time in millis that an aggregated exchange should be inactive before its 363 * complete (timeout). This option can be set as either a fixed value or 364 * using an Expression which allows you to evaluate a timeout dynamically - 365 * will use Long as result. If both are set Camel will fallback to use the 366 * fixed value if the Expression result was null or 0. You cannot use this 367 * option together with completionInterval, only one of the two can be used. 368 * <p/> 369 * By default the timeout checker runs every second, you can use the 370 * completionTimeoutCheckerInterval option to configure how frequently to 371 * run the checker. The timeout is an approximation and there is no 372 * guarantee that the a timeout is triggered exactly after the timeout 373 * value. It is not recommended to use very low timeout values or checker 374 * intervals. 375 * 376 * @param completionTimeoutExpression the timeout as an {@link Expression} 377 * which is evaluated as a {@link Long} type 378 */ 379 public void setCompletionTimeoutExpression(ExpressionSubElementDefinition completionTimeoutExpression) { 380 this.completionTimeoutExpression = completionTimeoutExpression; 381 } 382 383 public ExpressionSubElementDefinition getCompletionSizeExpression() { 384 return completionSizeExpression; 385 } 386 387 /** 388 * Number of messages aggregated before the aggregation is complete. This 389 * option can be set as either a fixed value or using an Expression which 390 * allows you to evaluate a size dynamically - will use Integer as result. 391 * If both are set Camel will fallback to use the fixed value if the 392 * Expression result was null or 0. 393 * 394 * @param completionSizeExpression the completion size as an 395 * {@link org.apache.camel.Expression} which is evaluated as a 396 * {@link Integer} type 397 */ 398 public void setCompletionSizeExpression(ExpressionSubElementDefinition completionSizeExpression) { 399 this.completionSizeExpression = completionSizeExpression; 400 } 401 402 public Boolean getCompletionFromBatchConsumer() { 403 return completionFromBatchConsumer; 404 } 405 406 public void setCompletionFromBatchConsumer(Boolean completionFromBatchConsumer) { 407 this.completionFromBatchConsumer = completionFromBatchConsumer; 408 } 409 410 public Boolean getCompletionOnNewCorrelationGroup() { 411 return completionOnNewCorrelationGroup; 412 } 413 414 public void setCompletionOnNewCorrelationGroup(Boolean completionOnNewCorrelationGroup) { 415 this.completionOnNewCorrelationGroup = completionOnNewCorrelationGroup; 416 } 417 418 @Override 419 public ExecutorService getExecutorService() { 420 return executorService; 421 } 422 423 @Override 424 public void setExecutorService(ExecutorService executorService) { 425 this.executorService = executorService; 426 } 427 428 public Boolean getOptimisticLocking() { 429 return optimisticLocking; 430 } 431 432 public void setOptimisticLocking(boolean optimisticLocking) { 433 this.optimisticLocking = optimisticLocking; 434 } 435 436 public Boolean getParallelProcessing() { 437 return parallelProcessing; 438 } 439 440 public void setParallelProcessing(boolean parallelProcessing) { 441 this.parallelProcessing = parallelProcessing; 442 } 443 444 @Override 445 public String getExecutorServiceRef() { 446 return executorServiceRef; 447 } 448 449 @Override 450 public void setExecutorServiceRef(String executorServiceRef) { 451 this.executorServiceRef = executorServiceRef; 452 } 453 454 public Boolean getEagerCheckCompletion() { 455 return eagerCheckCompletion; 456 } 457 458 public void setEagerCheckCompletion(Boolean eagerCheckCompletion) { 459 this.eagerCheckCompletion = eagerCheckCompletion; 460 } 461 462 public Boolean getIgnoreInvalidCorrelationKeys() { 463 return ignoreInvalidCorrelationKeys; 464 } 465 466 public void setIgnoreInvalidCorrelationKeys(Boolean ignoreInvalidCorrelationKeys) { 467 this.ignoreInvalidCorrelationKeys = ignoreInvalidCorrelationKeys; 468 } 469 470 public Integer getCloseCorrelationKeyOnCompletion() { 471 return closeCorrelationKeyOnCompletion; 472 } 473 474 public void setCloseCorrelationKeyOnCompletion(Integer closeCorrelationKeyOnCompletion) { 475 this.closeCorrelationKeyOnCompletion = closeCorrelationKeyOnCompletion; 476 } 477 478 public AggregationRepository getAggregationRepository() { 479 return aggregationRepository; 480 } 481 482 public void setAggregationRepository(AggregationRepository aggregationRepository) { 483 this.aggregationRepository = aggregationRepository; 484 } 485 486 public String getAggregationRepositoryRef() { 487 return aggregationRepositoryRef; 488 } 489 490 public void setAggregationRepositoryRef(String aggregationRepositoryRef) { 491 this.aggregationRepositoryRef = aggregationRepositoryRef; 492 } 493 494 public Boolean getDiscardOnCompletionTimeout() { 495 return discardOnCompletionTimeout; 496 } 497 498 public void setDiscardOnCompletionTimeout(Boolean discardOnCompletionTimeout) { 499 this.discardOnCompletionTimeout = discardOnCompletionTimeout; 500 } 501 502 public Boolean getDiscardOnAggregationFailure() { 503 return discardOnAggregationFailure; 504 } 505 506 public void setDiscardOnAggregationFailure(Boolean discardOnAggregationFailure) { 507 this.discardOnAggregationFailure = discardOnAggregationFailure; 508 } 509 510 public void setTimeoutCheckerExecutorService(ScheduledExecutorService timeoutCheckerExecutorService) { 511 this.timeoutCheckerExecutorService = timeoutCheckerExecutorService; 512 } 513 514 public ScheduledExecutorService getTimeoutCheckerExecutorService() { 515 return timeoutCheckerExecutorService; 516 } 517 518 public void setTimeoutCheckerExecutorServiceRef(String timeoutCheckerExecutorServiceRef) { 519 this.timeoutCheckerExecutorServiceRef = timeoutCheckerExecutorServiceRef; 520 } 521 522 public String getTimeoutCheckerExecutorServiceRef() { 523 return timeoutCheckerExecutorServiceRef; 524 } 525 526 public Boolean getForceCompletionOnStop() { 527 return forceCompletionOnStop; 528 } 529 530 public void setForceCompletionOnStop(Boolean forceCompletionOnStop) { 531 this.forceCompletionOnStop = forceCompletionOnStop; 532 } 533 534 public Boolean getCompleteAllOnStop() { 535 return completeAllOnStop; 536 } 537 538 public void setCompleteAllOnStop(Boolean completeAllOnStop) { 539 this.completeAllOnStop = completeAllOnStop; 540 } 541 542 public AggregateController getAggregateController() { 543 return aggregateController; 544 } 545 546 public void setAggregateController(AggregateController aggregateController) { 547 this.aggregateController = aggregateController; 548 } 549 550 public String getAggregateControllerRef() { 551 return aggregateControllerRef; 552 } 553 554 /** 555 * To use a {@link org.apache.camel.processor.aggregate.AggregateController} 556 * to allow external sources to control this aggregator. 557 */ 558 public void setAggregateControllerRef(String aggregateControllerRef) { 559 this.aggregateControllerRef = aggregateControllerRef; 560 } 561 562 // Fluent API 563 // ------------------------------------------------------------------------- 564 565 /** 566 * Use eager completion checking which means that the completionPredicate 567 * will use the incoming Exchange. As opposed to without eager completion 568 * checking the completionPredicate will use the aggregated Exchange. 569 * 570 * @return builder 571 */ 572 public AggregateDefinition eagerCheckCompletion() { 573 setEagerCheckCompletion(true); 574 return this; 575 } 576 577 /** 578 * If a correlation key cannot be successfully evaluated it will be ignored 579 * by logging a DEBUG and then just ignore the incoming Exchange. 580 * 581 * @return builder 582 */ 583 public AggregateDefinition ignoreInvalidCorrelationKeys() { 584 setIgnoreInvalidCorrelationKeys(true); 585 return this; 586 } 587 588 /** 589 * Closes a correlation key when its complete. Any <i>late</i> received 590 * exchanges which has a correlation key that has been closed, it will be 591 * defined and a ClosedCorrelationKeyException is thrown. 592 * 593 * @param capacity the maximum capacity of the closed correlation key cache. 594 * Use <tt>0</tt> or negative value for unbounded capacity. 595 * @return builder 596 */ 597 public AggregateDefinition closeCorrelationKeyOnCompletion(int capacity) { 598 setCloseCorrelationKeyOnCompletion(capacity); 599 return this; 600 } 601 602 /** 603 * Discards the aggregated message on completion timeout. 604 * <p/> 605 * This means on timeout the aggregated message is dropped and not sent out 606 * of the aggregator. 607 * 608 * @return builder 609 */ 610 public AggregateDefinition discardOnCompletionTimeout() { 611 setDiscardOnCompletionTimeout(true); 612 return this; 613 } 614 615 /** 616 * Discards the aggregated message when aggregation failed (an exception was 617 * thrown from {@link AggregationStrategy}. This means the partly aggregated 618 * message is dropped and not sent out of the aggregator. 619 * <p/> 620 * This option cannot be used together with completionFromBatchConsumer. 621 * 622 * @return builder 623 */ 624 public AggregateDefinition discardOnAggregationFailure() { 625 setDiscardOnAggregationFailure(true); 626 return this; 627 } 628 629 /** 630 * Enables the batch completion mode where we aggregate from a 631 * {@link org.apache.camel.BatchConsumer} and aggregate the total number of 632 * exchanges the {@link org.apache.camel.BatchConsumer} has reported as 633 * total by checking the exchange property 634 * {@link org.apache.camel.Exchange#BATCH_COMPLETE} when its complete. 635 * <p/> 636 * This option cannot be used together with discardOnAggregationFailure. 637 * 638 * @return builder 639 */ 640 public AggregateDefinition completionFromBatchConsumer() { 641 setCompletionFromBatchConsumer(true); 642 return this; 643 } 644 645 /** 646 * Enables completion on all previous groups when a new incoming correlation 647 * group. This can for example be used to complete groups with same 648 * correlation keys when they are in consecutive order. Notice when this is 649 * enabled then only 1 correlation group can be in progress as when a new 650 * correlation group starts, then the previous groups is forced completed. 651 * 652 * @return builder 653 */ 654 public AggregateDefinition completionOnNewCorrelationGroup() { 655 setCompletionOnNewCorrelationGroup(true); 656 return this; 657 } 658 659 /** 660 * Number of messages aggregated before the aggregation is complete. This 661 * option can be set as either a fixed value or using an Expression which 662 * allows you to evaluate a size dynamically - will use Integer as result. 663 * If both are set Camel will fallback to use the fixed value if the 664 * Expression result was null or 0. 665 * 666 * @param completionSize the completion size, must be a positive number 667 * @return builder 668 */ 669 public AggregateDefinition completionSize(int completionSize) { 670 setCompletionSize(completionSize); 671 return this; 672 } 673 674 /** 675 * Number of messages aggregated before the aggregation is complete. This 676 * option can be set as either a fixed value or using an Expression which 677 * allows you to evaluate a size dynamically - will use Integer as result. 678 * If both are set Camel will fallback to use the fixed value if the 679 * Expression result was null or 0. 680 * 681 * @param completionSize the completion size as an 682 * {@link org.apache.camel.Expression} which is evaluated as a 683 * {@link Integer} type 684 * @return builder 685 */ 686 public AggregateDefinition completionSize(Expression completionSize) { 687 setCompletionSizeExpression(new ExpressionSubElementDefinition(completionSize)); 688 return this; 689 } 690 691 /** 692 * A repeating period in millis by which the aggregator will complete all 693 * current aggregated exchanges. Camel has a background task which is 694 * triggered every period. You cannot use this option together with 695 * completionTimeout, only one of them can be used. 696 * 697 * @param completionInterval the interval in millis, must be a positive 698 * value 699 * @return the builder 700 */ 701 public AggregateDefinition completionInterval(long completionInterval) { 702 setCompletionInterval(completionInterval); 703 return this; 704 } 705 706 /** 707 * Time in millis that an aggregated exchange should be inactive before its 708 * complete (timeout). This option can be set as either a fixed value or 709 * using an Expression which allows you to evaluate a timeout dynamically - 710 * will use Long as result. If both are set Camel will fallback to use the 711 * fixed value if the Expression result was null or 0. You cannot use this 712 * option together with completionInterval, only one of the two can be used. 713 * <p/> 714 * By default the timeout checker runs every second, you can use the 715 * completionTimeoutCheckerInterval option to configure how frequently to 716 * run the checker. The timeout is an approximation and there is no 717 * guarantee that the a timeout is triggered exactly after the timeout 718 * value. It is not recommended to use very low timeout values or checker 719 * intervals. 720 * 721 * @param completionTimeout the timeout in millis, must be a positive value 722 * @return the builder 723 */ 724 public AggregateDefinition completionTimeout(long completionTimeout) { 725 setCompletionTimeout(completionTimeout); 726 return this; 727 } 728 729 /** 730 * Time in millis that an aggregated exchange should be inactive before its 731 * complete (timeout). This option can be set as either a fixed value or 732 * using an Expression which allows you to evaluate a timeout dynamically - 733 * will use Long as result. If both are set Camel will fallback to use the 734 * fixed value if the Expression result was null or 0. You cannot use this 735 * option together with completionInterval, only one of the two can be used. 736 * <p/> 737 * By default the timeout checker runs every second, you can use the 738 * completionTimeoutCheckerInterval option to configure how frequently to 739 * run the checker. The timeout is an approximation and there is no 740 * guarantee that the a timeout is triggered exactly after the timeout 741 * value. It is not recommended to use very low timeout values or checker 742 * intervals. 743 * 744 * @param completionTimeout the timeout as an {@link Expression} which is 745 * evaluated as a {@link Long} type 746 * @return the builder 747 */ 748 public AggregateDefinition completionTimeout(Expression completionTimeout) { 749 setCompletionTimeoutExpression(new ExpressionSubElementDefinition(completionTimeout)); 750 return this; 751 } 752 753 /** 754 * Interval in millis that is used by the background task that checks for 755 * timeouts ({@link org.apache.camel.TimeoutMap}). 756 * <p/> 757 * By default the timeout checker runs every second. The timeout is an 758 * approximation and there is no guarantee that the a timeout is triggered 759 * exactly after the timeout value. It is not recommended to use very low 760 * timeout values or checker intervals. 761 * 762 * @param completionTimeoutCheckerInterval the interval in millis, must be a 763 * positive value 764 * @return the builder 765 */ 766 public AggregateDefinition completionTimeoutCheckerInterval(long completionTimeoutCheckerInterval) { 767 setCompletionTimeoutCheckerInterval(completionTimeoutCheckerInterval); 768 return this; 769 } 770 771 /** 772 * Sets the AggregationStrategy to use with a fluent builder. 773 */ 774 public AggregationStrategyClause<AggregateDefinition> aggregationStrategy() { 775 AggregationStrategyClause<AggregateDefinition> clause = new AggregationStrategyClause<>(this); 776 setAggregationStrategy(clause); 777 return clause; 778 } 779 780 /** 781 * Sets the AggregationStrategy to use with a fluent builder. 782 * 783 * @deprecated use {@link #aggregationStrategy()} 784 */ 785 @Deprecated 786 public AggregationStrategyClause<AggregateDefinition> strategy() { 787 return aggregationStrategy(); 788 } 789 790 /** 791 * Sets the aggregate strategy to use 792 * 793 * @param aggregationStrategy the aggregate strategy to use 794 * @return the builder 795 * @deprecated use {@link #aggregationStrategy(AggregationStrategy)} 796 */ 797 @Deprecated 798 public AggregateDefinition strategy(AggregationStrategy aggregationStrategy) { 799 return aggregationStrategy(aggregationStrategy); 800 } 801 802 /** 803 * Sets the aggregate strategy to use 804 * 805 * @param aggregationStrategy the aggregate strategy to use 806 * @return the builder 807 */ 808 public AggregateDefinition aggregationStrategy(AggregationStrategy aggregationStrategy) { 809 setAggregationStrategy(aggregationStrategy); 810 return this; 811 } 812 813 /** 814 * Sets the aggregate strategy to use 815 * 816 * @param aggregationStrategy the aggregate strategy to use 817 * @return the builder 818 */ 819 public AggregateDefinition aggregationStrategy(Supplier<AggregationStrategy> aggregationStrategy) { 820 setAggregationStrategy(aggregationStrategy.get()); 821 return this; 822 } 823 824 /** 825 * Sets the aggregate strategy to use 826 * 827 * @param aggregationStrategyRef reference to the strategy to lookup in the 828 * registry 829 * @return the builder 830 */ 831 public AggregateDefinition aggregationStrategyRef(String aggregationStrategyRef) { 832 setAggregationStrategyRef(aggregationStrategyRef); 833 return this; 834 } 835 836 /** 837 * Sets the method name to use when using a POJO as 838 * {@link AggregationStrategy}. 839 * 840 * @param methodName the method name to call 841 * @return the builder 842 */ 843 public AggregateDefinition aggregationStrategyMethodName(String methodName) { 844 setAggregationStrategyMethodName(methodName); 845 return this; 846 } 847 848 /** 849 * Sets allowing null when using a POJO as {@link AggregationStrategy}. 850 * 851 * @return the builder 852 */ 853 public AggregateDefinition aggregationStrategyMethodAllowNull() { 854 setStrategyMethodAllowNull(true); 855 return this; 856 } 857 858 /** 859 * Sets the custom aggregate repository to use. 860 * <p/> 861 * Will by default use 862 * {@link org.apache.camel.processor.aggregate.MemoryAggregationRepository} 863 * 864 * @param aggregationRepository the aggregate repository to use 865 * @return the builder 866 */ 867 public AggregateDefinition aggregationRepository(AggregationRepository aggregationRepository) { 868 setAggregationRepository(aggregationRepository); 869 return this; 870 } 871 872 /** 873 * Sets the custom aggregate repository to use. 874 * <p/> 875 * Will by default use 876 * {@link org.apache.camel.processor.aggregate.MemoryAggregationRepository} 877 * 878 * @param aggregationRepository the aggregate repository to use 879 * @return the builder 880 */ 881 public AggregateDefinition aggregationRepository(Supplier<AggregationRepository> aggregationRepository) { 882 setAggregationRepository(aggregationRepository.get()); 883 return this; 884 } 885 886 /** 887 * Sets the custom aggregate repository to use 888 * <p/> 889 * Will by default use 890 * {@link org.apache.camel.processor.aggregate.MemoryAggregationRepository} 891 * 892 * @param aggregationRepositoryRef reference to the repository to lookup in 893 * the registry 894 * @return the builder 895 */ 896 public AggregateDefinition aggregationRepositoryRef(String aggregationRepositoryRef) { 897 setAggregationRepositoryRef(aggregationRepositoryRef); 898 return this; 899 } 900 901 /** 902 * A Predicate to indicate when an aggregated exchange is complete. If this 903 * is not specified and the AggregationStrategy object implements Predicate, 904 * the aggregationStrategy object will be used as the completionPredicate. 905 */ 906 public AggregateDefinition completionPredicate(@AsPredicate Predicate predicate) { 907 checkNoCompletedPredicate(); 908 setCompletionPredicate(new ExpressionSubElementDefinition(predicate)); 909 return this; 910 } 911 912 /** 913 * A Predicate to indicate when an aggregated exchange is complete. If this 914 * is not specified and the AggregationStrategy object implements Predicate, 915 * the aggregationStrategy object will be used as the completionPredicate. 916 */ 917 @AsPredicate 918 public PredicateClause<AggregateDefinition> completionPredicate() { 919 PredicateClause<AggregateDefinition> clause = new PredicateClause<>(this); 920 completionPredicate(clause); 921 return clause; 922 } 923 924 /** 925 * A Predicate to indicate when an aggregated exchange is complete. If this 926 * is not specified and the AggregationStrategy object implements Predicate, 927 * the aggregationStrategy object will be used as the completionPredicate. 928 */ 929 @AsPredicate 930 public PredicateClause<AggregateDefinition> completion() { 931 return completionPredicate(); 932 } 933 934 /** 935 * A Predicate to indicate when an aggregated exchange is complete. If this 936 * is not specified and the AggregationStrategy object implements Predicate, 937 * the aggregationStrategy object will be used as the completionPredicate. 938 */ 939 public AggregateDefinition completion(@AsPredicate Predicate predicate) { 940 return completionPredicate(predicate); 941 } 942 943 /** 944 * Indicates to complete all current aggregated exchanges when the context 945 * is stopped 946 */ 947 public AggregateDefinition forceCompletionOnStop() { 948 setForceCompletionOnStop(true); 949 return this; 950 } 951 952 /** 953 * Indicates to wait to complete all current and partial (pending) 954 * aggregated exchanges when the context is stopped. 955 * <p/> 956 * This also means that we will wait for all pending exchanges which are 957 * stored in the aggregation repository to complete so the repository is 958 * empty before we can stop. 959 * <p/> 960 * You may want to enable this when using the memory based aggregation 961 * repository that is memory based only, and do not store data on disk. When 962 * this option is enabled, then the aggregator is waiting to complete all 963 * those exchanges before its stopped, when stopping CamelContext or the 964 * route using it. 965 */ 966 public AggregateDefinition completeAllOnStop() { 967 setCompleteAllOnStop(true); 968 return this; 969 } 970 971 /** 972 * When aggregated are completed they are being send out of the aggregator. 973 * This option indicates whether or not Camel should use a thread pool with 974 * multiple threads for concurrency. If no custom thread pool has been 975 * specified then Camel creates a default pool with 10 concurrent threads. 976 */ 977 public AggregateDefinition parallelProcessing() { 978 setParallelProcessing(true); 979 return this; 980 } 981 982 /** 983 * When aggregated are completed they are being send out of the aggregator. 984 * This option indicates whether or not Camel should use a thread pool with 985 * multiple threads for concurrency. If no custom thread pool has been 986 * specified then Camel creates a default pool with 10 concurrent threads. 987 */ 988 public AggregateDefinition parallelProcessing(boolean parallelProcessing) { 989 setParallelProcessing(parallelProcessing); 990 return this; 991 } 992 993 /** 994 * Turns on using optimistic locking, which requires the 995 * aggregationRepository being used, is supporting this by implementing 996 * {@link org.apache.camel.spi.OptimisticLockingAggregationRepository}. 997 */ 998 public AggregateDefinition optimisticLocking() { 999 setOptimisticLocking(true); 1000 return this; 1001 } 1002 1003 /** 1004 * Allows to configure retry settings when using optimistic locking. 1005 */ 1006 public AggregateDefinition optimisticLockRetryPolicy(OptimisticLockRetryPolicy policy) { 1007 setOptimisticLockRetryPolicy(policy); 1008 return this; 1009 } 1010 1011 /** 1012 * If using parallelProcessing you can specify a custom thread pool to be 1013 * used. In fact also if you are not using parallelProcessing this custom 1014 * thread pool is used to send out aggregated exchanges as well. 1015 */ 1016 @Override 1017 public AggregateDefinition executorService(ExecutorService executorService) { 1018 setExecutorService(executorService); 1019 return this; 1020 } 1021 1022 /** 1023 * If using parallelProcessing you can specify a custom thread pool to be 1024 * used. In fact also if you are not using parallelProcessing this custom 1025 * thread pool is used to send out aggregated exchanges as well. 1026 */ 1027 @Override 1028 public AggregateDefinition executorServiceRef(String executorServiceRef) { 1029 setExecutorServiceRef(executorServiceRef); 1030 return this; 1031 } 1032 1033 /** 1034 * If using either of the completionTimeout, completionTimeoutExpression, or 1035 * completionInterval options a background thread is created to check for 1036 * the completion for every aggregator. Set this option to provide a custom 1037 * thread pool to be used rather than creating a new thread for every 1038 * aggregator. 1039 */ 1040 public AggregateDefinition timeoutCheckerExecutorService(ScheduledExecutorService executorService) { 1041 setTimeoutCheckerExecutorService(executorService); 1042 return this; 1043 } 1044 1045 /** 1046 * If using either of the completionTimeout, completionTimeoutExpression, or 1047 * completionInterval options a background thread is created to check for 1048 * the completion for every aggregator. Set this option to provide a custom 1049 * thread pool to be used rather than creating a new thread for every 1050 * aggregator. 1051 */ 1052 public AggregateDefinition timeoutCheckerExecutorService(Supplier<ScheduledExecutorService> executorService) { 1053 setTimeoutCheckerExecutorService(executorService.get()); 1054 return this; 1055 } 1056 1057 /** 1058 * If using either of the completionTimeout, completionTimeoutExpression, or 1059 * completionInterval options a background thread is created to check for 1060 * the completion for every aggregator. Set this option to provide a custom 1061 * thread pool to be used rather than creating a new thread for every 1062 * aggregator. 1063 */ 1064 public AggregateDefinition timeoutCheckerExecutorServiceRef(String executorServiceRef) { 1065 setTimeoutCheckerExecutorServiceRef(executorServiceRef); 1066 return this; 1067 } 1068 1069 /** 1070 * To use a {@link org.apache.camel.processor.aggregate.AggregateController} 1071 * to allow external sources to control this aggregator. 1072 */ 1073 public AggregateDefinition aggregateController(AggregateController aggregateController) { 1074 setAggregateController(aggregateController); 1075 return this; 1076 } 1077 1078 /** 1079 * To use a {@link org.apache.camel.processor.aggregate.AggregateController} 1080 * to allow external sources to control this aggregator. 1081 */ 1082 public AggregateDefinition aggregateController(Supplier<AggregateController> aggregateController) { 1083 setAggregateController(aggregateController.get()); 1084 return this; 1085 } 1086 1087 // Section - Methods from ExpressionNode 1088 // Needed to copy methods from ExpressionNode here so that I could specify 1089 // the 1090 // correlation expression as optional in JAXB 1091 1092 public ExpressionDefinition getExpression() { 1093 if (expression == null && correlationExpression != null) { 1094 expression = correlationExpression.getExpressionType(); 1095 } 1096 return expression; 1097 } 1098 1099 public void setExpression(ExpressionDefinition expression) { 1100 this.expression = expression; 1101 } 1102 1103 public void setExpression(Expression expression) { 1104 setExpression(new ExpressionDefinition(expression)); 1105 } 1106 1107 protected void checkNoCompletedPredicate() { 1108 if (getCompletionPredicate() != null) { 1109 throw new IllegalArgumentException("There is already a completionPredicate defined for this aggregator: " + this); 1110 } 1111 } 1112 1113 @Override 1114 public List<ProcessorDefinition<?>> getOutputs() { 1115 return outputs; 1116 } 1117 1118 public void setOutputs(List<ProcessorDefinition<?>> outputs) { 1119 this.outputs = outputs; 1120 } 1121 1122}