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.List;
020    
021    import org.apache.camel.CamelContext;
022    import org.apache.camel.ConsumerTemplate;
023    import org.apache.camel.Endpoint;
024    import org.apache.camel.Exchange;
025    import org.apache.camel.spi.Synchronization;
026    import org.apache.camel.support.ServiceSupport;
027    import org.apache.camel.util.CamelContextHelper;
028    import org.apache.camel.util.ServiceHelper;
029    import org.apache.camel.util.UnitOfWorkHelper;
030    import org.slf4j.Logger;
031    import org.slf4j.LoggerFactory;
032    
033    import static org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException;
034    
035    /**
036     * Template (named like Spring's TransactionTemplate & JmsTemplate
037     * et al) for working with Camel and consuming {@link org.apache.camel.Message} instances in an
038     * {@link Exchange} from an {@link Endpoint}.
039     *
040     * @version 
041     */
042    public class DefaultConsumerTemplate extends ServiceSupport implements ConsumerTemplate {
043    
044        private static final transient Logger LOG = LoggerFactory.getLogger(DefaultConsumerTemplate.class);
045        private final CamelContext context;
046        private ConsumerCache consumerCache;
047        private int maximumCacheSize;
048    
049        public DefaultConsumerTemplate(CamelContext context) {
050            this.context = context;
051        }
052    
053        public int getMaximumCacheSize() {
054            return maximumCacheSize;
055        }
056    
057        public void setMaximumCacheSize(int maximumCacheSize) {
058            this.maximumCacheSize = maximumCacheSize;
059        }
060    
061        public int getCurrentCacheSize() {
062            if (consumerCache == null) {
063                return 0;
064            }
065            return consumerCache.size();
066        }
067    
068        public CamelContext getCamelContext() {
069            return context;
070        }
071    
072        public Exchange receive(String endpointUri) {
073            Endpoint endpoint = resolveMandatoryEndpoint(endpointUri);
074            return getConsumerCache().receive(endpoint);
075        }
076    
077        public Exchange receive(Endpoint endpoint) {
078            return receive(endpoint.getEndpointUri());
079        }
080    
081        public Exchange receive(String endpointUri, long timeout) {
082            Endpoint endpoint = resolveMandatoryEndpoint(endpointUri);
083            return getConsumerCache().receive(endpoint, timeout);
084        }
085    
086        public Exchange receive(Endpoint endpoint, long timeout) {
087            return receive(endpoint.getEndpointUri(), timeout);
088        }
089    
090        public Exchange receiveNoWait(String endpointUri) {
091            Endpoint endpoint = resolveMandatoryEndpoint(endpointUri);
092            return getConsumerCache().receiveNoWait(endpoint);
093        }
094    
095        public Exchange receiveNoWait(Endpoint endpoint) {
096            return receiveNoWait(endpoint.getEndpointUri());
097        }
098    
099        public Object receiveBody(String endpointUri) {
100            Object answer = null;
101            Exchange exchange = receive(endpointUri);
102            try {
103                answer = extractResultBody(exchange);
104            } finally {
105                doneUoW(exchange);
106            }
107            return answer;
108        }
109    
110        public Object receiveBody(Endpoint endpoint) {
111            return receiveBody(endpoint.getEndpointUri());
112        }
113    
114        public Object receiveBody(String endpointUri, long timeout) {
115            Object answer = null;
116            Exchange exchange = receive(endpointUri, timeout);
117            try {
118                answer = extractResultBody(exchange);
119            } finally {
120                doneUoW(exchange);
121            }
122            return answer;
123        }
124    
125        public Object receiveBody(Endpoint endpoint, long timeout) {
126            return receiveBody(endpoint.getEndpointUri(), timeout);
127        }
128    
129        public Object receiveBodyNoWait(String endpointUri) {
130            Object answer = null;
131            Exchange exchange = receiveNoWait(endpointUri);
132            try {
133                answer = extractResultBody(exchange);
134            } finally {
135                doneUoW(exchange);
136            }
137            return answer;
138        }
139    
140        public Object receiveBodyNoWait(Endpoint endpoint) {
141            return receiveBodyNoWait(endpoint.getEndpointUri());
142        }
143    
144        @SuppressWarnings("unchecked")
145        public <T> T receiveBody(String endpointUri, Class<T> type) {
146            Object answer = null;
147            Exchange exchange = receive(endpointUri);
148            try {
149                answer = extractResultBody(exchange);
150                answer = context.getTypeConverter().convertTo(type, answer);
151            } finally {
152                doneUoW(exchange);
153            }
154            return (T) answer;
155        }
156    
157        public <T> T receiveBody(Endpoint endpoint, Class<T> type) {
158            return receiveBody(endpoint.getEndpointUri(), type);
159        }
160    
161        @SuppressWarnings("unchecked")
162        public <T> T receiveBody(String endpointUri, long timeout, Class<T> type) {
163            Object answer = null;
164            Exchange exchange = receive(endpointUri, timeout);
165            try {
166                answer = extractResultBody(exchange);
167                answer = context.getTypeConverter().convertTo(type, answer);
168            } finally {
169                doneUoW(exchange);
170            }
171            return (T) answer;
172        }
173    
174        public <T> T receiveBody(Endpoint endpoint, long timeout, Class<T> type) {
175            return receiveBody(endpoint.getEndpointUri(), timeout, type);
176        }
177    
178        @SuppressWarnings("unchecked")
179        public <T> T receiveBodyNoWait(String endpointUri, Class<T> type) {
180            Object answer = null;
181            Exchange exchange = receiveNoWait(endpointUri);
182            try {
183                answer = extractResultBody(exchange);
184                answer = context.getTypeConverter().convertTo(type, answer);
185            } finally {
186                doneUoW(exchange);
187            }
188            return (T) answer;
189        }
190    
191        public <T> T receiveBodyNoWait(Endpoint endpoint, Class<T> type) {
192            return receiveBodyNoWait(endpoint.getEndpointUri(), type);
193        }
194    
195        public void doneUoW(Exchange exchange) {
196            try {
197                // The receiveBody method will get a null exchange
198                if (exchange == null) {
199                    return;
200                }
201                if (exchange.getUnitOfWork() == null) {
202                    // handover completions and done them manually to ensure they are being executed
203                    List<Synchronization> synchronizations = exchange.handoverCompletions();
204                    UnitOfWorkHelper.doneSynchronizations(exchange, synchronizations, LOG);
205                } else {
206                    // done the unit of work
207                    exchange.getUnitOfWork().done(exchange);
208                }
209            } catch (Throwable e) {
210                LOG.warn("Exception occurred during done UnitOfWork for Exchange: " + exchange
211                        + ". This exception will be ignored.", e);
212            }
213        }
214    
215        protected Endpoint resolveMandatoryEndpoint(String endpointUri) {
216            return CamelContextHelper.getMandatoryEndpoint(context, endpointUri);
217        }
218    
219        /**
220         * Extracts the body from the given result.
221         * <p/>
222         * If the exchange pattern is provided it will try to honor it and retrieve the body
223         * from either IN or OUT according to the pattern.
224         *
225         * @param result   the result
226         * @return  the result, can be <tt>null</tt>.
227         */
228        protected Object extractResultBody(Exchange result) {
229            Object answer = null;
230            if (result != null) {
231                // rethrow if there was an exception
232                if (result.getException() != null) {
233                    throw wrapRuntimeCamelException(result.getException());
234                }
235    
236                // okay no fault then return the response
237                if (result.hasOut()) {
238                    // use OUT as the response
239                    answer = result.getOut().getBody();
240                } else {
241                    // use IN as the response
242                    answer = result.getIn().getBody();
243                }
244            }
245            return answer;
246        }
247    
248        private ConsumerCache getConsumerCache() {
249            if (!isStarted()) {
250                throw new IllegalStateException("ConsumerTemplate has not been started");
251            }
252            return consumerCache;
253        }
254    
255        protected void doStart() throws Exception {
256            if (consumerCache == null) {
257                if (maximumCacheSize > 0) {
258                    consumerCache = new ConsumerCache(this, context, maximumCacheSize);
259                } else {
260                    consumerCache = new ConsumerCache(this, context);
261                }
262            }
263            ServiceHelper.startService(consumerCache);
264        }
265    
266        protected void doStop() throws Exception {
267            // we should shutdown the services as this is our intention, to not re-use the services anymore
268            ServiceHelper.stopAndShutdownService(consumerCache);
269            consumerCache = null;
270        }
271    
272    }