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