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