1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.ws.server.endpoint;
18
19 import java.io.ByteArrayInputStream;
20 import java.io.ByteArrayOutputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.io.Reader;
25 import java.util.Locale;
26 import javax.xml.stream.XMLEventReader;
27 import javax.xml.stream.XMLStreamConstants;
28 import javax.xml.stream.XMLStreamException;
29 import javax.xml.stream.XMLStreamReader;
30 import javax.xml.transform.Source;
31 import javax.xml.transform.stream.StreamSource;
32
33 import nu.xom.Attribute;
34 import nu.xom.Builder;
35 import nu.xom.Document;
36 import nu.xom.Element;
37 import nu.xom.NodeFactory;
38 import nu.xom.ParentNode;
39 import nu.xom.ParsingException;
40 import nu.xom.Serializer;
41 import nu.xom.ValidityException;
42 import nu.xom.converters.DOMConverter;
43 import org.w3c.dom.Node;
44 import org.xml.sax.InputSource;
45 import org.xml.sax.SAXException;
46 import org.xml.sax.XMLReader;
47
48 import org.springframework.core.NestedRuntimeException;
49 import org.springframework.xml.namespace.QNameUtils;
50 import org.springframework.xml.transform.TransformerObjectSupport;
51 import org.springframework.xml.transform.TraxUtils;
52
53
54
55
56
57
58
59
60
61
62
63
64 public abstract class AbstractXomPayloadEndpoint extends TransformerObjectSupport implements PayloadEndpoint {
65
66 public final Source invoke(Source request) throws Exception {
67 Element requestElement = null;
68 if (request != null) {
69 XomSourceCallback sourceCallback = new XomSourceCallback();
70 try {
71 TraxUtils.doWithSource(request, sourceCallback);
72 }
73 catch (XomParsingException ex) {
74 throw (ParsingException) ex.getCause();
75 }
76 requestElement = sourceCallback.element;
77 }
78 Element responseElement = invokeInternal(requestElement);
79 return responseElement != null ? convertResponse(responseElement) : null;
80 }
81
82 private Source convertResponse(Element responseElement) throws IOException {
83 ByteArrayOutputStream os = new ByteArrayOutputStream();
84 Serializer serializer = createSerializer(os);
85 Document document = responseElement.getDocument();
86 if (document == null) {
87 document = new Document(responseElement);
88 }
89 serializer.write(document);
90 byte[] bytes = os.toByteArray();
91 return new StreamSource(new ByteArrayInputStream(bytes));
92 }
93
94
95
96
97
98
99
100
101
102
103 protected Serializer createSerializer(OutputStream outputStream) {
104 return new Serializer(outputStream);
105 }
106
107
108
109
110
111
112
113
114 protected abstract Element invokeInternal(Element requestElement) throws Exception;
115
116 private static class XomSourceCallback implements TraxUtils.SourceCallback {
117
118 private Element element;
119
120 public void domSource(Node node) {
121 if (node.getNodeType() == Node.ELEMENT_NODE) {
122 element = DOMConverter.convert((org.w3c.dom.Element) node);
123 }
124 else if (node.getNodeType() == Node.DOCUMENT_NODE) {
125 Document document = DOMConverter.convert((org.w3c.dom.Document) node);
126 element = document.getRootElement();
127 }
128 else {
129 throw new IllegalArgumentException("DOMSource contains neither Document nor Element");
130 }
131 }
132
133 public void saxSource(XMLReader reader, InputSource inputSource) throws IOException, SAXException {
134 try {
135 Builder builder = new Builder(reader);
136 Document document;
137 if (inputSource.getByteStream() != null) {
138 document = builder.build(inputSource.getByteStream());
139 }
140 else if (inputSource.getCharacterStream() != null) {
141 document = builder.build(inputSource.getCharacterStream());
142 }
143 else {
144 throw new IllegalArgumentException(
145 "InputSource in SAXSource contains neither byte stream nor character stream");
146 }
147 element = document.getRootElement();
148 }
149 catch (ValidityException ex) {
150 throw new XomParsingException(ex);
151 }
152 catch (ParsingException ex) {
153 throw new XomParsingException(ex);
154 }
155 }
156
157 public void staxSource(XMLEventReader eventReader) throws XMLStreamException {
158 throw new IllegalArgumentException("XMLEventReader not supported");
159 }
160
161 public void staxSource(XMLStreamReader streamReader) throws XMLStreamException {
162 Document document = StaxStreamConverter.convert(streamReader);
163 element = document.getRootElement();
164 }
165
166 public void streamSource(InputStream inputStream) throws IOException {
167 try {
168 Builder builder = new Builder();
169 Document document = builder.build(inputStream);
170 element = document.getRootElement();
171 }
172 catch (ParsingException ex) {
173 throw new XomParsingException(ex);
174 }
175 }
176
177 public void streamSource(Reader reader) throws IOException {
178 try {
179 Builder builder = new Builder();
180 Document document = builder.build(reader);
181 element = document.getRootElement();
182 }
183 catch (ParsingException ex) {
184 throw new XomParsingException(ex);
185 }
186 }
187 }
188
189 private static class XomParsingException extends NestedRuntimeException {
190
191 private XomParsingException(ParsingException ex) {
192 super(ex.getMessage(), ex);
193 }
194 }
195
196 private static class StaxStreamConverter {
197
198 private static Document convert(XMLStreamReader streamReader) throws XMLStreamException {
199 NodeFactory nodeFactory = new NodeFactory();
200 Document document = null;
201 Element element = null;
202 ParentNode parent = null;
203 boolean documentFinished = false;
204 while (streamReader.hasNext()) {
205 int event = streamReader.next();
206 switch (event) {
207 case XMLStreamConstants.START_DOCUMENT:
208 document = nodeFactory.startMakingDocument();
209 parent = document;
210 break;
211 case XMLStreamConstants.END_DOCUMENT:
212 nodeFactory.finishMakingDocument(document);
213 documentFinished = true;
214 break;
215 case XMLStreamConstants.START_ELEMENT:
216 if (document == null) {
217 document = nodeFactory.startMakingDocument();
218 parent = document;
219 }
220 String name = QNameUtils.toQualifiedName(streamReader.getName());
221 if (element == null) {
222 element = nodeFactory.makeRootElement(name, streamReader.getNamespaceURI());
223 document.setRootElement(element);
224 }
225 else {
226 element = nodeFactory.startMakingElement(name, streamReader.getNamespaceURI());
227 parent.appendChild(element);
228 }
229 convertNamespaces(streamReader, element);
230 convertAttributes(streamReader, nodeFactory);
231 parent = element;
232 break;
233 case XMLStreamConstants.END_ELEMENT:
234 nodeFactory.finishMakingElement(element);
235 parent = parent.getParent();
236 break;
237 case XMLStreamConstants.ATTRIBUTE:
238 convertAttributes(streamReader, nodeFactory);
239 break;
240 case XMLStreamConstants.CHARACTERS:
241 nodeFactory.makeText(streamReader.getText());
242 break;
243 case XMLStreamConstants.COMMENT:
244 nodeFactory.makeComment(streamReader.getText());
245 break;
246 default:
247 break;
248 }
249 }
250 if (!documentFinished) {
251 nodeFactory.finishMakingDocument(document);
252 }
253 return document;
254 }
255
256 private static void convertNamespaces(XMLStreamReader streamReader, Element element) {
257 for (int i = 0; i < streamReader.getNamespaceCount(); i++) {
258 String uri = streamReader.getNamespaceURI(i);
259 String prefix = streamReader.getNamespacePrefix(i);
260
261 element.addNamespaceDeclaration(prefix, uri);
262 }
263
264 }
265
266 private static void convertAttributes(XMLStreamReader streamReader, NodeFactory nodeFactory) {
267 for (int i = 0; i < streamReader.getAttributeCount(); i++) {
268 String name = QNameUtils.toQualifiedName(streamReader.getAttributeName(i));
269 String uri = streamReader.getAttributeNamespace(i);
270 String value = streamReader.getAttributeValue(i);
271 Attribute.Type type = convertAttributeType(streamReader.getAttributeType(i));
272
273 nodeFactory.makeAttribute(name, uri, value, type);
274 }
275 }
276
277 private static Attribute.Type convertAttributeType(String type) {
278 type = type.toUpperCase(Locale.ENGLISH);
279 if ("CDATA".equals(type)) {
280 return Attribute.Type.CDATA;
281 }
282 else if ("ENTITIES".equals(type)) {
283 return Attribute.Type.ENTITIES;
284 }
285 else if ("ENTITY".equals(type)) {
286 return Attribute.Type.ENTITY;
287 }
288 else if ("ENUMERATION".equals(type)) {
289 return Attribute.Type.ENUMERATION;
290 }
291 else if ("ID".equals(type)) {
292 return Attribute.Type.ID;
293 }
294 else if ("IDREF".equals(type)) {
295 return Attribute.Type.IDREF;
296 }
297 else if ("IDREFS".equals(type)) {
298 return Attribute.Type.IDREFS;
299 }
300 else if ("NMTOKEN".equals(type)) {
301 return Attribute.Type.NMTOKEN;
302 }
303 else if ("NMTOKENS".equals(type)) {
304 return Attribute.Type.NMTOKENS;
305 }
306 else if ("NOTATION".equals(type)) {
307 return Attribute.Type.NOTATION;
308 }
309 else {
310 return Attribute.Type.UNDECLARED;
311 }
312 }
313
314 }
315 }