View Javadoc

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.springframework.core.MethodParameter;
33  import org.springframework.xml.JaxpVersion;
34  
35  import org.w3c.dom.Document;
36  import org.w3c.dom.Node;
37  import org.xml.sax.InputSource;
38  
39  /**
40   * Implementation of {@link MethodArgumentResolver} and {@link MethodReturnValueHandler} that supports {@link Source}
41   * objects.
42   *
43   * @author Arjen Poutsma
44   * @since 2.0
45   */
46  public class SourcePayloadMethodProcessor extends AbstractPayloadSourceMethodProcessor {
47  
48      private XMLInputFactory inputFactory = createXmlInputFactory();
49  
50      // MethodArgumentResolver
51  
52      @Override
53      protected boolean supportsRequestPayloadParameter(MethodParameter parameter) {
54          return supports(parameter);
55      }
56  
57      @Override
58      protected Source resolveRequestPayloadArgument(MethodParameter parameter, Source requestPayload) throws Exception {
59          Class<?> parameterType = parameter.getParameterType();
60          if (parameterType.isAssignableFrom(requestPayload.getClass())) {
61              return requestPayload;
62          }
63          if (DOMSource.class.isAssignableFrom(parameterType)) {
64              DOMResult domResult = new DOMResult();
65              transform(requestPayload, domResult);
66              Node node = domResult.getNode();
67              if (node.getNodeType() == Node.DOCUMENT_NODE) {
68                  return new DOMSource(((Document) node).getDocumentElement());
69              }
70              else {
71                  return new DOMSource(domResult.getNode());
72              }
73          }
74          else if (SAXSource.class.isAssignableFrom(parameterType)) {
75              ByteArrayInputStream bis = convertToByteArrayInputStream(requestPayload);
76              InputSource inputSource = new InputSource(bis);
77              return new SAXSource(inputSource);
78          }
79          else if (StreamSource.class.isAssignableFrom(parameterType)) {
80              ByteArrayInputStream bis = convertToByteArrayInputStream(requestPayload);
81              return new StreamSource(bis);
82          }
83          else if (JaxpVersion.isAtLeastJaxp14() && Jaxp14StaxHandler.isStaxSource(parameterType)) {
84              XMLStreamReader streamReader;
85              try {
86                  streamReader = inputFactory.createXMLStreamReader(requestPayload);
87              } catch (UnsupportedOperationException ignored) {
88                  streamReader = null;
89              }
90              catch (XMLStreamException ignored) {
91                  streamReader = null;
92              }
93              if (streamReader == null) {
94                  ByteArrayInputStream bis = convertToByteArrayInputStream(requestPayload);
95                  streamReader = inputFactory.createXMLStreamReader(bis);
96              }
97              return Jaxp14StaxHandler.createStaxSource(streamReader, requestPayload.getSystemId());
98          }
99          throw new IllegalArgumentException("Unknown Source type: " + parameterType);
100     }
101 
102     // MethodReturnValueHandler
103 
104     @Override
105     protected boolean supportsResponsePayloadReturnType(MethodParameter returnType) {
106         return supports(returnType);
107     }
108 
109     @Override
110     protected Source createResponsePayload(MethodParameter returnType, Object returnValue) {
111         return (Source) returnValue;
112     }
113 
114     private boolean supports(MethodParameter parameter) {
115         return Source.class.isAssignableFrom(parameter.getParameterType());
116     }
117 
118     /**
119      * Create a {@code XMLInputFactory} that this resolver will use to create {@link javax.xml.stream.XMLStreamReader}
120      * and {@link javax.xml.stream.XMLEventReader} objects.
121      * <p/>
122      * Can be overridden in subclasses, adding further initialization of the factory. The resulting factory is cached,
123      * so this method will only be called once.
124      *
125      * @return the created factory
126      */
127     protected XMLInputFactory createXmlInputFactory() {
128         return XMLInputFactory.newInstance();
129     }
130 
131     /** Inner class to avoid a static JAXP 1.4 dependency. */
132     private static class Jaxp14StaxHandler {
133 
134         private static boolean isStaxSource(Class<?> clazz) {
135             return StAXSource.class.isAssignableFrom(clazz);
136         }
137 
138         private static Source createStaxSource(XMLStreamReader streamReader, String systemId) {
139             return new StAXSource(new SystemIdStreamReaderDelegate(streamReader, systemId));
140         }
141 
142     }
143 
144     private static class SystemIdStreamReaderDelegate extends StreamReaderDelegate {
145 
146         private final String systemId;
147 
148         private SystemIdStreamReaderDelegate(XMLStreamReader reader, String systemId) {
149             super(reader);
150             this.systemId = systemId;
151         }
152 
153         @Override
154         public Location getLocation() {
155             final Location parentLocation = getParent().getLocation();
156             return new Location() {
157                 public int getLineNumber() {
158                     return parentLocation != null ? parentLocation.getLineNumber() : -1;
159                 }
160 
161                 public int getColumnNumber() {
162                     return parentLocation != null ? parentLocation.getColumnNumber() : -1;
163                 }
164 
165                 public int getCharacterOffset() {
166                     return parentLocation != null ? parentLocation.getLineNumber() : -1;
167                 }
168 
169                 public String getPublicId() {
170                     return parentLocation != null ? parentLocation.getPublicId() : null;
171                 }
172 
173                 public String getSystemId() {
174                     return systemId;
175                 }
176             };
177         }
178     }
179 
180 }