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;
18  
19  import java.io.ByteArrayInputStream;
20  import java.io.ByteArrayOutputStream;
21  import javax.xml.namespace.NamespaceContext;
22  import javax.xml.stream.XMLEventFactory;
23  import javax.xml.stream.XMLEventReader;
24  import javax.xml.stream.XMLEventWriter;
25  import javax.xml.stream.XMLStreamException;
26  import javax.xml.stream.XMLStreamReader;
27  import javax.xml.stream.events.XMLEvent;
28  import javax.xml.stream.util.XMLEventConsumer;
29  import javax.xml.transform.Result;
30  import javax.xml.transform.Source;
31  import javax.xml.transform.TransformerException;
32  import javax.xml.transform.stream.StreamResult;
33  import javax.xml.transform.stream.StreamSource;
34  
35  import org.springframework.util.xml.StaxUtils;
36  import org.springframework.ws.WebServiceMessage;
37  import org.springframework.ws.context.MessageContext;
38  
39  /**
40   * Abstract base class for endpoints that handle the message payload with event-based StAX. Allows subclasses to read
41   * the request with a <code>XMLEventReader</code>, and to create a response using a <code>XMLEventWriter</code>.
42   *
43   * @author Arjen Poutsma
44   * @see #invokeInternal(javax.xml.stream.XMLEventReader,javax.xml.stream.util.XMLEventConsumer,
45   *      javax.xml.stream.XMLEventFactory)
46   * @see XMLEventReader
47   * @see XMLEventWriter
48   * @since 1.0.0
49   * @deprecated as of Spring Web Services 2.0, in favor of annotated endpoints
50   */
51  @Deprecated
52  public abstract class AbstractStaxEventPayloadEndpoint extends AbstractStaxPayloadEndpoint implements MessageEndpoint {
53  
54      private XMLEventFactory eventFactory;
55  
56      public final void invoke(MessageContext messageContext) throws Exception {
57          XMLEventReader eventReader = getEventReader(messageContext.getRequest().getPayloadSource());
58          XMLEventWriter streamWriter = new ResponseCreatingEventWriter(messageContext);
59          invokeInternal(eventReader, streamWriter, getEventFactory());
60          streamWriter.flush();
61      }
62  
63      /**
64       * Create a <code>XMLEventFactory</code> that this endpoint will use to create <code>XMLEvent</code>s. Can be
65       * overridden in subclasses, adding further initialization of the factory. The resulting
66       * <code>XMLEventFactory</code> is cached, so this method will only be called once.
67       *
68       * @return the created <code>XMLEventFactory</code>
69       */
70      protected XMLEventFactory createXmlEventFactory() {
71          return XMLEventFactory.newInstance();
72      }
73  
74      /** Returns an <code>XMLEventFactory</code> to read XML from. */
75      private XMLEventFactory getEventFactory() {
76          if (eventFactory == null) {
77              eventFactory = createXmlEventFactory();
78          }
79          return eventFactory;
80      }
81  
82      private XMLEventReader getEventReader(Source source) throws XMLStreamException, TransformerException {
83          if (source == null) {
84              return null;
85          }
86          XMLEventReader eventReader = null;
87          if (StaxUtils.isStaxSource(source)) {
88              eventReader = StaxUtils.getXMLEventReader(source);
89              if (eventReader == null) {
90                  XMLStreamReader streamReader = StaxUtils.getXMLStreamReader(source);
91                  if (streamReader != null) {
92                      try {
93                          eventReader = getInputFactory().createXMLEventReader(streamReader);
94                      }
95                      catch (XMLStreamException ex) {
96                          eventReader = null;
97                      }
98                  }
99              }
100         }
101         if (eventReader == null) {
102             try {
103                 eventReader = getInputFactory().createXMLEventReader(source);
104             }
105             catch (XMLStreamException ex) {
106                 eventReader = null;
107             }
108             catch (UnsupportedOperationException ex) {
109                 eventReader = null;
110             }
111         }
112         if (eventReader == null) {
113             // as a final resort, transform the source to a stream, and read from that
114             ByteArrayOutputStream os = new ByteArrayOutputStream();
115             transform(source, new StreamResult(os));
116             ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
117             eventReader = getInputFactory().createXMLEventReader(is);
118         }
119         return eventReader;
120     }
121 
122     private XMLEventWriter getEventWriter(Result result) {
123         XMLEventWriter eventWriter = null;
124         if (StaxUtils.isStaxResult(result)) {
125             eventWriter = StaxUtils.getXMLEventWriter(result);
126         }
127         if (eventWriter == null) {
128             try {
129                 eventWriter = getOutputFactory().createXMLEventWriter(result);
130             }
131             catch (XMLStreamException ex) {
132                 // ignore
133             }
134         }
135         return eventWriter;
136     }
137 
138     /**
139      * Template method. Subclasses must implement this. Offers the request payload as a <code>XMLEventReader</code>, and
140      * a <code>XMLEventWriter</code> to write the response payload to.
141      *
142      * @param eventReader  the reader to read the payload events from
143      * @param eventWriter  the writer to write payload events to
144      * @param eventFactory an <code>XMLEventFactory</code> that can be used to create events
145      */
146     protected abstract void invokeInternal(XMLEventReader eventReader,
147                                            XMLEventConsumer eventWriter,
148                                            XMLEventFactory eventFactory) throws Exception;
149 
150     /**
151      * Implementation of the <code>XMLEventWriter</code> interface that creates a response
152      * <code>WebServiceMessage</code> as soon as any method is called, thus lazily creating the response.
153      */
154     private class ResponseCreatingEventWriter implements XMLEventWriter {
155 
156         private XMLEventWriter eventWriter;
157 
158         private MessageContext messageContext;
159 
160         private ByteArrayOutputStream os;
161 
162         public ResponseCreatingEventWriter(MessageContext messageContext) {
163             this.messageContext = messageContext;
164         }
165 
166         public NamespaceContext getNamespaceContext() {
167             return eventWriter.getNamespaceContext();
168         }
169 
170         public void setNamespaceContext(NamespaceContext context) throws XMLStreamException {
171             createEventWriter();
172             eventWriter.setNamespaceContext(context);
173         }
174 
175         public void add(XMLEventReader reader) throws XMLStreamException {
176             createEventWriter();
177             while (reader.hasNext()) {
178                 add(reader.nextEvent());
179             }
180         }
181 
182         public void add(XMLEvent event) throws XMLStreamException {
183             createEventWriter();
184             eventWriter.add(event);
185             if (event.isEndDocument()) {
186                 if (os != null) {
187                     eventWriter.flush();
188                     // if we used an output stream cache, we have to transform it to the response again
189                     try {
190                         ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
191                         transform(new StreamSource(is), messageContext.getResponse().getPayloadResult());
192                     }
193                     catch (TransformerException ex) {
194                         throw new XMLStreamException(ex);
195                     }
196                 }
197             }
198         }
199 
200         public void close() throws XMLStreamException {
201             if (eventWriter != null) {
202                 eventWriter.close();
203             }
204         }
205 
206         public void flush() throws XMLStreamException {
207             if (eventWriter != null) {
208                 eventWriter.flush();
209             }
210         }
211 
212         public String getPrefix(String uri) throws XMLStreamException {
213             createEventWriter();
214             return eventWriter.getPrefix(uri);
215         }
216 
217         public void setDefaultNamespace(String uri) throws XMLStreamException {
218             createEventWriter();
219             eventWriter.setDefaultNamespace(uri);
220         }
221 
222         public void setPrefix(String prefix, String uri) throws XMLStreamException {
223             createEventWriter();
224             eventWriter.setPrefix(prefix, uri);
225         }
226 
227         private void createEventWriter() throws XMLStreamException {
228             if (eventWriter == null) {
229                 WebServiceMessage response = messageContext.getResponse();
230                 eventWriter = getEventWriter(response.getPayloadResult());
231                 if (eventWriter == null) {
232                     // as a final resort, use a stream, and transform that at endDocument()
233                     os = new ByteArrayOutputStream();
234                     eventWriter = getOutputFactory().createXMLEventWriter(os);
235                 }
236             }
237         }
238     }
239 }