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 */
017package org.apache.camel.util;
018
019import java.io.IOException;
020import java.io.InputStream;
021import java.net.URL;
022import java.util.Enumeration;
023import java.util.HashMap;
024import java.util.Iterator;
025import java.util.List;
026import java.util.Locale;
027import java.util.Map;
028import java.util.Properties;
029import java.util.Set;
030import java.util.SortedMap;
031import java.util.StringTokenizer;
032import java.util.TreeMap;
033
034import org.apache.camel.CamelContext;
035import org.apache.camel.Component;
036import org.apache.camel.Endpoint;
037import org.apache.camel.Exchange;
038import org.apache.camel.NoSuchBeanException;
039import org.apache.camel.NoSuchEndpointException;
040import org.apache.camel.component.properties.PropertiesComponent;
041import org.apache.camel.model.FromDefinition;
042import org.apache.camel.model.ProcessorDefinition;
043import org.apache.camel.model.ProcessorDefinitionHelper;
044import org.apache.camel.model.RouteDefinition;
045import org.apache.camel.spi.ClassResolver;
046import org.apache.camel.spi.RouteStartupOrder;
047import org.slf4j.Logger;
048import org.slf4j.LoggerFactory;
049
050import static org.apache.camel.util.ObjectHelper.isEmpty;
051import static org.apache.camel.util.ObjectHelper.isNotEmpty;
052import static org.apache.camel.util.ObjectHelper.notNull;
053
054/**
055 * A number of helper methods
056 *
057 * @version 
058 */
059public final class CamelContextHelper {
060    public static final String COMPONENT_BASE = "META-INF/services/org/apache/camel/component/";
061    public static final String COMPONENT_DESCRIPTOR = "META-INF/services/org/apache/camel/component.properties";
062    public static final String COMPONENT_DOCUMENTATION_PREFIX = "org/apache/camel/component/";
063    public static final String MODEL_DESCRIPTOR = "META-INF/services/org/apache/camel/model.properties";
064    public static final String MODEL_DOCUMENTATION_PREFIX = "org/apache/camel/model/";
065
066    private static final Logger LOG = LoggerFactory.getLogger(CamelContextHelper.class);
067
068    /**
069     * Utility classes should not have a public constructor.
070     */
071    private CamelContextHelper() {
072    }
073
074    /**
075     * Returns the mandatory endpoint for the given URI or the
076     * {@link org.apache.camel.NoSuchEndpointException} is thrown
077     */
078    public static Endpoint getMandatoryEndpoint(CamelContext camelContext, String uri)
079        throws NoSuchEndpointException {
080        Endpoint endpoint = camelContext.getEndpoint(uri);
081        if (endpoint == null) {
082            throw new NoSuchEndpointException(uri);
083        } else {
084            return endpoint;
085        }
086    }
087
088    /**
089     * Returns the mandatory endpoint for the given URI and type or the
090     * {@link org.apache.camel.NoSuchEndpointException} is thrown
091     */
092    public static <T extends Endpoint> T getMandatoryEndpoint(CamelContext camelContext, String uri, Class<T> type) {
093        Endpoint endpoint = getMandatoryEndpoint(camelContext, uri);
094        return ObjectHelper.cast(type, endpoint);
095    }
096
097    /**
098     * Converts the given value to the requested type
099     */
100    public static <T> T convertTo(CamelContext context, Class<T> type, Object value) {
101        notNull(context, "camelContext");
102        return context.getTypeConverter().convertTo(type, value);
103    }
104
105    /**
106     * Tried to convert the given value to the requested type
107     */
108    public static <T> T tryConvertTo(CamelContext context, Class<T> type, Object value) {
109        notNull(context, "camelContext");
110        return context.getTypeConverter().tryConvertTo(type, value);
111    }
112
113    /**
114     * Converts the given value to the specified type throwing an {@link IllegalArgumentException}
115     * if the value could not be converted to a non null value
116     */
117    public static <T> T mandatoryConvertTo(CamelContext context, Class<T> type, Object value) {
118        T answer = convertTo(context, type, value);
119        if (answer == null) {
120            throw new IllegalArgumentException("Value " + value + " converted to " + type.getName() + " cannot be null");
121        }
122        return answer;
123    }
124
125    /**
126     * Creates a new instance of the given type using the {@link org.apache.camel.spi.Injector} on the given
127     * {@link CamelContext}
128     */
129    public static <T> T newInstance(CamelContext context, Class<T> beanType) {
130        return context.getInjector().newInstance(beanType);
131    }
132
133    /**
134     * Look up the given named bean in the {@link org.apache.camel.spi.Registry} on the
135     * {@link CamelContext}
136     */
137    public static Object lookup(CamelContext context, String name) {
138        return context.getRegistry().lookupByName(name);
139    }
140
141    /**
142     * Look up the given named bean of the given type in the {@link org.apache.camel.spi.Registry} on the
143     * {@link CamelContext}
144     */
145    public static <T> T lookup(CamelContext context, String name, Class<T> beanType) {
146        return context.getRegistry().lookupByNameAndType(name, beanType);
147    }
148
149    /**
150     * Look up the given named bean in the {@link org.apache.camel.spi.Registry} on the
151     * {@link CamelContext} and try to convert it to the given type.
152     */
153    public static <T> T lookupAndConvert(CamelContext context, String name, Class<T> beanType) {
154        return tryConvertTo(context, beanType, lookup(context, name));
155    }
156
157    /**
158     * Look up a bean of the give type in the {@link org.apache.camel.spi.Registry} on the
159     * {@link CamelContext} returning an instance if only one bean is present,
160     */
161    public static <T> T findByType(CamelContext camelContext, Class<T> type) {
162        Set<T> set = camelContext.getRegistry().findByType(type);
163        if (set.size() == 1) {
164            return set.iterator().next();
165        }
166
167        return null;
168    }
169
170    /**
171     * Look up the given named bean in the {@link org.apache.camel.spi.Registry} on the
172     * {@link CamelContext} or throws {@link NoSuchBeanException} if not found.
173     */
174    public static Object mandatoryLookup(CamelContext context, String name) {
175        Object answer = lookup(context, name);
176        if (answer == null) {
177            throw new NoSuchBeanException(name);
178        }
179        return answer;
180    }
181
182    /**
183     * Look up the given named bean of the given type in the {@link org.apache.camel.spi.Registry} on the
184     * {@link CamelContext} or throws NoSuchBeanException if not found.
185     */
186    public static <T> T mandatoryLookup(CamelContext context, String name, Class<T> beanType) {
187        T answer = lookup(context, name, beanType);
188        if (answer == null) {
189            throw new NoSuchBeanException(name, beanType.getName());
190        }
191        return answer;
192    }
193
194    /**
195     * Look up the given named bean in the {@link org.apache.camel.spi.Registry} on the
196     * {@link CamelContext} and convert it to the given type or throws NoSuchBeanException if not found.
197     */
198    public static <T> T mandatoryLookupAndConvert(CamelContext context, String name, Class<T> beanType) {
199        Object value = lookup(context, name);
200        if (value == null) {
201            throw new NoSuchBeanException(name, beanType.getName());
202        }
203        return convertTo(context, beanType, value);
204    }
205
206    /**
207     * Evaluates the @EndpointInject annotation using the given context
208     */
209    public static Endpoint getEndpointInjection(CamelContext camelContext, String uri, String ref, String injectionPointName, boolean mandatory) {
210        if (ObjectHelper.isNotEmpty(uri) && ObjectHelper.isNotEmpty(ref)) {
211            throw new IllegalArgumentException("Both uri and name is provided, only either one is allowed: uri=" + uri + ", ref=" + ref);
212        }
213
214        Endpoint endpoint;
215        if (isNotEmpty(uri)) {
216            endpoint = camelContext.getEndpoint(uri);
217        } else {
218            // if a ref is given then it should be possible to lookup
219            // otherwise we do not catch situations where there is a typo etc
220            if (isNotEmpty(ref)) {
221                endpoint = mandatoryLookup(camelContext, ref, Endpoint.class);
222            } else {
223                if (isEmpty(ref)) {
224                    ref = injectionPointName;
225                }
226                if (mandatory) {
227                    endpoint = mandatoryLookup(camelContext, ref, Endpoint.class);
228                } else {
229                    endpoint = lookup(camelContext, ref, Endpoint.class);
230                }
231            }
232        }
233        return endpoint;
234    }
235
236    /**
237     * Gets the maximum cache pool size.
238     * <p/>
239     * Will use the property set on CamelContext with the key {@link Exchange#MAXIMUM_CACHE_POOL_SIZE}.
240     * If no property has been set, then it will fallback to return a size of 1000.
241     *
242     * @param camelContext the camel context
243     * @return the maximum cache size
244     * @throws IllegalArgumentException is thrown if the property is illegal
245     */
246    public static int getMaximumCachePoolSize(CamelContext camelContext) throws IllegalArgumentException {
247        if (camelContext != null) {
248            String s = camelContext.getGlobalOption(Exchange.MAXIMUM_CACHE_POOL_SIZE);
249            if (s != null) {
250                try {
251                    // we cannot use Camel type converters as they may not be ready this early
252                    Integer size = Integer.valueOf(s);
253                    if (size == null || size <= 0) {
254                        throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_CACHE_POOL_SIZE + " must be a positive number, was: " + s);
255                    }
256                    return size;
257                } catch (NumberFormatException e) {
258                    throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_CACHE_POOL_SIZE + " must be a positive number, was: " + s, e);
259                }
260            }
261        }
262
263        // 1000 is the default fallback
264        return 1000;
265    }
266
267    /**
268     * Gets the maximum endpoint cache size.
269     * <p/>
270     * Will use the property set on CamelContext with the key {@link Exchange#MAXIMUM_ENDPOINT_CACHE_SIZE}.
271     * If no property has been set, then it will fallback to return a size of 1000.
272     *
273     * @param camelContext the camel context
274     * @return the maximum cache size
275     * @throws IllegalArgumentException is thrown if the property is illegal
276     */
277    public static int getMaximumEndpointCacheSize(CamelContext camelContext) throws IllegalArgumentException {
278        if (camelContext != null) {
279            String s = camelContext.getGlobalOption(Exchange.MAXIMUM_ENDPOINT_CACHE_SIZE);
280            if (s != null) {
281                // we cannot use Camel type converters as they may not be ready this early
282                try {
283                    Integer size = Integer.valueOf(s);
284                    if (size == null || size <= 0) {
285                        throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_ENDPOINT_CACHE_SIZE + " must be a positive number, was: " + s);
286                    }
287                    return size;
288                } catch (NumberFormatException e) {
289                    throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_ENDPOINT_CACHE_SIZE + " must be a positive number, was: " + s, e);
290                }
291            }
292        }
293
294        // 1000 is the default fallback
295        return 1000;
296    }
297
298    /**
299     * Gets the maximum transformer cache size.
300     * <p/>
301     * Will use the property set on CamelContext with the key {@link Exchange#MAXIMUM_TRANSFORMER_CACHE_SIZE}.
302     * If no property has been set, then it will fallback to return a size of 1000.
303     *
304     * @param camelContext the camel context
305     * @return the maximum cache size
306     * @throws IllegalArgumentException is thrown if the property is illegal
307     */
308    public static int getMaximumTransformerCacheSize(CamelContext camelContext) throws IllegalArgumentException {
309        if (camelContext != null) {
310            String s = camelContext.getGlobalOption(Exchange.MAXIMUM_TRANSFORMER_CACHE_SIZE);
311            if (s != null) {
312                // we cannot use Camel type converters as they may not be ready this early
313                try {
314                    Integer size = Integer.valueOf(s);
315                    if (size == null || size <= 0) {
316                        throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_TRANSFORMER_CACHE_SIZE + " must be a positive number, was: " + s);
317                    }
318                    return size;
319                } catch (NumberFormatException e) {
320                    throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_TRANSFORMER_CACHE_SIZE + " must be a positive number, was: " + s, e);
321                }
322            }
323        }
324
325        // 1000 is the default fallback
326        return 1000;
327    }
328
329    /**
330     * Gets the maximum validator cache size.
331     * <p/>
332     * Will use the property set on CamelContext with the key {@link Exchange#MAXIMUM_VALIDATOR_CACHE_SIZE}.
333     * If no property has been set, then it will fallback to return a size of 1000.
334     *
335     * @param camelContext the camel context
336     * @return the maximum cache size
337     * @throws IllegalArgumentException is thrown if the property is illegal
338     */
339    public static int getMaximumValidatorCacheSize(CamelContext camelContext) throws IllegalArgumentException {
340        if (camelContext != null) {
341            String s = camelContext.getGlobalOption(Exchange.MAXIMUM_VALIDATOR_CACHE_SIZE);
342            if (s != null) {
343                // we cannot use Camel type converters as they may not be ready this early
344                try {
345                    Integer size = Integer.valueOf(s);
346                    if (size == null || size <= 0) {
347                        throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_VALIDATOR_CACHE_SIZE + " must be a positive number, was: " + s);
348                    }
349                    return size;
350                } catch (NumberFormatException e) {
351                    throw new IllegalArgumentException("Property " + Exchange.MAXIMUM_VALIDATOR_CACHE_SIZE + " must be a positive number, was: " + s, e);
352                }
353            }
354        }
355
356        // 1000 is the default fallback
357        return 1000;
358    }
359
360    /**
361     * Parses the given text and handling property placeholders as well
362     *
363     * @param camelContext the camel context
364     * @param text  the text
365     * @return the parsed text, or <tt>null</tt> if the text was <tt>null</tt>
366     * @throws Exception is thrown if illegal argument
367     */
368    public static String parseText(CamelContext camelContext, String text) throws Exception {
369        // ensure we support property placeholders
370        return camelContext.resolvePropertyPlaceholders(text);
371    }
372
373    /**
374     * Parses the given text and converts it to an Integer and handling property placeholders as well
375     *
376     * @param camelContext the camel context
377     * @param text  the text
378     * @return the integer vale, or <tt>null</tt> if the text was <tt>null</tt>
379     * @throws Exception is thrown if illegal argument or type conversion not possible
380     */
381    public static Integer parseInteger(CamelContext camelContext, String text) throws Exception {
382        // ensure we support property placeholders
383        String s = camelContext.resolvePropertyPlaceholders(text);
384        if (s != null) {
385            try {
386                return camelContext.getTypeConverter().mandatoryConvertTo(Integer.class, s);
387            } catch (NumberFormatException e) {
388                if (s.equals(text)) {
389                    throw new IllegalArgumentException("Error parsing [" + s + "] as an Integer.", e);
390                } else {
391                    throw new IllegalArgumentException("Error parsing [" + s + "] from property " + text + " as an Integer.", e);
392                }
393            }
394        }
395        return null;
396    }
397
398    /**
399     * Parses the given text and converts it to an Long and handling property placeholders as well
400     *
401     * @param camelContext the camel context
402     * @param text  the text
403     * @return the long vale, or <tt>null</tt> if the text was <tt>null</tt>
404     * @throws Exception is thrown if illegal argument or type conversion not possible
405     */
406    public static Long parseLong(CamelContext camelContext, String text) throws Exception {
407        // ensure we support property placeholders
408        String s = camelContext.resolvePropertyPlaceholders(text);
409        if (s != null) {
410            try {
411                return camelContext.getTypeConverter().mandatoryConvertTo(Long.class, s);
412            } catch (NumberFormatException e) {
413                if (s.equals(text)) {
414                    throw new IllegalArgumentException("Error parsing [" + s + "] as a Long.", e);
415                } else {
416                    throw new IllegalArgumentException("Error parsing [" + s + "] from property " + text + " as a Long.", e);
417                }
418            }
419        }
420        return null;
421    }
422
423    /**
424     * Parses the given text and converts it to a Double and handling property placeholders as well
425     *
426     * @param camelContext the camel context
427     * @param text  the text
428     * @return the double vale, or <tt>null</tt> if the text was <tt>null</tt>
429     * @throws Exception is thrown if illegal argument or type conversion not possible
430     */
431    public static Double parseDouble(CamelContext camelContext, String text) throws Exception {
432        // ensure we support property placeholders
433        String s = camelContext.resolvePropertyPlaceholders(text);
434        if (s != null) {
435            try {
436                return camelContext.getTypeConverter().mandatoryConvertTo(Double.class, s);
437            } catch (NumberFormatException e) {
438                if (s.equals(text)) {
439                    throw new IllegalArgumentException("Error parsing [" + s + "] as an Integer.", e);
440                } else {
441                    throw new IllegalArgumentException("Error parsing [" + s + "] from property " + text + " as an Integer.", e);
442                }
443            }
444        }
445        return null;
446    }
447
448    /**
449     * Parses the given text and converts it to an Boolean and handling property placeholders as well
450     *
451     * @param camelContext the camel context
452     * @param text  the text
453     * @return the boolean vale, or <tt>null</tt> if the text was <tt>null</tt>
454     * @throws Exception is thrown if illegal argument or type conversion not possible
455     */
456    public static Boolean parseBoolean(CamelContext camelContext, String text) throws Exception {
457        // ensure we support property placeholders
458        String s = camelContext.resolvePropertyPlaceholders(text);
459        if (s != null) {
460            s = s.trim().toLowerCase(Locale.ENGLISH);
461            if (s.equals("true") || s.equals("false")) {
462                return "true".equals(s) ? Boolean.TRUE : Boolean.FALSE;
463            } else {
464                if (s.equals(text)) {
465                    throw new IllegalArgumentException("Error parsing [" + s + "] as a Boolean.");
466                } else {
467                    throw new IllegalArgumentException("Error parsing [" + s + "] from property " + text + " as a Boolean.");
468                }
469            }
470        }
471        return null;
472    }
473
474    /**
475     * Finds all possible Components on the classpath, already registered in {@link org.apache.camel.CamelContext},
476     * and from the {@link org.apache.camel.spi.Registry}.
477     */
478    public static SortedMap<String, Properties> findComponents(CamelContext camelContext) throws LoadPropertiesException {
479        ClassResolver resolver = camelContext.getClassResolver();
480        LOG.debug("Finding all components using class resolver: {} -> {}", new Object[]{resolver});
481        Enumeration<URL> iter = resolver.loadAllResourcesAsURL(COMPONENT_DESCRIPTOR);
482        return findComponents(camelContext, iter);
483    }
484
485    public static SortedMap<String, Properties> findComponents(CamelContext camelContext, Enumeration<URL> componentDescriptionIter)
486        throws LoadPropertiesException {
487
488        SortedMap<String, Properties> map = new TreeMap<String, Properties>();
489        while (componentDescriptionIter != null && componentDescriptionIter.hasMoreElements()) {
490            URL url = componentDescriptionIter.nextElement();
491            LOG.trace("Finding components in url: {}", url);
492            try {
493                Properties properties = new Properties();
494                properties.load(url.openStream());
495                String names = properties.getProperty("components");
496                if (names != null) {
497                    StringTokenizer tok = new StringTokenizer(names);
498                    while (tok.hasMoreTokens()) {
499                        String name = tok.nextToken();
500
501                        // try to find the class name for this component
502                        String className = null;
503                        InputStream is = null;
504                        try {
505                            // now load the component name resource so we can grab its properties and the class name
506                            Enumeration<URL> urls = camelContext.getClassResolver().loadAllResourcesAsURL(COMPONENT_BASE + name);
507                            if (urls != null && urls.hasMoreElements()) {
508                                is = urls.nextElement().openStream();
509                            }
510                            if (is != null) {
511                                Properties compProperties = new Properties();
512                                compProperties.load(is);
513                                if (!compProperties.isEmpty()) {
514                                    className = compProperties.getProperty("class");
515                                }
516                            }
517                        } catch (Exception e) {
518                            // ignore
519                        } finally {
520                            IOHelper.close(is);
521                        }
522
523                        // inherit properties we loaded first, as it has maven details
524                        Properties prop = new Properties();
525                        prop.putAll(properties);
526                        if (camelContext.hasComponent(name) != null) {
527                            prop.put("component", camelContext.getComponent(name));
528                        }
529                        if (className != null) {
530                            prop.put("class", className);
531                        }
532                        prop.put("name", name);
533                        map.put(name, prop);
534                    }
535                }
536            } catch (IOException e) {
537                throw new LoadPropertiesException(url, e);
538            }
539        }
540
541        // lets see what other components are registered on camel context
542        List<String> names = camelContext.getComponentNames();
543        for (String name : names) {
544            if (!map.containsKey(name)) {
545                Component component = camelContext.getComponent(name);
546                if (component != null) {
547                    Properties properties = new Properties();
548                    properties.put("component", component);
549                    properties.put("class", component.getClass().getName());
550                    properties.put("name", name);
551                    // override default component if name clash
552                    map.put(name, properties);
553                }
554            }
555        }
556
557        // lets see what other components are in the registry
558        Map<String, Component> beanMap = camelContext.getRegistry().findByTypeWithName(Component.class);
559        Set<Map.Entry<String, Component>> entries = beanMap.entrySet();
560        for (Map.Entry<String, Component> entry : entries) {
561            String name = entry.getKey();
562            if (!map.containsKey(name)) {
563                Component component = entry.getValue();
564                if (component != null) {
565                    Properties properties = new Properties();
566                    properties.put("component", component);
567                    properties.put("class", component.getClass().getName());
568                    properties.put("name", name);
569                    map.put(name, properties);
570                }
571            }
572        }
573        return map;
574    }
575
576    /**
577     * Find information about all the EIPs from camel-core.
578     */
579    public static SortedMap<String, Properties> findEips(CamelContext camelContext) throws LoadPropertiesException {
580        SortedMap<String, Properties> answer = new TreeMap<String, Properties>();
581
582        ClassResolver resolver = camelContext.getClassResolver();
583        LOG.debug("Finding all EIPs using class resolver: {} -> {}", new Object[]{resolver});
584        URL url = resolver.loadResourceAsURL(MODEL_DESCRIPTOR);
585        if (url != null) {
586            InputStream is = null;
587            try {
588                is = url.openStream();
589                String all = IOHelper.loadText(is);
590                String[] lines = all.split("\n");
591                for (String line : lines) {
592                    if (line.startsWith("#")) {
593                        continue;
594                    }
595
596                    Properties prop = new Properties();
597                    prop.put("name", line);
598
599                    String description = null;
600                    String label = null;
601                    String javaType = null;
602                    String title = null;
603
604                    // enrich with more meta-data
605                    String json = camelContext.explainEipJson(line, false);
606                    if (json != null) {
607                        List<Map<String, String>> rows = JsonSchemaHelper.parseJsonSchema("model", json, false);
608
609                        for (Map<String, String> row : rows) {
610                            if (row.get("title") != null) {
611                                title = row.get("title");
612                            }
613                            if (row.get("description") != null) {
614                                description = row.get("description");
615                            }
616                            if (row.get("label") != null) {
617                                label = row.get("label");
618                            }
619                            if (row.get("javaType") != null) {
620                                javaType = row.get("javaType");
621                            }
622                        }
623                    }
624
625                    if (title != null) {
626                        prop.put("title", title);
627                    }
628                    if (description != null) {
629                        prop.put("description", description);
630                    }
631                    if (label != null) {
632                        prop.put("label", label);
633                    }
634                    if (javaType != null) {
635                        prop.put("class", javaType);
636                    }
637
638                    answer.put(line, prop);
639                }
640            } catch (IOException e) {
641                throw new LoadPropertiesException(url, e);
642            } finally {
643                IOHelper.close(is);
644            }
645        }
646
647        return answer;
648    }
649
650    /**
651     * Gets the route startup order for the given route id
652     *
653     * @param camelContext  the camel context
654     * @param routeId       the id of the route
655     * @return the startup order, or <tt>0</tt> if not possible to determine
656     */
657    public static int getRouteStartupOrder(CamelContext camelContext, String routeId) {
658        for (RouteStartupOrder order : camelContext.getRouteStartupOrder()) {
659            if (order.getRoute().getId().equals(routeId)) {
660                return order.getStartupOrder();
661            }
662        }
663        return 0;
664    }
665
666    /**
667     * Lookup the {@link org.apache.camel.component.properties.PropertiesComponent} from the {@link org.apache.camel.CamelContext}.
668     * <p/>
669     * @param camelContext the camel context
670     * @param autoCreate whether to automatic create a new default {@link org.apache.camel.component.properties.PropertiesComponent} if no custom component
671     *                   has been configured.
672     * @return the properties component, or <tt>null</tt> if none has been defined, and auto create is <tt>false</tt>.
673     */
674    public static Component lookupPropertiesComponent(CamelContext camelContext, boolean autoCreate) {
675        // no existing properties component so lookup and add as component if possible
676        PropertiesComponent answer = (PropertiesComponent) camelContext.hasComponent("properties");
677        if (answer == null) {
678            // lookup what is stored under properties, as it may not be the Camel properties component
679            Object found = camelContext.getRegistry().lookupByName("properties");
680            if (found != null && found instanceof PropertiesComponent) {
681                answer = (PropertiesComponent) found;
682                camelContext.addComponent("properties", answer);
683            }
684        }
685        if (answer == null && autoCreate) {
686            // create a default properties component to be used as there may be default values we can use
687            LOG.info("No existing PropertiesComponent has been configured, creating a new default PropertiesComponent with name: properties");
688            // do not auto create using getComponent as spring auto-wire by constructor causes a side effect
689            answer = new PropertiesComponent(true);
690            camelContext.addComponent("properties", answer);
691        }
692        return answer;
693    }
694
695    /**
696     * Checks if any of the Camel routes is using an EIP with the given name
697     *
698     * @param camelContext  the Camel context
699     * @param name          the name of the EIP
700     * @return <tt>true</tt> if in use, <tt>false</tt> if not
701     */
702    public static boolean isEipInUse(CamelContext camelContext, String name) {
703        for (RouteDefinition route : camelContext.getRouteDefinitions()) {
704            for (FromDefinition from : route.getInputs()) {
705                if (name.equals(from.getShortName())) {
706                    return true;
707                }
708            }
709            Iterator<ProcessorDefinition> it = ProcessorDefinitionHelper.filterTypeInOutputs(route.getOutputs(), ProcessorDefinition.class);
710            while (it.hasNext()) {
711                ProcessorDefinition def = it.next();
712                if (name.equals(def.getShortName())) {
713                    return true;
714                }
715            }
716        }
717        return false;
718    }
719
720    /**
721     * Inspects the given object and resolves any property placeholders from its properties.
722     * <p/>
723     * This implementation will check all the getter/setter pairs on this instance and for all the values
724     * (which is a String type) will be property placeholder resolved.
725     *
726     * @param camelContext the Camel context
727     * @param target       the object that should have the properties (eg getter/setter) resolved
728     * @throws Exception is thrown if property placeholders was used and there was an error resolving them
729     * @see org.apache.camel.CamelContext#resolvePropertyPlaceholders(String)
730     * @see org.apache.camel.component.properties.PropertiesComponent
731     */
732    public static void resolvePropertyPlaceholders(CamelContext camelContext, Object target) throws Exception {
733        LOG.trace("Resolving property placeholders for: {}", target);
734
735        // find all getter/setter which we can use for property placeholders
736        Map<String, Object> properties = new HashMap<String, Object>();
737        IntrospectionSupport.getProperties(target, properties, null);
738
739        Map<String, Object> changedProperties = new HashMap<String, Object>();
740        if (!properties.isEmpty()) {
741            LOG.trace("There are {} properties on: {}", properties.size(), target);
742            // lookup and resolve properties for String based properties
743            for (Map.Entry<String, Object> entry : properties.entrySet()) {
744                // the name is always a String
745                String name = entry.getKey();
746                Object value = entry.getValue();
747                if (value instanceof String) {
748                    // value must be a String, as a String is the key for a property placeholder
749                    String text = (String) value;
750                    text = camelContext.resolvePropertyPlaceholders(text);
751                    if (text != value) {
752                        // invoke setter as the text has changed
753                        boolean changed = IntrospectionSupport.setProperty(camelContext.getTypeConverter(), target, name, text);
754                        if (!changed) {
755                            throw new IllegalArgumentException("No setter to set property: " + name + " to: " + text + " on: " + target);
756                        }
757                        changedProperties.put(name, value);
758                        if (LOG.isDebugEnabled()) {
759                            LOG.debug("Changed property [{}] from: {} to: {}", new Object[]{name, value, text});
760                        }
761                    }
762                }
763            }
764        }
765    }
766
767}