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}