001/*
002 * Copyright 2002-2018 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 *      https://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.jms.config;
018
019import javax.jms.MessageListener;
020
021import org.springframework.jms.listener.AbstractMessageListenerContainer;
022import org.springframework.jms.listener.MessageListenerContainer;
023import org.springframework.jms.listener.endpoint.JmsActivationSpecConfig;
024import org.springframework.jms.listener.endpoint.JmsMessageEndpointManager;
025import org.springframework.lang.Nullable;
026
027/**
028 * Base model for a JMS listener endpoint.
029 *
030 * @author Stephane Nicoll
031 * @author Juergen Hoeller
032 * @since 4.1
033 * @see MethodJmsListenerEndpoint
034 * @see SimpleJmsListenerEndpoint
035 */
036public abstract class AbstractJmsListenerEndpoint implements JmsListenerEndpoint {
037
038        private String id = "";
039
040        @Nullable
041        private String destination;
042
043        @Nullable
044        private String subscription;
045
046        @Nullable
047        private String selector;
048
049        @Nullable
050        private String concurrency;
051
052
053        public void setId(String id) {
054                this.id = id;
055        }
056
057        @Override
058        public String getId() {
059                return this.id;
060        }
061
062        /**
063         * Set the name of the destination for this endpoint.
064         */
065        public void setDestination(@Nullable String destination) {
066                this.destination = destination;
067        }
068
069        /**
070         * Return the name of the destination for this endpoint.
071         */
072        @Nullable
073        public String getDestination() {
074                return this.destination;
075        }
076
077        /**
078         * Set the name for the durable subscription.
079         */
080        public void setSubscription(@Nullable String subscription) {
081                this.subscription = subscription;
082        }
083
084        /**
085         * Return the name for the durable subscription, if any.
086         */
087        @Nullable
088        public String getSubscription() {
089                return this.subscription;
090        }
091
092        /**
093         * Set the JMS message selector expression.
094         * <p>See the JMS specification for a detailed definition of selector expressions.
095         */
096        public void setSelector(@Nullable String selector) {
097                this.selector = selector;
098        }
099
100        /**
101         * Return the JMS message selector expression, if any.
102         */
103        @Nullable
104        public String getSelector() {
105                return this.selector;
106        }
107
108        /**
109         * Set a concurrency for the listener, if any.
110         * <p>The concurrency limits can be a "lower-upper" String, e.g. "5-10", or a simple
111         * upper limit String, e.g. "10" (the lower limit will be 1 in this case).
112         * <p>The underlying container may or may not support all features. For instance, it
113         * may not be able to scale: in that case only the upper value is used.
114         */
115        public void setConcurrency(@Nullable String concurrency) {
116                this.concurrency = concurrency;
117        }
118
119        /**
120         * Return the concurrency for the listener, if any.
121         */
122        @Nullable
123        public String getConcurrency() {
124                return this.concurrency;
125        }
126
127
128        @Override
129        public void setupListenerContainer(MessageListenerContainer listenerContainer) {
130                if (listenerContainer instanceof AbstractMessageListenerContainer) {
131                        setupJmsListenerContainer((AbstractMessageListenerContainer) listenerContainer);
132                }
133                else {
134                        new JcaEndpointConfigurer().configureEndpoint(listenerContainer);
135                }
136        }
137
138        private void setupJmsListenerContainer(AbstractMessageListenerContainer listenerContainer) {
139                if (getDestination() != null) {
140                        listenerContainer.setDestinationName(getDestination());
141                }
142                if (getSubscription() != null) {
143                        listenerContainer.setSubscriptionName(getSubscription());
144                }
145                if (getSelector() != null) {
146                        listenerContainer.setMessageSelector(getSelector());
147                }
148                if (getConcurrency() != null) {
149                        listenerContainer.setConcurrency(getConcurrency());
150                }
151                setupMessageListener(listenerContainer);
152        }
153
154        /**
155         * Create a {@link MessageListener} that is able to serve this endpoint for the
156         * specified container.
157         */
158        protected abstract MessageListener createMessageListener(MessageListenerContainer container);
159
160        private void setupMessageListener(MessageListenerContainer container) {
161                container.setupMessageListener(createMessageListener(container));
162        }
163
164        /**
165         * Return a description for this endpoint.
166         * <p>Available to subclasses, for inclusion in their {@code toString()} result.
167         */
168        protected StringBuilder getEndpointDescription() {
169                StringBuilder result = new StringBuilder();
170                return result.append(getClass().getSimpleName()).append("[").append(this.id).append("] destination=").
171                                append(this.destination).append("' | subscription='").append(this.subscription).
172                                append(" | selector='").append(this.selector).append("'");
173        }
174
175        @Override
176        public String toString() {
177                return getEndpointDescription().toString();
178        }
179
180
181        /**
182         * Inner class to avoid a hard dependency on the JCA API.
183         */
184        private class JcaEndpointConfigurer {
185
186                public void configureEndpoint(Object listenerContainer) {
187                        if (listenerContainer instanceof JmsMessageEndpointManager) {
188                                setupJcaMessageContainer((JmsMessageEndpointManager) listenerContainer);
189                        }
190                        else {
191                                throw new IllegalArgumentException("Could not configure endpoint with the specified container '" +
192                                                listenerContainer + "' Only JMS (" + AbstractMessageListenerContainer.class.getName() +
193                                                " subclass) or JCA (" + JmsMessageEndpointManager.class.getName() + ") are supported.");
194                        }
195                }
196
197                private void setupJcaMessageContainer(JmsMessageEndpointManager container) {
198                        JmsActivationSpecConfig activationSpecConfig = container.getActivationSpecConfig();
199                        if (activationSpecConfig == null) {
200                                activationSpecConfig = new JmsActivationSpecConfig();
201                                container.setActivationSpecConfig(activationSpecConfig);
202                        }
203                        if (getDestination() != null) {
204                                activationSpecConfig.setDestinationName(getDestination());
205                        }
206                        if (getSubscription() != null) {
207                                activationSpecConfig.setSubscriptionName(getSubscription());
208                        }
209                        if (getSelector() != null) {
210                                activationSpecConfig.setMessageSelector(getSelector());
211                        }
212                        if (getConcurrency() != null) {
213                                activationSpecConfig.setConcurrency(getConcurrency());
214                        }
215                        setupMessageListener(container);
216                }
217        }
218
219}