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