Skip to content

Commit 0e85927

Browse files
committed
Making the StAX-based XML readers and handlers more compliant
1 parent 16d0a8f commit 0e85927

File tree

13 files changed

+538
-49
lines changed

13 files changed

+538
-49
lines changed
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*
2+
* Copyright 2006 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ws.soap.axiom;
18+
19+
import java.util.ArrayList;
20+
import java.util.HashMap;
21+
import java.util.Iterator;
22+
import java.util.List;
23+
import java.util.Map;
24+
import javax.xml.namespace.QName;
25+
import javax.xml.stream.XMLStreamConstants;
26+
27+
import org.apache.axiom.om.OMAttribute;
28+
import org.apache.axiom.om.OMContainer;
29+
import org.apache.axiom.om.OMElement;
30+
import org.apache.axiom.om.OMFactory;
31+
import org.apache.axiom.om.OMNamespace;
32+
import org.xml.sax.Attributes;
33+
import org.xml.sax.ContentHandler;
34+
import org.xml.sax.Locator;
35+
import org.xml.sax.SAXException;
36+
import org.xml.sax.ext.LexicalHandler;
37+
38+
import org.springframework.util.Assert;
39+
import org.springframework.xml.namespace.QNameUtils;
40+
41+
/**
42+
* Specific SAX {@link ContentHandler} and {@link LexicalHandler} that adds the resulting AXIOM OMElement to a specified
43+
* parent element when <code>endDocument</code> is called. Used for returing <code>SAXResult</code>s from Axiom
44+
* elements.
45+
*
46+
* @author Arjen Poutsma
47+
* @since 1.0.0
48+
*/
49+
class AxiomHandler implements ContentHandler, LexicalHandler {
50+
51+
private final OMFactory factory;
52+
53+
private final List elements = new ArrayList();
54+
55+
private Map namespaces = new HashMap();
56+
57+
private final OMContainer container;
58+
59+
private int charactersType = XMLStreamConstants.CHARACTERS;
60+
61+
AxiomHandler(OMContainer container, OMFactory factory) {
62+
Assert.notNull(container, "'container' must not be null");
63+
Assert.notNull(factory, "'factory' must not be null");
64+
this.factory = factory;
65+
this.container = container;
66+
}
67+
68+
private OMContainer getParent() {
69+
if (!elements.isEmpty()) {
70+
return (OMContainer) elements.get(elements.size() - 1);
71+
}
72+
else {
73+
return container;
74+
}
75+
}
76+
77+
public void startPrefixMapping(String prefix, String uri) throws SAXException {
78+
namespaces.put(prefix, uri);
79+
}
80+
81+
public void endPrefixMapping(String prefix) throws SAXException {
82+
namespaces.remove(prefix);
83+
}
84+
85+
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
86+
OMContainer parent = getParent();
87+
OMElement element = factory.createOMElement(localName, null, parent);
88+
for (Iterator iterator = namespaces.entrySet().iterator(); iterator.hasNext();) {
89+
Map.Entry entry = (Map.Entry) iterator.next();
90+
String prefix = (String) entry.getKey();
91+
if (prefix.length() == 0) {
92+
element.declareDefaultNamespace((String) entry.getValue());
93+
}
94+
else {
95+
element.declareNamespace((String) entry.getValue(), prefix);
96+
}
97+
}
98+
QName qname = QNameUtils.toQName(uri, qName);
99+
element.setLocalName(qname.getLocalPart());
100+
element.setNamespace(element.findNamespace(qname.getNamespaceURI(), qname.getPrefix()));
101+
for (int i = 0; i < atts.getLength(); i++) {
102+
QName attrName = QNameUtils.toQName(atts.getURI(i), atts.getQName(i));
103+
String value = atts.getValue(i);
104+
if (!atts.getQName(i).startsWith("xmlns")) {
105+
OMNamespace namespace = factory.createOMNamespace(attrName.getNamespaceURI(), attrName.getPrefix());
106+
OMAttribute attribute = factory.createOMAttribute(attrName.getLocalPart(), namespace, value);
107+
element.addAttribute(attribute);
108+
}
109+
}
110+
111+
elements.add(element);
112+
}
113+
114+
public void endElement(String uri, String localName, String qName) throws SAXException {
115+
elements.remove(elements.size() - 1);
116+
}
117+
118+
public void characters(char ch[], int start, int length) throws SAXException {
119+
String data = new String(ch, start, length);
120+
OMContainer parent = getParent();
121+
factory.createOMText(parent, data, charactersType);
122+
}
123+
124+
public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
125+
charactersType = XMLStreamConstants.SPACE;
126+
characters(ch, start, length);
127+
charactersType = XMLStreamConstants.CHARACTERS;
128+
}
129+
130+
public void processingInstruction(String target, String data) throws SAXException {
131+
OMContainer parent = getParent();
132+
factory.createOMProcessingInstruction(parent, target, data);
133+
}
134+
135+
public void comment(char ch[], int start, int length) throws SAXException {
136+
String content = new String(ch, start, length);
137+
OMContainer parent = getParent();
138+
factory.createOMComment(parent, content);
139+
}
140+
141+
public void startCDATA() throws SAXException {
142+
charactersType = XMLStreamConstants.CDATA;
143+
}
144+
145+
public void endCDATA() throws SAXException {
146+
charactersType = XMLStreamConstants.CHARACTERS;
147+
}
148+
149+
public void startEntity(String name) throws SAXException {
150+
charactersType = XMLStreamConstants.ENTITY_REFERENCE;
151+
}
152+
153+
public void endEntity(String name) throws SAXException {
154+
charactersType = XMLStreamConstants.CHARACTERS;
155+
}
156+
157+
/*
158+
* Unsupported
159+
*/
160+
161+
public void setDocumentLocator(Locator locator) {
162+
}
163+
164+
public void startDocument() throws SAXException {
165+
}
166+
167+
public void endDocument() throws SAXException {
168+
}
169+
170+
public void skippedEntity(String name) throws SAXException {
171+
}
172+
173+
public void startDTD(String name, String publicId, String systemId) throws SAXException {
174+
}
175+
176+
public void endDTD() throws SAXException {
177+
}
178+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2008 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ws.soap.axiom;
18+
19+
import javax.xml.transform.sax.SAXResult;
20+
21+
import org.apache.axiom.om.OMContainer;
22+
import org.apache.axiom.om.OMFactory;
23+
import org.xml.sax.ContentHandler;
24+
import org.xml.sax.ext.LexicalHandler;
25+
26+
/**
27+
* Specific TrAX {@link javax.xml.transform.Result} that adds the resulting AXIOM OMElement to a specified parent
28+
* element when <code>endDocument</code> is called.
29+
*
30+
* @author Arjen Poutsma
31+
* @see AxiomHandler
32+
* @since 1.5.0
33+
*/
34+
class AxiomResult extends SAXResult {
35+
36+
AxiomResult(OMContainer container, OMFactory factory) {
37+
AxiomHandler handler = new AxiomHandler(container, factory);
38+
super.setHandler(handler);
39+
super.setLexicalHandler(handler);
40+
}
41+
42+
/**
43+
* Throws a <code>UnsupportedOperationException</code>.
44+
*
45+
* @throws UnsupportedOperationException always
46+
*/
47+
public void setHandler(ContentHandler handler) {
48+
throw new UnsupportedOperationException("setHandler is not supported");
49+
}
50+
51+
/**
52+
* Throws a <code>UnsupportedOperationException</code>.
53+
*
54+
* @throws UnsupportedOperationException always
55+
*/
56+
public void setLexicalHandler(LexicalHandler handler) {
57+
throw new UnsupportedOperationException("setLexicalHandler is not supported");
58+
}
59+
}

core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapBody.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import javax.xml.stream.XMLStreamReader;
2121
import javax.xml.transform.Result;
2222
import javax.xml.transform.Source;
23-
import javax.xml.transform.sax.SAXResult;
2423

2524
import org.apache.axiom.om.OMElement;
2625
import org.apache.axiom.om.OMException;
@@ -70,7 +69,7 @@ else if (payloadCaching) {
7069

7170
public Result getPayloadResult() {
7271
AxiomUtils.removeContents(getAxiomBody());
73-
return new SAXResult(new AxiomContentHandler(getAxiomBody(), getAxiomFactory()));
72+
return new AxiomResult(getAxiomBody(), getAxiomFactory());
7473
}
7574

7675
public boolean hasFault() {

core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFaultDetail.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.util.Iterator;
2020
import javax.xml.namespace.QName;
2121
import javax.xml.transform.Result;
22-
import javax.xml.transform.sax.SAXResult;
2322

2423
import org.apache.axiom.om.OMElement;
2524
import org.apache.axiom.om.OMException;
@@ -57,7 +56,7 @@ public Iterator getDetailEntries() {
5756
}
5857

5958
public Result getResult() {
60-
return new SAXResult(new AxiomContentHandler(getAxiomFaultDetail(), getAxiomFactory()));
59+
return new AxiomResult(getAxiomFaultDetail(), getAxiomFactory());
6160
}
6261

6362
protected SOAPFaultDetail getAxiomFaultDetail() {

core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFaultDetailElement.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.springframework.ws.soap.axiom;
1818

1919
import javax.xml.transform.Result;
20-
import javax.xml.transform.sax.SAXResult;
2120

2221
import org.apache.axiom.om.OMElement;
2322
import org.apache.axiom.om.OMException;
@@ -39,7 +38,7 @@ public AxiomSoapFaultDetailElement(OMElement axiomElement, SOAPFactory soapFacto
3938

4039
public Result getResult() {
4140
try {
42-
return new SAXResult(new AxiomContentHandler(getAxiomElement(), getAxiomFactory()));
41+
return new AxiomResult(getAxiomElement(), getAxiomFactory());
4342
}
4443
catch (OMException ex) {
4544
throw new AxiomSoapFaultException(ex);

core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapHeader.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.util.Iterator;
2020
import javax.xml.namespace.QName;
2121
import javax.xml.transform.Result;
22-
import javax.xml.transform.sax.SAXResult;
2322

2423
import org.apache.axiom.om.OMElement;
2524
import org.apache.axiom.om.OMException;
@@ -46,7 +45,7 @@ abstract class AxiomSoapHeader extends AxiomSoapElement implements SoapHeader {
4645
}
4746

4847
public Result getResult() {
49-
return new SAXResult(new AxiomContentHandler(getAxiomHeader(), getAxiomFactory()));
48+
return new AxiomResult(getAxiomHeader(), getAxiomFactory());
5049
}
5150

5251
public SoapHeaderElement addHeaderElement(QName name) {

core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapHeaderElement.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.springframework.ws.soap.axiom;
1818

1919
import javax.xml.transform.Result;
20-
import javax.xml.transform.sax.SAXResult;
2120

2221
import org.apache.axiom.om.OMException;
2322
import org.apache.axiom.soap.SOAPFactory;
@@ -50,7 +49,7 @@ public void setMustUnderstand(boolean mustUnderstand) {
5049

5150
public Result getResult() {
5251
try {
53-
return new SAXResult(new AxiomContentHandler(getAxiomHeaderBlock(), getAxiomFactory()));
52+
return new AxiomResult(getAxiomHeaderBlock(), getAxiomFactory());
5453
}
5554
catch (OMException ex) {
5655
throw new AxiomSoapHeaderException(ex);

core/src/test/java/org/springframework/ws/server/endpoint/StaxStreamPayloadEndpointTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.ws.server.endpoint;
1818

19+
import javax.xml.soap.MessageFactory;
1920
import javax.xml.stream.XMLOutputFactory;
2021
import javax.xml.stream.XMLStreamConstants;
2122
import javax.xml.stream.XMLStreamReader;
@@ -30,6 +31,8 @@
3031
import org.springframework.ws.context.MessageContext;
3132
import org.springframework.ws.soap.axiom.AxiomSoapMessage;
3233
import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
34+
import org.springframework.ws.soap.saaj.SaajSoapMessage;
35+
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
3336
import org.springframework.xml.transform.StringResult;
3437
import org.springframework.xml.transform.StringSource;
3538

@@ -82,6 +85,23 @@ protected XMLOutputFactory createXmlOutputFactory() {
8285
};
8386
}
8487

88+
public void testSaajResponse() throws Exception {
89+
Transformer transformer = TransformerFactory.newInstance().newTransformer();
90+
MessageFactory messageFactory = MessageFactory.newInstance();
91+
SaajSoapMessage request = new SaajSoapMessage(messageFactory.createMessage());
92+
transformer.transform(new StringSource(REQUEST), request.getPayloadResult());
93+
SaajSoapMessageFactory soapMessageFactory = new SaajSoapMessageFactory();
94+
soapMessageFactory.afterPropertiesSet();
95+
MessageContext context = new DefaultMessageContext(request, soapMessageFactory);
96+
97+
MessageEndpoint endpoint = createResponseEndpoint();
98+
endpoint.invoke(context);
99+
assertTrue("context has not response", context.hasResponse());
100+
StringResult stringResult = new StringResult();
101+
transformer.transform(context.getResponse().getPayloadSource(), stringResult);
102+
assertXMLEqual(RESPONSE, stringResult.toString());
103+
}
104+
85105
public void testAxiomResponse() throws Exception {
86106
Transformer transformer = TransformerFactory.newInstance().newTransformer();
87107
SOAPFactory axiomFactory = OMAbstractFactory.getSOAP11Factory();

0 commit comments

Comments
 (0)