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.io.IOException;
020    import java.net.URL;
021    import java.util.Enumeration;
022    import java.util.Locale;
023    import java.util.Map;
024    import java.util.Properties;
025    import java.util.Set;
026    import java.util.SortedMap;
027    import java.util.StringTokenizer;
028    import java.util.TreeMap;
029    
030    import org.apache.camel.CamelContext;
031    import org.apache.camel.Component;
032    import org.apache.camel.Endpoint;
033    import org.apache.camel.Exchange;
034    import org.apache.camel.NoSuchBeanException;
035    import org.apache.camel.NoSuchEndpointException;
036    
037    import static org.apache.camel.util.ObjectHelper.isEmpty;
038    import static org.apache.camel.util.ObjectHelper.isNotEmpty;
039    import static org.apache.camel.util.ObjectHelper.notNull;
040    
041    /**
042     * A number of helper methods
043     *
044     * @version 
045     */
046    public final class CamelContextHelper {
047        public static final String COMPONENT_DESCRIPTOR = "META-INF/services/org/apache/camel/component.properties";
048    
049        /**
050         * Utility classes should not have a public constructor.
051         */
052        private CamelContextHelper() {
053        }
054    
055        /**
056         * Returns the mandatory endpoint for the given URI or the
057         * {@link org.apache.camel.NoSuchEndpointException} is thrown
058         */
059        public static Endpoint getMandatoryEndpoint(CamelContext camelContext, String uri)
060            throws NoSuchEndpointException {
061            Endpoint endpoint = camelContext.getEndpoint(uri);
062            if (endpoint == null) {
063                throw new NoSuchEndpointException(uri);
064            } else {
065                return endpoint;
066            }
067        }
068    
069        /**
070         * Returns the mandatory endpoint for the given URI and type or the
071         * {@link org.apache.camel.NoSuchEndpointException} is thrown
072         */
073        public static <T extends Endpoint> T getMandatoryEndpoint(CamelContext camelContext, String uri, Class<T> type) {
074            Endpoint endpoint = getMandatoryEndpoint(camelContext, uri);
075            return ObjectHelper.cast(type, endpoint);
076        }
077    
078        /**
079         * Converts the given value to the requested type
080         */
081        public static <T> T convertTo(CamelContext context, Class<T> type, Object value) {
082            notNull(context, "camelContext");
083            return context.getTypeConverter().convertTo(type, value);
084        }
085    
086        /**
087         * Converts the given value to the specified type throwing an {@link IllegalArgumentException}
088         * if the value could not be converted to a non null value
089         */
090        public static <T> T mandatoryConvertTo(CamelContext context, Class<T> type, Object value) {
091            T answer = convertTo(context, type, value);
092            if (answer == null) {
093                throw new IllegalArgumentException("Value " + value + " converted to " + type.getName() + " cannot be null");
094            }
095            return answer;
096        }
097    
098        /**
099         * Creates a new instance of the given type using the {@link org.apache.camel.spi.Injector} on the given
100         * {@link CamelContext}
101         */
102        public static <T> T newInstance(CamelContext context, Class<T> beanType) {
103            return context.getInjector().newInstance(beanType);
104        }
105    
106        /**
107         * Look up the given named bean in the {@link org.apache.camel.spi.Registry} on the
108         * {@link CamelContext}
109         */
110        public static Object lookup(CamelContext context, String name) {
111            return context.getRegistry().lookup(name);
112        }
113    
114        /**
115         * Look up the given named bean of the given type in the {@link org.apache.camel.spi.Registry} on the
116         * {@link CamelContext}
117         */
118        public static <T> T lookup(CamelContext context, String name, Class<T> beanType) {
119            return context.getRegistry().lookup(name, beanType);
120        }
121    
122        /**
123         * Look up the given named bean in the {@link org.apache.camel.spi.Registry} on the
124         * {@link CamelContext} or throws {@link NoSuchBeanException} if not found.
125         */
126        public static Object mandatoryLookup(CamelContext context, String name) {
127            Object answer = lookup(context, name);
128            if (answer == null) {
129                throw new NoSuchBeanException(name);
130            }
131            return answer;
132        }
133    
134        /**
135         * Look up the given named bean of the given type in the {@link org.apache.camel.spi.Registry} on the
136         * {@link CamelContext} or throws NoSuchBeanException if not found.
137         */
138        public static <T> T mandatoryLookup(CamelContext context, String name, Class<T> beanType) {
139            T answer = lookup(context, name, beanType);
140            if (answer == null) {
141                throw new NoSuchBeanException(name, beanType.getName());
142            }
143            return answer;
144        }
145    
146        /**
147         * Evaluates the @EndpointInject annotation using the given context
148         */
149        public static Endpoint getEndpointInjection(CamelContext camelContext, String uri, String ref, String injectionPointName, boolean mandatory) {
150            if (ObjectHelper.isNotEmpty(uri) && ObjectHelper.isNotEmpty(ref)) {
151                throw new IllegalArgumentException("Both uri and name is provided, only either one is allowed: uri=" + uri + ", ref=" + ref);
152            }
153    
154            Endpoint endpoint;
155            if (isNotEmpty(uri)) {
156                endpoint = camelContext.getEndpoint(uri);
157            } else {
158                // if a ref is given then it should be possible to lookup
159                // otherwise we do not catch situations where there is a typo etc
160                if (isNotEmpty(ref)) {
161                    endpoint = mandatoryLookup(camelContext, ref, Endpoint.class);
162                } else {
163                    if (isEmpty(ref)) {
164                        ref = injectionPointName;
165                    }
166                    if (mandatory) {
167                        endpoint = mandatoryLookup(camelContext, ref, Endpoint.class);
168                    } else {
169                        endpoint = lookup(camelContext, ref, Endpoint.class);
170                    }
171                }
172            }
173            return endpoint;
174        }
175    
176        /**
177         * Gets the maximum cache pool size.
178         * <p/>
179         * Will use the property set on CamelContext with the key {@link Exchange#MAXIMUM_CACHE_POOL_SIZE}.
180         * If no property has been set, then it will fallback to return a size of 1000.
181         *
182         * @param camelContext the camel context
183         * @return the maximum cache size
184         * @throws IllegalArgumentException is thrown if the property is illegal
185         */
186        public static int getMaximumCachePoolSize(CamelContext camelContext) throws IllegalArgumentException {
187            if (camelContext != null) {
188                String s = camelContext.getProperties().get(Exchange.MAXIMUM_CACHE_POOL_SIZE);
189                if (s != null) {
190                    try {
191                        // we cannot use Camel type converters as they may not be ready this early
192                        Integer size = Integer.valueOf(s);
193                        if (size == null || size <= 0) {
194                            throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_CACHE_POOL_SIZE + " must be a positive number, was: " + s);
195                        }
196                        return size;
197                    } catch (NumberFormatException e) {
198                        throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_CACHE_POOL_SIZE + " must be a positive number, was: " + s, e);
199                    }
200                }
201            }
202    
203            // 1000 is the default fallback
204            return 1000;
205        }
206    
207        /**
208         * Gets the maximum endpoint cache size.
209         * <p/>
210         * Will use the property set on CamelContext with the key {@link Exchange#MAXIMUM_ENDPOINT_CACHE_SIZE}.
211         * If no property has been set, then it will fallback to return a size of 1000.
212         *
213         * @param camelContext the camel context
214         * @return the maximum cache size
215         * @throws IllegalArgumentException is thrown if the property is illegal
216         */
217        public static int getMaximumEndpointCacheSize(CamelContext camelContext) throws IllegalArgumentException {
218            if (camelContext != null) {
219                String s = camelContext.getProperties().get(Exchange.MAXIMUM_ENDPOINT_CACHE_SIZE);
220                if (s != null) {
221                    // we cannot use Camel type converters as they may not be ready this early
222                    try {
223                        Integer size = Integer.valueOf(s);
224                        if (size == null || size <= 0) {
225                            throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_ENDPOINT_CACHE_SIZE + " must be a positive number, was: " + s);
226                        }
227                        return size;
228                    } catch (NumberFormatException e) {
229                        throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_ENDPOINT_CACHE_SIZE + " must be a positive number, was: " + s, e);
230                    }
231                }
232            }
233    
234            // 1000 is the default fallback
235            return 1000;
236        }
237    
238        /**
239         * Parses the given text and handling property placeholders as well
240         *
241         * @param camelContext the camel context
242         * @param text  the text
243         * @return the parsed text, or <tt>null</tt> if the text was <tt>null</tt>
244         * @throws Exception is thrown if illegal argument
245         */
246        public static String parseText(CamelContext camelContext, String text) throws Exception {
247            // ensure we support property placeholders
248            return camelContext.resolvePropertyPlaceholders(text);
249        }
250    
251        /**
252         * Parses the given text and converts it to an Integer and handling property placeholders as well
253         *
254         * @param camelContext the camel context
255         * @param text  the text
256         * @return the integer vale, or <tt>null</tt> if the text was <tt>null</tt>
257         * @throws Exception is thrown if illegal argument or type conversion not possible
258         */
259        public static Integer parseInteger(CamelContext camelContext, String text) throws Exception {
260            // ensure we support property placeholders
261            String s = camelContext.resolvePropertyPlaceholders(text);
262            if (s != null) {
263                try {
264                    return camelContext.getTypeConverter().mandatoryConvertTo(Integer.class, s);
265                } catch (NumberFormatException e) {
266                    if (s.equals(text)) {
267                        throw new IllegalArgumentException("Error parsing [" + s + "] as an Integer.", e);
268                    } else {
269                        throw new IllegalArgumentException("Error parsing [" + s + "] from property " + text + " as an Integer.", e);
270                    }
271                }
272            }
273            return null;
274        }
275    
276        /**
277         * Parses the given text and converts it to an Long and handling property placeholders as well
278         *
279         * @param camelContext the camel context
280         * @param text  the text
281         * @return the long vale, or <tt>null</tt> if the text was <tt>null</tt>
282         * @throws Exception is thrown if illegal argument or type conversion not possible
283         */
284        public static Long parseLong(CamelContext camelContext, String text) throws Exception {
285            // ensure we support property placeholders
286            String s = camelContext.resolvePropertyPlaceholders(text);
287            if (s != null) {
288                try {
289                    return camelContext.getTypeConverter().mandatoryConvertTo(Long.class, s);
290                } catch (NumberFormatException e) {
291                    if (s.equals(text)) {
292                        throw new IllegalArgumentException("Error parsing [" + s + "] as a Long.", e);
293                    } else {
294                        throw new IllegalArgumentException("Error parsing [" + s + "] from property " + text + " as a Long.", e);
295                    }
296                }
297            }
298            return null;
299        }
300    
301        /**
302         * Parses the given text and converts it to a Double and handling property placeholders as well
303         *
304         * @param camelContext the camel context
305         * @param text  the text
306         * @return the double vale, or <tt>null</tt> if the text was <tt>null</tt>
307         * @throws Exception is thrown if illegal argument or type conversion not possible
308         */
309        public static Double parseDouble(CamelContext camelContext, String text) throws Exception {
310            // ensure we support property placeholders
311            String s = camelContext.resolvePropertyPlaceholders(text);
312            if (s != null) {
313                try {
314                    return camelContext.getTypeConverter().mandatoryConvertTo(Double.class, s);
315                } catch (NumberFormatException e) {
316                    if (s.equals(text)) {
317                        throw new IllegalArgumentException("Error parsing [" + s + "] as an Integer.", e);
318                    } else {
319                        throw new IllegalArgumentException("Error parsing [" + s + "] from property " + text + " as an Integer.", e);
320                    }
321                }
322            }
323            return null;
324        }
325    
326        /**
327         * Parses the given text and converts it to an Boolean and handling property placeholders as well
328         *
329         * @param camelContext the camel context
330         * @param text  the text
331         * @return the boolean vale, or <tt>null</tt> if the text was <tt>null</tt>
332         * @throws Exception is thrown if illegal argument or type conversion not possible
333         */
334        public static Boolean parseBoolean(CamelContext camelContext, String text) throws Exception {
335            // ensure we support property placeholders
336            String s = camelContext.resolvePropertyPlaceholders(text);
337            if (s != null) {
338                s = s.trim().toLowerCase(Locale.ENGLISH);
339                if (s.equals("true") || s.equals("false")) {
340                    return "true".equals(s) ? Boolean.TRUE : Boolean.FALSE;
341                } else {
342                    if (s.equals(text)) {
343                        throw new IllegalArgumentException("Error parsing [" + s + "] as a Boolean.");
344                    } else {
345                        throw new IllegalArgumentException("Error parsing [" + s + "] from property " + text + " as a Boolean.");
346                    }
347                }
348            }
349            return null;
350        }
351    
352        /**
353         * Finds all possible Components on the classpath and Registry
354         */
355        public static SortedMap<String, Properties> findComponents(CamelContext camelContext) throws LoadPropertiesException {
356            SortedMap<String,Properties> map = new TreeMap<String, Properties>();
357            Enumeration<URL> iter = camelContext.getClassResolver().loadResourcesAsURL(COMPONENT_DESCRIPTOR);
358            while (iter.hasMoreElements()) {
359                URL url = iter.nextElement();
360                try {
361                    Properties properties = new Properties();
362                    properties.load(url.openStream());
363                    String names = properties.getProperty("components");
364                    if (names != null) {
365                        StringTokenizer tok = new StringTokenizer(names);
366                        while (tok.hasMoreTokens()) {
367                            String name = tok.nextToken();
368                            map.put(name, properties);
369                        }
370                    }
371                } catch (IOException e) {
372                    throw new LoadPropertiesException(url, e);
373                }
374            }
375    
376            // lets see what other components are in the registry
377            Map<String,Component> beanMap = camelContext.getRegistry().lookupByType(Component.class);
378            Set<Map.Entry<String,Component>> entries = beanMap.entrySet();
379            for (Map.Entry<String, Component> entry : entries) {
380                String name = entry.getKey();
381                if (!map.containsKey(name)) {
382                    Properties properties = new Properties();
383                    Component component = entry.getValue();
384                    if (component != null) {
385                        properties.put("component", component);
386                        properties.put("class", component.getClass().getName());
387                        map.put(name, properties);
388                    }
389                }
390            }
391            return map;
392        }
393    }