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