View Javadoc
1   /*
2    * Copyright 2002-2014 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.jms.config;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.springframework.beans.factory.BeanFactory;
23  import org.springframework.beans.factory.BeanFactoryAware;
24  import org.springframework.beans.factory.InitializingBean;
25  import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;
26  import org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory;
27  import org.springframework.util.Assert;
28  
29  /**
30   * Helper bean for registering {@link JmsListenerEndpoint} with
31   * a {@link JmsListenerEndpointRegistry}.
32   *
33   * @author Stephane Nicoll
34   * @author Juergen Hoeller
35   * @since 4.1
36   * @see org.springframework.jms.annotation.JmsListenerConfigurer
37   */
38  public class JmsListenerEndpointRegistrar implements BeanFactoryAware, InitializingBean {
39  
40  	private JmsListenerEndpointRegistry endpointRegistry;
41  
42  	private MessageHandlerMethodFactory messageHandlerMethodFactory;
43  
44  	private JmsListenerContainerFactory<?> containerFactory;
45  
46  	private String containerFactoryBeanName;
47  
48  	private BeanFactory beanFactory;
49  
50  	private final List<JmsListenerEndpointDescriptor> endpointDescriptors =
51  			new ArrayList<JmsListenerEndpointDescriptor>();
52  
53  
54  	/**
55  	 * Set the {@link JmsListenerEndpointRegistry} instance to use.
56  	 */
57  	public void setEndpointRegistry(JmsListenerEndpointRegistry endpointRegistry) {
58  		this.endpointRegistry = endpointRegistry;
59  	}
60  
61  	/**
62  	 * Return the {@link JmsListenerEndpointRegistry} instance for this
63  	 * registrar, may be {@code null}.
64  	 */
65  	public JmsListenerEndpointRegistry getEndpointRegistry() {
66  		return this.endpointRegistry;
67  	}
68  
69  	/**
70  	 * Set the {@link MessageHandlerMethodFactory} to use to configure the message
71  	 * listener responsible to serve an endpoint detected by this processor.
72  	 * <p>By default, {@link DefaultMessageHandlerMethodFactory} is used and it
73  	 * can be configured further to support additional method arguments
74  	 * or to customize conversion and validation support. See
75  	 * {@link DefaultMessageHandlerMethodFactory} javadoc for more details.
76  	 */
77  	public void setMessageHandlerMethodFactory(MessageHandlerMethodFactory messageHandlerMethodFactory) {
78  		this.messageHandlerMethodFactory = messageHandlerMethodFactory;
79  	}
80  
81  	/**
82  	 * Return the custom {@link MessageHandlerMethodFactory} to use, if any.
83  	 */
84  	public MessageHandlerMethodFactory getMessageHandlerMethodFactory() {
85  		return this.messageHandlerMethodFactory;
86  	}
87  
88  	/**
89  	 * Set the {@link JmsListenerContainerFactory} to use in case a {@link JmsListenerEndpoint}
90  	 * is registered with a {@code null} container factory.
91  	 * <p>Alternatively, the bean name of the {@link JmsListenerContainerFactory} to use
92  	 * can be specified for a lazy lookup, see {@link #setContainerFactoryBeanName}.
93  	 */
94  	public void setContainerFactory(JmsListenerContainerFactory<?> containerFactory) {
95  		this.containerFactory = containerFactory;
96  	}
97  
98  	/**
99  	 * Set the bean name of the {@link JmsListenerContainerFactory} to use in case
100 	 * a {@link JmsListenerEndpoint} is registered with a {@code null} container factory.
101 	 * Alternatively, the container factory instance can be registered directly:
102 	 * see {@link #setContainerFactory(JmsListenerContainerFactory)}.
103 	 * @see #setBeanFactory
104 	 */
105 	public void setContainerFactoryBeanName(String containerFactoryBeanName) {
106 		this.containerFactoryBeanName = containerFactoryBeanName;
107 	}
108 
109 	/**
110 	 * A {@link BeanFactory} only needs to be available in conjunction with
111 	 * {@link #setContainerFactoryBeanName}.
112 	 */
113 	@Override
114 	public void setBeanFactory(BeanFactory beanFactory) {
115 		this.beanFactory = beanFactory;
116 	}
117 
118 
119 	@Override
120 	public void afterPropertiesSet() {
121 		registerAllEndpoints();
122 	}
123 
124 	protected void registerAllEndpoints() {
125 		for (JmsListenerEndpointDescriptor descriptor : this.endpointDescriptors) {
126 			this.endpointRegistry.registerListenerContainer(descriptor.endpoint, resolveContainerFactory(descriptor));
127 		}
128 	}
129 
130 	private JmsListenerContainerFactory<?> resolveContainerFactory(JmsListenerEndpointDescriptor descriptor) {
131 		if (descriptor.containerFactory != null) {
132 			return descriptor.containerFactory;
133 		}
134 		else if (this.containerFactory != null) {
135 			return this.containerFactory;
136 		}
137 		else if (this.containerFactoryBeanName != null) {
138 			Assert.state(this.beanFactory != null, "BeanFactory must be set to obtain container factory by bean name");
139 			this.containerFactory = this.beanFactory.getBean(
140 					this.containerFactoryBeanName, JmsListenerContainerFactory.class);
141 			return this.containerFactory;  // Consider changing this if live change of the factory is required
142 		}
143 		else {
144 			throw new IllegalStateException("Could not resolve the " +
145 					JmsListenerContainerFactory.class.getSimpleName() + " to use for [" +
146 					descriptor.endpoint + "] no factory was given and no default is set.");
147 		}
148 	}
149 
150 	/**
151 	 * Register a new {@link JmsListenerEndpoint} alongside the
152 	 * {@link JmsListenerContainerFactory} to use to create the underlying container.
153 	 * <p>The {@code factory} may be {@code null} if the default factory has to be
154 	 * used for that endpoint.
155 	 */
156 	public void registerEndpoint(JmsListenerEndpoint endpoint, JmsListenerContainerFactory<?> factory) {
157 		Assert.notNull(endpoint, "Endpoint must be set");
158 		Assert.hasText(endpoint.getId(), "Endpoint id must be set");
159 		// Factory may be null, we defer the resolution right before actually creating the container
160 		this.endpointDescriptors.add(new JmsListenerEndpointDescriptor(endpoint, factory));
161 	}
162 
163 	/**
164 	 * Register a new {@link JmsListenerEndpoint} using the default
165 	 * {@link JmsListenerContainerFactory} to create the underlying container.
166 	 * @see #setContainerFactory(JmsListenerContainerFactory)
167 	 * @see #registerEndpoint(JmsListenerEndpoint, JmsListenerContainerFactory)
168 	 */
169 	public void registerEndpoint(JmsListenerEndpoint endpoint) {
170 		registerEndpoint(endpoint, null);
171 	}
172 
173 
174 	private static class JmsListenerEndpointDescriptor {
175 
176 		public final JmsListenerEndpoint endpoint;
177 
178 		public final JmsListenerContainerFactory<?> containerFactory;
179 
180 		public JmsListenerEndpointDescriptor(JmsListenerEndpoint endpoint, JmsListenerContainerFactory<?> containerFactory) {
181 			this.endpoint = endpoint;
182 			this.containerFactory = containerFactory;
183 		}
184 	}
185 
186 }