1 /*
2  * Copyright 2005-2014 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 java.io.ByteArrayOutputStream;
21 import javax.xml.stream.XMLEventReader;
22 import javax.xml.stream.XMLInputFactory;
23 import javax.xml.stream.XMLStreamException;
24 import javax.xml.stream.XMLStreamReader;
25 import javax.xml.transform.Source;
26 import javax.xml.transform.TransformerException;
27 import javax.xml.transform.stream.StreamResult;
28
29 import org.springframework.core.MethodParameter;
30 import org.springframework.util.xml.StaxUtils;
31 import org.springframework.ws.context.MessageContext;
32 import org.springframework.ws.server.endpoint.annotation.RequestPayload;
33 import org.springframework.xml.XMLInputFactoryUtils;
34 import org.springframework.xml.transform.TransformerObjectSupport;
35
36 /**
37  * Implementation of {@link MethodArgumentResolver} that supports StAX {@link XMLStreamReader} and {@link
38  * XMLEventReader} arguments.
39  *
40  * @author Arjen Poutsma
41  * @since 2.0
42  */

43 public class StaxPayloadMethodArgumentResolver extends TransformerObjectSupport implements MethodArgumentResolver {
44
45     private final XMLInputFactory inputFactory = createXmlInputFactory();
46
47     @Override
48     public boolean supportsParameter(MethodParameter parameter) {
49         if (parameter.getParameterAnnotation(RequestPayload.class) == null) {
50             return false;
51         }
52         else {
53             Class<?> parameterType = parameter.getParameterType();
54             return XMLStreamReader.class.equals(parameterType) || XMLEventReader.class.equals(parameterType);
55         }
56     }
57
58     @Override
59     public Object resolveArgument(MessageContext messageContext, MethodParameter parameter)
60             throws TransformerException, XMLStreamException {
61         Source source = messageContext.getRequest().getPayloadSource();
62         if (source == null) {
63             return null;
64         }
65         Class<?> parameterType = parameter.getParameterType();
66         if (XMLStreamReader.class.equals(parameterType)) {
67             return resolveStreamReader(source);
68         }
69         else if (XMLEventReader.class.equals(parameterType)) {
70             return resolveEventReader(source);
71         }
72         throw new UnsupportedOperationException();
73     }
74
75     private XMLStreamReader resolveStreamReader(Source requestSource) throws TransformerException, XMLStreamException {
76         XMLStreamReader streamReader = null;
77         if (StaxUtils.isStaxSource(requestSource)) {
78             streamReader = StaxUtils.getXMLStreamReader(requestSource);
79             if (streamReader == null) {
80                 XMLEventReader eventReader = StaxUtils.getXMLEventReader(requestSource);
81                 if (eventReader != null) {
82                     try {
83                         streamReader = StaxUtils.createEventStreamReader(eventReader);
84                     }
85                     catch (XMLStreamException ex) {
86                         streamReader = null;
87                     }
88                 }
89             }
90         }
91         if (streamReader == null) {
92             try {
93                 streamReader = inputFactory.createXMLStreamReader(requestSource);
94             }
95             catch (XMLStreamException ex) {
96                 streamReader = null;
97             }
98             catch (UnsupportedOperationException ex) {
99                 streamReader = null;
100             }
101         }
102         if (streamReader == null) {
103             // as a final resort, transform the source to a stream, and read from that
104             ByteArrayInputStream bis = convertToByteArrayInputStream(requestSource);
105             streamReader = inputFactory.createXMLStreamReader(bis);
106         }
107         return streamReader;
108     }
109
110     private XMLEventReader resolveEventReader(Source requestSource) throws TransformerException, XMLStreamException {
111         XMLEventReader eventReader = null;
112         if (StaxUtils.isStaxSource(requestSource)) {
113             eventReader = StaxUtils.getXMLEventReader(requestSource);
114             if (eventReader == null) {
115                 XMLStreamReader streamReader = StaxUtils.getXMLStreamReader(requestSource);
116                 if (streamReader != null) {
117                     try {
118                         eventReader = inputFactory.createXMLEventReader(streamReader);
119                     }
120                     catch (XMLStreamException ex) {
121                         eventReader = null;
122                     }
123                 }
124
125             }
126         }
127         if (eventReader == null) {
128             try {
129                 eventReader = inputFactory.createXMLEventReader(requestSource);
130             }
131             catch (XMLStreamException ex) {
132                 eventReader = null;
133             }
134             catch (UnsupportedOperationException ex) {
135                 eventReader = null;
136             }
137         }
138         if (eventReader == null) {
139             // as a final resort, transform the source to a stream, and read from that
140             ByteArrayInputStream bis = convertToByteArrayInputStream(requestSource);
141             eventReader = inputFactory.createXMLEventReader(bis);
142         }
143         return eventReader;
144     }
145
146     /**
147      * Create a {@code XMLInputFactory} that this resolver will use to create {@link XMLStreamReader} and {@link
148      * XMLEventReader} objects.
149      *
150      * <p>Can be overridden in subclasses, adding further initialization of the factory. The resulting factory is cached,
151      * so this method will only be called once.
152      *
153      * @return the created factory
154      */

155     protected XMLInputFactory createXmlInputFactory() {
156         return XMLInputFactoryUtils.newInstance();
157     }
158
159     private ByteArrayInputStream convertToByteArrayInputStream(Source source) throws TransformerException {
160         ByteArrayOutputStream bos = new ByteArrayOutputStream();
161         transform(source, new StreamResult(bos));
162         return new ByteArrayInputStream(bos.toByteArray());
163     }
164
165
166
167 }
168