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.impl;
018
019import java.util.Map;
020import java.util.concurrent.CompletableFuture;
021import java.util.concurrent.ExecutorService;
022import java.util.concurrent.Future;
023import java.util.concurrent.TimeUnit;
024import java.util.concurrent.TimeoutException;
025import java.util.function.Function;
026
027import org.apache.camel.CamelContext;
028import org.apache.camel.CamelExecutionException;
029import org.apache.camel.Endpoint;
030import org.apache.camel.Exchange;
031import org.apache.camel.ExchangePattern;
032import org.apache.camel.Message;
033import org.apache.camel.NoSuchEndpointException;
034import org.apache.camel.Processor;
035import org.apache.camel.ProducerTemplate;
036import org.apache.camel.processor.ConvertBodyProcessor;
037import org.apache.camel.spi.Synchronization;
038import org.apache.camel.support.ServiceSupport;
039import org.apache.camel.util.CamelContextHelper;
040import org.apache.camel.util.ExchangeHelper;
041import org.apache.camel.util.ObjectHelper;
042import org.apache.camel.util.ServiceHelper;
043import org.apache.camel.util.concurrent.SynchronousExecutorService;
044
045/**
046 * Template (named like Spring's TransactionTemplate & JmsTemplate
047 * et al) for working with Camel and sending {@link Message} instances in an
048 * {@link Exchange} to an {@link Endpoint}.
049 *
050 * @version 
051 */
052public class DefaultProducerTemplate extends ServiceSupport implements ProducerTemplate {
053    private final CamelContext camelContext;
054    private volatile ProducerCache producerCache;
055    private volatile ExecutorService executor;
056    private Endpoint defaultEndpoint;
057    private int maximumCacheSize;
058    private boolean eventNotifierEnabled = true;
059    private volatile boolean threadedAsyncMode = true;
060
061    public DefaultProducerTemplate(CamelContext camelContext) {
062        this.camelContext = camelContext;
063    }
064
065    public DefaultProducerTemplate(CamelContext camelContext, ExecutorService executor) {
066        this.camelContext = camelContext;
067        this.executor = executor;
068    }
069
070    public DefaultProducerTemplate(CamelContext camelContext, Endpoint defaultEndpoint) {
071        this(camelContext);
072        this.defaultEndpoint = defaultEndpoint;
073    }
074
075    public static DefaultProducerTemplate newInstance(CamelContext camelContext, String defaultEndpointUri) {
076        Endpoint endpoint = CamelContextHelper.getMandatoryEndpoint(camelContext, defaultEndpointUri);
077        return new DefaultProducerTemplate(camelContext, endpoint);
078    }
079
080    public int getMaximumCacheSize() {
081        return maximumCacheSize;
082    }
083
084    public void setMaximumCacheSize(int maximumCacheSize) {
085        this.maximumCacheSize = maximumCacheSize;
086    }
087
088    @Override
089    public boolean isThreadedAsyncMode() {
090        return threadedAsyncMode;
091    }
092
093    @Override
094    public void setThreadedAsyncMode(boolean useExecutor) {
095        this.threadedAsyncMode = useExecutor;
096    }
097
098    public int getCurrentCacheSize() {
099        if (producerCache == null) {
100            return 0;
101        }
102        return producerCache.size();
103    }
104
105    public boolean isEventNotifierEnabled() {
106        return eventNotifierEnabled;
107    }
108
109    public void cleanUp() {
110        if (producerCache != null) {
111            producerCache.cleanUp();
112        }
113    }
114
115    public void setEventNotifierEnabled(boolean eventNotifierEnabled) {
116        this.eventNotifierEnabled = eventNotifierEnabled;
117        // if we already created the cache then adjust its setting as well
118        if (producerCache != null) {
119            producerCache.setEventNotifierEnabled(eventNotifierEnabled);
120        }
121    }
122
123    public Exchange send(String endpointUri, Exchange exchange) {
124        Endpoint endpoint = resolveMandatoryEndpoint(endpointUri);
125        return send(endpoint, exchange);
126    }
127
128    public Exchange send(String endpointUri, Processor processor) {
129        Endpoint endpoint = resolveMandatoryEndpoint(endpointUri);
130        return send(endpoint, processor);
131    }
132
133    public Exchange send(String endpointUri, ExchangePattern pattern, Processor processor) {
134        Endpoint endpoint = resolveMandatoryEndpoint(endpointUri);
135        return send(endpoint, pattern, processor);
136    }
137
138    public Exchange send(Endpoint endpoint, Exchange exchange) {
139        getProducerCache().send(endpoint, exchange);
140        return exchange;
141    }
142
143    public Exchange send(Endpoint endpoint, Processor processor) {
144        return getProducerCache().send(endpoint, processor);
145    }
146
147    public Exchange send(Endpoint endpoint, ExchangePattern pattern, Processor processor) {
148        return getProducerCache().send(endpoint, pattern, processor);
149    }
150
151    public Exchange send(Endpoint endpoint, ExchangePattern pattern, Processor processor, Processor resultProcessor) {
152        return getProducerCache().send(endpoint, pattern, processor, resultProcessor);
153    }
154
155    public Object sendBody(Endpoint endpoint, ExchangePattern pattern, Object body) {
156        Exchange result = send(endpoint, pattern, createSetBodyProcessor(body));
157        return extractResultBody(result, pattern);
158    }
159
160    public void sendBody(Endpoint endpoint, Object body) throws CamelExecutionException {
161        Exchange result = send(endpoint, createSetBodyProcessor(body));
162        // must invoke extract result body in case of exception to be rethrown
163        extractResultBody(result);
164    }
165
166    public void sendBody(String endpointUri, Object body) throws CamelExecutionException {
167        Endpoint endpoint = resolveMandatoryEndpoint(endpointUri);
168        sendBody(endpoint, body);
169    }
170
171    public Object sendBody(String endpointUri, ExchangePattern pattern, Object body) throws CamelExecutionException {
172        Endpoint endpoint = resolveMandatoryEndpoint(endpointUri);
173        Object result = sendBody(endpoint, pattern, body);
174        if (pattern.isOutCapable()) {
175            return result;
176        } else {
177            // return null if not OUT capable
178            return null;
179        }
180    }
181
182    public void sendBodyAndHeader(String endpointUri, final Object body, final String header, final Object headerValue) throws CamelExecutionException {
183        sendBodyAndHeader(resolveMandatoryEndpoint(endpointUri), body, header, headerValue);
184    }
185
186    public void sendBodyAndHeader(Endpoint endpoint, final Object body, final String header, final Object headerValue) throws CamelExecutionException {
187        Exchange result = send(endpoint, createBodyAndHeaderProcessor(body, header, headerValue));
188        // must invoke extract result body in case of exception to be rethrown
189        extractResultBody(result);
190    }
191
192    public Object sendBodyAndHeader(Endpoint endpoint, ExchangePattern pattern, final Object body,
193                                    final String header, final Object headerValue) throws CamelExecutionException {
194        Exchange exchange = send(endpoint, pattern, createBodyAndHeaderProcessor(body, header, headerValue));
195        Object result = extractResultBody(exchange, pattern);
196        if (pattern.isOutCapable()) {
197            return result;
198        } else {
199            // return null if not OUT capable
200            return null;
201        }
202    }
203
204    public Object sendBodyAndHeader(String endpoint, ExchangePattern pattern, final Object body,
205                                    final String header, final Object headerValue) throws CamelExecutionException {
206        Exchange exchange = send(endpoint, pattern, createBodyAndHeaderProcessor(body, header, headerValue));
207        Object result = extractResultBody(exchange, pattern);
208        if (pattern.isOutCapable()) {
209            return result;
210        } else {
211            // return null if not OUT capable
212            return null;
213        }
214    }
215
216    public void sendBodyAndProperty(String endpointUri, final Object body,
217                                    final String property, final Object propertyValue) throws CamelExecutionException {
218        sendBodyAndProperty(resolveMandatoryEndpoint(endpointUri), body, property, propertyValue);
219    }
220
221    public void sendBodyAndProperty(Endpoint endpoint, final Object body,
222                                    final String property, final Object propertyValue) throws CamelExecutionException {
223        Exchange result = send(endpoint, createBodyAndPropertyProcessor(body, property, propertyValue));
224        // must invoke extract result body in case of exception to be rethrown
225        extractResultBody(result);
226    }
227
228    public Object sendBodyAndProperty(Endpoint endpoint, ExchangePattern pattern, final Object body,
229                                      final String property, final Object propertyValue) throws CamelExecutionException {
230        Exchange exchange = send(endpoint, pattern, createBodyAndPropertyProcessor(body, property, propertyValue));
231        Object result = extractResultBody(exchange, pattern);
232        if (pattern.isOutCapable()) {
233            return result;
234        } else {
235            // return null if not OUT capable
236            return null;
237        }
238    }
239
240    public Object sendBodyAndProperty(String endpoint, ExchangePattern pattern, final Object body,
241                                      final String property, final Object propertyValue) throws CamelExecutionException {
242        Exchange exchange = send(endpoint, pattern, createBodyAndPropertyProcessor(body, property, propertyValue));
243        Object result = extractResultBody(exchange, pattern);
244        if (pattern.isOutCapable()) {
245            return result;
246        } else {
247            // return null if not OUT capable
248            return null;
249        }
250    }
251
252    public void sendBodyAndHeaders(String endpointUri, final Object body, final Map<String, Object> headers) throws CamelExecutionException {
253        sendBodyAndHeaders(resolveMandatoryEndpoint(endpointUri), body, headers);
254    }
255
256    public void sendBodyAndHeaders(Endpoint endpoint, final Object body, final Map<String, Object> headers) throws CamelExecutionException {
257        Exchange result = send(endpoint, createBodyAndHeaders(body, headers));
258        // must invoke extract result body in case of exception to be rethrown
259        extractResultBody(result);
260    }
261
262    public Object sendBodyAndHeaders(String endpointUri, ExchangePattern pattern, Object body, Map<String, Object> headers) throws CamelExecutionException {
263        return sendBodyAndHeaders(resolveMandatoryEndpoint(endpointUri), pattern, body, headers);
264    }
265
266    public Object sendBodyAndHeaders(Endpoint endpoint, ExchangePattern pattern, final Object body, final Map<String, Object> headers) throws CamelExecutionException {
267        Exchange exchange = send(endpoint, pattern, createBodyAndHeaders(body, headers));
268        Object result = extractResultBody(exchange, pattern);
269        if (pattern.isOutCapable()) {
270            return result;
271        } else {
272            // return null if not OUT capable
273            return null;
274        }
275    }
276
277    // Methods using an InOut ExchangePattern
278    // -----------------------------------------------------------------------
279
280    public Exchange request(Endpoint endpoint, Processor processor) {
281        return send(endpoint, ExchangePattern.InOut, processor);
282    }
283
284    public Object requestBody(Object body) throws CamelExecutionException {
285        return sendBody(getMandatoryDefaultEndpoint(), ExchangePattern.InOut, body);
286    }
287
288    public Object requestBody(Endpoint endpoint, Object body) throws CamelExecutionException {
289        return sendBody(endpoint, ExchangePattern.InOut, body);
290    }
291
292    public Object requestBodyAndHeader(Object body, String header, Object headerValue) throws CamelExecutionException {
293        return sendBodyAndHeader(getMandatoryDefaultEndpoint(), ExchangePattern.InOut, body, header, headerValue);
294    }
295
296    public Object requestBodyAndHeader(Endpoint endpoint, Object body, String header, Object headerValue) throws CamelExecutionException {
297        return sendBodyAndHeader(endpoint, ExchangePattern.InOut, body, header, headerValue);
298    }
299
300    public Exchange request(String endpoint, Processor processor) throws CamelExecutionException {
301        return send(endpoint, ExchangePattern.InOut, processor);
302    }
303
304    public Object requestBody(String endpoint, Object body) throws CamelExecutionException {
305        return sendBody(endpoint, ExchangePattern.InOut, body);
306    }
307
308    public Object requestBodyAndHeader(String endpoint, Object body, String header, Object headerValue) throws CamelExecutionException {
309        return sendBodyAndHeader(endpoint, ExchangePattern.InOut, body, header, headerValue);
310    }
311
312    public Object requestBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers) {
313        return requestBodyAndHeaders(resolveMandatoryEndpoint(endpointUri), body, headers);
314    }
315
316    public Object requestBodyAndHeaders(Endpoint endpoint, final Object body, final Map<String, Object> headers) {
317        return sendBodyAndHeaders(endpoint, ExchangePattern.InOut, body, headers);
318    }
319
320    public Object requestBodyAndHeaders(final Object body, final Map<String, Object> headers) {
321        return sendBodyAndHeaders(getDefaultEndpoint(), ExchangePattern.InOut, body, headers);
322    }
323
324    public <T> T requestBody(Object body, Class<T> type) {
325        Exchange exchange = producerCache.send(getMandatoryDefaultEndpoint(), ExchangePattern.InOut, createSetBodyProcessor(body), createConvertBodyProcessor(type));
326        Object answer = extractResultBody(exchange);
327        return camelContext.getTypeConverter().convertTo(type, answer);
328    }
329
330    public <T> T requestBody(Endpoint endpoint, Object body, Class<T> type) {
331        Exchange exchange = producerCache.send(endpoint, ExchangePattern.InOut, createSetBodyProcessor(body), createConvertBodyProcessor(type));
332        Object answer = extractResultBody(exchange);
333        return camelContext.getTypeConverter().convertTo(type, answer);
334    }
335
336    public <T> T requestBody(String endpointUri, Object body, Class<T> type) {
337        Exchange exchange = producerCache.send(resolveMandatoryEndpoint(endpointUri), ExchangePattern.InOut, createSetBodyProcessor(body), createConvertBodyProcessor(type));
338        Object answer = extractResultBody(exchange);
339        return camelContext.getTypeConverter().convertTo(type, answer);
340    }
341
342    public <T> T requestBodyAndHeader(Endpoint endpoint, Object body, String header, Object headerValue, Class<T> type) {
343        Exchange exchange = producerCache.send(endpoint, ExchangePattern.InOut, createBodyAndHeaderProcessor(body, header, headerValue), createConvertBodyProcessor(type));
344        Object answer = extractResultBody(exchange);
345        return camelContext.getTypeConverter().convertTo(type, answer);
346    }
347
348    public <T> T requestBodyAndHeader(String endpointUri, Object body, String header, Object headerValue, Class<T> type) {
349        Exchange exchange = producerCache.send(resolveMandatoryEndpoint(endpointUri), ExchangePattern.InOut, createBodyAndHeaderProcessor(body, header, headerValue), createConvertBodyProcessor(type));
350        Object answer = extractResultBody(exchange);
351        return camelContext.getTypeConverter().convertTo(type, answer);
352    }
353
354    public <T> T requestBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers, Class<T> type) {
355        Exchange exchange = producerCache.send(resolveMandatoryEndpoint(endpointUri), ExchangePattern.InOut, createBodyAndHeaders(body, headers), createConvertBodyProcessor(type));
356        Object answer = extractResultBody(exchange);
357        return camelContext.getTypeConverter().convertTo(type, answer);
358    }
359
360    public <T> T requestBodyAndHeaders(Endpoint endpoint, Object body, Map<String, Object> headers, Class<T> type) {
361        Exchange exchange = producerCache.send(endpoint, ExchangePattern.InOut, createBodyAndHeaders(body, headers), createConvertBodyProcessor(type));
362        Object answer = extractResultBody(exchange);
363        return camelContext.getTypeConverter().convertTo(type, answer);
364    }
365
366    // Methods using the default endpoint
367    // -----------------------------------------------------------------------
368
369    public void sendBody(Object body) {
370        sendBody(getMandatoryDefaultEndpoint(), body);
371    }
372
373    public Exchange send(Exchange exchange) {
374        return send(getMandatoryDefaultEndpoint(), exchange);
375    }
376
377    public Exchange send(Processor processor) {
378        return send(getMandatoryDefaultEndpoint(), processor);
379    }
380
381    public void sendBodyAndHeader(Object body, String header, Object headerValue) {
382        sendBodyAndHeader(getMandatoryDefaultEndpoint(), body, header, headerValue);
383    }
384
385    public void sendBodyAndProperty(Object body, String property, Object propertyValue) {
386        sendBodyAndProperty(getMandatoryDefaultEndpoint(), body, property, propertyValue);
387    }
388
389    public void sendBodyAndHeaders(Object body, Map<String, Object> headers) {
390        sendBodyAndHeaders(getMandatoryDefaultEndpoint(), body, headers);
391    }
392
393    // Properties
394    // -----------------------------------------------------------------------
395
396    /**
397     * @deprecated use {@link #getCamelContext()}
398     */
399    @Deprecated
400    public CamelContext getContext() {
401        return getCamelContext();
402    }
403
404    public CamelContext getCamelContext() {
405        return camelContext;
406    }
407
408    public Endpoint getDefaultEndpoint() {
409        return defaultEndpoint;
410    }
411
412    public void setDefaultEndpoint(Endpoint defaultEndpoint) {
413        this.defaultEndpoint = defaultEndpoint;
414    }
415
416    /**
417     * Sets the default endpoint to use if none is specified
418     */
419    public void setDefaultEndpointUri(String endpointUri) {
420        setDefaultEndpoint(getCamelContext().getEndpoint(endpointUri));
421    }
422
423    /**
424     * @deprecated use {@link CamelContext#getEndpoint(String, Class)}
425     */
426    @Deprecated
427    public <T extends Endpoint> T getResolvedEndpoint(String endpointUri, Class<T> expectedClass) {
428        return camelContext.getEndpoint(endpointUri, expectedClass);
429    }
430
431    // Implementation methods
432    // -----------------------------------------------------------------------
433
434    protected Processor createBodyAndHeaderProcessor(final Object body, final String header, final Object headerValue) {
435        return new Processor() {
436            public void process(Exchange exchange) {
437                Message in = exchange.getIn();
438                in.setHeader(header, headerValue);
439                in.setBody(body);
440            }
441        };
442    }
443
444    protected Processor createBodyAndHeaders(final Object body, final Map<String, Object> headers) {
445        return new Processor() {
446            public void process(Exchange exchange) {
447                Message in = exchange.getIn();
448                if (headers != null) {
449                    for (Map.Entry<String, Object> header : headers.entrySet()) {
450                        in.setHeader(header.getKey(), header.getValue());
451                    }
452                }
453                in.setBody(body);
454            }
455        };
456    }
457
458    protected Processor createBodyAndPropertyProcessor(final Object body, final String property, final Object propertyValue) {
459        return new Processor() {
460            public void process(Exchange exchange) {
461                exchange.setProperty(property, propertyValue);
462                Message in = exchange.getIn();
463                in.setBody(body);
464            }
465        };
466    }
467
468    protected Processor createSetBodyProcessor(final Object body) {
469        return new Processor() {
470            public void process(Exchange exchange) {
471                Message in = exchange.getIn();
472                in.setBody(body);
473            }
474        };
475    }
476
477    protected Processor createConvertBodyProcessor(final Class<?> type) {
478        return new ConvertBodyProcessor(type);
479    }
480
481    protected Function<Exchange, Exchange> createCompletionFunction(Synchronization onCompletion) {
482        return (answer) -> {
483            // invoke callback before returning answer
484            // as it allows callback to be used without unit of work invoking it
485            // and thus it works directly from a producer template as well, as opposed
486            // to the unit of work that is injected in routes
487            if (answer.isFailed()) {
488                onCompletion.onFailure(answer);
489            } else {
490                onCompletion.onComplete(answer);
491            }
492            return answer;
493        };
494    }
495
496    protected Endpoint resolveMandatoryEndpoint(String endpointUri) {
497        Endpoint endpoint = camelContext.getEndpoint(endpointUri);
498        if (endpoint == null) {
499            throw new NoSuchEndpointException(endpointUri);
500        }
501        return endpoint;
502    }
503
504    protected Endpoint getMandatoryDefaultEndpoint() {
505        Endpoint answer = getDefaultEndpoint();
506        ObjectHelper.notNull(answer, "defaultEndpoint");
507        return answer;
508    }
509
510    protected Object extractResultBody(Exchange result) {
511        return extractResultBody(result, null);
512    }
513
514    protected Object extractResultBody(Exchange result, ExchangePattern pattern) {
515        return ExchangeHelper.extractResultBody(result, pattern);
516    }
517
518    public void setExecutorService(ExecutorService executorService) {
519        this.executor = executorService;
520    }
521
522    public CompletableFuture<Exchange> asyncSend(final String uri, final Exchange exchange) {
523        return asyncSend(resolveMandatoryEndpoint(uri), exchange);
524    }
525
526    public CompletableFuture<Exchange> asyncSend(final String uri, final Processor processor) {
527        return asyncSend(resolveMandatoryEndpoint(uri), processor);
528    }
529
530    public CompletableFuture<Object> asyncSendBody(final String uri, final Object body) {
531        return asyncSendBody(resolveMandatoryEndpoint(uri), body);
532    }
533
534    public CompletableFuture<Object> asyncRequestBody(final String uri, final Object body) {
535        return asyncRequestBody(resolveMandatoryEndpoint(uri), body);
536    }
537
538    public <T> CompletableFuture<T> asyncRequestBody(final String uri, final Object body, final Class<T> type) {
539        return asyncRequestBody(resolveMandatoryEndpoint(uri), createSetBodyProcessor(body), type);
540    }
541
542    public CompletableFuture<Object> asyncRequestBodyAndHeader(final String endpointUri, final Object body, final String header, final Object headerValue) {
543        return asyncRequestBodyAndHeader(resolveMandatoryEndpoint(endpointUri), body, header, headerValue);
544    }
545
546    public <T> CompletableFuture<T> asyncRequestBodyAndHeader(final String endpointUri, final Object body, final String header, final Object headerValue, final Class<T> type) {
547        return asyncRequestBodyAndHeader(resolveMandatoryEndpoint(endpointUri), body, header, headerValue, type);
548    }
549
550    public CompletableFuture<Object> asyncRequestBodyAndHeaders(final String endpointUri, final Object body, final Map<String, Object> headers) {
551        return asyncRequestBodyAndHeaders(resolveMandatoryEndpoint(endpointUri), body, headers);
552    }
553
554    public <T> CompletableFuture<T> asyncRequestBodyAndHeaders(final String endpointUri, final Object body, final Map<String, Object> headers, final Class<T> type) {
555        return asyncRequestBodyAndHeaders(resolveMandatoryEndpoint(endpointUri), body, headers, type);
556    }
557
558    public <T> T extractFutureBody(Future<?> future, Class<T> type) {
559        return ExchangeHelper.extractFutureBody(camelContext, future, type);
560    }
561
562    public <T> T extractFutureBody(Future<?> future, long timeout, TimeUnit unit, Class<T> type) throws TimeoutException {
563        return ExchangeHelper.extractFutureBody(camelContext, future, timeout, unit, type);
564    }
565
566    public CompletableFuture<Object> asyncCallbackSendBody(String uri, Object body, Synchronization onCompletion) {
567        return asyncCallbackSendBody(resolveMandatoryEndpoint(uri), body, onCompletion);
568    }
569
570    public CompletableFuture<Object> asyncCallbackSendBody(Endpoint endpoint, Object body, Synchronization onCompletion) {
571        return asyncCallback(endpoint, ExchangePattern.InOnly, body, onCompletion);
572    }
573
574    public CompletableFuture<Object> asyncCallbackRequestBody(String uri, Object body, Synchronization onCompletion) {
575        return asyncCallbackRequestBody(resolveMandatoryEndpoint(uri), body, onCompletion);
576    }
577
578    public CompletableFuture<Object> asyncCallbackRequestBody(Endpoint endpoint, Object body, Synchronization onCompletion) {
579        return asyncCallback(endpoint, ExchangePattern.InOut, body, onCompletion);
580    }
581
582    public CompletableFuture<Exchange> asyncCallback(String uri, Exchange exchange, Synchronization onCompletion) {
583        return asyncCallback(resolveMandatoryEndpoint(uri), exchange, onCompletion);
584    }
585
586    public CompletableFuture<Exchange> asyncCallback(String uri, Processor processor, Synchronization onCompletion) {
587        return asyncCallback(resolveMandatoryEndpoint(uri), processor, onCompletion);
588    }
589
590    public CompletableFuture<Object> asyncRequestBody(final Endpoint endpoint, final Object body) {
591        return asyncRequestBody(endpoint, createSetBodyProcessor(body));
592    }
593
594    public <T> CompletableFuture<T> asyncRequestBody(Endpoint endpoint, Object body, Class<T> type) {
595        return asyncRequestBody(endpoint, createSetBodyProcessor(body), type);
596    }
597
598    public CompletableFuture<Object> asyncRequestBodyAndHeader(final Endpoint endpoint, final Object body, final String header,
599                                                    final Object headerValue) {
600        return asyncRequestBody(endpoint, createBodyAndHeaderProcessor(body, header, headerValue));
601    }
602
603    protected  <T> CompletableFuture<T> asyncRequestBody(final Endpoint endpoint, Processor processor, final Class<T> type) {
604        return asyncRequestBody(endpoint, processor, createConvertBodyProcessor(type))
605                .thenApply(answer -> camelContext.getTypeConverter().convertTo(type, answer));
606    }
607
608    public <T> CompletableFuture<T> asyncRequestBodyAndHeader(final Endpoint endpoint, final Object body, final String header,
609                                                   final Object headerValue, final Class<T> type) {
610        return asyncRequestBody(endpoint, createBodyAndHeaderProcessor(body, header, headerValue), type);
611    }
612
613    public CompletableFuture<Object> asyncRequestBodyAndHeaders(final Endpoint endpoint, final Object body,
614                                                     final Map<String, Object> headers) {
615        return asyncRequestBody(endpoint, createBodyAndHeaders(body, headers));
616    }
617
618    public <T> CompletableFuture<T> asyncRequestBodyAndHeaders(final Endpoint endpoint, final Object body,
619                                                    final Map<String, Object> headers, final Class<T> type) {
620        return asyncRequestBody(endpoint, createBodyAndHeaders(body, headers), type);
621    }
622
623    public CompletableFuture<Exchange> asyncSend(final Endpoint endpoint, final Exchange exchange) {
624        return asyncSendExchange(endpoint, null, null, null, exchange);
625    }
626
627    public CompletableFuture<Exchange> asyncSend(final Endpoint endpoint, final Processor processor) {
628        return asyncSend(endpoint, null, processor, null);
629    }
630
631    public CompletableFuture<Object> asyncSendBody(final Endpoint endpoint, final Object body) {
632        return asyncSend(endpoint, createSetBodyProcessor(body))
633                .thenApply(this::extractResultBody);
634    }
635
636    public CompletableFuture<Exchange> asyncCallback(final Endpoint endpoint, final Exchange exchange, final Synchronization onCompletion) {
637        return asyncSend(endpoint, exchange).thenApply(createCompletionFunction(onCompletion));
638    }
639
640    public CompletableFuture<Exchange> asyncCallback(final Endpoint endpoint, final Processor processor, final Synchronization onCompletion) {
641        return asyncSend(endpoint, processor).thenApply(createCompletionFunction(onCompletion));
642    }
643
644    protected CompletableFuture<Object> asyncRequestBody(final Endpoint endpoint, Processor processor) {
645        return asyncRequestBody(endpoint, processor, (Processor) null);
646    }
647
648    protected CompletableFuture<Object> asyncRequestBody(final Endpoint endpoint, Processor processor, Processor resultProcessor) {
649        return asyncRequest(endpoint, processor, resultProcessor)
650                .thenApply(e -> extractResultBody(e, ExchangePattern.InOut));
651    }
652
653    protected CompletableFuture<Exchange> asyncRequest(Endpoint endpoint, Processor processor,
654            Processor resultProcessor) {
655        return asyncSend(endpoint, ExchangePattern.InOut, processor, resultProcessor);
656    }
657
658    protected CompletableFuture<Exchange> asyncSend(
659            Endpoint endpoint, ExchangePattern pattern, Processor processor, Processor resultProcessor) {
660        return asyncSendExchange(endpoint, pattern, processor, resultProcessor, null);
661    }
662
663    protected CompletableFuture<Exchange> asyncSendExchange(
664            Endpoint endpoint, ExchangePattern pattern, Processor processor, Processor resultProcessor,
665            Exchange inExchange) {
666        CompletableFuture<Exchange> exchangeFuture = new CompletableFuture<>();
667        getExecutorService().submit(() -> getProducerCache().asyncSendExchange(endpoint, pattern, processor,
668                resultProcessor, inExchange, exchangeFuture));
669        return exchangeFuture;
670    }
671
672    protected CompletableFuture<Object> asyncCallback(final Endpoint endpoint, final ExchangePattern pattern,
673            final Object body, final Synchronization onCompletion) {
674        return asyncSend(endpoint, pattern, createSetBodyProcessor(body), null)
675                .thenApply(createCompletionFunction(onCompletion))
676                .thenApply(answer -> {
677                    Object result = extractResultBody(answer, pattern);
678                    if (pattern.isOutCapable()) {
679                        return result;
680                    } else {
681                        // return null if not OUT capable
682                        return null;
683                    }
684                });
685    }
686
687    private ProducerCache getProducerCache() {
688        if (!isStarted()) {
689            throw new IllegalStateException("ProducerTemplate has not been started");
690        }
691        return producerCache;
692    }
693
694    private ExecutorService getExecutorService() {
695        if (!isStarted()) {
696            throw new IllegalStateException("ProducerTemplate has not been started");
697        }
698
699        if (executor != null) {
700            return executor;
701        }
702
703        // create a default executor which must be synchronized
704        synchronized (this) {
705            if (executor != null) {
706                return executor;
707            }
708            if (!threadedAsyncMode) {
709                executor = new SynchronousExecutorService();
710            } else {
711                executor = camelContext.getExecutorServiceManager().newDefaultThreadPool(this, "ProducerTemplate");
712            }
713        }
714
715        ObjectHelper.notNull(executor, "ExecutorService");
716        return executor;
717    }
718
719    protected void doStart() throws Exception {
720        if (producerCache == null) {
721            if (maximumCacheSize > 0) {
722                producerCache = new ProducerCache(this, camelContext, maximumCacheSize);
723            } else {
724                producerCache = new ProducerCache(this, camelContext);
725            }
726            producerCache.setEventNotifierEnabled(isEventNotifierEnabled());
727        }
728
729        // need to lookup default endpoint as it may have been intercepted
730        if (defaultEndpoint != null) {
731            defaultEndpoint = camelContext.getEndpoint(defaultEndpoint.getEndpointUri());
732        }
733
734        ServiceHelper.startService(producerCache);
735    }
736
737    protected void doStop() throws Exception {
738        ServiceHelper.stopService(producerCache);
739        producerCache = null;
740
741        if (executor != null) {
742            camelContext.getExecutorServiceManager().shutdownNow(executor);
743            executor = null;
744        }
745    }
746
747}