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.impl; 018 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.HashMap; 022import java.util.HashSet; 023import java.util.List; 024import java.util.Map; 025import java.util.Optional; 026import java.util.Set; 027import java.util.function.Function; 028 029import org.apache.camel.CamelContext; 030import org.apache.camel.Expression; 031import org.apache.camel.FailedToStartRouteException; 032import org.apache.camel.LoggingLevel; 033import org.apache.camel.Predicate; 034import org.apache.camel.Processor; 035import org.apache.camel.Route; 036import org.apache.camel.RouteTemplateContext; 037import org.apache.camel.StartupStep; 038import org.apache.camel.ValueHolder; 039import org.apache.camel.api.management.JmxSystemPropertyKeys; 040import org.apache.camel.impl.engine.DefaultExecutorServiceManager; 041import org.apache.camel.impl.engine.RouteService; 042import org.apache.camel.impl.engine.SimpleCamelContext; 043import org.apache.camel.impl.engine.TransformerKey; 044import org.apache.camel.impl.engine.ValidatorKey; 045import org.apache.camel.impl.scan.AssignableToPackageScanFilter; 046import org.apache.camel.impl.scan.InvertingPackageScanFilter; 047import org.apache.camel.model.DataFormatDefinition; 048import org.apache.camel.model.FaultToleranceConfigurationDefinition; 049import org.apache.camel.model.Model; 050import org.apache.camel.model.ModelCamelContext; 051import org.apache.camel.model.ModelLifecycleStrategy; 052import org.apache.camel.model.ProcessorDefinition; 053import org.apache.camel.model.ProcessorDefinitionHelper; 054import org.apache.camel.model.Resilience4jConfigurationDefinition; 055import org.apache.camel.model.RouteConfigurationDefinition; 056import org.apache.camel.model.RouteDefinition; 057import org.apache.camel.model.RouteDefinitionHelper; 058import org.apache.camel.model.RouteTemplateDefinition; 059import org.apache.camel.model.TemplatedRouteDefinition; 060import org.apache.camel.model.app.RegistryBeanDefinition; 061import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition; 062import org.apache.camel.model.language.ExpressionDefinition; 063import org.apache.camel.model.rest.RestDefinition; 064import org.apache.camel.model.transformer.TransformerDefinition; 065import org.apache.camel.model.validator.ValidatorDefinition; 066import org.apache.camel.spi.BeanRepository; 067import org.apache.camel.spi.DataFormat; 068import org.apache.camel.spi.DataType; 069import org.apache.camel.spi.DumpRoutesStrategy; 070import org.apache.camel.spi.ExecutorServiceManager; 071import org.apache.camel.spi.LocalBeanRepositoryAware; 072import org.apache.camel.spi.ModelReifierFactory; 073import org.apache.camel.spi.PackageScanClassResolver; 074import org.apache.camel.spi.PropertiesComponent; 075import org.apache.camel.spi.Registry; 076import org.apache.camel.spi.StartupStepRecorder; 077import org.apache.camel.spi.Transformer; 078import org.apache.camel.spi.UuidGenerator; 079import org.apache.camel.spi.Validator; 080import org.apache.camel.support.CamelContextHelper; 081import org.apache.camel.support.DefaultRegistry; 082import org.apache.camel.support.LocalBeanRegistry; 083import org.apache.camel.support.ResolverHelper; 084import org.apache.camel.support.SimpleUuidGenerator; 085import org.apache.camel.util.ObjectHelper; 086import org.apache.camel.util.OrderedLocationProperties; 087import org.apache.camel.util.StopWatch; 088import org.apache.camel.util.concurrent.NamedThreadLocal; 089import org.slf4j.Logger; 090import org.slf4j.LoggerFactory; 091 092/** 093 * Represents the context used to configure routes and the policies to use. 094 */ 095public class DefaultCamelContext extends SimpleCamelContext implements ModelCamelContext { 096 097 // global options that can be set on CamelContext as part of concurrent testing 098 // which means options should be isolated via thread-locals and not a static instance 099 // use a HashMap to store only JDK classes in the thread-local so there will not be any Camel classes leaking 100 private static final ThreadLocal<Map<String, Object>> OPTIONS = new NamedThreadLocal<>("CamelContextOptions", HashMap::new); 101 private static final String OPTION_NO_START = "OptionNoStart"; 102 private static final String OPTION_DISABLE_JMX = "OptionDisableJMX"; 103 private static final String OPTION_EXCLUDE_ROUTES = "OptionExcludeRoutes"; 104 105 private static final Logger LOG = LoggerFactory.getLogger(DefaultCamelContext.class); 106 private static final UuidGenerator UUID = new SimpleUuidGenerator(); 107 108 private Model model = new DefaultModel(this); 109 110 /** 111 * Creates the {@link ModelCamelContext} using {@link org.apache.camel.support.DefaultRegistry} as registry. 112 * <p/> 113 * Use one of the other constructors to force use an explicit registry. 114 */ 115 public DefaultCamelContext() { 116 this(true); 117 } 118 119 /** 120 * Creates the {@link CamelContext} using the given {@link BeanRepository} as first-choice repository, and the 121 * {@link org.apache.camel.support.SimpleRegistry} as fallback, via the {@link DefaultRegistry} implementation. 122 * 123 * @param repository the bean repository. 124 */ 125 public DefaultCamelContext(BeanRepository repository) { 126 this(new DefaultRegistry(repository)); 127 } 128 129 /** 130 * Creates the {@link ModelCamelContext} using the given registry 131 * 132 * @param registry the registry 133 */ 134 public DefaultCamelContext(Registry registry) { 135 this(); 136 getCamelContextExtension().setRegistry(registry); 137 } 138 139 public DefaultCamelContext(boolean init) { 140 super(init); 141 // setup model factory which must be done very early 142 setModelReifierFactory(createModelReifierFactory()); 143 if (isDisableJmx()) { 144 disableJMX(); 145 } 146 } 147 148 @Override 149 protected void doStop() throws Exception { 150 super.doStop(); 151 OPTIONS.remove(); 152 } 153 154 @Override 155 protected void doDumpRoutes() { 156 DumpRoutesStrategy strategy = CamelContextHelper.findSingleByType(this, DumpRoutesStrategy.class); 157 if (strategy == null) { 158 strategy = getCamelContextExtension().getContextPlugin(DumpRoutesStrategy.class); 159 } 160 if (strategy != null) { 161 strategy.dumpRoutes(getDumpRoutes()); 162 } 163 } 164 165 public static void setNoStart(boolean b) { 166 getOptions().put(OPTION_NO_START, b); 167 } 168 169 public static boolean isNoStart() { 170 return (Boolean) getOptions().getOrDefault(OPTION_NO_START, Boolean.FALSE); 171 } 172 173 public static void setDisableJmx(boolean b) { 174 getOptions().put(OPTION_DISABLE_JMX, b); 175 } 176 177 public static boolean isDisableJmx() { 178 return (Boolean) getOptions().getOrDefault(OPTION_DISABLE_JMX, Boolean.getBoolean(JmxSystemPropertyKeys.DISABLED)); 179 } 180 181 @Override 182 public String getTestExcludeRoutes() { 183 return getExcludeRoutes(); 184 } 185 186 public static String getExcludeRoutes() { 187 return (String) getOptions().get(OPTION_EXCLUDE_ROUTES); 188 } 189 190 public static void setExcludeRoutes(String s) { 191 getOptions().put(OPTION_EXCLUDE_ROUTES, s); 192 } 193 194 public static void clearOptions() { 195 OPTIONS.get().clear(); 196 } 197 198 private static Map<String, Object> getOptions() { 199 return OPTIONS.get(); 200 } 201 202 @Override 203 public void start() { 204 // for example from unit testing we want to start Camel later (manually) 205 if (isNoStart()) { 206 LOG.trace("Ignoring start() as NO_START is true"); 207 return; 208 } 209 210 if (!isStarted() && !isStarting()) { 211 StopWatch watch = new StopWatch(); 212 super.start(); 213 LOG.debug("start() took {} millis", watch.taken()); 214 } else { 215 // ignore as Camel is already started 216 LOG.trace("Ignoring start() as Camel is already started"); 217 } 218 } 219 220 @Override 221 protected PackageScanClassResolver createPackageScanClassResolver() { 222 PackageScanClassResolver resolver = super.createPackageScanClassResolver(); 223 String excluded = getExcludeRoutes(); 224 if (ObjectHelper.isNotEmpty(excluded)) { 225 Set<Class<?>> excludedClasses = new HashSet<>(); 226 for (String str : excluded.split(",")) { 227 excludedClasses.add(getClassResolver().resolveClass(str)); 228 } 229 resolver.addFilter(new InvertingPackageScanFilter(new AssignableToPackageScanFilter(excludedClasses))); 230 } 231 return resolver; 232 } 233 234 @Override 235 public void disposeModel() { 236 LOG.debug("Disposing Model on CamelContext"); 237 model = null; 238 } 239 240 @Override 241 public void addModelLifecycleStrategy(ModelLifecycleStrategy modelLifecycleStrategy) { 242 model.addModelLifecycleStrategy(modelLifecycleStrategy); 243 } 244 245 @Override 246 public List<ModelLifecycleStrategy> getModelLifecycleStrategies() { 247 return model.getModelLifecycleStrategies(); 248 } 249 250 @Override 251 public void addRouteConfiguration(RouteConfigurationDefinition routesConfiguration) { 252 model.addRouteConfiguration(routesConfiguration); 253 } 254 255 @Override 256 public void addRouteConfigurations(List<RouteConfigurationDefinition> routesConfigurations) { 257 model.addRouteConfigurations(routesConfigurations); 258 } 259 260 @Override 261 public List<RouteConfigurationDefinition> getRouteConfigurationDefinitions() { 262 return model.getRouteConfigurationDefinitions(); 263 } 264 265 @Override 266 public RouteConfigurationDefinition getRouteConfigurationDefinition(String id) { 267 return model.getRouteConfigurationDefinition(id); 268 } 269 270 @Override 271 public void removeRouteConfiguration(RouteConfigurationDefinition routeConfigurationDefinition) throws Exception { 272 model.removeRouteConfiguration(routeConfigurationDefinition); 273 } 274 275 @Override 276 public List<RouteDefinition> getRouteDefinitions() { 277 return model.getRouteDefinitions(); 278 } 279 280 @Override 281 public RouteDefinition getRouteDefinition(String id) { 282 return model.getRouteDefinition(id); 283 } 284 285 @Override 286 public void addRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception { 287 model.addRouteDefinitions(routeDefinitions); 288 } 289 290 @Override 291 public void addRouteDefinition(RouteDefinition routeDefinition) throws Exception { 292 model.addRouteDefinition(routeDefinition); 293 } 294 295 @Override 296 public void removeRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception { 297 if (!isLockModel()) { 298 model.removeRouteDefinitions(routeDefinitions); 299 } 300 } 301 302 @Override 303 public void removeRouteDefinition(RouteDefinition routeDefinition) throws Exception { 304 if (!isLockModel()) { 305 model.removeRouteDefinition(routeDefinition); 306 } 307 } 308 309 @Override 310 public List<RouteTemplateDefinition> getRouteTemplateDefinitions() { 311 return model.getRouteTemplateDefinitions(); 312 } 313 314 @Override 315 public RouteTemplateDefinition getRouteTemplateDefinition(String id) { 316 return model.getRouteTemplateDefinition(id); 317 } 318 319 @Override 320 public void addRouteTemplateDefinitions(Collection<RouteTemplateDefinition> routeTemplateDefinitions) throws Exception { 321 model.addRouteTemplateDefinitions(routeTemplateDefinitions); 322 } 323 324 @Override 325 public void addRouteTemplateDefinition(RouteTemplateDefinition routeTemplateDefinition) throws Exception { 326 327 model.addRouteTemplateDefinition(routeTemplateDefinition); 328 } 329 330 @Override 331 public void removeRouteTemplateDefinitions(Collection<RouteTemplateDefinition> routeTemplateDefinitions) throws Exception { 332 333 if (!isLockModel()) { 334 model.removeRouteTemplateDefinitions(routeTemplateDefinitions); 335 } 336 } 337 338 @Override 339 public void removeRouteTemplateDefinition(RouteTemplateDefinition routeTemplateDefinition) throws Exception { 340 if (!isLockModel()) { 341 model.removeRouteTemplateDefinition(routeTemplateDefinition); 342 } 343 } 344 345 @Override 346 public void removeRouteTemplateDefinitions(String pattern) throws Exception { 347 if (!isLockModel()) { 348 model.removeRouteTemplateDefinitions(pattern); 349 } 350 } 351 352 @Override 353 public void addRouteTemplateDefinitionConverter(String templateIdPattern, RouteTemplateDefinition.Converter converter) { 354 355 model.addRouteTemplateDefinitionConverter(templateIdPattern, converter); 356 } 357 358 @Override 359 public String addRouteFromTemplate(String routeId, String routeTemplateId, Map<String, Object> parameters) 360 throws Exception { 361 362 return model.addRouteFromTemplate(routeId, routeTemplateId, parameters); 363 } 364 365 @Override 366 public String addRouteFromTemplate(String routeId, String routeTemplateId, String prefixId, Map<String, Object> parameters) 367 throws Exception { 368 369 return model.addRouteFromTemplate(routeId, routeTemplateId, prefixId, parameters); 370 } 371 372 @Override 373 public String addRouteFromTemplate( 374 String routeId, String routeTemplateId, String prefixId, RouteTemplateContext routeTemplateContext) 375 throws Exception { 376 377 return model.addRouteFromTemplate(routeId, routeTemplateId, prefixId, routeTemplateContext); 378 } 379 380 @Override 381 public void addRouteFromTemplatedRoute(TemplatedRouteDefinition templatedRouteDefinition) 382 throws Exception { 383 384 model.addRouteFromTemplatedRoute(templatedRouteDefinition); 385 } 386 387 @Override 388 public void removeRouteTemplates(String pattern) throws Exception { 389 390 if (!isLockModel()) { 391 model.removeRouteTemplateDefinitions(pattern); 392 } 393 } 394 395 @Override 396 public List<RestDefinition> getRestDefinitions() { 397 return model.getRestDefinitions(); 398 } 399 400 @Override 401 public void addRestDefinitions(Collection<RestDefinition> restDefinitions, boolean addToRoutes) throws Exception { 402 model.addRestDefinitions(restDefinitions, addToRoutes); 403 } 404 405 @Override 406 public void setDataFormats(Map<String, DataFormatDefinition> dataFormats) { 407 model.setDataFormats(dataFormats); 408 } 409 410 @Override 411 public Map<String, DataFormatDefinition> getDataFormats() { 412 return model.getDataFormats(); 413 } 414 415 @Override 416 public DataFormatDefinition resolveDataFormatDefinition(String name) { 417 return model.resolveDataFormatDefinition(name); 418 } 419 420 @Override 421 public ProcessorDefinition<?> getProcessorDefinition(String id) { 422 return model.getProcessorDefinition(id); 423 } 424 425 @Override 426 public <T extends ProcessorDefinition<T>> T getProcessorDefinition(String id, Class<T> type) { 427 return model.getProcessorDefinition(id, type); 428 } 429 430 @Override 431 public void setValidators(List<ValidatorDefinition> validators) { 432 model.setValidators(validators); 433 } 434 435 @Override 436 public Resilience4jConfigurationDefinition getResilience4jConfiguration(String id) { 437 return model.getResilience4jConfiguration(id); 438 } 439 440 @Override 441 public void setResilience4jConfiguration(Resilience4jConfigurationDefinition configuration) { 442 model.setResilience4jConfiguration(configuration); 443 } 444 445 @Override 446 public void setResilience4jConfigurations(List<Resilience4jConfigurationDefinition> configurations) { 447 model.setResilience4jConfigurations(configurations); 448 } 449 450 @Override 451 public void addResilience4jConfiguration(String id, Resilience4jConfigurationDefinition configuration) { 452 model.addResilience4jConfiguration(id, configuration); 453 } 454 455 @Override 456 public FaultToleranceConfigurationDefinition getFaultToleranceConfiguration(String id) { 457 return model.getFaultToleranceConfiguration(id); 458 } 459 460 @Override 461 public void setFaultToleranceConfiguration(FaultToleranceConfigurationDefinition configuration) { 462 model.setFaultToleranceConfiguration(configuration); 463 } 464 465 @Override 466 public void setFaultToleranceConfigurations(List<FaultToleranceConfigurationDefinition> configurations) { 467 model.setFaultToleranceConfigurations(configurations); 468 } 469 470 @Override 471 public void addFaultToleranceConfiguration(String id, FaultToleranceConfigurationDefinition configuration) { 472 model.addFaultToleranceConfiguration(id, configuration); 473 } 474 475 @Override 476 public List<ValidatorDefinition> getValidators() { 477 return model.getValidators(); 478 } 479 480 @Override 481 public void setTransformers(List<TransformerDefinition> transformers) { 482 model.setTransformers(transformers); 483 } 484 485 @Override 486 public List<TransformerDefinition> getTransformers() { 487 return model.getTransformers(); 488 } 489 490 @Override 491 public ServiceCallConfigurationDefinition getServiceCallConfiguration(String serviceName) { 492 return model.getServiceCallConfiguration(serviceName); 493 } 494 495 @Override 496 public void setServiceCallConfiguration(ServiceCallConfigurationDefinition configuration) { 497 model.setServiceCallConfiguration(configuration); 498 } 499 500 @Override 501 public void setServiceCallConfigurations(List<ServiceCallConfigurationDefinition> configurations) { 502 model.setServiceCallConfigurations(configurations); 503 } 504 505 @Override 506 public void addServiceCallConfiguration(String serviceName, ServiceCallConfigurationDefinition configuration) { 507 model.addServiceCallConfiguration(serviceName, configuration); 508 } 509 510 @Override 511 public void setRouteFilterPattern(String include, String exclude) { 512 model.setRouteFilterPattern(include, exclude); 513 } 514 515 @Override 516 public void setRouteFilter(Function<RouteDefinition, Boolean> filter) { 517 model.setRouteFilter(filter); 518 } 519 520 @Override 521 public Function<RouteDefinition, Boolean> getRouteFilter() { 522 return model.getRouteFilter(); 523 } 524 525 @Override 526 public void addRegistryBean(RegistryBeanDefinition bean) { 527 model.addRegistryBean(bean); 528 } 529 530 @Override 531 public List<RegistryBeanDefinition> getRegistryBeans() { 532 return model.getRegistryBeans(); 533 } 534 535 @Override 536 public ModelReifierFactory getModelReifierFactory() { 537 return model.getModelReifierFactory(); 538 } 539 540 @Override 541 public void setModelReifierFactory(ModelReifierFactory modelReifierFactory) { 542 model.setModelReifierFactory(modelReifierFactory); 543 } 544 545 @Override 546 protected void bindDataFormats() throws Exception { 547 // eager lookup data formats and bind to registry so the dataformats can 548 // be looked up and used 549 if (model != null) { 550 for (Map.Entry<String, DataFormatDefinition> e : model.getDataFormats().entrySet()) { 551 String id = e.getKey(); 552 DataFormatDefinition def = e.getValue(); 553 LOG.debug("Creating Dataformat with id: {} and definition: {}", id, def); 554 DataFormat df = model.getModelReifierFactory().createDataFormat(this, def); 555 addService(df, true); 556 getRegistry().bind(id, df); 557 } 558 } 559 } 560 561 @Override 562 protected synchronized void shutdownRouteService(RouteService routeService) throws Exception { 563 if (model != null) { 564 RouteDefinition rd = model.getRouteDefinition(routeService.getId()); 565 if (rd != null) { 566 model.getRouteDefinitions().remove(rd); 567 } 568 } 569 super.shutdownRouteService(routeService); 570 } 571 572 @Override 573 protected boolean isStreamCachingInUse() throws Exception { 574 boolean streamCachingInUse = super.isStreamCachingInUse(); 575 if (!streamCachingInUse) { 576 for (RouteDefinition route : model.getRouteDefinitions()) { 577 Boolean routeCache = CamelContextHelper.parseBoolean(this, route.getStreamCache()); 578 if (routeCache != null && routeCache) { 579 streamCachingInUse = true; 580 break; 581 } 582 } 583 } 584 return streamCachingInUse; 585 } 586 587 @Override 588 public void startRouteDefinitions() throws Exception { 589 List<RouteDefinition> routeDefinitions = model.getRouteDefinitions(); 590 if (routeDefinitions != null) { 591 // defensive copy of routes to be started as kamelets 592 // can add route definitions from existing routes 593 List<RouteDefinition> toBeStarted = new ArrayList<>(routeDefinitions); 594 startRouteDefinitions(toBeStarted); 595 } 596 } 597 598 @Override 599 public void removeRouteDefinitionsFromTemplate() throws Exception { 600 List<RouteDefinition> toBeRemoved = new ArrayList<>(); 601 for (RouteDefinition rd : model.getRouteDefinitions()) { 602 if (rd.isTemplate() != null && rd.isTemplate()) { 603 toBeRemoved.add(rd); 604 } 605 } 606 removeRouteDefinitions(toBeRemoved); 607 } 608 609 public void startRouteDefinitions(List<RouteDefinition> routeDefinitions) throws Exception { 610 // indicate we are staring the route using this thread so 611 // we are able to query this if needed 612 boolean alreadyStartingRoutes = isStartingRoutes(); 613 if (!alreadyStartingRoutes) { 614 setStartingRoutes(true); 615 } 616 617 PropertiesComponent pc = getCamelContextReference().getPropertiesComponent(); 618 // route templates supports binding beans that are local for the template only 619 // in this local mode then we need to check for side-effects (see further) 620 LocalBeanRepositoryAware localBeans = null; 621 if (getCamelContextReference().getRegistry() instanceof LocalBeanRepositoryAware) { 622 localBeans = (LocalBeanRepositoryAware) getCamelContextReference().getRegistry(); 623 } 624 try { 625 RouteDefinitionHelper.forceAssignIds(getCamelContextReference(), routeDefinitions); 626 List<RouteDefinition> routeDefinitionsToRemove = null; 627 for (RouteDefinition routeDefinition : routeDefinitions) { 628 // assign ids to the routes and validate that the id's is all unique 629 String duplicate = RouteDefinitionHelper.validateUniqueIds(routeDefinition, routeDefinitions, 630 routeDefinition.getNodePrefixId()); 631 if (duplicate != null) { 632 throw new FailedToStartRouteException( 633 routeDefinition.getId(), 634 "duplicate id detected: " + duplicate + ". Please correct ids to be unique among all your routes."); 635 } 636 637 // if the route definition was created via a route template then we need to prepare its parameters when the route is being created and started 638 if (routeDefinition.isTemplate() != null && routeDefinition.isTemplate() 639 && routeDefinition.getTemplateParameters() != null) { 640 641 // apply configurer if any present 642 if (routeDefinition.getRouteTemplateContext().getConfigurer() != null) { 643 routeDefinition.getRouteTemplateContext().getConfigurer() 644 .accept(routeDefinition.getRouteTemplateContext()); 645 } 646 647 // copy parameters/bean repository to not cause side effect 648 Map<Object, Object> params = new HashMap<>(routeDefinition.getTemplateParameters()); 649 LocalBeanRegistry bbr 650 = (LocalBeanRegistry) routeDefinition.getRouteTemplateContext().getLocalBeanRepository(); 651 LocalBeanRegistry bbrCopy = new LocalBeanRegistry(); 652 653 // make all bean in the bean repository use unique keys (need to add uuid counter) 654 // so when the route template is used again to create another route, then there is 655 // no side-effect from previously used values that Camel may use in its endpoint 656 // registry and elsewhere 657 if (bbr != null && !bbr.isEmpty()) { 658 for (Map.Entry<Object, Object> param : params.entrySet()) { 659 Object value = param.getValue(); 660 if (value instanceof String) { 661 String oldKey = (String) value; 662 boolean clash = bbr.keys().stream().anyMatch(k -> k.equals(oldKey)); 663 if (clash) { 664 String newKey = oldKey + "-" + UUID.generateUuid(); 665 LOG.debug( 666 "Route: {} re-assigning local-bean id: {} to: {} to ensure ids are globally unique", 667 routeDefinition.getId(), oldKey, newKey); 668 bbrCopy.put(newKey, bbr.remove(oldKey)); 669 param.setValue(newKey); 670 } 671 } 672 } 673 // the remainder of the local beans must also have their ids made global unique 674 for (Map.Entry<String, Map<Class<?>, Object>> entry : bbr.entrySet()) { 675 String oldKey = entry.getKey(); 676 String newKey = oldKey + "-" + UUID.generateUuid(); 677 LOG.debug( 678 "Route: {} re-assigning local-bean id: {} to: {} to ensure ids are globally unique", 679 routeDefinition.getId(), oldKey, newKey); 680 bbrCopy.put(newKey, entry.getValue()); 681 if (!params.containsKey(oldKey)) { 682 // if a bean was bound as local bean with a key and it was not defined as template parameter 683 // then store it as if it was a template parameter with same key=value which allows us 684 // to use this local bean in the route without any problem such as: 685 // to("bean:{{myBean}}") 686 // and myBean is the local bean id. 687 params.put(oldKey, newKey); 688 } 689 } 690 } 691 692 OrderedLocationProperties prop = new OrderedLocationProperties(); 693 if (routeDefinition.getTemplateDefaultParameters() != null) { 694 // need to keep track if a parameter is set as default value or end user configured value 695 params.forEach((k, v) -> { 696 Object dv = routeDefinition.getTemplateDefaultParameters().get(k); 697 prop.put(routeDefinition.getLocation(), k, v, dv); 698 }); 699 } else { 700 prop.putAll(routeDefinition.getLocation(), params); 701 } 702 pc.setLocalProperties(prop); 703 704 // we need to shadow the bean registry on the CamelContext with the local beans from the route template context 705 if (localBeans != null && bbrCopy != null) { 706 localBeans.setLocalBeanRepository(bbrCopy); 707 } 708 709 // need to reset auto assigned ids, so there is no clash when creating routes 710 ProcessorDefinitionHelper.resetAllAutoAssignedNodeIds(routeDefinition); 711 // must re-init parent when created from a template 712 RouteDefinitionHelper.initParent(routeDefinition); 713 } 714 // Check if the route is included 715 if (includedRoute(routeDefinition)) { 716 // must ensure route is prepared, before we can start it 717 if (!routeDefinition.isPrepared()) { 718 RouteDefinitionHelper.prepareRoute(getCamelContextReference(), routeDefinition); 719 routeDefinition.markPrepared(); 720 } 721 // force the creation of ids on all nodes in the route 722 RouteDefinitionHelper.forceAssignIds(this, routeDefinition.getInput()); 723 RouteDefinitionHelper.forceAssignIds(this, routeDefinition); 724 725 StartupStepRecorder recorder 726 = getCamelContextReference().getCamelContextExtension().getStartupStepRecorder(); 727 StartupStep step = recorder.beginStep(Route.class, routeDefinition.getRouteId(), "Create Route"); 728 Route route = model.getModelReifierFactory().createRoute(this, routeDefinition); 729 recorder.endStep(step); 730 731 RouteService routeService = new RouteService(route); 732 startRouteService(routeService, true); 733 } else { 734 // Add the definition to the list of definitions to remove as the route is excluded 735 if (routeDefinitionsToRemove == null) { 736 routeDefinitionsToRemove = new ArrayList<>(routeDefinitions.size()); 737 } 738 routeDefinitionsToRemove.add(routeDefinition); 739 } 740 741 // clear local after the route is created via the reifier 742 pc.setLocalProperties(null); 743 if (localBeans != null) { 744 localBeans.setLocalBeanRepository(null); 745 } 746 } 747 if (routeDefinitionsToRemove != null) { 748 // Remove all the excluded routes 749 model.removeRouteDefinitions(routeDefinitionsToRemove); 750 } 751 } finally { 752 if (!alreadyStartingRoutes) { 753 setStartingRoutes(false); 754 } 755 pc.setLocalProperties(null); 756 if (localBeans != null) { 757 localBeans.setLocalBeanRepository(null); 758 } 759 } 760 } 761 762 @Override 763 protected ExecutorServiceManager createExecutorServiceManager() { 764 return new DefaultExecutorServiceManager(this); 765 } 766 767 @Override 768 public Processor createErrorHandler(Route route, Processor processor) throws Exception { 769 return model.getModelReifierFactory().createErrorHandler(route, processor); 770 } 771 772 @Override 773 public Expression createExpression(ExpressionDefinition definition) { 774 return model.getModelReifierFactory().createExpression(this, definition); 775 } 776 777 @Override 778 public Predicate createPredicate(ExpressionDefinition definition) { 779 return model.getModelReifierFactory().createPredicate(this, definition); 780 } 781 782 @Override 783 public void registerValidator(ValidatorDefinition def) { 784 model.getValidators().add(def); 785 Validator validator = model.getModelReifierFactory().createValidator(this, def); 786 getValidatorRegistry().put(createValidatorKey(def), validator); 787 } 788 789 private static ValueHolder<String> createValidatorKey(ValidatorDefinition def) { 790 return new ValidatorKey(new DataType(def.getType())); 791 } 792 793 @Override 794 public void registerTransformer(TransformerDefinition def) { 795 model.getTransformers().add(def); 796 Transformer transformer = model.getModelReifierFactory().createTransformer(this, def); 797 getTransformerRegistry().put(createTransformerKey(def), transformer); 798 } 799 800 @Override 801 protected boolean removeRoute(String routeId, LoggingLevel loggingLevel) throws Exception { 802 // synchronize on model first to avoid deadlock with concurrent 'addRoutes' calls: 803 synchronized (model) { 804 synchronized (this) { 805 boolean removed = super.removeRoute(routeId, loggingLevel); 806 if (removed) { 807 // must also remove the route definition 808 RouteDefinition def = getRouteDefinition(routeId); 809 if (def != null) { 810 removeRouteDefinition(def); 811 } 812 } 813 return removed; 814 } 815 } 816 } 817 818 @Override 819 public boolean removeRoute(String routeId) throws Exception { 820 // synchronize on model first to avoid deadlock with concurrent 'addRoutes' calls: 821 synchronized (model) { 822 return super.removeRoute(routeId); 823 } 824 } 825 826 /** 827 * Indicates whether the route should be included according to the precondition. 828 * 829 * @param definition the definition of the route to check. 830 * @return {@code true} if the route should be included, {@code false} otherwise. 831 */ 832 private boolean includedRoute(RouteDefinition definition) { 833 return PreconditionHelper.included(definition, this); 834 } 835 836 private static ValueHolder<String> createTransformerKey(TransformerDefinition def) { 837 if (ObjectHelper.isNotEmpty(def.getScheme())) { 838 return ObjectHelper.isNotEmpty(def.getName()) 839 ? new TransformerKey(def.getScheme() + ":" + def.getName()) : new TransformerKey(def.getScheme()); 840 } 841 if (ObjectHelper.isNotEmpty(def.getName())) { 842 return new TransformerKey(def.getName()); 843 } else { 844 return new TransformerKey(new DataType(def.getFromType()), new DataType(def.getToType())); 845 } 846 } 847 848 protected ModelReifierFactory createModelReifierFactory() { 849 Optional<ModelReifierFactory> result = ResolverHelper.resolveService( 850 this, 851 this.getCamelContextExtension().getBootstrapFactoryFinder(), 852 ModelReifierFactory.FACTORY, 853 ModelReifierFactory.class); 854 855 return result.orElseGet(DefaultModelReifierFactory::new); 856 } 857 858}