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