001/* 002 * Copyright 2012-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.autoconfigure.amqp; 018 019import java.util.ArrayList; 020import java.util.List; 021 022import org.springframework.amqp.core.AcknowledgeMode; 023import org.springframework.amqp.rabbit.connection.CachingConnectionFactory.CacheMode; 024import org.springframework.boot.context.properties.ConfigurationProperties; 025import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; 026import org.springframework.boot.context.properties.NestedConfigurationProperty; 027import org.springframework.util.CollectionUtils; 028import org.springframework.util.StringUtils; 029 030/** 031 * Configuration properties for Rabbit. 032 * 033 * @author Greg Turnquist 034 * @author Dave Syer 035 * @author Stephane Nicoll 036 * @author Andy Wilkinson 037 * @author Josh Thornhill 038 * @author Gary Russell 039 */ 040@ConfigurationProperties(prefix = "spring.rabbitmq") 041public class RabbitProperties { 042 043 /** 044 * RabbitMQ host. 045 */ 046 private String host = "localhost"; 047 048 /** 049 * RabbitMQ port. 050 */ 051 private int port = 5672; 052 053 /** 054 * Login user to authenticate to the broker. 055 */ 056 private String username; 057 058 /** 059 * Login to authenticate against the broker. 060 */ 061 private String password; 062 063 /** 064 * SSL configuration. 065 */ 066 private final Ssl ssl = new Ssl(); 067 068 /** 069 * Virtual host to use when connecting to the broker. 070 */ 071 private String virtualHost; 072 073 /** 074 * Comma-separated list of addresses to which the client should connect. 075 */ 076 private String addresses; 077 078 /** 079 * Requested heartbeat timeout, in seconds; zero for none. 080 */ 081 private Integer requestedHeartbeat; 082 083 /** 084 * Enable publisher confirms. 085 */ 086 private boolean publisherConfirms; 087 088 /** 089 * Enable publisher returns. 090 */ 091 private boolean publisherReturns; 092 093 /** 094 * Connection timeout, in milliseconds; zero for infinite. 095 */ 096 private Integer connectionTimeout; 097 098 /** 099 * Cache configuration. 100 */ 101 private final Cache cache = new Cache(); 102 103 /** 104 * Listener container configuration. 105 */ 106 private final Listener listener = new Listener(); 107 108 private final Template template = new Template(); 109 110 private List<Address> parsedAddresses; 111 112 public String getHost() { 113 return this.host; 114 } 115 116 /** 117 * Returns the host from the first address, or the configured host if no addresses 118 * have been set. 119 * @return the host 120 * @see #setAddresses(String) 121 * @see #getHost() 122 */ 123 public String determineHost() { 124 if (CollectionUtils.isEmpty(this.parsedAddresses)) { 125 return getHost(); 126 } 127 return this.parsedAddresses.get(0).host; 128 } 129 130 public void setHost(String host) { 131 this.host = host; 132 } 133 134 public int getPort() { 135 return this.port; 136 } 137 138 /** 139 * Returns the port from the first address, or the configured port if no addresses 140 * have been set. 141 * @return the port 142 * @see #setAddresses(String) 143 * @see #getPort() 144 */ 145 public int determinePort() { 146 if (CollectionUtils.isEmpty(this.parsedAddresses)) { 147 return getPort(); 148 } 149 Address address = this.parsedAddresses.get(0); 150 return address.port; 151 } 152 153 public void setPort(int port) { 154 this.port = port; 155 } 156 157 public String getAddresses() { 158 return this.addresses; 159 } 160 161 /** 162 * Returns the comma-separated addresses or a single address ({@code host:port}) 163 * created from the configured host and port if no addresses have been set. 164 * @return the addresses 165 */ 166 public String determineAddresses() { 167 if (CollectionUtils.isEmpty(this.parsedAddresses)) { 168 return this.host + ":" + this.port; 169 } 170 List<String> addressStrings = new ArrayList<String>(); 171 for (Address parsedAddress : this.parsedAddresses) { 172 addressStrings.add(parsedAddress.host + ":" + parsedAddress.port); 173 } 174 return StringUtils.collectionToCommaDelimitedString(addressStrings); 175 } 176 177 public void setAddresses(String addresses) { 178 this.addresses = addresses; 179 this.parsedAddresses = parseAddresses(addresses); 180 } 181 182 private List<Address> parseAddresses(String addresses) { 183 List<Address> parsedAddresses = new ArrayList<Address>(); 184 for (String address : StringUtils.commaDelimitedListToStringArray(addresses)) { 185 parsedAddresses.add(new Address(address)); 186 } 187 return parsedAddresses; 188 } 189 190 public String getUsername() { 191 return this.username; 192 } 193 194 /** 195 * If addresses have been set and the first address has a username it is returned. 196 * Otherwise returns the result of calling {@code getUsername()}. 197 * @return the username 198 * @see #setAddresses(String) 199 * @see #getUsername() 200 */ 201 public String determineUsername() { 202 if (CollectionUtils.isEmpty(this.parsedAddresses)) { 203 return this.username; 204 } 205 Address address = this.parsedAddresses.get(0); 206 return address.username == null ? this.username : address.username; 207 } 208 209 public void setUsername(String username) { 210 this.username = username; 211 } 212 213 public String getPassword() { 214 return this.password; 215 } 216 217 /** 218 * If addresses have been set and the first address has a password it is returned. 219 * Otherwise returns the result of calling {@code getPassword()}. 220 * @return the password or {@code null} 221 * @see #setAddresses(String) 222 * @see #getPassword() 223 */ 224 public String determinePassword() { 225 if (CollectionUtils.isEmpty(this.parsedAddresses)) { 226 return getPassword(); 227 } 228 Address address = this.parsedAddresses.get(0); 229 return address.password == null ? getPassword() : address.password; 230 } 231 232 public void setPassword(String password) { 233 this.password = password; 234 } 235 236 public Ssl getSsl() { 237 return this.ssl; 238 } 239 240 public String getVirtualHost() { 241 return this.virtualHost; 242 } 243 244 /** 245 * If addresses have been set and the first address has a virtual host it is returned. 246 * Otherwise returns the result of calling {@code getVirtualHost()}. 247 * @return the virtual host or {@code null} 248 * @see #setAddresses(String) 249 * @see #getVirtualHost() 250 */ 251 public String determineVirtualHost() { 252 if (CollectionUtils.isEmpty(this.parsedAddresses)) { 253 return getVirtualHost(); 254 } 255 Address address = this.parsedAddresses.get(0); 256 return address.virtualHost == null ? getVirtualHost() : address.virtualHost; 257 } 258 259 public void setVirtualHost(String virtualHost) { 260 this.virtualHost = ("".equals(virtualHost) ? "/" : virtualHost); 261 } 262 263 public Integer getRequestedHeartbeat() { 264 return this.requestedHeartbeat; 265 } 266 267 public void setRequestedHeartbeat(Integer requestedHeartbeat) { 268 this.requestedHeartbeat = requestedHeartbeat; 269 } 270 271 public boolean isPublisherConfirms() { 272 return this.publisherConfirms; 273 } 274 275 public void setPublisherConfirms(boolean publisherConfirms) { 276 this.publisherConfirms = publisherConfirms; 277 } 278 279 public boolean isPublisherReturns() { 280 return this.publisherReturns; 281 } 282 283 public void setPublisherReturns(boolean publisherReturns) { 284 this.publisherReturns = publisherReturns; 285 } 286 287 public Integer getConnectionTimeout() { 288 return this.connectionTimeout; 289 } 290 291 public void setConnectionTimeout(Integer connectionTimeout) { 292 this.connectionTimeout = connectionTimeout; 293 } 294 295 public Cache getCache() { 296 return this.cache; 297 } 298 299 public Listener getListener() { 300 return this.listener; 301 } 302 303 public Template getTemplate() { 304 return this.template; 305 } 306 307 public static class Ssl { 308 309 /** 310 * Enable SSL support. 311 */ 312 private boolean enabled; 313 314 /** 315 * Path to the key store that holds the SSL certificate. 316 */ 317 private String keyStore; 318 319 /** 320 * Password used to access the key store. 321 */ 322 private String keyStorePassword; 323 324 /** 325 * Trust store that holds SSL certificates. 326 */ 327 private String trustStore; 328 329 /** 330 * Password used to access the trust store. 331 */ 332 private String trustStorePassword; 333 334 /** 335 * SSL algorithm to use (e.g. TLSv1.1). Default is set automatically by the rabbit 336 * client library. 337 */ 338 private String algorithm; 339 340 public boolean isEnabled() { 341 return this.enabled; 342 } 343 344 public void setEnabled(boolean enabled) { 345 this.enabled = enabled; 346 } 347 348 public String getKeyStore() { 349 return this.keyStore; 350 } 351 352 public void setKeyStore(String keyStore) { 353 this.keyStore = keyStore; 354 } 355 356 public String getKeyStorePassword() { 357 return this.keyStorePassword; 358 } 359 360 public void setKeyStorePassword(String keyStorePassword) { 361 this.keyStorePassword = keyStorePassword; 362 } 363 364 public String getTrustStore() { 365 return this.trustStore; 366 } 367 368 public void setTrustStore(String trustStore) { 369 this.trustStore = trustStore; 370 } 371 372 public String getTrustStorePassword() { 373 return this.trustStorePassword; 374 } 375 376 public void setTrustStorePassword(String trustStorePassword) { 377 this.trustStorePassword = trustStorePassword; 378 } 379 380 public String getAlgorithm() { 381 return this.algorithm; 382 } 383 384 public void setAlgorithm(String sslAlgorithm) { 385 this.algorithm = sslAlgorithm; 386 } 387 388 } 389 390 public static class Cache { 391 392 private final Channel channel = new Channel(); 393 394 private final Connection connection = new Connection(); 395 396 public Channel getChannel() { 397 return this.channel; 398 } 399 400 public Connection getConnection() { 401 return this.connection; 402 } 403 404 public static class Channel { 405 406 /** 407 * Number of channels to retain in the cache. When "check-timeout" > 0, max 408 * channels per connection. 409 */ 410 private Integer size; 411 412 /** 413 * Number of milliseconds to wait to obtain a channel if the cache size has 414 * been reached. If 0, always create a new channel. 415 */ 416 private Long checkoutTimeout; 417 418 public Integer getSize() { 419 return this.size; 420 } 421 422 public void setSize(Integer size) { 423 this.size = size; 424 } 425 426 public Long getCheckoutTimeout() { 427 return this.checkoutTimeout; 428 } 429 430 public void setCheckoutTimeout(Long checkoutTimeout) { 431 this.checkoutTimeout = checkoutTimeout; 432 } 433 434 } 435 436 public static class Connection { 437 438 /** 439 * Connection factory cache mode. 440 */ 441 private CacheMode mode = CacheMode.CHANNEL; 442 443 /** 444 * Number of connections to cache. Only applies when mode is CONNECTION. 445 */ 446 private Integer size; 447 448 public CacheMode getMode() { 449 return this.mode; 450 } 451 452 public void setMode(CacheMode mode) { 453 this.mode = mode; 454 } 455 456 public Integer getSize() { 457 return this.size; 458 } 459 460 public void setSize(Integer size) { 461 this.size = size; 462 } 463 464 } 465 466 } 467 468 public static class Listener { 469 470 @NestedConfigurationProperty 471 private final AmqpContainer simple = new AmqpContainer(); 472 473 @DeprecatedConfigurationProperty(replacement = "spring.rabbitmq.listener.simple.auto-startup") 474 @Deprecated 475 public boolean isAutoStartup() { 476 return getSimple().isAutoStartup(); 477 } 478 479 @Deprecated 480 public void setAutoStartup(boolean autoStartup) { 481 getSimple().setAutoStartup(autoStartup); 482 } 483 484 @DeprecatedConfigurationProperty(replacement = "spring.rabbitmq.listener.simple.acknowledge-mode") 485 @Deprecated 486 public AcknowledgeMode getAcknowledgeMode() { 487 return getSimple().getAcknowledgeMode(); 488 } 489 490 @Deprecated 491 public void setAcknowledgeMode(AcknowledgeMode acknowledgeMode) { 492 getSimple().setAcknowledgeMode(acknowledgeMode); 493 } 494 495 @DeprecatedConfigurationProperty(replacement = "spring.rabbitmq.listener.simple.concurrency") 496 @Deprecated 497 public Integer getConcurrency() { 498 return getSimple().getConcurrency(); 499 } 500 501 @Deprecated 502 public void setConcurrency(Integer concurrency) { 503 getSimple().setConcurrency(concurrency); 504 } 505 506 @DeprecatedConfigurationProperty(replacement = "spring.rabbitmq.listener.simple.max-concurrency") 507 @Deprecated 508 public Integer getMaxConcurrency() { 509 return getSimple().getMaxConcurrency(); 510 } 511 512 @Deprecated 513 public void setMaxConcurrency(Integer maxConcurrency) { 514 getSimple().setMaxConcurrency(maxConcurrency); 515 } 516 517 @DeprecatedConfigurationProperty(replacement = "spring.rabbitmq.listener.simple.prefetch") 518 @Deprecated 519 public Integer getPrefetch() { 520 return getSimple().getPrefetch(); 521 } 522 523 @Deprecated 524 public void setPrefetch(Integer prefetch) { 525 getSimple().setPrefetch(prefetch); 526 } 527 528 @DeprecatedConfigurationProperty(replacement = "spring.rabbitmq.listener.simple.transaction-size") 529 @Deprecated 530 public Integer getTransactionSize() { 531 return getSimple().getTransactionSize(); 532 } 533 534 @Deprecated 535 public void setTransactionSize(Integer transactionSize) { 536 getSimple().setTransactionSize(transactionSize); 537 } 538 539 @DeprecatedConfigurationProperty(replacement = "spring.rabbitmq.listener.simple.default-requeue-rejected") 540 @Deprecated 541 public Boolean getDefaultRequeueRejected() { 542 return getSimple().getDefaultRequeueRejected(); 543 } 544 545 @Deprecated 546 public void setDefaultRequeueRejected(Boolean defaultRequeueRejected) { 547 getSimple().setDefaultRequeueRejected(defaultRequeueRejected); 548 } 549 550 @DeprecatedConfigurationProperty(replacement = "spring.rabbitmq.listener.simple.idle-event-interval") 551 @Deprecated 552 public Long getIdleEventInterval() { 553 return getSimple().getIdleEventInterval(); 554 } 555 556 @Deprecated 557 public void setIdleEventInterval(Long idleEventInterval) { 558 getSimple().setIdleEventInterval(idleEventInterval); 559 } 560 561 @DeprecatedConfigurationProperty(replacement = "spring.rabbitmq.listener.simple.retry") 562 @Deprecated 563 public ListenerRetry getRetry() { 564 return getSimple().getRetry(); 565 } 566 567 public AmqpContainer getSimple() { 568 return this.simple; 569 } 570 571 } 572 573 public static class AmqpContainer { 574 575 /** 576 * Start the container automatically on startup. 577 */ 578 private boolean autoStartup = true; 579 580 /** 581 * Acknowledge mode of container. 582 */ 583 private AcknowledgeMode acknowledgeMode; 584 585 /** 586 * Minimum number of consumers. 587 */ 588 private Integer concurrency; 589 590 /** 591 * Maximum number of consumers. 592 */ 593 private Integer maxConcurrency; 594 595 /** 596 * Number of messages to be handled in a single request. It should be greater than 597 * or equal to the transaction size (if used). 598 */ 599 private Integer prefetch; 600 601 /** 602 * Number of messages to be processed in a transaction. For best results it should 603 * be less than or equal to the prefetch count. 604 */ 605 private Integer transactionSize; 606 607 /** 608 * Whether rejected deliveries are requeued by default; default true. 609 */ 610 private Boolean defaultRequeueRejected; 611 612 /** 613 * How often idle container events should be published in milliseconds. 614 */ 615 private Long idleEventInterval; 616 617 /** 618 * Optional properties for a retry interceptor. 619 */ 620 @NestedConfigurationProperty 621 private final ListenerRetry retry = new ListenerRetry(); 622 623 public boolean isAutoStartup() { 624 return this.autoStartup; 625 } 626 627 public void setAutoStartup(boolean autoStartup) { 628 this.autoStartup = autoStartup; 629 } 630 631 public AcknowledgeMode getAcknowledgeMode() { 632 return this.acknowledgeMode; 633 } 634 635 public void setAcknowledgeMode(AcknowledgeMode acknowledgeMode) { 636 this.acknowledgeMode = acknowledgeMode; 637 } 638 639 public Integer getConcurrency() { 640 return this.concurrency; 641 } 642 643 public void setConcurrency(Integer concurrency) { 644 this.concurrency = concurrency; 645 } 646 647 public Integer getMaxConcurrency() { 648 return this.maxConcurrency; 649 } 650 651 public void setMaxConcurrency(Integer maxConcurrency) { 652 this.maxConcurrency = maxConcurrency; 653 } 654 655 public Integer getPrefetch() { 656 return this.prefetch; 657 } 658 659 public void setPrefetch(Integer prefetch) { 660 this.prefetch = prefetch; 661 } 662 663 public Integer getTransactionSize() { 664 return this.transactionSize; 665 } 666 667 public void setTransactionSize(Integer transactionSize) { 668 this.transactionSize = transactionSize; 669 } 670 671 public Boolean getDefaultRequeueRejected() { 672 return this.defaultRequeueRejected; 673 } 674 675 public void setDefaultRequeueRejected(Boolean defaultRequeueRejected) { 676 this.defaultRequeueRejected = defaultRequeueRejected; 677 } 678 679 public Long getIdleEventInterval() { 680 return this.idleEventInterval; 681 } 682 683 public void setIdleEventInterval(Long idleEventInterval) { 684 this.idleEventInterval = idleEventInterval; 685 } 686 687 public ListenerRetry getRetry() { 688 return this.retry; 689 } 690 691 } 692 693 public static class Template { 694 695 @NestedConfigurationProperty 696 private final Retry retry = new Retry(); 697 698 /** 699 * Enable mandatory messages. If a mandatory message cannot be routed to a queue 700 * by the server, it will return an unroutable message with a Return method. 701 */ 702 private Boolean mandatory; 703 704 /** 705 * Timeout for receive() operations. 706 */ 707 private Long receiveTimeout; 708 709 /** 710 * Timeout for sendAndReceive() operations. 711 */ 712 private Long replyTimeout; 713 714 public Retry getRetry() { 715 return this.retry; 716 } 717 718 public Boolean getMandatory() { 719 return this.mandatory; 720 } 721 722 public void setMandatory(Boolean mandatory) { 723 this.mandatory = mandatory; 724 } 725 726 public Long getReceiveTimeout() { 727 return this.receiveTimeout; 728 } 729 730 public void setReceiveTimeout(Long receiveTimeout) { 731 this.receiveTimeout = receiveTimeout; 732 } 733 734 public Long getReplyTimeout() { 735 return this.replyTimeout; 736 } 737 738 public void setReplyTimeout(Long replyTimeout) { 739 this.replyTimeout = replyTimeout; 740 } 741 742 } 743 744 public static class Retry { 745 746 /** 747 * Whether or not publishing retries are enabled. 748 */ 749 private boolean enabled; 750 751 /** 752 * Maximum number of attempts to publish or deliver a message. 753 */ 754 private int maxAttempts = 3; 755 756 /** 757 * Interval between the first and second attempt to publish or deliver a message. 758 */ 759 private long initialInterval = 1000L; 760 761 /** 762 * A multiplier to apply to the previous retry interval. 763 */ 764 private double multiplier = 1.0; 765 766 /** 767 * Maximum interval between attempts. 768 */ 769 private long maxInterval = 10000L; 770 771 public boolean isEnabled() { 772 return this.enabled; 773 } 774 775 public void setEnabled(boolean enabled) { 776 this.enabled = enabled; 777 } 778 779 public int getMaxAttempts() { 780 return this.maxAttempts; 781 } 782 783 public void setMaxAttempts(int maxAttempts) { 784 this.maxAttempts = maxAttempts; 785 } 786 787 public long getInitialInterval() { 788 return this.initialInterval; 789 } 790 791 public void setInitialInterval(long initialInterval) { 792 this.initialInterval = initialInterval; 793 } 794 795 public double getMultiplier() { 796 return this.multiplier; 797 } 798 799 public void setMultiplier(double multiplier) { 800 this.multiplier = multiplier; 801 } 802 803 public long getMaxInterval() { 804 return this.maxInterval; 805 } 806 807 public void setMaxInterval(long maxInterval) { 808 this.maxInterval = maxInterval; 809 } 810 811 } 812 813 public static class ListenerRetry extends Retry { 814 815 /** 816 * Whether or not retries are stateless or stateful. 817 */ 818 private boolean stateless = true; 819 820 public boolean isStateless() { 821 return this.stateless; 822 } 823 824 public void setStateless(boolean stateless) { 825 this.stateless = stateless; 826 } 827 828 } 829 830 private static final class Address { 831 832 private static final String PREFIX_AMQP = "amqp://"; 833 834 private static final int DEFAULT_PORT = 5672; 835 836 private String host; 837 838 private int port; 839 840 private String username; 841 842 private String password; 843 844 private String virtualHost; 845 846 private Address(String input) { 847 input = input.trim(); 848 input = trimPrefix(input); 849 input = parseUsernameAndPassword(input); 850 input = parseVirtualHost(input); 851 parseHostAndPort(input); 852 } 853 854 private String trimPrefix(String input) { 855 if (input.startsWith(PREFIX_AMQP)) { 856 input = input.substring(PREFIX_AMQP.length()); 857 } 858 return input; 859 } 860 861 private String parseUsernameAndPassword(String input) { 862 if (input.contains("@")) { 863 String[] split = StringUtils.split(input, "@"); 864 String creds = split[0]; 865 input = split[1]; 866 split = StringUtils.split(creds, ":"); 867 this.username = split[0]; 868 if (split.length > 0) { 869 this.password = split[1]; 870 } 871 } 872 return input; 873 } 874 875 private String parseVirtualHost(String input) { 876 int hostIndex = input.indexOf("/"); 877 if (hostIndex >= 0) { 878 this.virtualHost = input.substring(hostIndex + 1); 879 if (this.virtualHost.isEmpty()) { 880 this.virtualHost = "/"; 881 } 882 input = input.substring(0, hostIndex); 883 } 884 return input; 885 } 886 887 private void parseHostAndPort(String input) { 888 int portIndex = input.indexOf(':'); 889 if (portIndex == -1) { 890 this.host = input; 891 this.port = DEFAULT_PORT; 892 } 893 else { 894 this.host = input.substring(0, portIndex); 895 this.port = Integer.valueOf(input.substring(portIndex + 1)); 896 } 897 } 898 899 } 900 901}