INT-1446 added DefaultSoapHeaderMapper. SimpleWebServiceInboundGateway now delegates to it.

This commit is contained in:
Mark Fisher
2010-10-18 08:14:38 -04:00
parent 5b6583dfe6
commit 93c08e6e3e
4 changed files with 179 additions and 43 deletions

View File

@@ -0,0 +1,125 @@
/*
* Copyright 2002-2010 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.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.namespace.QName;
import org.springframework.integration.MessageHeaders;
import org.springframework.integration.mapping.HeaderMapper;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.PatternMatchUtils;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapHeaderElement;
import org.springframework.xml.namespace.QNameUtils;
/**
* A {@link HeaderMapper} implementation for mapping to and from a SoapHeader.
* The {@link #inboundHeaderNames} and {@link #outboundHeaderNames} may be configured.
* They accept exact name Strings or simple patterns (e.g. "start*", "*end", or "*").
* By default all inbound headers will be accepted, but any outbound header that should
* be mapped must be configured explicitly. Note that the outbound mapping only writes
* String header values into attributes on the SoapHeader. For anything more advanced,
* one should implement the HeaderMapper interface directly.
*
* @author Mark Fisher
* @since 2.0
*/
public class DefaultSoapHeaderMapper implements HeaderMapper<SoapHeader> {
private volatile String[] outboundHeaderNames = new String[0];
private volatile String[] inboundHeaderNames = new String[] { "*" };
public void setOutboundHeaderNames(String[] outboundHeaderNames) {
this.outboundHeaderNames = (outboundHeaderNames != null) ? outboundHeaderNames : new String[0];
}
public void setInboundHeaderNames(String[] inboundHeaderNames) {
this.inboundHeaderNames = (inboundHeaderNames != null) ? inboundHeaderNames : new String[0];
}
public void fromHeaders(MessageHeaders headers, SoapHeader target) {
if (target != null && !CollectionUtils.isEmpty(headers)) {
for (String headerName : headers.keySet()) {
if (this.shouldMapOutboundHeader(headerName)) {
Object value = headers.get(headerName);
if (value instanceof String) {
QName qname = QNameUtils.parseQNameString(headerName);
target.addAttribute(qname, (String) value);
}
}
}
}
}
public Map<String, Object> toHeaders(SoapHeader source) {
Map<String, Object> headers = new HashMap<String, Object>();
if (source != null) {
Iterator<?> attributeIter = source.getAllAttributes();
while (attributeIter.hasNext()) {
Object name = attributeIter.next();
if (name instanceof QName) {
String qnameString = QNameUtils.toQualifiedName((QName) name);
if (this.shouldMapInboundHeader(qnameString)) {
String value = source.getAttributeValue((QName) name);
if (value != null) {
headers.put(qnameString, value);
}
}
}
}
Iterator<?> elementIter = source.examineAllHeaderElements();
while (elementIter.hasNext()) {
Object element = elementIter.next();
if (element instanceof SoapHeaderElement) {
QName qname = ((SoapHeaderElement) element).getName();
String qnameString = QNameUtils.toQualifiedName(qname);
if (this.shouldMapInboundHeader(qnameString)) {
headers.put(qnameString, element);
}
}
}
}
return headers;
}
private boolean shouldMapInboundHeader(String headerName) {
return matchesAny(this.inboundHeaderNames, headerName);
}
private boolean shouldMapOutboundHeader(String headerName) {
return matchesAny(this.outboundHeaderNames, headerName);
}
private static boolean matchesAny(String[] patterns, String candidate) {
if (!ObjectUtils.isEmpty(patterns) && QNameUtils.validateQName(candidate)) {
for (String pattern : patterns) {
if (PatternMatchUtils.simpleMatch(pattern, candidate)) {
return true;
}
}
}
return false;
}
}

View File

@@ -43,7 +43,10 @@ public class MarshallingWebServiceInboundGateway extends AbstractMarshallingPayl
private final ReentrantLock lifecycleLock = new ReentrantLock();
private final GatewayDelegate gatewayDelegate = new GatewayDelegate();
private volatile int phase = 0;
/**
* Creates a new <code>MarshallingWebServiceInboundGateway</code>.
* The {@link Marshaller} and {@link Unmarshaller} must be injected using properties.
@@ -95,10 +98,34 @@ public class MarshallingWebServiceInboundGateway extends AbstractMarshallingPayl
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);
}
@@ -143,7 +170,7 @@ public class MarshallingWebServiceInboundGateway extends AbstractMarshallingPayl
public void start() {
this.lifecycleLock.lock();
try {
if (!gatewayDelegate.isRunning()) {
if (!this.gatewayDelegate.isRunning()) {
this.gatewayDelegate.start();
if (logger.isInfoEnabled()) {
logger.info("started " + this);
@@ -170,10 +197,6 @@ public class MarshallingWebServiceInboundGateway extends AbstractMarshallingPayl
}
}
public boolean isAutoStartup() {
return true;
}
public void stop(Runnable callback) {
this.lifecycleLock.lock();
try {
@@ -185,29 +208,16 @@ public class MarshallingWebServiceInboundGateway extends AbstractMarshallingPayl
}
}
public int getPhase() {
return 0;
}
private static class GatewayDelegate extends MessagingGatewaySupport {
public Object sendAndReceive(Object request) {
return super.sendAndReceive(request);
}
public String getComponentType() {
return "ws:outbound-gateway";
}
}
public String getComponentName() {
return this.gatewayDelegate.getComponentName();
}
public String getComponentType() {
return this.gatewayDelegate.getComponentType();
}
public void setShouldTrack(boolean shouldTrack) {
this.gatewayDelegate.setShouldTrack(shouldTrack);
}
}

View File

@@ -16,9 +16,8 @@
package org.springframework.integration.ws;
import java.util.Iterator;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
@@ -30,13 +29,14 @@ 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.SoapHeaderElement;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.xml.transform.StringSource;
import org.springframework.xml.transform.TransformerObjectSupport;
@@ -51,11 +51,22 @@ public class SimpleWebServiceInboundGateway extends MessagingGatewaySupport impl
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);
@@ -83,21 +94,9 @@ public class SimpleWebServiceInboundGateway extends MessagingGatewaySupport impl
}
if (request instanceof SoapMessage) {
SoapMessage soapMessage = (SoapMessage) request;
SoapHeader soapHeader = soapMessage.getSoapHeader();
if (soapHeader != null) {
Iterator<?> attributeIter = soapHeader.getAllAttributes();
while (attributeIter.hasNext()) {
QName name = (QName) attributeIter.next();
builder.setHeader(name.toString(), soapHeader.getAttributeValue(name));
}
Iterator<?> elementIter = soapHeader.examineAllHeaderElements();
while (elementIter.hasNext()) {
Object element = elementIter.next();
if (element instanceof SoapHeaderElement) {
QName name = ((SoapHeaderElement) element).getName();
builder.setHeader(name.toString(), element);
}
}
Map<String, ?> headers = this.headerMapper.toHeaders(soapMessage.getSoapHeader());
if (!CollectionUtils.isEmpty(headers)) {
builder.copyHeaders(headers);
}
}
Message<?> replyMessage = this.sendAndReceiveMessage(builder.build());
@@ -120,17 +119,19 @@ 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());
}
}
private class TransformerSupportDelegate extends TransformerObjectSupport {
private static class TransformerSupportDelegate extends TransformerObjectSupport {
void transformSourceToResult(Source source, Result result) throws TransformerException {
this.transform(source, result);
}
}
public String getComponentType() {
return "ws:outbound-gateway";
}
}

View File

@@ -11,7 +11,7 @@ Import-Template:
org.springframework.util;version="[3.0.3, 4.0.0)",
org.springframework.oxm;version="[1.5.8.A, 3.1.0)",
org.springframework.ws.*;version="[1.5.8.A, 2.0.0)",
org.springframework.xml.transform;version="[1.5.8.A, 2.0.0)",
org.springframework.xml.*;version="[1.5.8.A, 2.0.0)",
org.apache.commons.logging;version="[1.1.1, 2.0.0)",
org.w3c.dom.*;version="0",
javax.xml.*;version="0"