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