1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.ws.soap.axiom;
18
19 import java.io.IOException;
20 import java.io.OutputStream;
21 import java.io.OutputStreamWriter;
22 import java.io.StringWriter;
23 import java.io.UnsupportedEncodingException;
24 import java.io.Writer;
25 import java.util.Iterator;
26 import javax.activation.DataHandler;
27 import javax.xml.stream.XMLStreamException;
28
29 import org.apache.axiom.attachments.Attachments;
30 import org.apache.axiom.om.OMElement;
31 import org.apache.axiom.om.OMException;
32 import org.apache.axiom.om.OMOutputFormat;
33 import org.apache.axiom.om.impl.MTOMConstants;
34 import org.apache.axiom.om.impl.OMMultipartWriter;
35 import org.apache.axiom.soap.SOAPBody;
36 import org.apache.axiom.soap.SOAPEnvelope;
37 import org.apache.axiom.soap.SOAPFactory;
38 import org.apache.axiom.soap.SOAPMessage;
39 import org.apache.axiom.soap.SOAPProcessingException;
40 import org.w3c.dom.Document;
41
42 import org.springframework.util.Assert;
43 import org.springframework.util.StringUtils;
44 import org.springframework.ws.mime.Attachment;
45 import org.springframework.ws.soap.AbstractSoapMessage;
46 import org.springframework.ws.soap.SoapEnvelope;
47 import org.springframework.ws.soap.SoapMessage;
48 import org.springframework.ws.soap.SoapVersion;
49 import org.springframework.ws.soap.axiom.support.AxiomUtils;
50 import org.springframework.ws.soap.support.SoapUtils;
51 import org.springframework.ws.stream.StreamingPayload;
52 import org.springframework.ws.stream.StreamingWebServiceMessage;
53 import org.springframework.ws.transport.TransportConstants;
54 import org.springframework.ws.transport.TransportOutputStream;
55
56
57
58
59
60
61
62
63
64 public class AxiomSoapMessage extends AbstractSoapMessage implements StreamingWebServiceMessage {
65
66 private static final String EMPTY_SOAP_ACTION = "\"\"";
67
68 private SOAPMessage axiomMessage;
69
70 private final SOAPFactory axiomFactory;
71
72 private final Attachments attachments;
73
74 private final boolean payloadCaching;
75
76 private AxiomSoapEnvelope envelope;
77
78 private String soapAction;
79
80 private final boolean langAttributeOnSoap11FaultString;
81
82 private OMOutputFormat outputFormat;
83
84
85
86
87
88
89 public AxiomSoapMessage(SOAPFactory soapFactory) {
90 this(soapFactory, true, true);
91 }
92
93
94
95
96
97
98 public AxiomSoapMessage(SOAPFactory soapFactory, boolean payloadCaching, boolean langAttributeOnSoap11FaultString) {
99 SOAPEnvelope soapEnvelope = soapFactory.getDefaultEnvelope();
100 axiomFactory = soapFactory;
101 axiomMessage = axiomFactory.createSOAPMessage();
102 axiomMessage.setSOAPEnvelope(soapEnvelope);
103 attachments = new Attachments();
104 this.payloadCaching = payloadCaching;
105 this.langAttributeOnSoap11FaultString = langAttributeOnSoap11FaultString;
106 soapAction = EMPTY_SOAP_ACTION;
107 }
108
109
110
111
112
113
114
115
116 public AxiomSoapMessage(SOAPMessage soapMessage,
117 String soapAction,
118 boolean payloadCaching,
119 boolean langAttributeOnSoap11FaultString) {
120 this(soapMessage, new Attachments(), soapAction, payloadCaching, langAttributeOnSoap11FaultString);
121 }
122
123
124
125
126
127
128
129
130
131 public AxiomSoapMessage(SOAPMessage soapMessage,
132 Attachments attachments,
133 String soapAction,
134 boolean payloadCaching,
135 boolean langAttributeOnSoap11FaultString) {
136 Assert.notNull(soapMessage, "'soapMessage' must not be null");
137 Assert.notNull(attachments, "'attachments' must not be null");
138 axiomMessage = soapMessage;
139 axiomFactory = (SOAPFactory) soapMessage.getSOAPEnvelope().getOMFactory();
140 this.attachments = attachments;
141 if (!StringUtils.hasLength(soapAction)) {
142 soapAction = EMPTY_SOAP_ACTION;
143 }
144 this.soapAction = soapAction;
145 this.payloadCaching = payloadCaching;
146 this.langAttributeOnSoap11FaultString = langAttributeOnSoap11FaultString;
147 }
148
149
150 public final SOAPMessage getAxiomMessage() {
151 return axiomMessage;
152 }
153
154
155
156
157
158
159 public final void setAxiomMessage(SOAPMessage axiomMessage) {
160 Assert.notNull(axiomMessage, "'axiomMessage' must not be null");
161 this.axiomMessage = axiomMessage;
162 this.envelope = null;
163 this.soapAction = EMPTY_SOAP_ACTION;
164 }
165
166
167
168
169
170
171 public void setOutputFormat(OMOutputFormat outputFormat) {
172 this.outputFormat = outputFormat;
173 }
174
175 public void setStreamingPayload(StreamingPayload payload) {
176 AxiomSoapBody soapBody = (AxiomSoapBody) getSoapBody();
177 soapBody.setStreamingPayload(payload);
178 }
179
180 public SoapEnvelope getEnvelope() {
181 if (envelope == null) {
182 try {
183 envelope = new AxiomSoapEnvelope(axiomMessage.getSOAPEnvelope(), axiomFactory, payloadCaching,
184 langAttributeOnSoap11FaultString);
185 }
186 catch (SOAPProcessingException ex) {
187 throw new AxiomSoapEnvelopeException(ex);
188 }
189 }
190 return envelope;
191 }
192
193 public String getSoapAction() {
194 return soapAction;
195 }
196
197 public void setSoapAction(String soapAction) {
198 soapAction = SoapUtils.escapeAction(soapAction);
199 this.soapAction = soapAction;
200 }
201
202 public Document getDocument() {
203 return AxiomUtils.toDocument(axiomMessage.getSOAPEnvelope());
204 }
205
206 public void setDocument(Document document) {
207
208 String soapAction = getSoapAction();
209 SOAPEnvelope envelope = AxiomUtils.toEnvelope(document);
210 SOAPMessage newMessage = axiomFactory.createSOAPMessage();
211 newMessage.setSOAPEnvelope(envelope);
212
213
214 setAxiomMessage(newMessage);
215
216 setSoapAction(soapAction);
217 }
218
219 public boolean isXopPackage() {
220 try {
221 return MTOMConstants.MTOM_TYPE.equals(attachments.getAttachmentSpecType());
222 }
223 catch (OMException ex) {
224 return false;
225 }
226 catch (NullPointerException ex) {
227
228 return false;
229 }
230 }
231
232 public boolean convertToXopPackage() {
233 return false;
234 }
235
236 public Attachment getAttachment(String contentId) {
237 Assert.hasLength(contentId, "contentId must not be empty");
238 if (contentId.startsWith("<") && contentId.endsWith(">")) {
239 contentId = contentId.substring(1, contentId.length() - 1);
240 }
241 DataHandler dataHandler = attachments.getDataHandler(contentId);
242 return dataHandler != null ? new AxiomAttachment(contentId, dataHandler) : null;
243 }
244
245 public Iterator<Attachment> getAttachments() {
246 return new AxiomAttachmentIterator();
247 }
248
249 public Attachment addAttachment(String contentId, DataHandler dataHandler) {
250 Assert.hasLength(contentId, "contentId must not be empty");
251 Assert.notNull(dataHandler, "dataHandler must not be null");
252 attachments.addDataHandler(contentId, dataHandler);
253 return new AxiomAttachment(contentId, dataHandler);
254 }
255
256 public void writeTo(OutputStream outputStream) throws IOException {
257 try {
258
259 OMOutputFormat outputFormat = getOutputFormat();
260 if (outputStream instanceof TransportOutputStream) {
261 TransportOutputStream transportOutputStream = (TransportOutputStream) outputStream;
262 String contentType = outputFormat.getContentType();
263 if (!(outputFormat.isDoingSWA() || outputFormat.isOptimized())) {
264 String charsetEncoding = axiomMessage.getCharsetEncoding();
265 contentType += "; charset=" + charsetEncoding;
266 }
267 SoapVersion version = getVersion();
268 if (SoapVersion.SOAP_11 == version) {
269 transportOutputStream.addHeader(TransportConstants.HEADER_SOAP_ACTION, soapAction);
270 transportOutputStream.addHeader(TransportConstants.HEADER_ACCEPT, version.getContentType());
271 }
272 else if (SoapVersion.SOAP_12 == version) {
273 contentType += "; action=" + soapAction;
274 transportOutputStream.addHeader(TransportConstants.HEADER_ACCEPT, version.getContentType());
275 }
276 transportOutputStream.addHeader(TransportConstants.HEADER_CONTENT_TYPE, contentType);
277
278 }
279 if (!(outputFormat.isOptimized()) & outputFormat.isDoingSWA()) {
280 writeSwAMessage(outputStream, outputFormat);
281 }
282 else {
283 if (payloadCaching) {
284 axiomMessage.serialize(outputStream, outputFormat);
285 }
286 else {
287 axiomMessage.serializeAndConsume(outputStream, outputFormat);
288 }
289 }
290 outputStream.flush();
291 }
292 catch (XMLStreamException ex) {
293 throw new AxiomSoapMessageException("Could not write message to OutputStream: " + ex.getMessage(), ex);
294 }
295 catch (OMException ex) {
296 throw new AxiomSoapMessageException("Could not write message to OutputStream: " + ex.getMessage(), ex);
297 }
298 }
299
300 private OMOutputFormat getOutputFormat() {
301 if (outputFormat != null) {
302 return outputFormat;
303 }
304 else {
305 String charsetEncoding = axiomMessage.getCharsetEncoding();
306
307 OMOutputFormat outputFormat = new OMOutputFormat();
308 outputFormat.setCharSetEncoding(charsetEncoding);
309 outputFormat.setSOAP11(getVersion() == SoapVersion.SOAP_11);
310 if (isXopPackage()) {
311 outputFormat.setDoOptimize(true);
312 }
313 else if (!attachments.getContentIDSet().isEmpty()) {
314 outputFormat.setDoingSWA(true);
315 }
316 return outputFormat;
317 }
318 }
319
320 private void writeSwAMessage(OutputStream outputStream, OMOutputFormat format)
321 throws XMLStreamException, UnsupportedEncodingException {
322 StringWriter writer = new StringWriter();
323 SOAPEnvelope envelope = axiomMessage.getSOAPEnvelope();
324 if (payloadCaching) {
325 envelope.serialize(writer, format);
326 }
327 else {
328 envelope.serializeAndConsume(writer, format);
329 }
330
331 try {
332 OMMultipartWriter mpw = new OMMultipartWriter(outputStream, format);
333
334 Writer rootPartWriter = new OutputStreamWriter(mpw.writeRootPart(),
335 format.getCharSetEncoding());
336 rootPartWriter.write(writer.toString());
337 rootPartWriter.close();
338
339
340 for (String id: attachments.getAllContentIDs()) {
341 mpw.writePart(attachments.getDataHandler(id), id);
342 }
343
344 mpw.complete();
345 }
346 catch (IOException ex) {
347 throw new OMException("Error writing SwA message", ex);
348 }
349 }
350
351 public String toString() {
352 StringBuilder builder = new StringBuilder("AxiomSoapMessage");
353 if (payloadCaching) {
354 try {
355 SOAPEnvelope envelope = axiomMessage.getSOAPEnvelope();
356 if (envelope != null) {
357 SOAPBody body = envelope.getBody();
358 if (body != null) {
359 OMElement bodyElement = body.getFirstElement();
360 if (bodyElement != null) {
361 builder.append(' ');
362 builder.append(bodyElement.getQName());
363 }
364 }
365 }
366 }
367 catch (OMException ex) {
368
369 }
370 }
371 return builder.toString();
372 }
373
374 private class AxiomAttachmentIterator implements Iterator<Attachment> {
375
376 private final Iterator<String> iterator;
377
378 @SuppressWarnings("unchecked")
379 private AxiomAttachmentIterator() {
380 iterator = attachments.getContentIDSet().iterator();
381 }
382
383 public boolean hasNext() {
384 return iterator.hasNext();
385 }
386
387 public Attachment next() {
388 String contentId = iterator.next();
389 DataHandler dataHandler = attachments.getDataHandler(contentId);
390 return new AxiomAttachment(contentId, dataHandler);
391 }
392
393 public void remove() {
394 iterator.remove();
395 }
396 }
397
398 }