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