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.function.Supplier; 022 023import javax.xml.bind.annotation.XmlAccessType; 024import javax.xml.bind.annotation.XmlAccessorType; 025import javax.xml.bind.annotation.XmlAttribute; 026import javax.xml.bind.annotation.XmlElementRef; 027import javax.xml.bind.annotation.XmlRootElement; 028import javax.xml.bind.annotation.XmlTransient; 029 030import org.apache.camel.AggregationStrategy; 031import org.apache.camel.Processor; 032import org.apache.camel.builder.AggregationStrategyClause; 033import org.apache.camel.builder.ProcessClause; 034import org.apache.camel.spi.Metadata; 035 036/** 037 * Routes the same message to multiple paths either sequentially or in parallel. 038 */ 039@Metadata(label = "eip,routing") 040@XmlRootElement(name = "multicast") 041@XmlAccessorType(XmlAccessType.FIELD) 042public class MulticastDefinition extends OutputDefinition<MulticastDefinition> implements ExecutorServiceAwareDefinition<MulticastDefinition> { 043 @XmlAttribute 044 @Metadata(javaType = "java.lang.Boolean") 045 private String parallelProcessing; 046 @XmlAttribute 047 private String strategyRef; 048 @XmlAttribute 049 private String strategyMethodName; 050 @XmlAttribute 051 @Metadata(javaType = "java.lang.Boolean") 052 private String strategyMethodAllowNull; 053 @XmlTransient 054 private ExecutorService executorService; 055 @XmlAttribute 056 private String executorServiceRef; 057 @XmlAttribute 058 @Metadata(javaType = "java.lang.Boolean") 059 private String streaming; 060 @XmlAttribute 061 @Metadata(javaType = "java.lang.Boolean") 062 private String stopOnException; 063 @XmlAttribute 064 @Metadata(javaType = "java.time.Duration", defaultValue = "0") 065 private String timeout; 066 @XmlTransient 067 private AggregationStrategy aggregationStrategy; 068 @XmlAttribute 069 private String onPrepareRef; 070 @XmlTransient 071 private Processor onPrepare; 072 @XmlAttribute 073 @Metadata(javaType = "java.lang.Boolean") 074 private String shareUnitOfWork; 075 @XmlAttribute 076 @Metadata(javaType = "java.lang.Boolean") 077 private String parallelAggregate; 078 @XmlAttribute 079 @Metadata(javaType = "java.lang.Boolean") 080 private String stopOnAggregateException; 081 082 public MulticastDefinition() { 083 } 084 085 @Override 086 public List<ProcessorDefinition<?>> getOutputs() { 087 return outputs; 088 } 089 090 @XmlElementRef 091 @Override 092 public void setOutputs(List<ProcessorDefinition<?>> outputs) { 093 super.setOutputs(outputs); 094 } 095 096 @Override 097 public String toString() { 098 return "Multicast[" + getOutputs() + "]"; 099 } 100 101 @Override 102 public String getShortName() { 103 return "multicast"; 104 } 105 106 @Override 107 public String getLabel() { 108 return "multicast"; 109 } 110 111 // Fluent API 112 // ------------------------------------------------------------------------- 113 114 /** 115 * Sets the AggregationStrategy to be used to assemble the replies from the 116 * multicasts, into a single outgoing message from the Multicast using a 117 * fluent builder. 118 */ 119 public AggregationStrategyClause<MulticastDefinition> aggregationStrategy() { 120 AggregationStrategyClause<MulticastDefinition> clause = new AggregationStrategyClause<>(this); 121 setAggregationStrategy(clause); 122 return clause; 123 } 124 125 /** 126 * Sets the AggregationStrategy to be used to assemble the replies from the 127 * multicasts, into a single outgoing message from the Multicast. By default 128 * Camel will use the last reply as the outgoing message. You can also use a 129 * POJO as the AggregationStrategy. If an exception is thrown from the 130 * aggregate method in the AggregationStrategy, then by default, that 131 * exception is not handled by the error handler. The error handler can be 132 * enabled to react if enabling the shareUnitOfWork option. 133 */ 134 public MulticastDefinition aggregationStrategy(AggregationStrategy aggregationStrategy) { 135 setAggregationStrategy(aggregationStrategy); 136 return this; 137 } 138 139 /** 140 * Sets the AggregationStrategy to be used to assemble the replies from the 141 * multicasts, into a single outgoing message from the Multicast. By default 142 * Camel will use the last reply as the outgoing message. You can also use a 143 * POJO as the AggregationStrategy. If an exception is thrown from the 144 * aggregate method in the AggregationStrategy, then by default, that 145 * exception is not handled by the error handler. The error handler can be 146 * enabled to react if enabling the shareUnitOfWork option. 147 */ 148 public MulticastDefinition aggregationStrategy(Supplier<AggregationStrategy> aggregationStrategy) { 149 setAggregationStrategy(aggregationStrategy.get()); 150 return this; 151 } 152 153 /** 154 * Sets a reference to the AggregationStrategy to be used to assemble the 155 * replies from the multicasts, into a single outgoing message from the 156 * Multicast. By default Camel will use the last reply as the outgoing 157 * message. You can also use a POJO as the AggregationStrategy If an 158 * exception is thrown from the aggregate method in the AggregationStrategy, 159 * then by default, that exception is not handled by the error handler. The 160 * error handler can be enabled to react if enabling the shareUnitOfWork 161 * option. 162 */ 163 public MulticastDefinition aggregationStrategyRef(String aggregationStrategyRef) { 164 setStrategyRef(aggregationStrategyRef); 165 return this; 166 } 167 168 /** 169 * This option can be used to explicit declare the method name to use, when 170 * using POJOs as the AggregationStrategy. 171 * 172 * @param methodName the method name to call 173 * @return the builder 174 */ 175 public MulticastDefinition aggregationStrategyMethodName(String methodName) { 176 setStrategyMethodName(methodName); 177 return this; 178 } 179 180 /** 181 * If this option is false then the aggregate method is not used if there 182 * was no data to enrich. If this option is true then null values is used as 183 * the oldExchange (when no data to enrich), when using POJOs as the 184 * AggregationStrategy 185 * 186 * @return the builder 187 */ 188 public MulticastDefinition aggregationStrategyMethodAllowNull() { 189 setStrategyMethodAllowNull(Boolean.toString(true)); 190 return this; 191 } 192 193 /** 194 * If enabled then sending messages to the multicasts occurs concurrently. 195 * Note the caller thread will still wait until all messages has been fully 196 * processed, before it continues. Its only the sending and processing the 197 * replies from the multicasts which happens concurrently. 198 * 199 * @return the builder 200 */ 201 public MulticastDefinition parallelProcessing() { 202 setParallelProcessing(Boolean.toString(true)); 203 return this; 204 } 205 206 /** 207 * If enabled then sending messages to the multicasts occurs concurrently. 208 * Note the caller thread will still wait until all messages has been fully 209 * processed, before it continues. Its only the sending and processing the 210 * replies from the multicasts which happens concurrently. 211 * 212 * @return the builder 213 */ 214 public MulticastDefinition parallelProcessing(boolean parallelProcessing) { 215 setParallelProcessing(Boolean.toString(parallelProcessing)); 216 return this; 217 } 218 219 /** 220 * If enabled then the aggregate method on AggregationStrategy can be called 221 * concurrently. Notice that this would require the implementation of 222 * AggregationStrategy to be implemented as thread-safe. By default this is 223 * false meaning that Camel synchronizes the call to the aggregate method. 224 * Though in some use-cases this can be used to archive higher performance 225 * when the AggregationStrategy is implemented as thread-safe. 226 * 227 * @return the builder 228 */ 229 public MulticastDefinition parallelAggregate() { 230 setParallelAggregate(Boolean.toString(true)); 231 return this; 232 } 233 234 /** 235 * If enabled, unwind exceptions occurring at aggregation time to the error 236 * handler when parallelProcessing is used. Currently, aggregation time 237 * exceptions do not stop the route processing when parallelProcessing is 238 * used. Enabling this option allows to work around this behavior. The 239 * default value is <code>false</code> for the sake of backward 240 * compatibility. 241 * 242 * @return the builder 243 */ 244 public MulticastDefinition stopOnAggregateException() { 245 setStopOnAggregateException(Boolean.toString(true)); 246 return this; 247 } 248 249 /** 250 * If enabled then Camel will process replies out-of-order, eg in the order 251 * they come back. If disabled, Camel will process replies in the same order 252 * as defined by the multicast. 253 * 254 * @return the builder 255 */ 256 public MulticastDefinition streaming() { 257 setStreaming(Boolean.toString(true)); 258 return this; 259 } 260 261 /** 262 * Will now stop further processing if an exception or failure occurred 263 * during processing of an {@link org.apache.camel.Exchange} and the caused 264 * exception will be thrown. 265 * <p/> 266 * Will also stop if processing the exchange failed (has a fault message) or 267 * an exception was thrown and handled by the error handler (such as using 268 * onException). In all situations the multicast will stop further 269 * processing. This is the same behavior as in pipeline, which is used by 270 * the routing engine. 271 * <p/> 272 * The default behavior is to <b>not</b> stop but continue processing till 273 * the end 274 * 275 * @return the builder 276 */ 277 public MulticastDefinition stopOnException() { 278 return stopOnException(Boolean.toString(true)); 279 } 280 281 /** 282 * Will now stop further processing if an exception or failure occurred 283 * during processing of an {@link org.apache.camel.Exchange} and the caused 284 * exception will be thrown. 285 * <p/> 286 * Will also stop if processing the exchange failed (has a fault message) or 287 * an exception was thrown and handled by the error handler (such as using 288 * onException). In all situations the multicast will stop further 289 * processing. This is the same behavior as in pipeline, which is used by 290 * the routing engine. 291 * <p/> 292 * The default behavior is to <b>not</b> stop but continue processing till 293 * the end 294 * 295 * @return the builder 296 */ 297 public MulticastDefinition stopOnException(String stopOnException) { 298 setStopOnException(stopOnException); 299 return this; 300 } 301 302 /** 303 * To use a custom Thread Pool to be used for parallel processing. Notice if 304 * you set this option, then parallel processing is automatic implied, and 305 * you do not have to enable that option as well. 306 */ 307 @Override 308 public MulticastDefinition executorService(ExecutorService executorService) { 309 setExecutorService(executorService); 310 return this; 311 } 312 313 /** 314 * Refers to a custom Thread Pool to be used for parallel processing. Notice 315 * if you set this option, then parallel processing is automatic implied, 316 * and you do not have to enable that option as well. 317 */ 318 @Override 319 public MulticastDefinition executorServiceRef(String executorServiceRef) { 320 setExecutorServiceRef(executorServiceRef); 321 return this; 322 } 323 324 /** 325 * Set the {@link Processor} to use when preparing the 326 * {@link org.apache.camel.Exchange} to be send using a fluent builder. 327 */ 328 public ProcessClause<MulticastDefinition> onPrepare() { 329 ProcessClause<MulticastDefinition> clause = new ProcessClause<>(this); 330 setOnPrepare(clause); 331 return clause; 332 } 333 334 /** 335 * Uses the {@link Processor} when preparing the 336 * {@link org.apache.camel.Exchange} to be send. This can be used to 337 * deep-clone messages that should be send, or any custom logic needed 338 * before the exchange is send. 339 * 340 * @param onPrepare the processor 341 * @return the builder 342 */ 343 public MulticastDefinition onPrepare(Processor onPrepare) { 344 setOnPrepare(onPrepare); 345 return this; 346 } 347 348 /** 349 * Uses the {@link Processor} when preparing the 350 * {@link org.apache.camel.Exchange} to be send. This can be used to 351 * deep-clone messages that should be send, or any custom logic needed 352 * before the exchange is send. 353 * 354 * @param onPrepareRef reference to the processor to lookup in the 355 * {@link org.apache.camel.spi.Registry} 356 * @return the builder 357 */ 358 public MulticastDefinition onPrepareRef(String onPrepareRef) { 359 setOnPrepareRef(onPrepareRef); 360 return this; 361 } 362 363 /** 364 * Sets a total timeout specified in millis, when using parallel processing. 365 * If the Multicast hasn't been able to send and process all replies within 366 * the given timeframe, then the timeout triggers and the Multicast breaks 367 * out and continues. Notice if you provide a 368 * TimeoutAwareAggregationStrategy then the timeout method is invoked before 369 * breaking out. If the timeout is reached with running tasks still 370 * remaining, certain tasks for which it is difficult for Camel to shut down 371 * in a graceful manner may continue to run. So use this option with a bit 372 * of care. 373 * 374 * @param timeout timeout in millis 375 * @return the builder 376 */ 377 public MulticastDefinition timeout(long timeout) { 378 return timeout(Long.toString(timeout)); 379 } 380 381 /** 382 * Sets a total timeout specified in millis, when using parallel processing. 383 * If the Multicast hasn't been able to send and process all replies within 384 * the given timeframe, then the timeout triggers and the Multicast breaks 385 * out and continues. Notice if you provide a 386 * TimeoutAwareAggregationStrategy then the timeout method is invoked before 387 * breaking out. If the timeout is reached with running tasks still 388 * remaining, certain tasks for which it is difficult for Camel to shut down 389 * in a graceful manner may continue to run. So use this option with a bit 390 * of care. 391 * 392 * @param timeout timeout in millis 393 * @return the builder 394 */ 395 public MulticastDefinition timeout(String timeout) { 396 setTimeout(timeout); 397 return this; 398 } 399 400 /** 401 * Shares the {@link org.apache.camel.spi.UnitOfWork} with the parent and 402 * each of the sub messages. Multicast will by default not share unit of 403 * work between the parent exchange and each multicasted exchange. This 404 * means each sub exchange has its own individual unit of work. 405 * 406 * @return the builder. 407 */ 408 public MulticastDefinition shareUnitOfWork() { 409 setShareUnitOfWork(Boolean.toString(true)); 410 return this; 411 } 412 413 public AggregationStrategy getAggregationStrategy() { 414 return aggregationStrategy; 415 } 416 417 public MulticastDefinition setAggregationStrategy(AggregationStrategy aggregationStrategy) { 418 this.aggregationStrategy = aggregationStrategy; 419 return this; 420 } 421 422 public String getParallelProcessing() { 423 return parallelProcessing; 424 } 425 426 public void setParallelProcessing(String parallelProcessing) { 427 this.parallelProcessing = parallelProcessing; 428 } 429 430 public String getStreaming() { 431 return streaming; 432 } 433 434 public void setStreaming(String streaming) { 435 this.streaming = streaming; 436 } 437 438 public String getStopOnException() { 439 return stopOnException; 440 } 441 442 public void setStopOnException(String stopOnException) { 443 this.stopOnException = stopOnException; 444 } 445 446 @Override 447 public ExecutorService getExecutorService() { 448 return executorService; 449 } 450 451 @Override 452 public void setExecutorService(ExecutorService executorService) { 453 this.executorService = executorService; 454 } 455 456 public String getStrategyRef() { 457 return strategyRef; 458 } 459 460 /** 461 * Refers to an AggregationStrategy to be used to assemble the replies from 462 * the multicasts, into a single outgoing message from the Multicast. By 463 * default Camel will use the last reply as the outgoing message. You can 464 * also use a POJO as the AggregationStrategy 465 */ 466 public void setStrategyRef(String strategyRef) { 467 this.strategyRef = strategyRef; 468 } 469 470 public String getStrategyMethodName() { 471 return strategyMethodName; 472 } 473 474 /** 475 * This option can be used to explicit declare the method name to use, when 476 * using POJOs as the AggregationStrategy. 477 */ 478 public void setStrategyMethodName(String strategyMethodName) { 479 this.strategyMethodName = strategyMethodName; 480 } 481 482 public String getStrategyMethodAllowNull() { 483 return strategyMethodAllowNull; 484 } 485 486 /** 487 * If this option is false then the aggregate method is not used if there 488 * was no data to enrich. If this option is true then null values is used as 489 * the oldExchange (when no data to enrich), when using POJOs as the 490 * AggregationStrategy 491 */ 492 public void setStrategyMethodAllowNull(String strategyMethodAllowNull) { 493 this.strategyMethodAllowNull = strategyMethodAllowNull; 494 } 495 496 @Override 497 public String getExecutorServiceRef() { 498 return executorServiceRef; 499 } 500 501 /** 502 * Refers to a custom Thread Pool to be used for parallel processing. Notice 503 * if you set this option, then parallel processing is automatic implied, 504 * and you do not have to enable that option as well. 505 */ 506 @Override 507 public void setExecutorServiceRef(String executorServiceRef) { 508 this.executorServiceRef = executorServiceRef; 509 } 510 511 public String getTimeout() { 512 return timeout; 513 } 514 515 public void setTimeout(String timeout) { 516 this.timeout = timeout; 517 } 518 519 public String getOnPrepareRef() { 520 return onPrepareRef; 521 } 522 523 public void setOnPrepareRef(String onPrepareRef) { 524 this.onPrepareRef = onPrepareRef; 525 } 526 527 public Processor getOnPrepare() { 528 return onPrepare; 529 } 530 531 public void setOnPrepare(Processor onPrepare) { 532 this.onPrepare = onPrepare; 533 } 534 535 public String getShareUnitOfWork() { 536 return shareUnitOfWork; 537 } 538 539 public void setShareUnitOfWork(String shareUnitOfWork) { 540 this.shareUnitOfWork = shareUnitOfWork; 541 } 542 543 public String getParallelAggregate() { 544 return parallelAggregate; 545 } 546 547 public void setParallelAggregate(String parallelAggregate) { 548 this.parallelAggregate = parallelAggregate; 549 } 550 551 public String getStopOnAggregateException() { 552 return stopOnAggregateException; 553 } 554 555 public void setStopOnAggregateException(String stopOnAggregateException) { 556 this.stopOnAggregateException = stopOnAggregateException; 557 } 558 559}