INT-1951, INT-1981 refactored WS module to remove dependency on deprecated version of Spring-WS, added validation checks to the Inbound Gateway Parser for 'extract-payload' attribute

This commit is contained in:
Oleg Zhurakousky
2011-08-08 17:21:17 -04:00
parent 74817b98fc
commit 5afd12a819
6 changed files with 177 additions and 231 deletions

View File

@@ -0,0 +1,91 @@
/*
* Copyright 2002-2011 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 java.util.Map;
import org.springframework.expression.ExpressionException;
import org.springframework.integration.Message;
import org.springframework.integration.MessagingException;
import org.springframework.integration.gateway.MessagingGatewaySupport;
import org.springframework.integration.mapping.HeaderMapper;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MessageEndpoint;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapMessage;
/**
* @author Oleg Zhurakousky
* @since 2.1
*/
abstract public class AbstractWebServiceInboundGateway extends MessagingGatewaySupport implements MessageEndpoint {
protected volatile HeaderMapper<SoapHeader> headerMapper = new DefaultSoapHeaderMapper();
public String getComponentType() {
return "ws:outbound-gateway";
}
public void setHeaderMapper(HeaderMapper<SoapHeader> headerMapper) {
Assert.notNull(headerMapper, "headerMapper must not be null");
this.headerMapper = headerMapper;
}
public void invoke(MessageContext messageContext) throws Exception {
Assert.notNull(messageContext,"'messageContext' is required; it must not be null.");
try {
this.doInvoke(messageContext);
}
catch (Exception e) {
while ((e instanceof MessagingException || e instanceof ExpressionException) &&
e.getCause() instanceof Exception) {
e = (Exception) e.getCause();
}
throw e;
}
}
protected void fromSoapHeaders(MessageContext messageContext, MessageBuilder<?> builder){
WebServiceMessage request = messageContext.getRequest();
String[] propertyNames = messageContext.getPropertyNames();
if (propertyNames != null) {
for (String propertyName : propertyNames) {
builder.setHeader(propertyName, messageContext.getProperty(propertyName));
}
}
if (request instanceof SoapMessage) {
SoapMessage soapMessage = (SoapMessage) request;
Map<String, ?> headers = this.headerMapper.toHeaders(soapMessage.getSoapHeader());
if (!CollectionUtils.isEmpty(headers)) {
builder.copyHeaders(headers);
}
}
}
protected void toSoapHeaders(WebServiceMessage response, Message<?> replyMessage){
if (response instanceof SoapMessage) {
this.headerMapper.fromHeaders(
replyMessage.getHeaders(), ((SoapMessage) response).getSoapHeader());
}
}
abstract protected void doInvoke(MessageContext messageContext) throws Exception;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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,37 +16,25 @@
package org.springframework.integration.ws;
import java.util.concurrent.locks.ReentrantLock;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.SmartLifecycle;
import org.springframework.expression.ExpressionException;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.MessagingException;
import org.springframework.integration.gateway.MessagingGatewaySupport;
import org.springframework.integration.history.TrackableComponent;
import org.springframework.integration.Message;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.ws.server.endpoint.AbstractMarshallingPayloadEndpoint;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.support.MarshallingUtils;
/**
* @author Mark Fisher
* @author Oleg Zhurakousky
* @since 1.0.2
*/
public class MarshallingWebServiceInboundGateway extends AbstractMarshallingPayloadEndpoint
implements BeanNameAware, BeanFactoryAware, InitializingBean, SmartLifecycle, TrackableComponent {
private final ReentrantLock lifecycleLock = new ReentrantLock();
private final GatewayDelegate gatewayDelegate = new GatewayDelegate();
private volatile int phase = 0;
public class MarshallingWebServiceInboundGateway extends AbstractWebServiceInboundGateway {
private volatile Marshaller marshaller;
private volatile Unmarshaller unmarshaller;
/**
* Creates a new <code>MarshallingWebServiceInboundGateway</code>.
@@ -68,161 +56,55 @@ public class MarshallingWebServiceInboundGateway extends AbstractMarshallingPayl
* @see #MarshallingWebServiceInboundGateway(Marshaller, Unmarshaller)
*/
public MarshallingWebServiceInboundGateway(Marshaller marshaller) {
super(marshaller);
Assert.notNull(marshaller, "'marshaller' must no be null");
Assert.isInstanceOf(Unmarshaller.class, marshaller, "When using this constructor the provided " +
"Marshaller must also implement Unmarshaller");
this.marshaller = marshaller;
this.unmarshaller = unmarshaller;
}
/**
* Creates a new <code>MarshallingWebServiceInboundGateway</code> with the given marshaller and unmarshaller.
*/
public MarshallingWebServiceInboundGateway(Marshaller marshaller, Unmarshaller unmarshaller) {
super(marshaller, unmarshaller);
Assert.notNull(marshaller, "'marshaller' must no be null");
Assert.notNull(unmarshaller, "'unmarshaller' must no be null");
this.marshaller = marshaller;
this.unmarshaller = unmarshaller;
}
public void setMarshaller(Marshaller marshaller) {
Assert.notNull(marshaller, "'marshaller' must no be null");
this.marshaller = marshaller;
}
public void setRequestChannel(MessageChannel requestChannel) {
this.gatewayDelegate.setRequestChannel(requestChannel);
}
public void setRequestTimeout(long requestTimeout) {
this.gatewayDelegate.setRequestTimeout(requestTimeout);
public void setUnmarshaller(Unmarshaller unmarshaller) {
Assert.notNull(unmarshaller, "'unmarshaller' must no be null");
this.unmarshaller = unmarshaller;
}
public void setErrorChannel(MessageChannel errorChannel) {
this.gatewayDelegate.setErrorChannel(errorChannel);
protected void onInit() throws Exception {
super.onInit();
Assert.notNull(marshaller, "This implementation requires Marshaller");
Assert.notNull(unmarshaller, "This implementation requires Unmarshaller");
}
public void setReplyChannel(MessageChannel replyChannel) {
this.gatewayDelegate.setReplyChannel(replyChannel);
}
public void setReplyTimeout(long replyTimeout) {
this.gatewayDelegate.setReplyTimeout(replyTimeout);
}
public void setTaskScheduler(TaskScheduler taskScheduler) {
this.gatewayDelegate.setTaskScheduler(taskScheduler);
}
public void setShouldTrack(boolean shouldTrack) {
this.gatewayDelegate.setShouldTrack(shouldTrack);
}
public String getComponentName() {
return this.gatewayDelegate.getComponentName();
}
public String getComponentType() {
return this.gatewayDelegate.getComponentType();
}
public void setAutoStartup(boolean autoStartup) {
this.gatewayDelegate.setAutoStartup(autoStartup);
}
public boolean isAutoStartup() {
return this.gatewayDelegate.isAutoStartup();
}
public void setPhase(int phase) {
this.phase = phase;
}
public int getPhase() {
return this.phase;
}
public void setBeanName(String beanName) {
this.gatewayDelegate.setBeanName(beanName);
}
public void setBeanFactory(BeanFactory beanFactory) {
this.gatewayDelegate.setBeanFactory(beanFactory);
}
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
this.gatewayDelegate.afterPropertiesSet();
}
@Override
protected Object invokeInternal(Object requestObject) throws Exception {
try {
return this.gatewayDelegate.sendAndReceive(requestObject);
}
catch (Exception e) {
while ((e instanceof MessagingException || e instanceof ExpressionException) &&
e.getCause() instanceof Exception) {
e = (Exception) e.getCause();
}
throw e;
}
protected void doInvoke(MessageContext messageContext) throws Exception{
WebServiceMessage request = messageContext.getRequest();
Assert.notNull(request, "Invalid message context: request was null.");
Object requestObject = MarshallingUtils.unmarshal(unmarshaller, request);
MessageBuilder<?> builder = MessageBuilder.withPayload(requestObject);
this.fromSoapHeaders(messageContext, builder);
Message<?> replyMessage = this.sendAndReceiveMessage(builder.build());
if (replyMessage != null) {
WebServiceMessage response = messageContext.getResponse();
this.toSoapHeaders(response, replyMessage);
MarshallingUtils.marshal(marshaller, replyMessage.getPayload(), response);
}
}
// Lifecycle implementation
public boolean isRunning() {
this.lifecycleLock.lock();
try {
return this.gatewayDelegate.isRunning();
}
finally {
this.lifecycleLock.unlock();
}
}
public void start() {
this.lifecycleLock.lock();
try {
if (!this.gatewayDelegate.isRunning()) {
this.gatewayDelegate.start();
if (logger.isInfoEnabled()) {
logger.info("started " + this);
}
}
}
finally {
this.lifecycleLock.unlock();
}
}
public void stop() {
this.lifecycleLock.lock();
try {
if (gatewayDelegate.isRunning()) {
this.gatewayDelegate.stop();
if (logger.isInfoEnabled()) {
logger.info("stopped " + this);
}
}
}
finally {
this.lifecycleLock.unlock();
}
}
public void stop(Runnable callback) {
this.lifecycleLock.lock();
try {
this.stop();
callback.run();
}
finally {
this.lifecycleLock.unlock();
}
}
private static class GatewayDelegate extends MessagingGatewaySupport {
public Object sendAndReceive(Object request) {
return super.sendAndReceive(request);
}
public String getComponentType() {
return "ws:outbound-gateway";
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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,91 +16,48 @@
package org.springframework.integration.ws;
import java.util.Map;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import org.w3c.dom.Document;
import org.springframework.expression.ExpressionException;
import org.springframework.integration.Message;
import org.springframework.integration.MessagingException;
import org.springframework.integration.gateway.MessagingGatewaySupport;
import org.springframework.integration.mapping.HeaderMapper;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MessageEndpoint;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.xml.transform.StringSource;
import org.springframework.xml.transform.TransformerObjectSupport;
import org.w3c.dom.Document;
/**
* @author Mark Fisher
* @author Oleg Zhurakousky
* @since 1.0.2
*/
public class SimpleWebServiceInboundGateway extends MessagingGatewaySupport implements MessageEndpoint {
public class SimpleWebServiceInboundGateway extends AbstractWebServiceInboundGateway {
private final TransformerSupportDelegate transformerSupportDelegate = new TransformerSupportDelegate();
private volatile boolean extractPayload = true;
private volatile HeaderMapper<SoapHeader> headerMapper = new DefaultSoapHeaderMapper();
public void setExtractPayload(boolean extractPayload) {
this.extractPayload = extractPayload;
}
public void setHeaderMapper(HeaderMapper<SoapHeader> headerMapper) {
Assert.notNull(headerMapper, "headerMapper must not be null");
this.headerMapper = headerMapper;
}
public String getComponentType() {
return "ws:outbound-gateway";
}
public void invoke(MessageContext messageContext) throws Exception {
try {
this.doInvoke(messageContext);
}
catch (Exception e) {
while ((e instanceof MessagingException || e instanceof ExpressionException) &&
e.getCause() instanceof Exception) {
e = (Exception) e.getCause();
}
throw e;
}
}
private void doInvoke(MessageContext messageContext) throws Exception {
Assert.notNull(messageContext,"'messageContext' is required; it must not be null.");
protected void doInvoke(MessageContext messageContext) throws Exception {
WebServiceMessage request = messageContext.getRequest();
Assert.notNull(request, "Invalid message context: request was null.");
MessageBuilder<?> builder = MessageBuilder.withPayload(
(this.extractPayload) ? request.getPayloadSource() : request);
String[] propertyNames = messageContext.getPropertyNames();
if (propertyNames != null) {
for (String propertyName : propertyNames) {
builder.setHeader(propertyName, messageContext.getProperty(propertyName));
}
}
if (request instanceof SoapMessage) {
SoapMessage soapMessage = (SoapMessage) request;
Map<String, ?> headers = this.headerMapper.toHeaders(soapMessage.getSoapHeader());
if (!CollectionUtils.isEmpty(headers)) {
builder.copyHeaders(headers);
}
}
this.fromSoapHeaders(messageContext, builder);
Message<?> replyMessage = this.sendAndReceiveMessage(builder.build());
if (replyMessage != null && replyMessage.getPayload() != null) {
if (replyMessage != null) {
Object replyPayload = replyMessage.getPayload();
Source responseSource = null;
if (replyPayload instanceof Source) {
@@ -119,11 +76,10 @@ public class SimpleWebServiceInboundGateway extends MessagingGatewaySupport impl
+ replyPayload.getClass().getName() + "]");
}
WebServiceMessage response = messageContext.getResponse();
if (response instanceof SoapMessage) {
this.headerMapper.fromHeaders(
replyMessage.getHeaders(), ((SoapMessage) response).getSoapHeader());
}
this.transformerSupportDelegate.transformSourceToResult(responseSource, response.getPayloadResult());
this.toSoapHeaders(response, replyMessage);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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.
@@ -18,6 +18,8 @@ package org.springframework.integration.ws.config;
import org.w3c.dom.Element;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.integration.config.xml.AbstractInboundGatewayParser;
import org.springframework.util.Assert;
@@ -26,9 +28,10 @@ import org.springframework.util.StringUtils;
/**
* @author Iwein Fuld
* @author Mark Fisher
* @author Oleg Zhurakousky
*/
public class WebServiceInboundGatewayParser extends AbstractInboundGatewayParser {
protected final Log logger = LogFactory.getLog(getClass());
@Override
protected String getBeanClassName(Element element) {
String simpleClassName = (StringUtils.hasText(element.getAttribute("marshaller"))) ?
@@ -44,13 +47,26 @@ public class WebServiceInboundGatewayParser extends AbstractInboundGatewayParser
@Override
protected void doPostProcess(BeanDefinitionBuilder builder, Element element) {
String marshallerRef = element.getAttribute("marshaller");
String unmarshallerRef = element.getAttribute("unmarshaller");
if (StringUtils.hasText(marshallerRef)) {
builder.addConstructorArgReference(marshallerRef);
String unmarshallerRef = element.getAttribute("unmarshaller");
if (StringUtils.hasText(unmarshallerRef)) {
builder.addConstructorArgReference(unmarshallerRef);
}
}
else { // check if unmarshaller is defined which is a mistake without marshaller
if (StringUtils.hasText(unmarshallerRef)){
throw new IllegalArgumentException("Defining 'unmarshaller' without 'marshaller' is not allowed");
}
}
if (StringUtils.hasText(marshallerRef) || StringUtils.hasText(unmarshallerRef)){
String extractPayload = element.getAttribute("extract-payload");
if (StringUtils.hasText(extractPayload)){
logger.warn("Setting 'extract-payload' attribute ihas no effect when used with MarshallingWebServiceInboundGateway");
}
}
String headerMapperRef = element.getAttribute("header-mapper");
if (StringUtils.hasText(headerMapperRef)) {
Assert.isTrue(!StringUtils.hasText(marshallerRef),

View File

@@ -260,7 +260,7 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="extract-payload" type="xsd:boolean"/>
<xsd:attribute name="extract-payload" type="xsd:string"/>
<xsd:attribute name="header-mapper">
<xsd:annotation>
<xsd:documentation>

View File

@@ -117,6 +117,7 @@ public class WebServiceInboundGatewayParserTests {
//marshalling
@Autowired
@Qualifier("marshalling")
MarshallingWebServiceInboundGateway marshallingGateway;
@Autowired
@@ -131,10 +132,10 @@ public class WebServiceInboundGatewayParserTests {
is(marshaller));
assertTrue("messaging gateway is not running", marshallingGateway.isRunning());
MessagingGatewaySupport mgs = (MessagingGatewaySupport) accessor.getPropertyValue("gatewayDelegate");
DirectFieldAccessor mgsAccessor = new DirectFieldAccessor(mgs);
//MessagingGatewaySupport mgs = (MessagingGatewaySupport) accessor.getPropertyValue("gatewayDelegate");
//DirectFieldAccessor mgsAccessor = new DirectFieldAccessor(mgs);
assertThat(
(MessageChannel) mgsAccessor.getPropertyValue("errorChannel"),
(MessageChannel) accessor.getPropertyValue("errorChannel"),
is(customErrorChannel));
}