Skip to content

Commit bb18f81

Browse files
committed
Added "recovery-interval" attribute to <jms:listener-container>
Issue: SPR-10711
1 parent 4c0da58 commit bb18f81

File tree

5 files changed

+100
-20
lines changed

5 files changed

+100
-20
lines changed

spring-jms/src/main/java/org/springframework/jms/config/JmsListenerContainerParser.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class JmsListenerContainerParser extends AbstractListenerContainerParser {
4949

5050
private static final String RECEIVE_TIMEOUT_ATTRIBUTE = "receive-timeout";
5151

52+
private static final String RECOVERY_INTERVAL_ATTRIBUTE = "recovery-interval";
53+
5254

5355
@Override
5456
protected BeanDefinition parseContainer(Element listenerEle, Element containerEle, ParserContext parserContext) {
@@ -160,6 +162,13 @@ else if (containerType.startsWith("simple")) {
160162
}
161163
}
162164

165+
String recoveryInterval = containerEle.getAttribute(RECOVERY_INTERVAL_ATTRIBUTE);
166+
if (StringUtils.hasText(recoveryInterval)) {
167+
if (containerType.startsWith("default")) {
168+
containerDef.getPropertyValues().add("recoveryInterval", recoveryInterval);
169+
}
170+
}
171+
163172
String phase = containerEle.getAttribute(PHASE_ATTRIBUTE);
164173
if (StringUtils.hasText(phase)) {
165174
containerDef.getPropertyValues().add("phase", phase);

spring-jms/src/main/resources/org/springframework/jms/config/spring-jms-4.0.xsd

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,14 @@
240240
]]></xsd:documentation>
241241
</xsd:annotation>
242242
</xsd:attribute>
243+
<xsd:attribute name="recovery-interval" type="xsd:string">
244+
<xsd:annotation>
245+
<xsd:documentation><![CDATA[
246+
Specify the interval between recovery attempts, in milliseconds.
247+
The default is 5000 ms, that is, 5 seconds.
248+
]]></xsd:documentation>
249+
</xsd:annotation>
250+
</xsd:attribute>
243251
<xsd:attribute name="phase" type="xsd:string">
244252
<xsd:annotation>
245253
<xsd:documentation><![CDATA[

spring-jms/src/test/java/org/springframework/jms/config/JmsNamespaceHandlerTests.java

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,17 @@ public void testListeners() throws Exception {
139139
assertSame(message3, testBean3.message);
140140
}
141141

142+
@Test
143+
public void testRecoveryInterval() {
144+
long recoveryInterval1 = getRecoveryInterval("listener1");
145+
long recoveryInterval2 = getRecoveryInterval("listener2");
146+
long recoveryInterval3 = getRecoveryInterval(DefaultMessageListenerContainer.class.getName() + "#0");
147+
148+
assertEquals(1000L, recoveryInterval1);
149+
assertEquals(1000L, recoveryInterval2);
150+
assertEquals(DefaultMessageListenerContainer.DEFAULT_RECOVERY_INTERVAL, recoveryInterval3);
151+
}
152+
142153
@Test
143154
public void testErrorHandlers() {
144155
ErrorHandler expected = this.context.getBean("testErrorHandler", ErrorHandler.class);
@@ -164,24 +175,6 @@ public void testPhases() {
164175
assertEquals(Integer.MAX_VALUE, defaultPhase);
165176
}
166177

167-
private MessageListener getListener(String containerBeanName) {
168-
DefaultMessageListenerContainer container = this.context.getBean(containerBeanName, DefaultMessageListenerContainer.class);
169-
return (MessageListener) container.getMessageListener();
170-
}
171-
172-
private ErrorHandler getErrorHandler(String containerBeanName) {
173-
DefaultMessageListenerContainer container = this.context.getBean(containerBeanName, DefaultMessageListenerContainer.class);
174-
return (ErrorHandler) new DirectFieldAccessor(container).getPropertyValue("errorHandler");
175-
}
176-
177-
public int getPhase(String containerBeanName) {
178-
Object container = this.context.getBean(containerBeanName);
179-
if (!(container instanceof Phased)) {
180-
throw new IllegalStateException("Container '" + containerBeanName + "' does not implement Phased.");
181-
}
182-
return ((Phased) container).getPhase();
183-
}
184-
185178
@Test
186179
public void testComponentRegistration() {
187180
assertTrue("Parser should have registered a component named 'listener1'", context.containsComponentDefinition("listener1"));
@@ -203,13 +196,38 @@ public void testSourceExtraction() {
203196
}
204197
}
205198

199+
206200
private void validateComponentDefinition(ComponentDefinition compDef) {
207201
BeanDefinition[] beanDefs = compDef.getBeanDefinitions();
208202
for (BeanDefinition beanDef : beanDefs) {
209203
assertNotNull("BeanDefinition has no source attachment", beanDef.getSource());
210204
}
211205
}
212206

207+
private MessageListener getListener(String containerBeanName) {
208+
DefaultMessageListenerContainer container = this.context.getBean(containerBeanName, DefaultMessageListenerContainer.class);
209+
return (MessageListener) container.getMessageListener();
210+
}
211+
212+
private ErrorHandler getErrorHandler(String containerBeanName) {
213+
DefaultMessageListenerContainer container = this.context.getBean(containerBeanName, DefaultMessageListenerContainer.class);
214+
return (ErrorHandler) new DirectFieldAccessor(container).getPropertyValue("errorHandler");
215+
}
216+
217+
private long getRecoveryInterval(String containerBeanName) {
218+
DefaultMessageListenerContainer container = this.context.getBean(containerBeanName, DefaultMessageListenerContainer.class);
219+
Long recoveryInterval = (Long) new DirectFieldAccessor(container).getPropertyValue("recoveryInterval");
220+
return recoveryInterval.longValue();
221+
}
222+
223+
private int getPhase(String containerBeanName) {
224+
Object container = this.context.getBean(containerBeanName);
225+
if (!(container instanceof Phased)) {
226+
throw new IllegalStateException("Container '" + containerBeanName + "' does not implement Phased.");
227+
}
228+
return ((Phased) container).getPhase();
229+
}
230+
213231

214232
public static class TestMessageListener implements MessageListener {
215233

spring-jms/src/test/java/org/springframework/jms/config/jmsNamespaceHandlerTests.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
44
xmlns:jms="http://www.springframework.org/schema/jms"
55
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
6-
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.1.xsd">
6+
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.0.xsd">
77

88
<jms:listener-container connection-factory="testConnectionFactory" task-executor="testTaskExecutor"
99
destination-resolver="testDestinationResolver" message-converter="testMessageConverter"
1010
transaction-manager="testTransactionManager" error-handler="testErrorHandler"
11-
concurrency="1-2" prefetch="50" receive-timeout="100" phase="99">
11+
concurrency="1-2" prefetch="50" receive-timeout="100" recovery-interval="1000" phase="99">
1212
<jms:listener id="listener1" destination="testDestination" ref="testBean1" method="setName"/>
1313
<jms:listener id="listener2" destination="testDestination" ref="testBean2" method="setName" response-destination="responseDestination"/>
1414
</jms:listener-container>

src/reference/docbook/jms.xml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,16 @@ http://www.springframework.org/schema/beans http://www.springframework.org/schem
10861086
<literal>'default'</literal>).</para></entry>
10871087
</row>
10881088

1089+
<row>
1090+
<entry>container-class</entry>
1091+
1092+
<entry><para>A custom listener container implementation class
1093+
as fully qualified class name. Default is Spring's standard
1094+
<classname>DefaultMessageListenerContainer</classname> or
1095+
<classname>SimpleMessageListenerContainer</classname>,
1096+
according to the "container-type" attribute.</para></entry>
1097+
</row>
1098+
10891099
<row>
10901100
<entry>connection-factory</entry>
10911101

@@ -1121,6 +1131,15 @@ http://www.springframework.org/schema/beans http://www.springframework.org/schem
11211131
<classname>SimpleMessageConverter</classname>.</para></entry>
11221132
</row>
11231133

1134+
<row>
1135+
<entry>error-handler</entry>
1136+
1137+
<entry><para>A reference to an
1138+
<interfacename>ErrorHandler</interfacename> strategy for handling
1139+
any uncaught Exceptions that may occur during the execution of the
1140+
<interfacename>MessageListener</interfacename>.</para></entry>
1141+
</row>
1142+
11241143
<row>
11251144
<entry>destination-type</entry>
11261145

@@ -1195,6 +1214,32 @@ http://www.springframework.org/schema/beans http://www.springframework.org/schem
11951214
session. Note that raising this number might lead to starvation of
11961215
concurrent consumers!</para></entry>
11971216
</row>
1217+
1218+
<row>
1219+
<entry>receive-timeout</entry>
1220+
1221+
<entry><para>The timeout to use for receive calls (in milliseconds).
1222+
The default is <literal>1000</literal> ms (1 sec); <literal>-1</literal>
1223+
indicates no timeout at all.</para></entry>
1224+
</row>
1225+
1226+
<row>
1227+
<entry>recovery-interval</entry>
1228+
1229+
<entry><para>Specify the interval between recovery attempts, in
1230+
milliseconds. The default is <literal>5000</literal> ms, that is,
1231+
5 seconds.</para></entry>
1232+
</row>
1233+
1234+
<row>
1235+
<entry>phase</entry>
1236+
1237+
<entry><para>The lifecycle phase within which this container should
1238+
start and stop. The lower the value the earlier this container will
1239+
start and the later it will stop. The default is
1240+
<literal>Integer.MAX_VALUE</literal> meaning the container will start
1241+
as late as possible and stop as soon as possible.</para></entry>
1242+
</row>
11981243
</tbody>
11991244
</tgroup>
12001245
</table>

0 commit comments

Comments
 (0)