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.HashMap;
020    import java.util.Map;
021    
022    import org.apache.camel.AsyncCallback;
023    import org.apache.camel.CamelContext;
024    import org.apache.camel.Endpoint;
025    import org.apache.camel.Exchange;
026    import org.apache.camel.ExchangePattern;
027    import org.apache.camel.Message;
028    import org.apache.camel.NoSuchEndpointException;
029    import org.apache.camel.Processor;
030    import org.apache.camel.Producer;
031    import org.apache.camel.ProducerTemplate;
032    import org.apache.camel.util.CamelContextHelper;
033    import org.apache.camel.util.ObjectHelper;
034    
035    import static org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException;
036    
037    /**
038     * A client helper object (named like Spring's TransactionTemplate & JmsTemplate
039     * et al) for working with Camel and sending {@link org.apache.camel.Message} instances in an
040     * {@link org.apache.camel.Exchange} to an {@link org.apache.camel.Endpoint}.
041     *
042     * @version $Revision: 750400 $
043     */
044    public class DefaultProducerTemplate extends ServiceSupport implements ProducerTemplate {
045        private final CamelContext context;
046        private final ProducerCache producerCache = new ProducerCache();
047        private boolean useEndpointCache = true;
048        private final Map<String, Endpoint> endpointCache = new HashMap<String, Endpoint>();
049        private Endpoint defaultEndpoint;
050        
051        public DefaultProducerTemplate(CamelContext context) {
052            this.context = context;
053        }
054    
055        public DefaultProducerTemplate(CamelContext context, Endpoint defaultEndpoint) {
056            this(context);
057            this.defaultEndpoint = defaultEndpoint;
058        }
059    
060        public static DefaultProducerTemplate newInstance(CamelContext camelContext, String defaultEndpointUri) {
061            Endpoint endpoint = CamelContextHelper.getMandatoryEndpoint(camelContext, defaultEndpointUri);
062            return new DefaultProducerTemplate(camelContext, endpoint);
063        }   
064    
065        public Exchange send(String endpointUri, Exchange exchange) {
066            Endpoint endpoint = resolveMandatoryEndpoint(endpointUri);
067            return send(endpoint, exchange);
068        }
069    
070        public Exchange send(String endpointUri, Processor processor) {
071            Endpoint endpoint = resolveMandatoryEndpoint(endpointUri);
072            return send(endpoint, processor);
073        }
074    
075        public Exchange send(String endpointUri, Processor processor, AsyncCallback callback) {
076            Endpoint endpoint = resolveMandatoryEndpoint(endpointUri);
077            return send(endpoint, processor, callback);
078        }
079    
080        public Exchange send(String endpointUri, ExchangePattern pattern, Processor processor) {
081            Endpoint endpoint = resolveMandatoryEndpoint(endpointUri);
082            return send(endpoint, pattern, processor);
083        }
084    
085        public Exchange send(Endpoint endpoint, Exchange exchange) {
086            producerCache.send(endpoint, exchange);
087            return exchange;
088        }
089    
090        public Exchange send(Endpoint endpoint, Processor processor) {
091            return producerCache.send(endpoint, processor);
092        }
093    
094        public Exchange send(Endpoint endpoint, Processor processor, AsyncCallback callback) {
095            return producerCache.send(endpoint, processor, callback);
096        }
097    
098        public Exchange send(Endpoint endpoint, ExchangePattern pattern, Processor processor) {
099            return producerCache.send(endpoint, pattern, processor);
100        }
101    
102        public Object sendBody(Endpoint endpoint, ExchangePattern pattern, Object body) {
103            Exchange result = send(endpoint, pattern, createSetBodyProcessor(body));
104            return extractResultBody(result, pattern);
105        }
106    
107        public Object sendBody(Endpoint endpoint, Object body) {
108            Exchange result = send(endpoint, createSetBodyProcessor(body));
109            return extractResultBody(result);
110        }
111    
112        public Object sendBody(String endpointUri, Object body) {
113            Endpoint endpoint = resolveMandatoryEndpoint(endpointUri);
114            return sendBody(endpoint, body);
115        }
116    
117        public Object sendBody(String endpointUri, ExchangePattern pattern, Object body) {
118            Endpoint endpoint = resolveMandatoryEndpoint(endpointUri);
119            return sendBody(endpoint, pattern, body);
120        }
121    
122        public Object sendBodyAndHeader(String endpointUri, final Object body, final String header,
123                final Object headerValue) {
124            return sendBodyAndHeader(resolveMandatoryEndpoint(endpointUri), body, header, headerValue);
125        }
126    
127        public Object sendBodyAndHeader(Endpoint endpoint, final Object body, final String header,
128                final Object headerValue) {
129            Exchange result = send(endpoint, createBodyAndHeaderProcessor(body, header, headerValue));
130            return extractResultBody(result);
131        }
132    
133        public Object sendBodyAndHeader(Endpoint endpoint, ExchangePattern pattern, final Object body, final String header,
134                final Object headerValue) {
135            Exchange result = send(endpoint, pattern, createBodyAndHeaderProcessor(body, header, headerValue));
136            return extractResultBody(result, pattern);
137        }
138    
139        public Object sendBodyAndHeader(String endpoint, ExchangePattern pattern, final Object body, final String header,
140                final Object headerValue) {
141            Exchange result = send(endpoint, pattern, createBodyAndHeaderProcessor(body, header, headerValue));
142            return extractResultBody(result, pattern);
143        }
144    
145        public Object sendBodyAndProperty(String endpointUri, final Object body, final String property,
146                final Object propertyValue) {
147            return sendBodyAndProperty(resolveMandatoryEndpoint(endpointUri), body, property, propertyValue);
148        }    
149        
150        public Object sendBodyAndProperty(Endpoint endpoint, final Object body, final String property,
151                final Object propertyValue) {
152            Exchange result = send(endpoint, createBodyAndPropertyProcessor(body, property, propertyValue));
153            return extractResultBody(result);
154        }    
155        
156        public Object sendBodyAndProperty(Endpoint endpoint, ExchangePattern pattern, final Object body, final String property,
157                final Object propertyValue) {
158            Exchange result = send(endpoint, pattern, createBodyAndPropertyProcessor(body, property, propertyValue));
159            return extractResultBody(result, pattern);
160        }
161    
162        public Object sendBodyAndProperty(String endpoint, ExchangePattern pattern, final Object body, final String property,
163                final Object propertyValue) {
164            Exchange result = send(endpoint, pattern, createBodyAndPropertyProcessor(body, property, propertyValue));
165            return extractResultBody(result, pattern);
166        }    
167        
168        public Object sendBodyAndHeaders(String endpointUri, final Object body, final Map<String, Object> headers) {
169            return sendBodyAndHeaders(resolveMandatoryEndpoint(endpointUri), body, headers);
170        }
171    
172        public Object sendBodyAndHeaders(Endpoint endpoint, final Object body, final Map<String, Object> headers) {
173            Exchange result = send(endpoint, new Processor() {
174                public void process(Exchange exchange) {
175                    Message in = exchange.getIn();
176                    for (Map.Entry<String, Object> header : headers.entrySet()) {
177                        in.setHeader(header.getKey(), header.getValue());
178                    }
179                    in.setBody(body);
180                }
181            });
182            return extractResultBody(result);
183        }
184    
185        public Object sendBodyAndHeaders(String endpointUri, ExchangePattern pattern, Object body, Map<String, Object> headers) {
186            return sendBodyAndHeaders(resolveMandatoryEndpoint(endpointUri), pattern, body, headers);
187        }
188    
189        public Object sendBodyAndHeaders(Endpoint endpoint, ExchangePattern pattern, final Object body, final Map<String, Object> headers) {
190            Exchange result = send(endpoint, pattern, new Processor() {
191                public void process(Exchange exchange) throws Exception {
192                    Message in = exchange.getIn();
193                    for (Map.Entry<String, Object> header : headers.entrySet()) {
194                        in.setHeader(header.getKey(), header.getValue());
195                    }
196                    in.setBody(body);
197                }
198            });
199            return extractResultBody(result);
200        }
201    
202        // Methods using an InOut ExchangePattern
203        // -----------------------------------------------------------------------
204    
205        public Exchange request(Endpoint endpoint, Processor processor) {
206            return send(endpoint, ExchangePattern.InOut, processor);
207        }
208    
209        public Object requestBody(Object body) {
210            return sendBody(getMandatoryDefaultEndpoint(), ExchangePattern.InOut, body);
211        }
212    
213        public Object requestBody(Endpoint endpoint, Object body) {
214            return sendBody(endpoint, ExchangePattern.InOut, body);
215        }
216    
217        public Object requestBodyAndHeader(Endpoint endpoint, Object body, String header, Object headerValue) {
218            return sendBodyAndHeader(endpoint, ExchangePattern.InOut, body, header, headerValue);
219        }
220    
221        public Exchange request(String endpoint, Processor processor) {
222            return send(endpoint, ExchangePattern.InOut, processor);
223        }
224    
225        public Object requestBody(String endpoint, Object body) {
226            return sendBody(endpoint, ExchangePattern.InOut, body);
227        }
228    
229        public Object requestBodyAndHeader(String endpoint, Object body, String header, Object headerValue) {
230            return sendBodyAndHeader(endpoint, ExchangePattern.InOut, body, header, headerValue);
231        }
232    
233        public Object requestBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers) {
234            return requestBodyAndHeaders(resolveMandatoryEndpoint(endpointUri), body, headers);
235        }
236    
237        public Object requestBodyAndHeaders(Endpoint endpoint, final Object body, final Map<String, Object> headers) {
238            return sendBodyAndHeaders(endpoint, ExchangePattern.InOut, body, headers);
239        }
240    
241        // Methods using the default endpoint
242        // -----------------------------------------------------------------------
243    
244        public Object sendBody(Object body) {
245            return sendBody(getMandatoryDefaultEndpoint(), body);
246        }
247    
248        public Exchange send(Exchange exchange) {
249            return send(getMandatoryDefaultEndpoint(), exchange);
250        }
251    
252        public Exchange send(Processor processor) {
253            return send(getMandatoryDefaultEndpoint(), processor);
254        }
255    
256        public Object sendBodyAndHeader(Object body, String header, Object headerValue) {
257            return sendBodyAndHeader(getMandatoryDefaultEndpoint(), body, header, headerValue);
258        }
259    
260        public Object sendBodyAndProperty(Object body, String property, Object propertyValue) {
261            return sendBodyAndProperty(getMandatoryDefaultEndpoint(), body, property, propertyValue);
262        }    
263        
264        public Object sendBodyAndHeaders(Object body, Map<String, Object> headers) {
265            return sendBodyAndHeaders(getMandatoryDefaultEndpoint(), body, headers);
266        }
267    
268        // Properties
269        // -----------------------------------------------------------------------
270        public Producer getProducer(Endpoint endpoint) {
271            return producerCache.getProducer(endpoint);
272        }
273    
274        public CamelContext getContext() {
275            return context;
276        }
277    
278        public Endpoint getDefaultEndpoint() {
279            return defaultEndpoint;
280        }
281    
282        public void setDefaultEndpoint(Endpoint defaultEndpoint) {
283            this.defaultEndpoint = defaultEndpoint;
284        }
285    
286        /**
287         * Sets the default endpoint to use if none is specified
288         */
289        public void setDefaultEndpointUri(String endpointUri) {
290            setDefaultEndpoint(getContext().getEndpoint(endpointUri));
291        }
292    
293        public boolean isUseEndpointCache() {
294            return useEndpointCache;
295        }
296    
297        public void setUseEndpointCache(boolean useEndpointCache) {
298            this.useEndpointCache = useEndpointCache;
299        }
300    
301        public <T extends Endpoint> T getResolvedEndpoint(String endpointUri, Class<T> expectedClass) {
302            Endpoint e;
303            synchronized (endpointCache) {
304                e = endpointCache.get(endpointUri);
305            }
306            if (e != null && expectedClass.isAssignableFrom(e.getClass())) {
307                return expectedClass.asSubclass(expectedClass).cast(e);
308            }
309            return null;
310        }
311    
312        // Implementation methods
313        // -----------------------------------------------------------------------
314    
315        protected Processor createBodyAndHeaderProcessor(final Object body, final String header, final Object headerValue) {
316            return new Processor() {
317                public void process(Exchange exchange) {
318                    Message in = exchange.getIn();
319                    in.setHeader(header, headerValue);
320                    in.setBody(body);
321                }
322            };
323        }
324    
325        protected Processor createBodyAndPropertyProcessor(final Object body, final String property, final Object propertyValue) {
326            return new Processor() {
327                public void process(Exchange exchange) {
328                    exchange.setProperty(property, propertyValue);
329                    
330                    Message in = exchange.getIn();
331                    in.setBody(body);
332                }
333            };
334        }    
335        
336        protected Processor createSetBodyProcessor(final Object body) {
337            return new Processor() {
338                public void process(Exchange exchange) {
339                    Message in = exchange.getIn();
340                    in.setBody(body);
341                }
342            };
343        }
344    
345        protected Endpoint resolveMandatoryEndpoint(String endpointUri) {
346            Endpoint endpoint;
347    
348            if (isUseEndpointCache()) {
349                synchronized (endpointCache) {
350                    endpoint = endpointCache.get(endpointUri);
351                    if (endpoint == null) {
352                        endpoint = context.getEndpoint(endpointUri);
353                        if (endpoint != null) {
354                            endpointCache.put(endpointUri, endpoint);
355                        }
356                    }
357                }
358            } else {
359                endpoint = context.getEndpoint(endpointUri);
360            }
361            if (endpoint == null) {
362                throw new NoSuchEndpointException(endpointUri);
363            }
364            return endpoint;
365        }
366    
367        protected Endpoint getMandatoryDefaultEndpoint() {
368            Endpoint answer = getDefaultEndpoint();
369            ObjectHelper.notNull(answer, "defaultEndpoint");
370            return answer;
371        }
372    
373        protected void doStart() throws Exception {
374            producerCache.start();
375        }
376    
377        protected void doStop() throws Exception {
378            producerCache.stop();
379            endpointCache.clear();
380        }
381    
382        /**
383         * Extracts the body from the given result.
384         *
385         * @param result   the result
386         * @return  the result, can be <tt>null</tt>.
387         */
388        protected Object extractResultBody(Exchange result) {
389            return extractResultBody(result, null);
390        }
391    
392        /**
393         * Extracts the body from the given result.
394         * <p/>
395         * If the exchange pattern is provided it will try to honor it and retrive the body
396         * from either IN or OUT according to the pattern.
397         *
398         * @param result   the result
399         * @param pattern  exchange pattern if given, can be <tt>null</tt>
400         * @return  the result, can be <tt>null</tt>.
401         */
402        protected Object extractResultBody(Exchange result, ExchangePattern pattern) {
403            Object answer = null;
404            if (result != null) {
405                // rethrow if there was an exception
406                if (result.getException() != null) {
407                    throw wrapRuntimeCamelException(result.getException());
408                }
409    
410                // result could have a fault message
411                if (hasFaultMessage(result)) {
412                    return result.getFault().getBody();
413                }
414    
415                // okay no fault then return the response according to the pattern
416                // try to honor pattern if provided
417                boolean notOut = pattern != null && !pattern.isOutCapable();
418                boolean hasOut = result.getOut(false) != null;
419                if (hasOut && !notOut) {
420                    // we have a response in out and the pattern is out capable
421                    answer = result.getOut().getBody();
422                } else if (!hasOut && result.getPattern() == ExchangePattern.InOptionalOut) {
423                    // special case where the result is InOptionalOut and with no OUT response
424                    // so we should return null to indicate this fact
425                    answer = null;
426                } else {
427                    // use IN as the response
428                    answer = result.getIn().getBody();
429                }
430            }
431            return answer;
432        }
433    
434        protected boolean hasFaultMessage(Exchange result) {
435            Message faultMessage = result.getFault(false);
436            if (faultMessage != null) {
437                Object faultBody = faultMessage.getBody();
438                if (faultBody != null) {
439                    return true;
440                }
441            }
442            return false;
443        }
444    }