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