Upgraded to Spring 4.0.3 and XMLUnit 1.5

Upgraded to XMLUnit 1.5, which broke some tests in SWS as well as SPR.
Spring 4.0.3 fixed those, so upgraded to that as well.
This commit is contained in:
Arjen Poutsma
2014-03-14 15:55:36 +01:00
parent 65245a1cbb
commit 3522effaea
5 changed files with 217 additions and 290 deletions

View File

@@ -11,7 +11,7 @@ buildscript {
configure(allprojects) {
group = "org.springframework.ws"
ext.springVersion = "3.2.4.RELEASE"
ext.springVersion = "4.0.3.RELEASE"
ext.axiomVersion = "1.2.14"
apply plugin: "java"
@@ -55,6 +55,7 @@ configure(allprojects) {
}
repositories {
mavenLocal()
maven { url 'http://repo.spring.io/libs-release' }
}
@@ -64,8 +65,8 @@ configure(allprojects) {
testCompile("junit:junit:4.10")
testCompile("org.easymock:easymock:3.1")
testCompile("xmlunit:xmlunit:1.1")
testRuntime("org.codehaus.woodstox:woodstox-core-asl:4.1.3")
testCompile("xmlunit:xmlunit:1.5")
testRuntime("org.codehaus.woodstox:woodstox-core-asl:4.2.0")
}
ext.javadocLinks = [
@@ -175,7 +176,7 @@ project('spring-ws-core') {
optional("wsdl4j:wsdl4j:1.6.1")
// Transport
provided("javax.servlet:servlet-api:2.5")
provided("javax.servlet:javax.servlet-api:3.1.0")
optional("org.apache.httpcomponents:httpclient:4.2.5")
optional("commons-httpclient:commons-httpclient:3.1")
testCompile("org.mortbay.jetty:jetty:6.1.26")
@@ -251,7 +252,7 @@ project('spring-ws-test') {
compile("org.springframework:spring-context:$springVersion")
compile("xmlunit:xmlunit:1.1")
compile("xmlunit:xmlunit:1.5")
testCompile("org.springframework:spring-test:$springVersion")
}

View File

@@ -20,12 +20,10 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamConstants;
import org.springframework.util.Assert;
import org.springframework.xml.namespace.QNameUtils;
import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMContainer;
import org.apache.axiom.om.OMElement;
@@ -37,145 +35,190 @@ import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
import org.springframework.util.Assert;
import org.springframework.xml.namespace.QNameUtils;
/**
* Specific SAX {@link ContentHandler} and {@link LexicalHandler} that adds the resulting AXIOM OMElement to a specified
* parent element when <code>endDocument</code> is called. Used for returing <code>SAXResult</code>s from Axiom
* elements.
*
* Specific SAX {@link ContentHandler} and {@link LexicalHandler} that adds the resulting
* AXIOM OMElement to a specified parent element when <code>endDocument</code> is called.
* Used for returing <code>SAXResult</code>s from Axiom elements.
* @author Arjen Poutsma
* @since 1.0.0
*/
class AxiomHandler implements ContentHandler, LexicalHandler {
private final OMFactory factory;
private final OMFactory factory;
private final List<OMContainer> elements = new ArrayList<OMContainer>();
private final List<OMContainer> elements = new ArrayList<OMContainer>();
private Map<String, String> namespaces = new HashMap<String, String>();
private final OMContainer container;
private final OMContainer container;
private int charactersType = XMLStreamConstants.CHARACTERS;
private int charactersType = XMLStreamConstants.CHARACTERS;
private List<Map<String, String>> namespaceMappings =
new ArrayList<Map<String, String>>();
AxiomHandler(OMContainer container, OMFactory factory) {
Assert.notNull(container, "'container' must not be null");
Assert.notNull(factory, "'factory' must not be null");
this.factory = factory;
this.container = container;
}
AxiomHandler(OMContainer container, OMFactory factory) {
Assert.notNull(container, "'container' must not be null");
Assert.notNull(factory, "'factory' must not be null");
this.factory = factory;
this.container = container;
}
private OMContainer getParent() {
if (!elements.isEmpty()) {
return elements.get(elements.size() - 1);
}
else {
return container;
}
}
private OMContainer getParent() {
if (!elements.isEmpty()) {
return elements.get(elements.size() - 1);
}
else {
return container;
}
}
public void startPrefixMapping(String prefix, String uri) throws SAXException {
namespaces.put(prefix, uri);
}
public void startDocument() throws SAXException {
removeAllNamespaceMappings();
newNamespaceMapping();
}
public void endPrefixMapping(String prefix) throws SAXException {
namespaces.remove(prefix);
}
public void endDocument() throws SAXException {
removeAllNamespaceMappings();
}
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
OMContainer parent = getParent();
OMNamespace ns = factory.createOMNamespace(uri, QNameUtils.toQName(uri, qName).getPrefix());
OMElement element = factory.createOMElement(localName, ns, parent);
for (Map.Entry<String, String> entry : namespaces.entrySet()) {
String prefix = entry.getKey();
if (prefix.length() == 0) {
element.declareDefaultNamespace((String) entry.getValue());
}
else {
element.declareNamespace((String) entry.getValue(), prefix);
}
}
for (int i = 0; i < atts.getLength(); i++) {
QName attrName = QNameUtils.toQName(atts.getURI(i), atts.getQName(i));
String value = atts.getValue(i);
if (!atts.getQName(i).startsWith("xmlns")) {
OMNamespace namespace = factory.createOMNamespace(attrName.getNamespaceURI(), attrName.getPrefix());
OMAttribute attribute = factory.createOMAttribute(attrName.getLocalPart(), namespace, value);
element.addAttribute(attribute);
}
}
public void startPrefixMapping(String prefix, String uri) throws SAXException {
currentNamespaceMapping().put(prefix, uri);
}
elements.add(element);
}
public void endPrefixMapping(String prefix) throws SAXException {
}
public void endElement(String uri, String localName, String qName) throws SAXException {
elements.remove(elements.size() - 1);
}
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
OMContainer parent = getParent();
OMNamespace ns = factory.createOMNamespace(uri,
QNameUtils.toQName(uri, qName).getPrefix());
OMElement element = factory.createOMElement(localName, ns, parent);
public void characters(char ch[], int start, int length) throws SAXException {
String data = new String(ch, start, length);
OMContainer parent = getParent();
factory.createOMText(parent, data, charactersType);
}
// declare namespaces
Map<String, String> namespaceMappings = currentNamespaceMapping();
for (Map.Entry<String, String> entry : namespaceMappings.entrySet()) {
String prefix = entry.getKey();
String namespaceUri = entry.getValue();
public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
charactersType = XMLStreamConstants.SPACE;
characters(ch, start, length);
charactersType = XMLStreamConstants.CHARACTERS;
}
if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
element.declareDefaultNamespace(namespaceUri);
} else {
element.declareNamespace(namespaceUri, prefix);
}
}
// declare attributes
for (int i = 0; i < attributes.getLength(); i++) {
QName attrName =
QNameUtils.toQName(attributes.getURI(i), attributes.getQName(i));
if (!isNamespaceDeclaration(attrName)) {
OMNamespace namespace =
factory.createOMNamespace(attrName.getNamespaceURI(),
attrName.getPrefix());
OMAttribute attribute =
factory.createOMAttribute(attrName.getLocalPart(), namespace,
attributes.getValue(i));
element.addAttribute(attribute);
}
}
elements.add(element);
newNamespaceMapping();
}
public void processingInstruction(String target, String data) throws SAXException {
OMContainer parent = getParent();
factory.createOMProcessingInstruction(parent, target, data);
}
private boolean isNamespaceDeclaration(QName qName) {
String prefix = qName.getPrefix();
String localPart = qName.getLocalPart();
return (XMLConstants.XMLNS_ATTRIBUTE.equals(localPart) && prefix.length() == 0) ||
(XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) && localPart.length() != 0);
}
public void comment(char ch[], int start, int length) throws SAXException {
String content = new String(ch, start, length);
OMContainer parent = getParent();
factory.createOMComment(parent, content);
}
public void endElement(String uri, String localName, String qName)
throws SAXException {
elements.remove(elements.size() - 1);
removeNamespaceMapping();
}
public void startCDATA() throws SAXException {
charactersType = XMLStreamConstants.CDATA;
}
public void characters(char ch[], int start, int length) throws SAXException {
String data = new String(ch, start, length);
OMContainer parent = getParent();
factory.createOMText(parent, data, charactersType);
}
public void endCDATA() throws SAXException {
charactersType = XMLStreamConstants.CHARACTERS;
}
public void ignorableWhitespace(char ch[], int start, int length)
throws SAXException {
charactersType = XMLStreamConstants.SPACE;
characters(ch, start, length);
charactersType = XMLStreamConstants.CHARACTERS;
}
public void startEntity(String name) throws SAXException {
if (!isPredefinedEntityReference(name)) {
charactersType = XMLStreamConstants.ENTITY_REFERENCE;
}
}
public void processingInstruction(String target, String data) throws SAXException {
OMContainer parent = getParent();
factory.createOMProcessingInstruction(parent, target, data);
}
public void endEntity(String name) throws SAXException {
charactersType = XMLStreamConstants.CHARACTERS;
}
public void comment(char ch[], int start, int length) throws SAXException {
String content = new String(ch, start, length);
OMContainer parent = getParent();
factory.createOMComment(parent, content);
}
private boolean isPredefinedEntityReference(String name) {
return "lt".equals(name) || "gt".equals(name) || "amp".equals(name) || "quot".equals(name) ||
"apos".equals(name);
}
public void startCDATA() throws SAXException {
charactersType = XMLStreamConstants.CDATA;
}
public void endCDATA() throws SAXException {
charactersType = XMLStreamConstants.CHARACTERS;
}
public void startEntity(String name) throws SAXException {
if (!isPredefinedEntityReference(name)) {
charactersType = XMLStreamConstants.ENTITY_REFERENCE;
}
}
public void endEntity(String name) throws SAXException {
charactersType = XMLStreamConstants.CHARACTERS;
}
private boolean isPredefinedEntityReference(String name) {
return "lt".equals(name) || "gt".equals(name) || "amp".equals(name) ||
"quot".equals(name) ||
"apos".equals(name);
}
/*
* Unsupported
*/
public void setDocumentLocator(Locator locator) {
}
public void setDocumentLocator(Locator locator) {
}
public void startDocument() throws SAXException {
}
public void skippedEntity(String name) throws SAXException {
}
public void endDocument() throws SAXException {
}
public void startDTD(String name, String publicId, String systemId)
throws SAXException {
}
public void skippedEntity(String name) throws SAXException {
}
public void endDTD() throws SAXException {
}
public void startDTD(String name, String publicId, String systemId) throws SAXException {
}
private Map<String, String> currentNamespaceMapping() {
return namespaceMappings.get(namespaceMappings.size() - 1);
}
private void newNamespaceMapping() {
namespaceMappings.add(new HashMap<String, String>());
}
private void removeNamespaceMapping() {
namespaceMappings.remove(namespaceMappings.size() - 1);
}
private void removeAllNamespaceMappings() {
namespaceMappings.clear();
}
public void endDTD() throws SAXException {
}
}

View File

@@ -16,24 +16,33 @@
package org.springframework.ws.soap.axiom;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import java.util.Iterator;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMDocument;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.junit.Before;
import org.junit.Test;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
public class AxiomHandlerTest {
@@ -158,4 +167,48 @@ public class AxiomHandlerTest {
result.serialize(bos);
assertXMLEqual("Invalid result", XML_3_ENTITY, bos.toString("UTF-8"));
}
@Test
public void testTransformDom() throws Exception {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
String XML = "<root xmlns=\"http://www.springframework.org/spring-ws\" xmlns:attr=\"http://www.springframework.org/spring-ws/attr\" attr:attribute=\"value\">" +
"<prefix:child xmlns:prefix=\"http://www.springframework.org/spring-ws/child\"/>" +
"</root>";
Document document =
documentBuilder.parse(new ByteArrayInputStream(XML.getBytes("UTF-8")));
DOMSource domSource = new DOMSource(document);
handler = new AxiomHandler(result, factory);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
SAXResult saxResult = new SAXResult(handler);
transformer.transform(domSource, saxResult);
OMElement root = result.getOMDocumentElement();
assertEquals(2, getNamespaceCount(root));
NamespaceContext namespaceContext = root.getNamespaceContext(false);
assertEquals("http://www.springframework.org/spring-ws", namespaceContext.getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX));
assertEquals("http://www.springframework.org/spring-ws/attr",
namespaceContext.getNamespaceURI("attr"));
OMElement child = root.getFirstElement();
assertEquals(1, getNamespaceCount(child));
namespaceContext = child.getNamespaceContext(false);
assertEquals("http://www.springframework.org/spring-ws", namespaceContext.getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX));
assertEquals("http://www.springframework.org/spring-ws/child", namespaceContext.getNamespaceURI("prefix"));
}
private int getNamespaceCount(OMElement element) {
int i = 0;
Iterator namespaces = element.getAllDeclaredNamespaces();
while (namespaces.hasNext()) {
namespaces.next();
i++;
}
return i;
}
}

View File

@@ -31,7 +31,7 @@ import org.springframework.ws.transport.support.SimpleWebServiceMessageReceiverO
* <code>textMessageEncoding</code> property, which determines the encoding used to read from and write to
* <code>TextMessages</code>. This property defaults to <code>UTF-8</code>.
* <p/>
* Used by {@link WebServiceMessageListener} and {@link WebServiceMessageDrivenBean}.
* Used by {@link WebServiceMessageListener}.
*
* @author Arjen Poutsma
* @since 1.5.0

View File

@@ -1,170 +0,0 @@
/*
* Copyright 2005-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.ws.transport.jms;
import javax.ejb.EJBException;
import javax.ejb.MessageDrivenBean;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.naming.NamingException;
import org.springframework.ejb.support.AbstractJmsMessageDrivenBean;
import org.springframework.jms.connection.ConnectionFactoryUtils;
import org.springframework.jms.core.MessagePostProcessor;
import org.springframework.jms.support.JmsUtils;
import org.springframework.jndi.JndiLookupFailureException;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.transport.WebServiceMessageReceiver;
/**
* EJB {@link MessageDrivenBean} that can be used to handleMessage incoming JMS messages.
* <p/>
* This class needs a JMS {@link ConnectionFactory}, a {@link WebServiceMessageFactory} and {@link
* WebServiceMessageReceiver} to operate. By default, these are obtained by doing a bean lookup on the bean factory
* provided by {@link #getBeanFactory()} the super class.
*
* @author Arjen Poutsma
* @see #createConnectionFactory()
* @see #createMessageFactory()
* @see #createMessageReceiver()
*/
public class WebServiceMessageDrivenBean extends AbstractJmsMessageDrivenBean {
/** Well-known name for the {@link ConnectionFactory} object in the bean factory for this bean. */
public static final String CONNECTION_FACTORY_BEAN_NAME = "connectionFactory";
/** Well-known name for the {@link WebServiceMessageFactory} bean in the bean factory for this bean. */
public static final String MESSAGE_FACTORY_BEAN_NAME = "messageFactory";
/** Well-known name for the {@link WebServiceMessageReceiver} object in the bean factory for this bean. */
public static final String MESSAGE_RECEIVER_BEAN_NAME = "messageReceiver";
private JmsMessageReceiver delegate;
private ConnectionFactory connectionFactory;
/** Delegates to {@link JmsMessageReceiver#handleMessage(Message,Session)}. */
public void onMessage(Message message) {
Connection connection = null;
Session session = null;
try {
connection = createConnection(connectionFactory);
session = createSession(connection);
delegate.handleMessage(message, session);
}
catch (JmsTransportException ex) {
throw JmsUtils.convertJmsAccessException(ex.getJmsException());
}
catch (JMSException ex) {
throw JmsUtils.convertJmsAccessException(ex);
}
catch (Exception ex) {
throw new EJBException(ex);
}
finally {
JmsUtils.closeSession(session);
ConnectionFactoryUtils.releaseConnection(connection, connectionFactory, true);
}
}
/**
* Creates a new {@link Connection}, {@link WebServiceMessageFactory}, and {@link WebServiceMessageReceiver}.
*
* @see #createConnectionFactory()
* @see #createMessageFactory()
* @see #createMessageReceiver()
*/
@Override
protected void onEjbCreate() {
try {
connectionFactory = createConnectionFactory();
delegate = new JmsMessageReceiver();
delegate.setMessageFactory(createMessageFactory());
delegate.setMessageReceiver(createMessageReceiver());
delegate.setPostProcessor(createPostProcessor());
}
catch (NamingException ex) {
throw new JndiLookupFailureException("Could not create connection", ex);
}
catch (JMSException ex) {
throw JmsUtils.convertJmsAccessException(ex);
}
catch (Exception ex) {
throw new EJBException(ex);
}
}
/** Creates a connection factory. Default implementation does a bean lookup for {@link #CONNECTION_FACTORY_BEAN_NAME}. */
protected ConnectionFactory createConnectionFactory() throws Exception {
return (ConnectionFactory) getBeanFactory().getBean(CONNECTION_FACTORY_BEAN_NAME, ConnectionFactory.class);
}
/** Creates a message factory. Default implementation does a bean lookup for {@link #MESSAGE_FACTORY_BEAN_NAME}. */
protected WebServiceMessageFactory createMessageFactory() {
return (WebServiceMessageFactory) getBeanFactory()
.getBean(MESSAGE_FACTORY_BEAN_NAME, WebServiceMessageFactory.class);
}
/** Creates a connection factory. Default implementation does a bean lookup for {@link #MESSAGE_RECEIVER_BEAN_NAME}. */
protected WebServiceMessageReceiver createMessageReceiver() {
return (WebServiceMessageReceiver) getBeanFactory()
.getBean(MESSAGE_RECEIVER_BEAN_NAME, WebServiceMessageReceiver.class);
}
/**
* Create a JMS {@link Connection} using the given {@link ConnectionFactory}.
* <p/>
* This implementation uses JMS 1.1 API.
*
* @param connectionFactory the JMS ConnectionFactory to create a Connection with
* @return the new JMS Connection
* @throws JMSException if thrown by JMS API methods
* @see ConnectionFactory#createConnection()
*/
protected Connection createConnection(ConnectionFactory connectionFactory) throws JMSException {
return connectionFactory.createConnection();
}
/**
* Creates a JMS {@link Session}. Default implementation creates a non-transactional, {@link Session#AUTO_ACKNOWLEDGE
* auto acknowledged} session.
* <p/>
* This implementation uses JMS 1.1 API.
*
* @param connection the JMS Connection to create a Session for
* @return the new JMS Session
* @throws JMSException if thrown by JMS API methods
* @see Connection#createSession(boolean,int)
*/
protected Session createSession(Connection connection) throws JMSException {
return connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
}
/**
* Creates a JMS {@link MessagePostProcessor} to process JMS messages. Default
* implementation returns {@code null}, meaning that no post processor is used.
*
* @return a message post processor
*/
protected MessagePostProcessor createPostProcessor() {
return null;
}
}