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