INT-3933: HTTP & WS Inbound Lifecycle Handling

JIRA: https://jira.spring.io/browse/INT-3933

Previously the HTTP and WS Inbound Endpoint haven't handled the `stopped` state properly.

* Add `lifecycle` parsing to the `HttpInboundEndpointParser`
* Handle `!isRunning()` state and throw an appropriate `503 Service Unavailable` HTTP response
* Expose `lifecycle` options for the `<int-ws:inbound-gateway>`
* Introduce `ServiceUnavailableException` `WebServiceException` to indicate `stopped` state for the WS Inbound Endpoint
* Fix tests for the new logic

INT-3933: PR comments: `OrderlyShutdownCapable` for `AbstractWebServiceInboundGateway`
This commit is contained in:
Artem Bilan
2016-01-18 16:09:11 -05:00
committed by Gary Russell
parent c97afe92fe
commit c0784bf6ef
18 changed files with 216 additions and 72 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -202,6 +202,9 @@ public class HttpInboundEndpointParser extends AbstractSingleBeanDefinitionParse
if (statusCodeExpressionDef != null) {
builder.addPropertyValue("statusCodeExpression", statusCodeExpressionDef);
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, IntegrationNamespaceUtils.AUTO_STARTUP);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, IntegrationNamespaceUtils.PHASE);
}
private String getInputChannelAttributeName() {

View File

@@ -148,8 +148,6 @@ public abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewa
private volatile Map<String, Expression> headerExpressions;
private volatile boolean shuttingDown;
private volatile Expression statusCodeExpression;
private volatile EvaluationContext evaluationContext;
@@ -397,11 +395,11 @@ public abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewa
*/
protected final Message<?> doHandleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
throws IOException {
if (this.isShuttingDown()) {
return createServiceUnavailableResponse();
if (isRunning()) {
return actualDoHandleRequest(servletRequest, servletResponse);
}
else {
return actualDoHandleRequest(servletRequest, servletResponse);
return createServiceUnavailableResponse();
}
}
@@ -536,9 +534,9 @@ public abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewa
private Message<?> createServiceUnavailableResponse() {
if (logger.isDebugEnabled()) {
logger.debug("Endpoint is shutting down; returning status " + HttpStatus.SERVICE_UNAVAILABLE);
logger.debug("Endpoint is stopped; returning status " + HttpStatus.SERVICE_UNAVAILABLE);
}
return this.getMessageBuilderFactory().withPayload("Endpoint is shutting down")
return this.getMessageBuilderFactory().withPayload("Endpoint is stopped")
.setHeader(org.springframework.integration.http.HttpHeaders.STATUS_CODE, HttpStatus.SERVICE_UNAVAILABLE)
.build();
}
@@ -688,22 +686,10 @@ public abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewa
}
}
/**
* Lifecycle
*/
@Override
protected void doStart() {
this.shuttingDown = false;
super.doStart();
}
protected boolean isShuttingDown() {
return this.shuttingDown;
}
@Override
public int beforeShutdown() {
this.shuttingDown = true;
stop();
return this.activeCount.get();
}

View File

@@ -188,7 +188,7 @@
<xsd:documentation><![CDATA[
Used to set the sendTimeout on the underlying MessagingTemplate instance
(org.springframework.integration.core.MessagingTemplate) for sending messages
to the request channel. If not specified this propery will default to "1000"
to the request channel. If not specified this property will default to "1000"
(1 second).
]]></xsd:documentation>
</xsd:annotation>
@@ -198,7 +198,7 @@
<xsd:documentation><![CDATA[
Used to set the receiveTimeout on the underlying MessagingTemplate instance
(org.springframework.integration.core.MessagingTemplate) for receiving messages
from the reply channel. If not specified this propery will default to "1000"
from the reply channel. If not specified this property will default to "1000"
(1 second).
]]></xsd:documentation>
</xsd:annotation>

View File

@@ -21,6 +21,8 @@
</si:channel>
<inbound-channel-adapter id="defaultAdapter" channel="requests" error-channel="errorChannel"
auto-startup="false"
phase="1001"
status-code-expression="'101'"/>
<inbound-channel-adapter id="postOnlyAdapter" path="/postOnly" channel="requests" supported-methods="POST"/>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@@ -123,11 +124,17 @@ public class HttpInboundChannelAdapterParserTests extends AbstractHttpInboundTes
@Test
@SuppressWarnings("unchecked")
public void getRequestOk() throws Exception {
assertFalse(TestUtils.getPropertyValue(this.defaultAdapter, "autoStartup", Boolean.class));
assertEquals(1001, TestUtils.getPropertyValue(this.defaultAdapter, "phase"));
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
request.setParameter("foo", "bar");
MockHttpServletResponse response = new MockHttpServletResponse();
defaultAdapter.handleRequest(request, response);
this.defaultAdapter.handleRequest(request, response);
assertEquals(HttpServletResponse.SC_SERVICE_UNAVAILABLE, response.getStatus());
this.defaultAdapter.start();
response = new MockHttpServletResponse();
this.defaultAdapter.handleRequest(request, response);
assertEquals(HttpServletResponse.SC_SWITCHING_PROTOCOLS, response.getStatus());
Message<?> message = requests.receive(0);
assertNotNull(message);
@@ -138,7 +145,7 @@ public class HttpInboundChannelAdapterParserTests extends AbstractHttpInboundTes
assertEquals("foo", map.keySet().iterator().next());
assertEquals(1, map.get("foo").size());
assertEquals("bar", map.getFirst("foo"));
assertNotNull(TestUtils.getPropertyValue(defaultAdapter, "errorChannel"));
assertNotNull(TestUtils.getPropertyValue(this.defaultAdapter, "errorChannel"));
}
@Test

View File

@@ -23,6 +23,8 @@
convert-exceptions="true"
request-timeout="1234"
reply-timeout="4567"
auto-startup="false"
phase="1001"
error-channel="errorChannel"/>
<inbound-gateway id="inboundController" request-channel="requests" reply-channel="responses" view-name="foo"

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -118,28 +118,33 @@ public class HttpInboundGatewayParserTests {
@Test
public void checkConfig() {
assertNotNull(gateway);
assertTrue(getPropertyValue(gateway, "expectReply", Boolean.class));
assertTrue(getPropertyValue(gateway, "convertExceptions", Boolean.class));
assertSame(this.responses, getPropertyValue(gateway, "replyChannel"));
assertNotNull(TestUtils.getPropertyValue(gateway, "errorChannel"));
MessagingTemplate messagingTemplate = TestUtils.getPropertyValue(
gateway, "messagingTemplate", MessagingTemplate.class);
assertNotNull(this.gateway);
assertTrue(getPropertyValue(this.gateway, "expectReply", Boolean.class));
assertTrue(getPropertyValue(this.gateway, "convertExceptions", Boolean.class));
assertSame(this.responses, getPropertyValue(this.gateway, "replyChannel"));
assertNotNull(TestUtils.getPropertyValue(this.gateway, "errorChannel"));
MessagingTemplate messagingTemplate =
TestUtils.getPropertyValue(this.gateway, "messagingTemplate", MessagingTemplate.class);
assertEquals(1234L, TestUtils.getPropertyValue(messagingTemplate, "sendTimeout"));
assertEquals(4567L, TestUtils.getPropertyValue(messagingTemplate, "receiveTimeout"));
boolean registerDefaultConverters = TestUtils.getPropertyValue(gateway,"mergeWithDefaultConverters", Boolean.class);
boolean registerDefaultConverters =
TestUtils.getPropertyValue(this.gateway,"mergeWithDefaultConverters", Boolean.class);
assertFalse("By default the register-default-converters flag should be false", registerDefaultConverters);
@SuppressWarnings("unchecked")
List<HttpMessageConverter<?>> messageConverters = TestUtils.getPropertyValue(gateway,"messageConverters", List.class);
List<HttpMessageConverter<?>> messageConverters =
TestUtils.getPropertyValue(this.gateway,"messageConverters", List.class);
assertTrue("The default converters should have been registered, given there are no custom converters",
messageConverters.size() > 0);
assertFalse(TestUtils.getPropertyValue(this.gateway, "autoStartup", Boolean.class));
assertEquals(1001, TestUtils.getPropertyValue(this.gateway, "phase"));
}
@Test @DirtiesContext
public void checkFlow() throws Exception {
requests.subscribe(handlerExpecting(any(Message.class)));
this.requests.subscribe(handlerExpecting(any(Message.class)));
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
request.addHeader("Accept", "application/x-java-serialized-object");
@@ -148,10 +153,11 @@ public class HttpInboundGatewayParserTests {
MockHttpServletResponse response = new MockHttpServletResponse();
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new SerializingHttpMessageConverter());
gateway.setMessageConverters(converters);
gateway.afterPropertiesSet();
this.gateway.setMessageConverters(converters);
this.gateway.afterPropertiesSet();
this.gateway.start();
gateway.handleRequest(request, response);
this.gateway.handleRequest(request, response);
assertThat(response.getStatus(), is(HttpServletResponse.SC_OK));
assertEquals(response.getContentType(), "application/x-java-serialized-object");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -53,6 +53,7 @@ import org.springframework.web.servlet.View;
* @author Gary Russell
* @author Gunnar Hillert
* @author Biju Kunjummen
* @author Artem Bilan
* @since 2.0
*/
public class HttpRequestHandlingControllerTests extends AbstractHttpInboundTests {
@@ -65,6 +66,8 @@ public class HttpRequestHandlingControllerTests extends AbstractHttpInboundTests
controller.setRequestChannel(requestChannel);
controller.setViewName("foo");
controller.afterPropertiesSet();
controller.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContent("hello".getBytes());
@@ -91,6 +94,8 @@ public class HttpRequestHandlingControllerTests extends AbstractHttpInboundTests
Expression viewExpression = new SpelExpressionParser().parseExpression("'baz'");
controller.setViewExpression(viewExpression);
controller.afterPropertiesSet();
controller.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContent("hello".getBytes());
@@ -123,6 +128,8 @@ public class HttpRequestHandlingControllerTests extends AbstractHttpInboundTests
controller.setRequestChannel(requestChannel);
controller.setViewName("foo");
controller.afterPropertiesSet();
controller.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
@@ -157,6 +164,8 @@ public class HttpRequestHandlingControllerTests extends AbstractHttpInboundTests
Expression viewExpression = new SpelExpressionParser().parseExpression("headers['bar']");
controller.setViewExpression(viewExpression);
controller.afterPropertiesSet();
controller.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContent("hello".getBytes());
@@ -188,6 +197,8 @@ public class HttpRequestHandlingControllerTests extends AbstractHttpInboundTests
Expression viewExpression = new SpelExpressionParser().parseExpression("headers['bar']");
controller.setViewExpression(viewExpression);
controller.afterPropertiesSet();
controller.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContent("hello".getBytes());
@@ -217,6 +228,8 @@ public class HttpRequestHandlingControllerTests extends AbstractHttpInboundTests
controller.setViewName("foo");
controller.setReplyKey("myReply");
controller.afterPropertiesSet();
controller.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContent("howdy".getBytes());
@@ -250,6 +263,8 @@ public class HttpRequestHandlingControllerTests extends AbstractHttpInboundTests
controller.setViewName("foo");
controller.setExtractReplyPayload(false);
controller.afterPropertiesSet();
controller.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContent("abc".getBytes());
@@ -280,6 +295,8 @@ public class HttpRequestHandlingControllerTests extends AbstractHttpInboundTests
controller.setBeanFactory(mock(BeanFactory.class));
controller.setRequestChannel(requestChannel);
controller.afterPropertiesSet();
controller.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContent("hello".getBytes());
@@ -319,6 +336,8 @@ public class HttpRequestHandlingControllerTests extends AbstractHttpInboundTests
controller.setRequestChannel(requestChannel);
controller.setViewName("foo");
controller.afterPropertiesSet();
controller.start();
final MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContent("hello".getBytes());

View File

@@ -76,6 +76,8 @@ public class HttpRequestHandlingMessagingGatewayTests extends AbstractHttpInboun
gateway.setBeanFactory(mock(BeanFactory.class));
gateway.setRequestChannel(requestChannel);
gateway.afterPropertiesSet();
gateway.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
request.setParameter("foo", "bar");
@@ -97,6 +99,8 @@ public class HttpRequestHandlingMessagingGatewayTests extends AbstractHttpInboun
gateway.setRequestPayloadType(String.class);
gateway.setRequestChannel(requestChannel);
gateway.afterPropertiesSet();
gateway.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContentType("text/plain");
@@ -133,6 +137,8 @@ public class HttpRequestHandlingMessagingGatewayTests extends AbstractHttpInboun
gateway.setRequestPayloadType(String.class);
gateway.setRequestChannel(requestChannel);
gateway.afterPropertiesSet();
gateway.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.addHeader("Accept", "x-application/octet-stream");
@@ -159,6 +165,8 @@ public class HttpRequestHandlingMessagingGatewayTests extends AbstractHttpInboun
gateway.setRequestPayloadType(String.class);
gateway.setRequestChannel(requestChannel);
gateway.afterPropertiesSet();
gateway.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContentType("text/plain");
@@ -184,6 +192,8 @@ public class HttpRequestHandlingMessagingGatewayTests extends AbstractHttpInboun
gateway.setConvertExceptions(true);
gateway.setMessageConverters(Arrays.<HttpMessageConverter<?>>asList(new TestHttpMessageConverter()));
gateway.afterPropertiesSet();
gateway.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Accept", "application/x-java-serialized-object");
request.setMethod("GET");
@@ -200,6 +210,8 @@ public class HttpRequestHandlingMessagingGatewayTests extends AbstractHttpInboun
gateway.setBeanFactory(mock(BeanFactory.class));
gateway.setRequestChannel(channel);
gateway.afterPropertiesSet();
gateway.start();
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test");
request.setParameter("foo", "123");
request.addParameter("bar", "456");
@@ -233,6 +245,7 @@ public class HttpRequestHandlingMessagingGatewayTests extends AbstractHttpInboun
converters.add(new SerializingHttpMessageConverter());
gateway.setMessageConverters(converters);
gateway.afterPropertiesSet();
gateway.start();
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/test");
@@ -281,6 +294,7 @@ public class HttpRequestHandlingMessagingGatewayTests extends AbstractHttpInboun
gateway.setBeanFactory(mock(BeanFactory.class));
gateway.setMessageConverters(messageConverters);
gateway.setRequestChannel(requestChannel);
gateway.start();
final MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
@@ -306,6 +320,7 @@ public class HttpRequestHandlingMessagingGatewayTests extends AbstractHttpInboun
gateway.setRequestChannel(requestChannel);
gateway.setReplyTimeout(0);
gateway.afterPropertiesSet();
gateway.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
MockHttpServletResponse response = new MockHttpServletResponse();
@@ -324,6 +339,8 @@ public class HttpRequestHandlingMessagingGatewayTests extends AbstractHttpInboun
gateway.setReplyTimeout(0);
gateway.setStatusCodeExpression(new LiteralExpression("501"));
gateway.afterPropertiesSet();
gateway.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
MockHttpServletResponse response = new MockHttpServletResponse();
@@ -352,6 +369,8 @@ public class HttpRequestHandlingMessagingGatewayTests extends AbstractHttpInboun
});
gateway.setErrorChannel(errorChannel);
gateway.afterPropertiesSet();
gateway.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
MockHttpServletResponse response = new MockHttpServletResponse();
@@ -372,6 +391,8 @@ public class HttpRequestHandlingMessagingGatewayTests extends AbstractHttpInboun
gateway.setErrorChannel(errorChannel);
gateway.setStatusCodeExpression(new LiteralExpression("501"));
gateway.afterPropertiesSet();
gateway.start();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
MockHttpServletResponse response = new MockHttpServletResponse();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -78,6 +78,7 @@ public class HttpRequestHandlingMessagingGatewayWithPathMappingTests extends Abs
requestMapping.setPathPatterns("/fname/{f}/lname/{l}");
gateway.setRequestMapping(requestMapping);
gateway.afterPropertiesSet();
gateway.start();
gateway.setRequestChannel(echoChannel);
@@ -125,6 +126,7 @@ public class HttpRequestHandlingMessagingGatewayWithPathMappingTests extends Abs
gateway.setRequestChannel(echoChannel);
gateway.setPayloadExpression(PARSER.parseExpression("#pathVariables.f"));
gateway.afterPropertiesSet();
gateway.start();
Object result = gateway.doHandleRequest(request, response);
assertTrue(result instanceof Message);
@@ -170,6 +172,7 @@ public class HttpRequestHandlingMessagingGatewayWithPathMappingTests extends Abs
gateway.setRequestChannel(echoChannel);
gateway.setPayloadExpression(PARSER.parseExpression("#pathVariables"));
gateway.afterPropertiesSet();
gateway.start();
Object result = gateway.doHandleRequest(request, response);
assertTrue(result instanceof Message);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -63,6 +63,7 @@ public class MultipartAsRawByteArrayTests {
gw.setBeanFactory(mock(BeanFactory.class));
gw.setRequestPayloadType(byte[].class);
gw.afterPropertiesSet();
gw.start();
HttpServletRequest request = mock(HttpServletRequest.class);
ServletInputStream sis = mock(ServletInputStream.class);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,8 +16,10 @@
package org.springframework.integration.ws;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.expression.ExpressionException;
import org.springframework.integration.context.OrderlyShutdownCapable;
import org.springframework.integration.gateway.MessagingGatewaySupport;
import org.springframework.integration.support.AbstractIntegrationMessageBuilder;
import org.springframework.messaging.Message;
@@ -31,9 +33,13 @@ import org.springframework.ws.soap.SoapMessage;
/**
* @author Oleg Zhurakousky
* @author Artem Bilan
* @since 2.1
*/
abstract public class AbstractWebServiceInboundGateway extends MessagingGatewaySupport implements MessageEndpoint {
public abstract class AbstractWebServiceInboundGateway extends MessagingGatewaySupport
implements MessageEndpoint, OrderlyShutdownCapable {
private final AtomicInteger activeCount = new AtomicInteger();
protected volatile SoapHeaderMapper headerMapper = new DefaultSoapHeaderMapper();
@@ -48,9 +54,13 @@ abstract public class AbstractWebServiceInboundGateway extends MessagingGatewayS
}
public void invoke(MessageContext messageContext) throws Exception {
if (!isRunning()) {
throw new ServiceUnavailableException("503 Service Unavailable");
}
Assert.notNull(messageContext,"'messageContext' is required; it must not be null.");
try {
this.activeCount.incrementAndGet();
this.doInvoke(messageContext);
}
catch (Exception e) {
@@ -60,6 +70,9 @@ abstract public class AbstractWebServiceInboundGateway extends MessagingGatewayS
}
throw e;
}
finally {
this.activeCount.decrementAndGet();
}
}
protected void fromSoapHeaders(MessageContext messageContext, AbstractIntegrationMessageBuilder<?> builder){
@@ -86,5 +99,17 @@ abstract public class AbstractWebServiceInboundGateway extends MessagingGatewayS
}
}
@Override
public int beforeShutdown() {
stop();
return this.activeCount.get();
}
@Override
public int afterShutdown() {
return this.activeCount.get();
}
abstract protected void doInvoke(MessageContext messageContext) throws Exception;
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.ws;
import org.springframework.ws.WebServiceException;
import org.springframework.ws.soap.server.endpoint.annotation.FaultCode;
import org.springframework.ws.soap.server.endpoint.annotation.SoapFault;
/**
* The {@link WebServiceException} extension to indicate that the server endpoint is
* temporary unavailable.
*
* @author Artem Bilan
* @since 4.3
*/
@SoapFault(faultCode = FaultCode.RECEIVER)
public class ServiceUnavailableException extends WebServiceException {
private static final long serialVersionUID = 1L;
public ServiceUnavailableException(String msg) {
super(msg);
}
public ServiceUnavailableException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -410,6 +410,7 @@ this list can also be simple patterns to be matched against the header names (e.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attributeGroup ref="integration:smartLifeCycleAttributeGroup"/>
</xsd:complexType>
</xsd:element>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -86,6 +86,8 @@ public class SimpleWebServiceInboundGatewayTests {
gateway.setRequestChannel(requestChannel);
gateway.setReplyChannel(replyChannel);
gateway.setBeanFactory(mock(BeanFactory.class));
gateway.start();
when(context.getResponse()).thenReturn(response);
when(response.getPayloadResult()).thenReturn(payloadResult);
when(context.getRequest()).thenReturn(request);
@@ -124,16 +126,20 @@ public class SimpleWebServiceInboundGatewayTests {
public void describeTo(Description description) {
description.appendText("A message with payload: " + payload);
}
});
}
private Answer<Boolean> withReplyTo(final MessageChannel replyChannel) {
return new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
replyChannel.send((Message<?>) invocation.getArguments()[0]);
return true;
}
};
}
}

View File

@@ -21,10 +21,14 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.StringWriter;
import java.util.Locale;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamResult;
@@ -34,6 +38,7 @@ import org.junit.runner.RunWith;
import org.w3c.dom.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.Lifecycle;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.expression.spel.standard.SpelExpressionParser;
@@ -58,6 +63,7 @@ import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.mapping.UriEndpointMapping;
import org.springframework.ws.soap.SoapBody;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.server.SoapMessageDispatcher;
import org.springframework.ws.transport.WebServiceMessageReceiver;
@@ -78,11 +84,15 @@ public class WebServiceInboundGatewayJavaConfigTests {
@Autowired
private PollableChannel webserviceRequestsQueue;
@Autowired
private Lifecycle wsGateway;
@Test
public void testWebServiceInboundGatewayJavaConfig() throws Exception {
MessageContext context = mock(MessageContext.class);
SoapMessage request = mock(SoapMessage.class);
SoapMessage response = mock(SoapMessage.class);
SoapBody soapBody = mock(SoapBody.class);
String input = "<hello/>";
Source payloadSource = new StringSource(input);
@@ -91,11 +101,18 @@ public class WebServiceInboundGatewayJavaConfigTests {
when(context.getResponse()).thenReturn(response);
when(response.getPayloadResult()).thenReturn(payloadResult);
when(response.getSoapBody()).thenReturn(soapBody);
when(context.getRequest()).thenReturn(request);
when(request.getPayloadSource()).thenReturn(payloadSource);
this.messageReceiver.receive(context);
verify(soapBody).addServerOrReceiverFault(eq("503 Service Unavailable"), any(Locale.class));
this.wsGateway.start();
this.messageReceiver.receive(context);
assertTrue(output.toString().endsWith(input));
@@ -138,6 +155,7 @@ public class WebServiceInboundGatewayJavaConfigTests {
public MessageEndpoint wsGateway() {
SimpleWebServiceInboundGateway gateway = new SimpleWebServiceInboundGateway();
gateway.setRequestChannel(gatewayRequests());
gateway.setAutoStartup(false);
return gateway;
}

View File

@@ -1,27 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:si="http://www.springframework.org/schema/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:si="http://www.springframework.org/schema/integration"
xmlns:ws="http://www.springframework.org/schema/integration/ws"
xmlns:util='http://www.springframework.org/schema/util'
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/ws
http://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
http://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd">
<si:message-history/>
<ws:inbound-gateway id="simple" request-channel="requestsVerySimple" error-channel="customErrorChannel"/>
<ws:inbound-gateway id="simple"
request-channel="requestsVerySimple"
error-channel="customErrorChannel"
auto-startup="false"
phase="101"/>
<si:channel id="customErrorChannel"/>
<si:channel id="requestsVerySimple"></si:channel>
<si:channel id="requestsVerySimple"/>
<ws:inbound-gateway id="extractsPayload" request-channel="requestsSimple" extract-payload="false"/>
<ws:inbound-gateway id="marshalling" request-channel="requestsMarshalling" error-channel="customErrorChannel"
marshaller="marshaller" unmarshaller="marshaller"
mapped-request-headers="testRequest"
@@ -30,7 +32,7 @@
<si:channel id="requestsMarshalling">
<si:queue/>
</si:channel>
<si:channel id="requestsSimple">
<si:queue/>
</si:channel>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
@@ -64,10 +65,11 @@ import org.springframework.ws.soap.SoapMessage;
* @author Mark Fisher
* @author Gunnar Hillert
* @author Stephane Nicoll
* @author Artem Bilan
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD)
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class WebServiceInboundGatewayParserTests {
@Autowired
@@ -98,14 +100,10 @@ public class WebServiceInboundGatewayParserTests {
@Test
public void simpleGatewayProperties() throws Exception {
DirectFieldAccessor accessor = new DirectFieldAccessor(simpleGateway);
assertThat(
(MessageChannel) accessor.getPropertyValue("requestChannel"),
is(requestsVerySimple));
assertThat(
(MessageChannel) accessor.getPropertyValue("errorChannel"),
is(customErrorChannel));
assertSame(this.requestsVerySimple, TestUtils.getPropertyValue(this.simpleGateway, "requestChannel"));
assertSame(this.customErrorChannel, TestUtils.getPropertyValue(this.simpleGateway, "errorChannel"));
assertFalse(TestUtils.getPropertyValue(this.simpleGateway, "autoStartup", Boolean.class));
assertEquals(101, TestUtils.getPropertyValue(this.simpleGateway, "phase"));
}
//extractPayload = false
@@ -160,7 +158,7 @@ public class WebServiceInboundGatewayParserTests {
public void testMessageHistoryWithMarshallingGateway() throws Exception {
MessageContext context = new DefaultMessageContext(new StubMessageFactory());
Unmarshaller unmarshaller = mock(Unmarshaller.class);
when(unmarshaller.unmarshal((Source)Mockito.any())).thenReturn("hello");
when(unmarshaller.unmarshal((Source) Mockito.any())).thenReturn("hello");
marshallingGateway.setUnmarshaller(unmarshaller);
marshallingGateway.invoke(context);
Message<?> message = requestsMarshalling.receive(100);
@@ -196,7 +194,8 @@ public class WebServiceInboundGatewayParserTests {
assertEquals(testHeaderMapper, headerMapper);
}
@Autowired @Qualifier("replyTimeoutGateway")
@Autowired
@Qualifier("replyTimeoutGateway")
private SimpleWebServiceInboundGateway replyTimeoutGateway;
@Test
@@ -212,7 +211,7 @@ public class WebServiceInboundGatewayParserTests {
@Override
public void fromHeadersToRequest(MessageHeaders headers,
SoapMessage target) {
SoapMessage target) {
}
@Override