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.util;
018    
019    import java.util.HashMap;
020    import java.util.Map;
021    
022    import org.apache.camel.CamelContext;
023    import org.apache.camel.Endpoint;
024    import org.apache.camel.Exchange;
025    import org.apache.camel.ExchangePattern;
026    import org.apache.camel.InvalidPayloadException;
027    import org.apache.camel.InvalidTypeException;
028    import org.apache.camel.Message;
029    import org.apache.camel.NoSuchBeanException;
030    import org.apache.camel.NoSuchEndpointException;
031    import org.apache.camel.NoSuchHeaderException;
032    import org.apache.camel.NoSuchPropertyException;
033    import org.apache.camel.NoTypeConversionAvailableException;
034    import org.apache.camel.TypeConverter;
035    import org.apache.commons.logging.Log;
036    import org.apache.commons.logging.LogFactory;
037    
038    /**
039     * Some helper methods for working with {@link Exchange} objects
040     *
041     * @version $Revision: 752532 $
042     */
043    public final class ExchangeHelper {
044        private static final transient Log LOG = LogFactory.getLog(ExchangeHelper.class);
045    
046        /**
047         * Utility classes should not have a public constructor.
048         */
049        private ExchangeHelper() {
050        }
051    
052        /**
053         * Extracts the exchange property of the given name and type; if it is not present then the
054         * default value will be used
055         *
056         * @param exchange the message exchange
057         * @param propertyName the name of the property on the exchange
058         * @param type the expected type of the property
059         * @param defaultValue the default value to be used if the property name does not exist or could not be
060         * converted to the given type
061         * @return the property value as the given type or the defaultValue if it could not be found or converted
062         */
063        public static <T> T getExchangeProperty(Exchange exchange, String propertyName, Class<T> type, T defaultValue) {
064            T answer = exchange.getProperty(propertyName, type);
065            if (answer == null) {
066                return defaultValue;
067            }
068            return answer;
069        }
070    
071    
072        /**
073         * Attempts to resolve the endpoint for the given value
074         *
075         * @param exchange the message exchange being processed
076         * @param value the value which can be an {@link Endpoint} or an object
077         *                which provides a String representation of an endpoint via
078         *                {@link #toString()}
079         *
080         * @return the endpoint
081         * @throws NoSuchEndpointException if the endpoint cannot be resolved
082         */
083        @SuppressWarnings({"unchecked" })
084        public static Endpoint resolveEndpoint(Exchange exchange, Object value)
085            throws NoSuchEndpointException {
086            Endpoint endpoint;
087            if (value instanceof Endpoint) {
088                endpoint = (Endpoint)value;
089            } else {
090                String uri = value.toString();
091                endpoint = CamelContextHelper.getMandatoryEndpoint(exchange.getContext(), uri);
092            }
093            return endpoint;
094        }
095    
096        public static <T> T getMandatoryProperty(Exchange exchange, String propertyName, Class<T> type)
097            throws NoSuchPropertyException {
098            try {
099                T result = exchange.getProperty(propertyName, type);
100                if (result != null) {
101                    return result;
102                }
103            } catch (NoTypeConversionAvailableException ex) {
104                // will throw NoSuchPropertyException below
105            }
106            throw new NoSuchPropertyException(exchange, propertyName, type);
107        }
108    
109        public static <T> T getMandatoryHeader(Exchange exchange, String propertyName, Class<T> type)
110            throws NoSuchHeaderException {
111            T answer = exchange.getIn().getHeader(propertyName, type);
112            if (answer == null) {
113                throw new NoSuchHeaderException(exchange, propertyName, type);
114            }
115            return answer;
116        }
117    
118        /**
119         * Returns the mandatory inbound message body of the correct type or throws
120         * an exception if it is not present
121         */
122        public static Object getMandatoryInBody(Exchange exchange) throws InvalidPayloadException {
123            Object answer = exchange.getIn().getBody();
124            if (answer == null) {
125                throw new InvalidPayloadException(exchange, Object.class);
126            }
127            return answer;
128        }
129    
130        /**
131         * Returns the mandatory inbound message body of the correct type or throws
132         * an exception if it is not present
133         */
134        public static <T> T getMandatoryInBody(Exchange exchange, Class<T> type) throws InvalidPayloadException {
135            T answer = exchange.getIn().getBody(type);
136            if (answer == null) {
137                throw new InvalidPayloadException(exchange, type);
138            }
139            return answer;
140        }
141    
142        /**
143         * Returns the mandatory outbound message body of the correct type or throws
144         * an exception if it is not present
145         */
146        public static Object getMandatoryOutBody(Exchange exchange) throws InvalidPayloadException {
147            Message out = exchange.getOut();
148            Object answer = out.getBody();
149            if (answer == null) {
150                throw new InvalidPayloadException(exchange, Object.class, out);
151            }
152            return answer;
153        }
154    
155        /**
156         * Returns the mandatory outbound message body of the correct type or throws
157         * an exception if it is not present
158         */
159        public static <T> T getMandatoryOutBody(Exchange exchange, Class<T> type) throws InvalidPayloadException {
160            Message out = exchange.getOut();
161            T answer = out.getBody(type);
162            if (answer == null) {
163                throw new InvalidPayloadException(exchange, type, out);
164            }
165            return answer;
166        }
167    
168        /**
169         * Converts the value to the given expected type or throws an exception
170         */
171        public static <T> T convertToMandatoryType(Exchange exchange, Class<T> type, Object value)
172            throws InvalidTypeException {
173            T answer = convertToType(exchange, type, value);
174            if (answer == null) {
175                throw new InvalidTypeException(exchange, value, type);
176            }
177            return answer;
178        }
179    
180        /**
181         * Converts the value to the given expected type returning null if it could
182         * not be converted
183         */
184        public static <T> T convertToType(Exchange exchange, Class<T> type, Object value) {
185            CamelContext camelContext = exchange.getContext();
186            if (camelContext != null) {
187                TypeConverter converter = camelContext.getTypeConverter();
188                if (converter != null) {
189                    return converter.convertTo(type, exchange, value);
190                }
191            }
192            LOG.warn("No CamelContext and type converter available to convert types for exchange " + exchange);
193    
194            if (type.isInstance(value)) {
195                return type.cast(value);
196            }
197            return null;
198        }
199    
200        /**
201         * Copies the results of a message exchange from the source exchange to the result exchange
202         * which will copy the out and fault message contents and the exception
203         *
204         * @param result the result exchange which will have the output and error state added
205         * @param source the source exchange which is not modified
206         */
207        public static void copyResults(Exchange result, Exchange source) {
208    
209            // --------------------------------------------------------------------
210            //  TODO: merge logic with that of copyResultsPreservePattern()
211            // --------------------------------------------------------------------
212            
213            if (result != source) {
214                result.setException(source.getException());
215                Message fault = source.getFault(false);
216                if (fault != null) {
217                    result.getFault(true).copyFrom(fault);
218                }
219    
220                Message out = source.getOut(false);
221                if (out != null) {
222                    result.getOut(true).copyFrom(out);
223                } else if (result.getPattern() == ExchangePattern.InOptionalOut) {
224                    // special case where the result is InOptionalOut and with no OUT response
225                    // so we should return null to indicate this fact
226                    result.setOut(null);
227                } else {
228                    // no results so lets copy the last input
229                    // as the final processor on a pipeline might not
230                    // have created any OUT; such as a mock:endpoint
231                    // so lets assume the last IN is the OUT
232                    if (result.getPattern().isOutCapable()) {
233                        // only set OUT if its OUT capable
234                        result.getOut(true).copyFrom(source.getIn());
235                    } else {
236                        // if not replace IN instead to keep the MEP
237                        result.getIn().copyFrom(source.getIn());
238                    }
239                }
240                result.getProperties().clear();
241                result.getProperties().putAll(source.getProperties());
242            }
243        }
244    
245        /**
246         * Copies the <code>source</code> exchange to <code>target</code> exchange
247         * preserving the {@link ExchangePattern} of <code>target</code>.  
248         * 
249         * @param source source exchange.
250         * @param result target exchange.
251         */
252        public static void copyResultsPreservePattern(Exchange result, Exchange source) {
253    
254            // --------------------------------------------------------------------
255            //  TODO: merge logic with that of copyResults()
256            // --------------------------------------------------------------------
257            
258            if (source == result) {
259                // no need to copy
260                return;
261            }
262            
263            // copy in message
264            Message m = source.getIn();
265            result.getIn().copyFrom(m);
266        
267            // copy out message
268            m = source.getOut(false);
269            if (m != null) {
270                // exchange pattern sensitive
271                getResultMessage(result).copyFrom(m);
272            }
273            
274            // copy fault message
275            m = source.getFault(false);
276            if (m != null) {
277                result.getFault().copyFrom(m);
278            }
279            
280            // copy exception
281            result.setException(source.getException());
282            
283            // copy properties
284            result.getProperties().clear();
285            result.getProperties().putAll(source.getProperties());
286        }
287    
288        /**
289         * Returns the message where to write results in an
290         * exchange-pattern-sensitive way.
291         * 
292         * @param exchange
293         *            message exchange.
294         * @return result message.
295         */
296        public static Message getResultMessage(Exchange exchange) {
297            if (exchange.getPattern().isOutCapable()) {
298                return exchange.getOut();
299            } else {
300                return exchange.getIn();
301            }
302        }
303    
304        /**
305         * Returns true if the given exchange pattern (if defined) can support IN messagea
306         *
307         * @param exchange the exchange to interrogate
308         * @return true if the exchange is defined as an {@link ExchangePattern} which supports
309         * IN messages
310         */
311        public static boolean isInCapable(Exchange exchange) {
312            ExchangePattern pattern = exchange.getPattern();
313            return pattern != null && pattern.isInCapable();
314        }
315    
316        /**
317         * Returns true if the given exchange pattern (if defined) can support OUT messagea
318         *
319         * @param exchange the exchange to interrogate
320         * @return true if the exchange is defined as an {@link ExchangePattern} which supports
321         * OUT messages
322         */
323        public static boolean isOutCapable(Exchange exchange) {
324            ExchangePattern pattern = exchange.getPattern();
325            return pattern != null && pattern.isOutCapable();
326        }
327    
328        /**
329         * Creates a new instance of the given type from the injector
330         */
331        public static <T> T newInstance(Exchange exchange, Class<T> type) {
332            return exchange.getContext().getInjector().newInstance(type);
333        }
334    
335        /**
336         * Creates a Map of the variables which are made available to a script or template
337         *
338         * @param exchange the exchange to make available
339         * @return a Map populated with the require dvariables
340         */
341        public static Map createVariableMap(Exchange exchange) {
342            Map answer = new HashMap();
343            populateVariableMap(exchange, answer);
344            return answer;
345        }
346    
347        /**
348         * Populates the Map with the variables which are made available to a script or template
349         *
350         * @param exchange the exchange to make available
351         * @param map      the map to populate
352         */
353        @SuppressWarnings("unchecked")
354        public static void populateVariableMap(Exchange exchange, Map map) {
355            map.put("exchange", exchange);
356            Message in = exchange.getIn();
357            map.put("in", in);
358            map.put("request", in);
359            map.put("headers", in.getHeaders());
360            map.put("body", in.getBody());
361            if (isOutCapable(exchange)) {
362                Message out = exchange.getOut(true);
363                map.put("out", out);
364                map.put("response", out);
365            }
366            map.put("camelContext", exchange.getContext());
367        }
368    
369        /**
370         * Returns the MIME content type on the input message or null if one is not defined
371         */
372        public static String getContentType(Exchange exchange) {
373            return exchange.getIn().getHeader("Content-Type", String.class);
374        }
375    
376        /**
377         * Performs a lookup in the registry of the mandatory bean name and throws an exception if it could not be found
378         */
379        public static Object lookupMandatoryBean(Exchange exchange, String name) {
380            Object value = lookupBean(exchange, name);
381            if (value == null) {
382                throw new NoSuchBeanException(name);
383            }
384            return value;
385        }
386    
387        /**
388         * Performs a lookup in the registry of the mandatory bean name and throws an exception if it could not be found
389         */
390        public static <T> T lookupMandatoryBean(Exchange exchange, String name, Class<T> type) {
391            T value = lookupBean(exchange, name, type);
392            if (value == null) {
393                throw new NoSuchBeanException(name);
394            }
395            return value;
396        }
397    
398        /**
399         * Performs a lookup in the registry of the bean name
400         */
401        public static Object lookupBean(Exchange exchange, String name) {
402            return exchange.getContext().getRegistry().lookup(name);
403        }
404    
405        /**
406         * Performs a lookup in the registry of the bean name and type
407         */
408        public static <T> T lookupBean(Exchange exchange, String name, Class<T> type) {
409            return exchange.getContext().getRegistry().lookup(name, type);
410        }
411    
412        /**
413         * Returns the first exchange in the given collection of exchanges which has the same exchange ID as the one given
414         * or null if none could be found
415         */
416        public static Exchange getExchangeById(Iterable<Exchange> exchanges, String exchangeId) {
417            for (Exchange exchange : exchanges) {
418                String id = exchange.getExchangeId();
419                if (id != null && id.equals(exchangeId)) {
420                    return exchange;
421                }
422            }
423            return null;
424        }
425    
426        public static boolean isFailureHandled(Exchange exchange) {
427            Boolean handled = exchange.getProperty(Exchange.FAILURE_HANDLED, Boolean.class);
428            return handled != null && handled;
429        }
430    
431        public static void setFailureHandled(Exchange exchange) {
432            exchange.setProperty(Exchange.FAILURE_HANDLED, Boolean.TRUE);
433            // clear exception since its failure handled
434            exchange.setException(null);
435        }
436    
437    }