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