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.model; 018 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.List; 022import java.util.StringTokenizer; 023import java.util.concurrent.atomic.AtomicBoolean; 024import javax.xml.bind.annotation.XmlAccessType; 025import javax.xml.bind.annotation.XmlAccessorType; 026import javax.xml.bind.annotation.XmlAttribute; 027import javax.xml.bind.annotation.XmlElementRef; 028import javax.xml.bind.annotation.XmlRootElement; 029import javax.xml.bind.annotation.XmlTransient; 030import javax.xml.bind.annotation.XmlType; 031 032import org.apache.camel.CamelContext; 033import org.apache.camel.Endpoint; 034import org.apache.camel.ErrorHandlerFactory; 035import org.apache.camel.FailedToCreateRouteException; 036import org.apache.camel.NoSuchEndpointException; 037import org.apache.camel.Route; 038import org.apache.camel.ServiceStatus; 039import org.apache.camel.ShutdownRoute; 040import org.apache.camel.ShutdownRunningTask; 041import org.apache.camel.StatefulService; 042import org.apache.camel.builder.AdviceWithRouteBuilder; 043import org.apache.camel.builder.AdviceWithTask; 044import org.apache.camel.builder.ErrorHandlerBuilderRef; 045import org.apache.camel.builder.RouteBuilder; 046import org.apache.camel.impl.DefaultRouteContext; 047import org.apache.camel.model.rest.RestDefinition; 048import org.apache.camel.processor.interceptor.HandleFault; 049import org.apache.camel.spi.LifecycleStrategy; 050import org.apache.camel.spi.Metadata; 051import org.apache.camel.spi.RouteContext; 052import org.apache.camel.spi.RoutePolicy; 053import org.apache.camel.spi.RoutePolicyFactory; 054import org.apache.camel.util.CamelContextHelper; 055import org.apache.camel.util.ObjectHelper; 056 057/** 058 * A Camel route 059 * 060 * @version 061 */ 062@Metadata(label = "configuration") 063@XmlRootElement(name = "route") 064@XmlType(propOrder = {"inputs", "outputs"}) 065@XmlAccessorType(XmlAccessType.PROPERTY) 066// must use XmlAccessType.PROPERTY as there is some custom logic needed to be executed in the setter methods 067public class RouteDefinition extends ProcessorDefinition<RouteDefinition> { 068 private final AtomicBoolean prepared = new AtomicBoolean(false); 069 private List<FromDefinition> inputs = new ArrayList<FromDefinition>(); 070 private List<ProcessorDefinition<?>> outputs = new ArrayList<ProcessorDefinition<?>>(); 071 private String group; 072 private String streamCache; 073 private String trace; 074 private String messageHistory; 075 private String handleFault; 076 private String delayer; 077 private String autoStartup; 078 private Integer startupOrder; 079 private List<RoutePolicy> routePolicies; 080 private String routePolicyRef; 081 private ShutdownRoute shutdownRoute; 082 private ShutdownRunningTask shutdownRunningTask; 083 private String errorHandlerRef; 084 private ErrorHandlerFactory errorHandlerBuilder; 085 // keep state whether the error handler is context scoped or not 086 // (will by default be context scoped of no explicit error handler configured) 087 private boolean contextScopedErrorHandler = true; 088 private Boolean rest; 089 private RestDefinition restDefinition; 090 091 public RouteDefinition() { 092 } 093 094 public RouteDefinition(String uri) { 095 from(uri); 096 } 097 098 public RouteDefinition(Endpoint endpoint) { 099 from(endpoint); 100 } 101 102 /** 103 * This route is created from the REST DSL. 104 */ 105 public void fromRest(String uri) { 106 from(uri); 107 rest = true; 108 } 109 110 /** 111 * Prepares the route definition to be ready to be added to {@link CamelContext} 112 * 113 * @param context the camel context 114 */ 115 public void prepare(ModelCamelContext context) { 116 if (prepared.compareAndSet(false, true)) { 117 RouteDefinitionHelper.prepareRoute(context, this); 118 } 119 } 120 121 /** 122 * Marks the route definition as prepared. 123 * <p/> 124 * This is needed if routes have been created by components such as 125 * <tt>camel-spring</tt> or <tt>camel-blueprint</tt>. 126 * Usually they share logic in the <tt>camel-core-xml</tt> module which prepares the routes. 127 */ 128 public void markPrepared() { 129 prepared.set(true); 130 } 131 132 /** 133 * Marks the route definition as un-prepared. 134 * <p/> 135 * This is needed if routes have been created by components such as 136 * <tt>camel-scala</tt>. To unset the prepare so the routes can be prepared 137 * at a later stage when scala has build the routes completely. 138 */ 139 public void markUnprepared() { 140 prepared.set(false); 141 } 142 143 @Override 144 public String toString() { 145 if (getId() != null) { 146 return "Route(" + getId() + ")[" + inputs + " -> " + outputs + "]"; 147 } else { 148 return "Route[" + inputs + " -> " + outputs + "]"; 149 } 150 } 151 152 /** 153 * Returns the status of the route if it has been registered with a {@link CamelContext} 154 */ 155 public ServiceStatus getStatus(CamelContext camelContext) { 156 if (camelContext != null) { 157 ServiceStatus answer = camelContext.getRouteStatus(this.getId()); 158 if (answer == null) { 159 answer = ServiceStatus.Stopped; 160 } 161 return answer; 162 } 163 return null; 164 } 165 166 public boolean isStartable(CamelContext camelContext) { 167 ServiceStatus status = getStatus(camelContext); 168 if (status == null) { 169 return true; 170 } else { 171 return status.isStartable(); 172 } 173 } 174 175 public boolean isStoppable(CamelContext camelContext) { 176 ServiceStatus status = getStatus(camelContext); 177 if (status == null) { 178 return false; 179 } else { 180 return status.isStoppable(); 181 } 182 } 183 184 public List<RouteContext> addRoutes(ModelCamelContext camelContext, Collection<Route> routes) throws Exception { 185 List<RouteContext> answer = new ArrayList<RouteContext>(); 186 187 @SuppressWarnings("deprecation") 188 ErrorHandlerFactory handler = camelContext.getErrorHandlerBuilder(); 189 if (handler != null) { 190 setErrorHandlerBuilderIfNull(handler); 191 } 192 193 for (FromDefinition fromType : inputs) { 194 RouteContext routeContext; 195 try { 196 routeContext = addRoutes(camelContext, routes, fromType); 197 } catch (FailedToCreateRouteException e) { 198 throw e; 199 } catch (Exception e) { 200 // wrap in exception which provide more details about which route was failing 201 throw new FailedToCreateRouteException(getId(), toString(), e); 202 } 203 answer.add(routeContext); 204 } 205 return answer; 206 } 207 208 209 public Endpoint resolveEndpoint(CamelContext camelContext, String uri) throws NoSuchEndpointException { 210 ObjectHelper.notNull(camelContext, "CamelContext"); 211 return CamelContextHelper.getMandatoryEndpoint(camelContext, uri); 212 } 213 214 public RouteDefinition adviceWith(CamelContext camelContext, RouteBuilder builder) throws Exception { 215 return adviceWith((ModelCamelContext)camelContext, builder); 216 } 217 218 /** 219 * Advices this route with the route builder. 220 * <p/> 221 * <b>Important:</b> It is recommended to only advice a given route once (you can of course advice multiple routes). 222 * If you do it multiple times, then it may not work as expected, especially when any kind of error handling is involved. 223 * The Camel team plan for Camel 3.0 to support this as internal refactorings in the routing engine is needed to support this properly. 224 * <p/> 225 * You can use a regular {@link RouteBuilder} but the specialized {@link org.apache.camel.builder.AdviceWithRouteBuilder} 226 * has additional features when using the <a href="http://camel.apache.org/advicewith.html">advice with</a> feature. 227 * We therefore suggest you to use the {@link org.apache.camel.builder.AdviceWithRouteBuilder}. 228 * <p/> 229 * The advice process will add the interceptors, on exceptions, on completions etc. configured 230 * from the route builder to this route. 231 * <p/> 232 * This is mostly used for testing purpose to add interceptors and the likes to an existing route. 233 * <p/> 234 * Will stop and remove the old route from camel context and add and start this new advised route. 235 * 236 * @param camelContext the camel context 237 * @param builder the route builder 238 * @return a new route which is this route merged with the route builder 239 * @throws Exception can be thrown from the route builder 240 * @see AdviceWithRouteBuilder 241 */ 242 @SuppressWarnings("deprecation") 243 public RouteDefinition adviceWith(ModelCamelContext camelContext, RouteBuilder builder) throws Exception { 244 ObjectHelper.notNull(camelContext, "CamelContext"); 245 ObjectHelper.notNull(builder, "RouteBuilder"); 246 247 log.debug("AdviceWith route before: {}", this); 248 249 // inject this route into the advice route builder so it can access this route 250 // and offer features to manipulate the route directly 251 if (builder instanceof AdviceWithRouteBuilder) { 252 ((AdviceWithRouteBuilder) builder).setOriginalRoute(this); 253 } 254 255 // configure and prepare the routes from the builder 256 RoutesDefinition routes = builder.configureRoutes(camelContext); 257 258 log.debug("AdviceWith routes: {}", routes); 259 260 // we can only advice with a route builder without any routes 261 if (!builder.getRouteCollection().getRoutes().isEmpty()) { 262 throw new IllegalArgumentException("You can only advice from a RouteBuilder which has no existing routes." 263 + " Remove all routes from the route builder."); 264 } 265 // we can not advice with error handlers (if you added a new error handler in the route builder) 266 // we must check the error handler on builder is not the same as on camel context, as that would be the default 267 // context scoped error handler, in case no error handlers was configured 268 if (builder.getRouteCollection().getErrorHandlerBuilder() != null 269 && camelContext.getErrorHandlerBuilder() != builder.getRouteCollection().getErrorHandlerBuilder()) { 270 throw new IllegalArgumentException("You can not advice with error handlers. Remove the error handlers from the route builder."); 271 } 272 273 // stop and remove this existing route 274 camelContext.removeRouteDefinition(this); 275 276 // any advice with tasks we should execute first? 277 if (builder instanceof AdviceWithRouteBuilder) { 278 List<AdviceWithTask> tasks = ((AdviceWithRouteBuilder) builder).getAdviceWithTasks(); 279 for (AdviceWithTask task : tasks) { 280 task.task(); 281 } 282 } 283 284 // now merge which also ensures that interceptors and the likes get mixed in correctly as well 285 RouteDefinition merged = routes.route(this); 286 287 // add the new merged route 288 camelContext.getRouteDefinitions().add(0, merged); 289 290 // log the merged route at info level to make it easier to end users to spot any mistakes they may have made 291 log.info("AdviceWith route after: " + merged); 292 293 // If the camel context is started then we start the route 294 if (camelContext instanceof StatefulService) { 295 StatefulService service = (StatefulService) camelContext; 296 if (service.isStarted()) { 297 camelContext.startRoute(merged); 298 } 299 } 300 return merged; 301 } 302 303 // Fluent API 304 // ----------------------------------------------------------------------- 305 306 /** 307 * Creates an input to the route 308 * 309 * @param uri the from uri 310 * @return the builder 311 */ 312 public RouteDefinition from(String uri) { 313 getInputs().add(new FromDefinition(uri)); 314 return this; 315 } 316 317 /** 318 * Creates an input to the route 319 * 320 * @param endpoint the from endpoint 321 * @return the builder 322 */ 323 public RouteDefinition from(Endpoint endpoint) { 324 getInputs().add(new FromDefinition(endpoint)); 325 return this; 326 } 327 328 /** 329 * Creates inputs to the route 330 * 331 * @param uris the from uris 332 * @return the builder 333 */ 334 public RouteDefinition from(String... uris) { 335 for (String uri : uris) { 336 getInputs().add(new FromDefinition(uri)); 337 } 338 return this; 339 } 340 341 /** 342 * Creates inputs to the route 343 * 344 * @param endpoints the from endpoints 345 * @return the builder 346 */ 347 public RouteDefinition from(Endpoint... endpoints) { 348 for (Endpoint endpoint : endpoints) { 349 getInputs().add(new FromDefinition(endpoint)); 350 } 351 return this; 352 } 353 354 /** 355 * Set the group name for this route 356 * 357 * @param name the group name 358 * @return the builder 359 */ 360 public RouteDefinition group(String name) { 361 setGroup(name); 362 return this; 363 } 364 365 /** 366 * Set the route id for this route 367 * 368 * @param id the route id 369 * @return the builder 370 */ 371 public RouteDefinition routeId(String id) { 372 setId(id); 373 return this; 374 } 375 376 /** 377 * Set the route description for this route 378 * 379 * @param description the route description 380 * @return the builder 381 */ 382 public RouteDefinition routeDescription(String description) { 383 DescriptionDefinition desc = new DescriptionDefinition(); 384 desc.setText(description); 385 setDescription(desc); 386 return this; 387 } 388 389 /** 390 * Disable stream caching for this route. 391 * 392 * @return the builder 393 */ 394 public RouteDefinition noStreamCaching() { 395 setStreamCache("false"); 396 return this; 397 } 398 399 /** 400 * Enable stream caching for this route. 401 * 402 * @return the builder 403 */ 404 public RouteDefinition streamCaching() { 405 setStreamCache("true"); 406 return this; 407 } 408 409 /** 410 * Enable stream caching for this route. 411 * 412 * @param streamCache whether to use stream caching (true or false), the value can be a property placeholder 413 * @return the builder 414 */ 415 public RouteDefinition streamCaching(String streamCache) { 416 setStreamCache(streamCache); 417 return this; 418 } 419 420 /** 421 * Disable tracing for this route. 422 * 423 * @return the builder 424 */ 425 public RouteDefinition noTracing() { 426 setTrace("false"); 427 return this; 428 } 429 430 /** 431 * Enable tracing for this route. 432 * 433 * @return the builder 434 */ 435 public RouteDefinition tracing() { 436 setTrace("true"); 437 return this; 438 } 439 440 /** 441 * Enable tracing for this route. 442 * 443 * @param tracing whether to use tracing (true or false), the value can be a property placeholder 444 * @return the builder 445 */ 446 public RouteDefinition tracing(String tracing) { 447 setTrace(tracing); 448 return this; 449 } 450 451 /** 452 * Enable message history for this route. 453 * 454 * @return the builder 455 */ 456 public RouteDefinition messageHistory() { 457 setMessageHistory("true"); 458 return this; 459 } 460 461 /** 462 * Enable message history for this route. 463 * 464 * @param messageHistory whether to use message history (true or false), the value can be a property placeholder 465 * @return the builder 466 */ 467 public RouteDefinition messageHistory(String messageHistory) { 468 setMessageHistory(messageHistory); 469 return this; 470 } 471 472 /** 473 * Disable message history for this route. 474 * 475 * @return the builder 476 */ 477 public RouteDefinition noMessageHistory() { 478 setMessageHistory("false"); 479 return this; 480 } 481 482 /** 483 * Disable handle fault for this route. 484 * 485 * @return the builder 486 */ 487 public RouteDefinition noHandleFault() { 488 setHandleFault("false"); 489 return this; 490 } 491 492 /** 493 * Enable handle fault for this route. 494 * 495 * @return the builder 496 */ 497 public RouteDefinition handleFault() { 498 setHandleFault("true"); 499 return this; 500 } 501 502 /** 503 * Disable delayer for this route. 504 * 505 * @return the builder 506 */ 507 public RouteDefinition noDelayer() { 508 setDelayer("0"); 509 return this; 510 } 511 512 /** 513 * Enable delayer for this route. 514 * 515 * @param delay delay in millis 516 * @return the builder 517 */ 518 public RouteDefinition delayer(long delay) { 519 setDelayer("" + delay); 520 return this; 521 } 522 523 /** 524 * Installs the given <a href="http://camel.apache.org/error-handler.html">error handler</a> builder. 525 * 526 * @param errorHandlerBuilder the error handler to be used by default for all child routes 527 * @return the current builder with the error handler configured 528 */ 529 public RouteDefinition errorHandler(ErrorHandlerFactory errorHandlerBuilder) { 530 setErrorHandlerBuilder(errorHandlerBuilder); 531 // we are now using a route scoped error handler 532 contextScopedErrorHandler = false; 533 return this; 534 } 535 536 /** 537 * Disables this route from being auto started when Camel starts. 538 * 539 * @return the builder 540 */ 541 public RouteDefinition noAutoStartup() { 542 setAutoStartup("false"); 543 return this; 544 } 545 546 /** 547 * Sets the auto startup property on this route. 548 * 549 * @param autoStartup whether to auto startup (true or false), the value can be a property placeholder 550 * @return the builder 551 */ 552 public RouteDefinition autoStartup(String autoStartup) { 553 setAutoStartup(autoStartup); 554 return this; 555 } 556 557 /** 558 * Sets the auto startup property on this route. 559 * 560 * @param autoStartup - boolean indicator 561 * @return the builder 562 */ 563 public RouteDefinition autoStartup(boolean autoStartup) { 564 setAutoStartup(Boolean.toString(autoStartup)); 565 return this; 566 } 567 568 /** 569 * Configures the startup order for this route 570 * <p/> 571 * Camel will reorder routes and star them ordered by 0..N where 0 is the lowest number and N the highest number. 572 * Camel will stop routes in reverse order when its stopping. 573 * 574 * @param order the order represented as a number 575 * @return the builder 576 */ 577 public RouteDefinition startupOrder(int order) { 578 setStartupOrder(order); 579 return this; 580 } 581 582 /** 583 * Configures route policies for this route 584 * 585 * @param policies the route policies 586 * @return the builder 587 */ 588 public RouteDefinition routePolicy(RoutePolicy... policies) { 589 if (routePolicies == null) { 590 routePolicies = new ArrayList<RoutePolicy>(); 591 } 592 for (RoutePolicy policy : policies) { 593 routePolicies.add(policy); 594 } 595 return this; 596 } 597 598 /** 599 * Configures a route policy for this route 600 * 601 * @param routePolicyRef reference to a {@link RoutePolicy} to lookup and use. 602 * You can specify multiple references by separating using comma. 603 * @return the builder 604 */ 605 public RouteDefinition routePolicyRef(String routePolicyRef) { 606 setRoutePolicyRef(routePolicyRef); 607 return this; 608 } 609 610 /** 611 * Configures a shutdown route option. 612 * 613 * @param shutdownRoute the option to use when shutting down this route 614 * @return the builder 615 */ 616 public RouteDefinition shutdownRoute(ShutdownRoute shutdownRoute) { 617 setShutdownRoute(shutdownRoute); 618 return this; 619 } 620 621 /** 622 * Configures a shutdown running task option. 623 * 624 * @param shutdownRunningTask the option to use when shutting down and how to act upon running tasks. 625 * @return the builder 626 */ 627 public RouteDefinition shutdownRunningTask(ShutdownRunningTask shutdownRunningTask) { 628 setShutdownRunningTask(shutdownRunningTask); 629 return this; 630 } 631 632 // Properties 633 // ----------------------------------------------------------------------- 634 635 public List<FromDefinition> getInputs() { 636 return inputs; 637 } 638 639 /** 640 * Input to the route. 641 */ 642 @XmlElementRef 643 public void setInputs(List<FromDefinition> inputs) { 644 this.inputs = inputs; 645 } 646 647 public List<ProcessorDefinition<?>> getOutputs() { 648 return outputs; 649 } 650 651 /** 652 * Outputs are processors that determines how messages are processed by this route. 653 */ 654 @XmlElementRef 655 public void setOutputs(List<ProcessorDefinition<?>> outputs) { 656 this.outputs = outputs; 657 658 if (outputs != null) { 659 for (ProcessorDefinition<?> output : outputs) { 660 configureChild(output); 661 } 662 } 663 } 664 665 public boolean isOutputSupported() { 666 return true; 667 } 668 669 /** 670 * The group that this route belongs to; could be the name of the RouteBuilder class 671 * or be explicitly configured in the XML. 672 * <p/> 673 * May be null. 674 */ 675 public String getGroup() { 676 return group; 677 } 678 679 /** 680 * The group that this route belongs to; could be the name of the RouteBuilder class 681 * or be explicitly configured in the XML. 682 * <p/> 683 * May be null. 684 */ 685 @XmlAttribute 686 public void setGroup(String group) { 687 this.group = group; 688 } 689 690 /** 691 * Whether stream caching is enabled on this route. 692 */ 693 public String getStreamCache() { 694 return streamCache; 695 } 696 697 /** 698 * Whether stream caching is enabled on this route. 699 */ 700 @XmlAttribute 701 public void setStreamCache(String streamCache) { 702 this.streamCache = streamCache; 703 } 704 705 /** 706 * Whether tracing is enabled on this route. 707 */ 708 public String getTrace() { 709 return trace; 710 } 711 712 /** 713 * Whether tracing is enabled on this route. 714 */ 715 @XmlAttribute 716 public void setTrace(String trace) { 717 this.trace = trace; 718 } 719 720 /** 721 * Whether message history is enabled on this route. 722 */ 723 public String getMessageHistory() { 724 return messageHistory; 725 } 726 727 /** 728 * Whether message history is enabled on this route. 729 */ 730 @XmlAttribute @Metadata(defaultValue = "true") 731 public void setMessageHistory(String messageHistory) { 732 this.messageHistory = messageHistory; 733 } 734 735 /** 736 * Whether handle fault is enabled on this route. 737 */ 738 public String getHandleFault() { 739 return handleFault; 740 } 741 742 /** 743 * Whether handle fault is enabled on this route. 744 */ 745 @XmlAttribute 746 public void setHandleFault(String handleFault) { 747 this.handleFault = handleFault; 748 } 749 750 /** 751 * Whether to slow down processing messages by a given delay in msec. 752 */ 753 public String getDelayer() { 754 return delayer; 755 } 756 757 /** 758 * Whether to slow down processing messages by a given delay in msec. 759 */ 760 @XmlAttribute 761 public void setDelayer(String delayer) { 762 this.delayer = delayer; 763 } 764 765 /** 766 * Whether to auto start this route 767 */ 768 public String getAutoStartup() { 769 return autoStartup; 770 } 771 772 public boolean isAutoStartup(CamelContext camelContext) throws Exception { 773 if (getAutoStartup() == null) { 774 // should auto startup by default 775 return true; 776 } 777 Boolean isAutoStartup = CamelContextHelper.parseBoolean(camelContext, getAutoStartup()); 778 return isAutoStartup != null && isAutoStartup; 779 } 780 781 /** 782 * Whether to auto start this route 783 */ 784 @XmlAttribute @Metadata(defaultValue = "true") 785 public void setAutoStartup(String autoStartup) { 786 this.autoStartup = autoStartup; 787 } 788 789 /** 790 * To configure the ordering of the routes being started 791 */ 792 public Integer getStartupOrder() { 793 return startupOrder; 794 } 795 796 /** 797 * To configure the ordering of the routes being started 798 */ 799 @XmlAttribute 800 public void setStartupOrder(Integer startupOrder) { 801 this.startupOrder = startupOrder; 802 } 803 804 /** 805 * Sets the bean ref name of the error handler builder to use on this route 806 */ 807 @XmlAttribute 808 public void setErrorHandlerRef(String errorHandlerRef) { 809 this.errorHandlerRef = errorHandlerRef; 810 // we use an specific error handler ref (from Spring DSL) then wrap that 811 // with a error handler build ref so Camel knows its not just the default one 812 setErrorHandlerBuilder(new ErrorHandlerBuilderRef(errorHandlerRef)); 813 } 814 815 /** 816 * Sets the bean ref name of the error handler builder to use on this route 817 */ 818 public String getErrorHandlerRef() { 819 return errorHandlerRef; 820 } 821 822 /** 823 * Sets the error handler if one is not already set 824 */ 825 public void setErrorHandlerBuilderIfNull(ErrorHandlerFactory errorHandlerBuilder) { 826 if (this.errorHandlerBuilder == null) { 827 setErrorHandlerBuilder(errorHandlerBuilder); 828 } 829 } 830 831 /** 832 * Reference to custom {@link org.apache.camel.spi.RoutePolicy} to use by the route. 833 * Multiple policies can be configured by separating values using comma. 834 */ 835 @XmlAttribute 836 public void setRoutePolicyRef(String routePolicyRef) { 837 this.routePolicyRef = routePolicyRef; 838 } 839 840 /** 841 * Reference to custom {@link org.apache.camel.spi.RoutePolicy} to use by the route. 842 * Multiple policies can be configured by separating values using comma. 843 */ 844 public String getRoutePolicyRef() { 845 return routePolicyRef; 846 } 847 848 public List<RoutePolicy> getRoutePolicies() { 849 return routePolicies; 850 } 851 852 @XmlTransient 853 public void setRoutePolicies(List<RoutePolicy> routePolicies) { 854 this.routePolicies = routePolicies; 855 } 856 857 public ShutdownRoute getShutdownRoute() { 858 return shutdownRoute; 859 } 860 861 /** 862 * To control how to shutdown the route. 863 */ 864 @XmlAttribute @Metadata(defaultValue = "Default") 865 public void setShutdownRoute(ShutdownRoute shutdownRoute) { 866 this.shutdownRoute = shutdownRoute; 867 } 868 869 /** 870 * To control how to shutdown the route. 871 */ 872 public ShutdownRunningTask getShutdownRunningTask() { 873 return shutdownRunningTask; 874 } 875 876 /** 877 * To control how to shutdown the route. 878 */ 879 @XmlAttribute @Metadata(defaultValue = "CompleteCurrentTaskOnly") 880 public void setShutdownRunningTask(ShutdownRunningTask shutdownRunningTask) { 881 this.shutdownRunningTask = shutdownRunningTask; 882 } 883 884 private ErrorHandlerFactory createErrorHandlerBuilder() { 885 if (errorHandlerRef != null) { 886 return new ErrorHandlerBuilderRef(errorHandlerRef); 887 } 888 889 // return a reference to the default error handler 890 return new ErrorHandlerBuilderRef(ErrorHandlerBuilderRef.DEFAULT_ERROR_HANDLER_BUILDER); 891 } 892 893 @XmlTransient 894 public ErrorHandlerFactory getErrorHandlerBuilder() { 895 if (errorHandlerBuilder == null) { 896 errorHandlerBuilder = createErrorHandlerBuilder(); 897 } 898 return errorHandlerBuilder; 899 } 900 901 /** 902 * Sets the error handler to use with processors created by this builder 903 */ 904 public void setErrorHandlerBuilder(ErrorHandlerFactory errorHandlerBuilder) { 905 this.errorHandlerBuilder = errorHandlerBuilder; 906 } 907 908 @XmlAttribute 909 public Boolean isRest() { 910 return rest; 911 } 912 913 public RestDefinition getRestDefinition() { 914 return restDefinition; 915 } 916 917 @XmlTransient 918 public void setRestDefinition(RestDefinition restDefinition) { 919 this.restDefinition = restDefinition; 920 } 921 922 @SuppressWarnings("deprecation") 923 public boolean isContextScopedErrorHandler(CamelContext context) { 924 if (!contextScopedErrorHandler) { 925 return false; 926 } 927 // if error handler ref is configured it may refer to a context scoped, so we need to check this first 928 // the XML DSL will configure error handlers using refs, so we need this additional test 929 if (errorHandlerRef != null) { 930 ErrorHandlerFactory routeScoped = getErrorHandlerBuilder(); 931 ErrorHandlerFactory contextScoped = context.getErrorHandlerBuilder(); 932 return routeScoped != null && contextScoped != null && routeScoped == contextScoped; 933 } 934 935 return true; 936 } 937 938 // Implementation methods 939 // ------------------------------------------------------------------------- 940 protected RouteContext addRoutes(CamelContext camelContext, Collection<Route> routes, FromDefinition fromType) throws Exception { 941 RouteContext routeContext = new DefaultRouteContext(camelContext, this, fromType, routes); 942 943 // configure tracing 944 if (trace != null) { 945 Boolean isTrace = CamelContextHelper.parseBoolean(camelContext, getTrace()); 946 if (isTrace != null) { 947 routeContext.setTracing(isTrace); 948 if (isTrace) { 949 log.debug("Tracing is enabled on route: {}", getId()); 950 // tracing is added in the DefaultChannel so we can enable it on the fly 951 } 952 } 953 } 954 955 // configure message history 956 if (messageHistory != null) { 957 Boolean isMessageHistory = CamelContextHelper.parseBoolean(camelContext, getMessageHistory()); 958 if (isMessageHistory != null) { 959 routeContext.setMessageHistory(isMessageHistory); 960 if (isMessageHistory) { 961 log.debug("Message history is enabled on route: {}", getId()); 962 } 963 } 964 } 965 966 // configure stream caching 967 if (streamCache != null) { 968 Boolean isStreamCache = CamelContextHelper.parseBoolean(camelContext, getStreamCache()); 969 if (isStreamCache != null) { 970 routeContext.setStreamCaching(isStreamCache); 971 if (isStreamCache) { 972 log.debug("StreamCaching is enabled on route: {}", getId()); 973 } 974 } 975 } 976 977 // configure handle fault 978 if (handleFault != null) { 979 Boolean isHandleFault = CamelContextHelper.parseBoolean(camelContext, getHandleFault()); 980 if (isHandleFault != null) { 981 routeContext.setHandleFault(isHandleFault); 982 if (isHandleFault) { 983 log.debug("HandleFault is enabled on route: {}", getId()); 984 // only add a new handle fault if not already a global configured on camel context 985 if (HandleFault.getHandleFault(camelContext) == null) { 986 addInterceptStrategy(new HandleFault()); 987 } 988 } 989 } 990 } 991 992 // configure delayer 993 if (delayer != null) { 994 Long delayer = CamelContextHelper.parseLong(camelContext, getDelayer()); 995 if (delayer != null) { 996 routeContext.setDelayer(delayer); 997 if (delayer > 0) { 998 log.debug("Delayer is enabled with: {} ms. on route: {}", delayer, getId()); 999 } else { 1000 log.debug("Delayer is disabled on route: {}", getId()); 1001 } 1002 } 1003 } 1004 1005 // configure route policy 1006 if (routePolicies != null && !routePolicies.isEmpty()) { 1007 for (RoutePolicy policy : routePolicies) { 1008 log.debug("RoutePolicy is enabled: {} on route: {}", policy, getId()); 1009 routeContext.getRoutePolicyList().add(policy); 1010 } 1011 } 1012 if (routePolicyRef != null) { 1013 StringTokenizer policyTokens = new StringTokenizer(routePolicyRef, ","); 1014 while (policyTokens.hasMoreTokens()) { 1015 String ref = policyTokens.nextToken().trim(); 1016 RoutePolicy policy = CamelContextHelper.mandatoryLookup(camelContext, ref, RoutePolicy.class); 1017 log.debug("RoutePolicy is enabled: {} on route: {}", policy, getId()); 1018 routeContext.getRoutePolicyList().add(policy); 1019 } 1020 } 1021 if (camelContext.getRoutePolicyFactories() != null) { 1022 for (RoutePolicyFactory factory : camelContext.getRoutePolicyFactories()) { 1023 RoutePolicy policy = factory.createRoutePolicy(camelContext, getId(), this); 1024 if (policy != null) { 1025 log.debug("RoutePolicy is enabled: {} on route: {}", policy, getId()); 1026 routeContext.getRoutePolicyList().add(policy); 1027 } 1028 } 1029 } 1030 1031 // configure auto startup 1032 Boolean isAutoStartup = CamelContextHelper.parseBoolean(camelContext, getAutoStartup()); 1033 if (isAutoStartup != null) { 1034 log.debug("Using AutoStartup {} on route: {}", isAutoStartup, getId()); 1035 routeContext.setAutoStartup(isAutoStartup); 1036 } 1037 1038 // configure shutdown 1039 if (shutdownRoute != null) { 1040 log.debug("Using ShutdownRoute {} on route: {}", getShutdownRoute(), getId()); 1041 routeContext.setShutdownRoute(getShutdownRoute()); 1042 } 1043 if (shutdownRunningTask != null) { 1044 log.debug("Using ShutdownRunningTask {} on route: {}", getShutdownRunningTask(), getId()); 1045 routeContext.setShutdownRunningTask(getShutdownRunningTask()); 1046 } 1047 1048 // should inherit the intercept strategies we have defined 1049 routeContext.setInterceptStrategies(this.getInterceptStrategies()); 1050 // force endpoint resolution 1051 routeContext.getEndpoint(); 1052 for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) { 1053 strategy.onRouteContextCreate(routeContext); 1054 } 1055 1056 // validate route has output processors 1057 if (!ProcessorDefinitionHelper.hasOutputs(outputs, true)) { 1058 RouteDefinition route = routeContext.getRoute(); 1059 String at = fromType.toString(); 1060 Exception cause = new IllegalArgumentException("Route " + route.getId() + " has no output processors." 1061 + " You need to add outputs to the route such as to(\"log:foo\")."); 1062 throw new FailedToCreateRouteException(route.getId(), route.toString(), at, cause); 1063 } 1064 1065 List<ProcessorDefinition<?>> list = new ArrayList<ProcessorDefinition<?>>(outputs); 1066 for (ProcessorDefinition<?> output : list) { 1067 try { 1068 output.addRoutes(routeContext, routes); 1069 } catch (Exception e) { 1070 RouteDefinition route = routeContext.getRoute(); 1071 throw new FailedToCreateRouteException(route.getId(), route.toString(), output.toString(), e); 1072 } 1073 } 1074 1075 routeContext.commit(); 1076 return routeContext; 1077 } 1078}