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}