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.Endpoint;
023    import org.apache.camel.Exchange;
024    import org.apache.camel.ExchangePattern;
025    import org.apache.camel.InvalidPayloadException;
026    import org.apache.camel.InvalidTypeException;
027    import org.apache.camel.Message;
028    import org.apache.camel.NoSuchBeanException;
029    import org.apache.camel.NoSuchEndpointException;
030    import org.apache.camel.NoSuchHeaderException;
031    import org.apache.camel.NoSuchPropertyException;
032    import org.apache.camel.NoTypeConversionAvailableException;
033    
034    /**
035     * Some helper methods for working with {@link Exchange} objects
036     *
037     * @version $Revision: 2184 $
038     */
039    public final class ExchangeHelper {
040    
041        /**
042         * Utility classes should not have a public constructor.
043         */
044        private ExchangeHelper() {
045        }
046    
047        /**
048         * Extracts the exchange property of the given name and type; if it is not present then the
049         * default value will be used
050         *
051         * @param exchange the message exchange
052         * @param propertyName the name of the property on the exchange
053         * @param type the expected type of the property
054         * @param defaultValue the default value to be used if the property name does not exist or could not be
055         * converted to the given type
056         * @return the property value as the given type or the defaultValue if it could not be found or converted
057         */
058        public static <T> T getExchangeProperty(Exchange exchange, String propertyName, Class<T> type, T defaultValue) {
059            T answer = exchange.getProperty(propertyName, type);
060            if (answer == null) {
061                return defaultValue;
062            }
063            return answer;
064        }
065    
066    
067        /**
068         * Attempts to resolve the endpoint for the given value
069         *
070         * @param exchange the message exchange being processed
071         * @param value the value which can be an {@link Endpoint} or an object
072         *                which provides a String representation of an endpoint via
073         *                {@link #toString()}
074         *
075         * @return the endpoint
076         * @throws NoSuchEndpointException if the endpoint cannot be resolved
077         */
078        @SuppressWarnings({"unchecked" })
079        public static <E extends Exchange> Endpoint<E> resolveEndpoint(E exchange, Object value)
080            throws NoSuchEndpointException {
081            Endpoint<E> endpoint;
082            if (value instanceof Endpoint) {
083                endpoint = (Endpoint<E>)value;
084            } else {
085                String uri = value.toString();
086                endpoint = CamelContextHelper.getMandatoryEndpoint(exchange.getContext(), uri);
087            }
088            return endpoint;
089        }
090    
091        public static <T> T getMandatoryProperty(Exchange exchange, String propertyName, Class<T> type)
092            throws NoSuchPropertyException {
093            try {
094                T result = exchange.getProperty(propertyName, type);
095                if (result != null) {
096                    return result;
097                }
098            } catch (NoTypeConversionAvailableException ex) {
099                // will throw NoSuchPropertyException below
100            }
101            throw new NoSuchPropertyException(exchange, propertyName, type);
102        }
103    
104        public static <T> T getMandatoryHeader(Exchange exchange, String propertyName, Class<T> type)
105            throws NoSuchHeaderException {
106            T answer = exchange.getIn().getHeader(propertyName, type);
107            if (answer == null) {
108                throw new NoSuchHeaderException(exchange, propertyName, type);
109            }
110            return answer;
111        }
112    
113        /**
114         * Returns the mandatory inbound message body of the correct type or throws
115         * an exception if it is not present
116         */
117        public static Object getMandatoryInBody(Exchange exchange) throws InvalidPayloadException {
118            Object answer = exchange.getIn().getBody();
119            if (answer == null) {
120                throw new InvalidPayloadException(exchange, Object.class);
121            }
122            return answer;
123        }
124    
125        /**
126         * Returns the mandatory inbound message body of the correct type or throws
127         * an exception if it is not present
128         */
129        public static <T> T getMandatoryInBody(Exchange exchange, Class<T> type) throws InvalidPayloadException {
130            T answer = exchange.getIn().getBody(type);
131            if (answer == null) {
132                throw new InvalidPayloadException(exchange, type);
133            }
134            return answer;
135        }
136    
137        /**
138         * Returns the mandatory outbound message body of the correct type or throws
139         * an exception if it is not present
140         */
141        public static Object getMandatoryOutBody(Exchange exchange) throws InvalidPayloadException {
142            Message out = exchange.getOut();
143            Object answer = out.getBody();
144            if (answer == null) {
145                throw new InvalidPayloadException(exchange, Object.class, out);
146            }
147            return answer;
148        }
149    
150        /**
151         * Returns the mandatory outbound message body of the correct type or throws
152         * an exception if it is not present
153         */
154        public static <T> T getMandatoryOutBody(Exchange exchange, Class<T> type) throws InvalidPayloadException {
155            Message out = exchange.getOut();
156            T answer = out.getBody(type);
157            if (answer == null) {
158                throw new InvalidPayloadException(exchange, type, out);
159            }
160            return answer;
161        }
162    
163        /**
164         * Converts the value to the given expected type or throws an exception
165         */
166        public static <T> T convertToMandatoryType(Exchange exchange, Class<T> type, Object value)
167            throws InvalidTypeException {
168            T answer = convertToType(exchange, type, value);
169            if (answer == null) {
170                throw new InvalidTypeException(exchange, value, type);
171            }
172            return answer;
173        }
174    
175        /**
176         * Converts the value to the given expected type returning null if it could
177         * not be converted
178         */
179        public static <T> T convertToType(Exchange exchange, Class<T> type, Object value) {
180            return exchange.getContext().getTypeConverter().convertTo(type, exchange, value);
181        }
182    
183        /**
184         * Copies the results of a message exchange from the source exchange to the result exchange
185         * which will copy the out and fault message contents and the exception
186         *
187         * @param result the result exchange which will have the output and error state added
188         * @param source the source exchange which is not modified
189         */
190        public static void copyResults(Exchange result, Exchange source) {
191            if (result != source) {
192                result.setException(source.getException());
193                Message fault = source.getFault(false);
194                if (fault != null) {
195                    result.getFault(true).copyFrom(fault);
196                }
197    
198                Message out = source.getOut(false);
199                if (out != null) {
200                    result.getOut(true).copyFrom(out);
201                } else {
202                    // no results so lets copy the last input
203                    // as the final processor on a pipeline might not
204                    // have created any OUT; such as a mock:endpoint
205                    // so lets assume the last IN is the OUT
206                    if (result.getPattern().isOutCapable()) {
207                        // only set OUT if its OUT capable
208                        result.getOut(true).copyFrom(source.getIn());
209                    } else {
210                        // if not replace IN instead to keep the MEP
211                        result.getIn().copyFrom(source.getIn());
212                    }
213                }
214                result.getProperties().clear();
215                result.getProperties().putAll(source.getProperties());
216            }
217        }
218    
219        /**
220         * Returns true if the given exchange pattern (if defined) can support IN messagea
221         *
222         * @param exchange the exchange to interrogate
223         * @return true if the exchange is defined as an {@link ExchangePattern} which supports
224         * IN messages
225         */
226        public static boolean isInCapable(Exchange exchange) {
227            ExchangePattern pattern = exchange.getPattern();
228            return pattern != null && pattern.isInCapable();
229        }
230    
231        /**
232         * Returns true if the given exchange pattern (if defined) can support OUT messagea
233         *
234         * @param exchange the exchange to interrogate
235         * @return true if the exchange is defined as an {@link ExchangePattern} which supports
236         * OUT messages
237         */
238        public static boolean isOutCapable(Exchange exchange) {
239            ExchangePattern pattern = exchange.getPattern();
240            return pattern != null && pattern.isOutCapable();
241        }
242    
243        /**
244         * Creates a new instance of the given type from the injector
245         */
246        public static <T> T newInstance(Exchange exchange, Class<T> type) {
247            return exchange.getContext().getInjector().newInstance(type);
248        }
249    
250        /**
251         * Creates a Map of the variables which are made available to a script or template
252         *
253         * @param exchange the exchange to make available
254         * @return a Map populated with the require dvariables
255         */
256        public static Map createVariableMap(Exchange exchange) {
257            Map answer = new HashMap();
258            populateVariableMap(exchange, answer);
259            return answer;
260        }
261    
262        /**
263         * Populates the Map with the variables which are made available to a script or template
264         *
265         * @param exchange the exchange to make available
266         * @param map      the map to populate
267         */
268        public static void populateVariableMap(Exchange exchange, Map map) {
269            map.put("exchange", exchange);
270            Message in = exchange.getIn();
271            map.put("in", in);
272            map.put("request", in);
273            map.put("headers", in.getHeaders());
274            map.put("body", in.getBody());
275            if (isOutCapable(exchange)) {
276                Message out = exchange.getOut(true);
277                map.put("out", out);
278                map.put("response", out);
279            }
280            map.put("camelContext", exchange.getContext());
281        }
282    
283        /**
284         * Returns the MIME content type on the input message or null if one is not defined
285         */
286        public static String getContentType(Exchange exchange) {
287            return exchange.getIn().getHeader("Content-Type", String.class);
288        }
289    
290        /**
291         * Performs a lookup in the registry of the mandatory bean name and throws an exception if it could not be found
292         */
293        public static Object lookupMandatoryBean(Exchange exchange, String name) {
294            Object value = lookupBean(exchange, name);
295            if (value == null) {
296                throw new NoSuchBeanException(name);
297            }
298            return value;
299        }
300    
301        /**
302         * Performs a lookup in the registry of the mandatory bean name and throws an exception if it could not be found
303         */
304        public static <T> T lookupMandatoryBean(Exchange exchange, String name, Class<T> type) {
305            T value = lookupBean(exchange, name, type);
306            if (value == null) {
307                throw new NoSuchBeanException(name);
308            }
309            return value;
310        }
311    
312        /**
313         * Performs a lookup in the registry of the bean name
314         */
315        public static Object lookupBean(Exchange exchange, String name) {
316            return exchange.getContext().getRegistry().lookup(name);
317        }
318    
319        /**
320         * Performs a lookup in the registry of the bean name and type
321         */
322        public static <T> T lookupBean(Exchange exchange, String name, Class<T> type) {
323            return exchange.getContext().getRegistry().lookup(name, type);
324        }
325    }