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