1 /*
2  * Copyright 2005-2010 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.server.endpoint.adapter.method;
18
19 import java.io.ByteArrayInputStream;
20 import javax.xml.stream.Location;
21 import javax.xml.stream.XMLInputFactory;
22 import javax.xml.stream.XMLStreamException;
23 import javax.xml.stream.XMLStreamReader;
24 import javax.xml.stream.util.StreamReaderDelegate;
25 import javax.xml.transform.Source;
26 import javax.xml.transform.dom.DOMResult;
27 import javax.xml.transform.dom.DOMSource;
28 import javax.xml.transform.sax.SAXSource;
29 import javax.xml.transform.stax.StAXSource;
30 import javax.xml.transform.stream.StreamSource;
31
32 import org.w3c.dom.Document;
33 import org.w3c.dom.Node;
34 import org.xml.sax.InputSource;
35
36 import org.springframework.core.MethodParameter;
37 import org.springframework.xml.JaxpVersion;
38 import org.springframework.xml.XMLInputFactoryUtils;
39
40 /**
41  * Implementation of {@link MethodArgumentResolver} and {@link MethodReturnValueHandler} that supports {@link Source}
42  * objects.
43  *
44  * @author Arjen Poutsma
45  * @since 2.0
46  */

47 public class SourcePayloadMethodProcessor extends AbstractPayloadSourceMethodProcessor {
48
49     private XMLInputFactory inputFactory = createXmlInputFactory();
50
51     // MethodArgumentResolver
52
53     @Override
54     protected boolean supportsRequestPayloadParameter(MethodParameter parameter) {
55         return supports(parameter);
56     }
57
58     @Override
59     protected Source resolveRequestPayloadArgument(MethodParameter parameter, Source requestPayload) throws Exception {
60         Class<?> parameterType = parameter.getParameterType();
61         if (parameterType.isAssignableFrom(requestPayload.getClass())) {
62             return requestPayload;
63         }
64         if (DOMSource.class.isAssignableFrom(parameterType)) {
65             DOMResult domResult = new DOMResult();
66             transform(requestPayload, domResult);
67             Node node = domResult.getNode();
68             if (node.getNodeType() == Node.DOCUMENT_NODE) {
69                 return new DOMSource(((Document) node).getDocumentElement());
70             }
71             else {
72                 return new DOMSource(domResult.getNode());
73             }
74         }
75         else if (SAXSource.class.isAssignableFrom(parameterType)) {
76             ByteArrayInputStream bis = convertToByteArrayInputStream(requestPayload);
77             InputSource inputSource = new InputSource(bis);
78             return new SAXSource(inputSource);
79         }
80         else if (StreamSource.class.isAssignableFrom(parameterType)) {
81             ByteArrayInputStream bis = convertToByteArrayInputStream(requestPayload);
82             return new StreamSource(bis);
83         }
84         else if (JaxpVersion.isAtLeastJaxp14() && Jaxp14StaxHandler.isStaxSource(parameterType)) {
85             XMLStreamReader streamReader;
86             try {
87                 streamReader = inputFactory.createXMLStreamReader(requestPayload);
88             } catch (UnsupportedOperationException ignored) {
89                 streamReader = null;
90             }
91             catch (XMLStreamException ignored) {
92                 streamReader = null;
93             }
94             if (streamReader == null) {
95                 ByteArrayInputStream bis = convertToByteArrayInputStream(requestPayload);
96                 streamReader = inputFactory.createXMLStreamReader(bis);
97             }
98             return Jaxp14StaxHandler.createStaxSource(streamReader, requestPayload.getSystemId());
99         }
100         throw new IllegalArgumentException("Unknown Source type: " + parameterType);
101     }
102
103     // MethodReturnValueHandler
104
105     @Override
106     protected boolean supportsResponsePayloadReturnType(MethodParameter returnType) {
107         return supports(returnType);
108     }
109
110     @Override
111     protected Source createResponsePayload(MethodParameter returnType, Object returnValue) {
112         return (Source) returnValue;
113     }
114
115     private boolean supports(MethodParameter parameter) {
116         return Source.class.isAssignableFrom(parameter.getParameterType());
117     }
118
119     /**
120      * Create a {@code XMLInputFactory} that this resolver will use to create {@link javax.xml.stream.XMLStreamReader}
121      * and {@link javax.xml.stream.XMLEventReader} objects.
122      *
123      * <p>Can be overridden in subclasses, adding further initialization of the factory. The resulting factory is cached,
124      * so this method will only be called once.
125      *
126      * @return the created factory
127      */

128     protected XMLInputFactory createXmlInputFactory() {
129         return XMLInputFactoryUtils.newInstance();
130     }
131
132     /** Inner class to avoid a static JAXP 1.4 dependency. */
133     private static class Jaxp14StaxHandler {
134
135         private static boolean isStaxSource(Class<?> clazz) {
136             return StAXSource.class.isAssignableFrom(clazz);
137         }
138
139         private static Source createStaxSource(XMLStreamReader streamReader, String systemId) {
140             return new StAXSource(new SystemIdStreamReaderDelegate(streamReader, systemId));
141         }
142
143     }
144
145     private static class SystemIdStreamReaderDelegate extends StreamReaderDelegate {
146
147         private final String systemId;
148
149         private SystemIdStreamReaderDelegate(XMLStreamReader reader, String systemId) {
150             super(reader);
151             this.systemId = systemId;
152         }
153
154         @Override
155         public Location getLocation() {
156             final Location parentLocation = getParent().getLocation();
157             return new Location() {
158                 public int getLineNumber() {
159                     return parentLocation != null ? parentLocation.getLineNumber() : -1;
160                 }
161
162                 public int getColumnNumber() {
163                     return parentLocation != null ? parentLocation.getColumnNumber() : -1;
164                 }
165
166                 public int getCharacterOffset() {
167                     return parentLocation != null ? parentLocation.getLineNumber() : -1;
168                 }
169
170                 public String getPublicId() {
171                     return parentLocation != null ? parentLocation.getPublicId() : null;
172                 }
173
174                 public String getSystemId() {
175                     return systemId;
176                 }
177             };
178         }
179     }
180
181 }
182