1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.ws.soap.saaj;
18
19 import java.io.ByteArrayInputStream;
20 import java.io.ByteArrayOutputStream;
21 import java.io.IOException;
22 import java.io.OutputStream;
23 import java.util.Iterator;
24 import javax.activation.DataHandler;
25 import javax.xml.soap.AttachmentPart;
26 import javax.xml.soap.MessageFactory;
27 import javax.xml.soap.MimeHeaders;
28 import javax.xml.soap.SOAPBody;
29 import javax.xml.soap.SOAPElement;
30 import javax.xml.soap.SOAPEnvelope;
31 import javax.xml.soap.SOAPException;
32 import javax.xml.soap.SOAPMessage;
33 import javax.xml.soap.SOAPPart;
34
35 import org.springframework.util.Assert;
36 import org.springframework.util.ObjectUtils;
37 import org.springframework.ws.mime.Attachment;
38 import org.springframework.ws.mime.AttachmentException;
39 import org.springframework.ws.soap.AbstractSoapMessage;
40 import org.springframework.ws.soap.SoapEnvelope;
41 import org.springframework.ws.soap.SoapMessage;
42 import org.springframework.ws.soap.SoapVersion;
43 import org.springframework.ws.soap.saaj.support.SaajUtils;
44 import org.springframework.ws.soap.support.SoapUtils;
45 import org.springframework.ws.transport.TransportConstants;
46
47 import org.w3c.dom.DOMImplementation;
48 import org.w3c.dom.Document;
49 import org.w3c.dom.ls.DOMImplementationLS;
50 import org.w3c.dom.ls.LSOutput;
51 import org.w3c.dom.ls.LSSerializer;
52
53
54
55
56
57
58
59
60
61 public class SaajSoapMessage extends AbstractSoapMessage {
62
63 private static final String CONTENT_TYPE_XOP = "application/xop+xml";
64
65 private final MessageFactory messageFactory;
66
67 private SOAPMessage saajMessage;
68
69 private SoapEnvelope envelope;
70
71 private final boolean langAttributeOnSoap11FaultString;
72
73 private SaajImplementation implementation;
74
75
76
77
78
79
80 public SaajSoapMessage(SOAPMessage soapMessage) {
81 this(soapMessage, true, null);
82 }
83
84
85
86
87
88
89
90 public SaajSoapMessage(SOAPMessage soapMessage, MessageFactory messageFactory) {
91 this(soapMessage, true, messageFactory);
92 }
93
94
95
96
97
98
99
100
101 public SaajSoapMessage(SOAPMessage soapMessage, boolean langAttributeOnSoap11FaultString) {
102 this(soapMessage, langAttributeOnSoap11FaultString, null);
103 }
104
105
106
107
108
109
110
111
112
113 public SaajSoapMessage(SOAPMessage soapMessage, boolean langAttributeOnSoap11FaultString, MessageFactory messageFactory) {
114 Assert.notNull(soapMessage, "soapMessage must not be null");
115 saajMessage = soapMessage;
116 this.langAttributeOnSoap11FaultString = langAttributeOnSoap11FaultString;
117 MimeHeaders headers = getImplementation().getMimeHeaders(soapMessage);
118 if (ObjectUtils.isEmpty(headers.getHeader(TransportConstants.HEADER_SOAP_ACTION))) {
119 headers.addHeader(TransportConstants.HEADER_SOAP_ACTION, "\"\"");
120 }
121 this.messageFactory = messageFactory;
122 }
123
124
125 public SOAPMessage getSaajMessage() {
126 return saajMessage;
127 }
128
129
130 public void setSaajMessage(SOAPMessage soapMessage) {
131 Assert.notNull(soapMessage, "soapMessage must not be null");
132 saajMessage = soapMessage;
133 envelope = null;
134 }
135
136 public SoapEnvelope getEnvelope() {
137 if (envelope == null) {
138 try {
139 SOAPEnvelope saajEnvelope = getImplementation().getEnvelope(getSaajMessage());
140 envelope = new SaajSoapEnvelope(saajEnvelope, langAttributeOnSoap11FaultString);
141 }
142 catch (SOAPException ex) {
143 throw new SaajSoapEnvelopeException(ex);
144 }
145 }
146 return envelope;
147 }
148
149 public String getSoapAction() {
150 MimeHeaders mimeHeaders = getImplementation().getMimeHeaders(getSaajMessage());
151 if (SoapVersion.SOAP_11 == getVersion()) {
152 String[] actions = mimeHeaders.getHeader(TransportConstants.HEADER_SOAP_ACTION);
153 return ObjectUtils.isEmpty(actions) ? TransportConstants.EMPTY_SOAP_ACTION : actions[0];
154 }
155 else if (SoapVersion.SOAP_12 == getVersion()) {
156 String[] contentTypes = mimeHeaders.getHeader(TransportConstants.HEADER_CONTENT_TYPE);
157 return !ObjectUtils.isEmpty(contentTypes) ? SoapUtils.extractActionFromContentType(contentTypes[0]) :
158 TransportConstants.EMPTY_SOAP_ACTION;
159 }
160 else {
161 throw new IllegalStateException("Unsupported SOAP version: " + getVersion());
162 }
163 }
164
165 public void setSoapAction(String soapAction) {
166 MimeHeaders mimeHeaders = getImplementation().getMimeHeaders(getSaajMessage());
167 soapAction = SoapUtils.escapeAction(soapAction);
168 if (SoapVersion.SOAP_11 == getVersion()) {
169 mimeHeaders.setHeader(TransportConstants.HEADER_SOAP_ACTION, soapAction);
170 }
171 else if (SoapVersion.SOAP_12 == getVersion()) {
172
173 if (saajMessage.saveRequired()) {
174 try {
175 saajMessage.saveChanges();
176 }
177 catch (SOAPException ex) {
178 throw new SaajSoapMessageException("Could not save message", ex);
179 }
180 }
181 String[] contentTypes = mimeHeaders.getHeader(TransportConstants.HEADER_CONTENT_TYPE);
182 String contentType = !ObjectUtils.isEmpty(contentTypes) ? contentTypes[0] : getVersion().getContentType();
183 contentType = SoapUtils.setActionInContentType(contentType, soapAction);
184 mimeHeaders.setHeader(TransportConstants.HEADER_CONTENT_TYPE, contentType);
185 mimeHeaders.removeHeader(TransportConstants.HEADER_SOAP_ACTION);
186 }
187 else {
188 throw new IllegalStateException("Unsupported SOAP version: " + getVersion());
189 }
190
191 }
192
193 public Document getDocument() {
194 Assert.state(messageFactory != null, "Could find message factory to use");
195
196 try {
197 ByteArrayOutputStream bos = new ByteArrayOutputStream();
198 getSaajMessage().writeTo(bos);
199 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
200 SOAPMessage saajMessage = messageFactory.createMessage(getSaajMessage().getMimeHeaders(), bis);
201 setSaajMessage(saajMessage);
202 return saajMessage.getSOAPPart();
203 }
204 catch (SOAPException ex) {
205 throw new SaajSoapMessageException("Could not save changes", ex);
206 }
207 catch (IOException ex) {
208 throw new SaajSoapMessageException("Could not save changes", ex);
209 }
210 }
211
212 public void setDocument(Document document) {
213 if (saajMessage.getSOAPPart() != document) {
214 Assert.state(messageFactory != null, "Could find message factory to use");
215 try {
216 DOMImplementation implementation = document.getImplementation();
217 Assert.isInstanceOf(DOMImplementationLS.class, implementation);
218
219 DOMImplementationLS loadSaveImplementation = (DOMImplementationLS) implementation;
220 LSOutput output = loadSaveImplementation.createLSOutput();
221 ByteArrayOutputStream bos = new ByteArrayOutputStream();
222 output.setByteStream(bos);
223
224 LSSerializer serializer = loadSaveImplementation.createLSSerializer();
225 serializer.write(document, output);
226
227 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
228
229 this.saajMessage = messageFactory.createMessage(saajMessage.getMimeHeaders(), bis);
230
231 }
232 catch (SOAPException ex) {
233 throw new SaajSoapMessageException("Could not read input stream", ex);
234 }
235 catch (IOException ex) {
236 throw new SaajSoapMessageException("Could not read input stream", ex);
237 }
238 }
239 }
240
241 public void writeTo(OutputStream outputStream) throws IOException {
242 MimeHeaders mimeHeaders = getImplementation().getMimeHeaders(getSaajMessage());
243 if (ObjectUtils.isEmpty(mimeHeaders.getHeader(TransportConstants.HEADER_ACCEPT))) {
244 mimeHeaders.setHeader(TransportConstants.HEADER_ACCEPT, getVersion().getContentType());
245 }
246 try {
247 getImplementation().writeTo(getSaajMessage(), outputStream);
248 outputStream.flush();
249 }
250 catch (SOAPException ex) {
251 throw new SaajSoapMessageException("Could not write message to OutputStream: " + ex.getMessage(), ex);
252 }
253 }
254
255 private int getSaajVersion() {
256 try {
257 return SaajUtils.getSaajVersion(saajMessage);
258 }
259 catch (SOAPException ex) {
260 throw new SaajSoapEnvelopeException("Could not access envelope: " + ex.getMessage(), ex);
261 }
262 }
263
264 public boolean isXopPackage() {
265 if (getSaajVersion() >= SaajUtils.SAAJ_13) {
266 SOAPPart saajPart = saajMessage.getSOAPPart();
267 String[] contentTypes = saajPart.getMimeHeader(TransportConstants.HEADER_CONTENT_TYPE);
268 for (String contentType : contentTypes) {
269 if (contentType.indexOf(CONTENT_TYPE_XOP) != -1) {
270 return true;
271 }
272 }
273 }
274 return false;
275 }
276
277 public boolean convertToXopPackage() {
278 if (getSaajVersion() >= SaajUtils.SAAJ_13) {
279 convertMessageToXop();
280 convertPartToXop();
281 return true;
282 }
283 else {
284 return false;
285 }
286 }
287
288 private void convertMessageToXop() {
289 MimeHeaders mimeHeaders = saajMessage.getMimeHeaders();
290 String[] oldContentTypes = mimeHeaders.getHeader(TransportConstants.HEADER_CONTENT_TYPE);
291 String oldContentType =
292 !ObjectUtils.isEmpty(oldContentTypes) ? oldContentTypes[0] : getVersion().getContentType();
293 StringBuilder builder = new StringBuilder(CONTENT_TYPE_XOP);
294 builder.append(";type=");
295 builder.append('"');
296 builder.append(oldContentType);
297 builder.append('"');
298 mimeHeaders.setHeader(TransportConstants.HEADER_CONTENT_TYPE, builder.toString());
299 }
300
301 private void convertPartToXop() {
302 SOAPPart saajPart = saajMessage.getSOAPPart();
303 String[] oldContentTypes = saajPart.getMimeHeader(TransportConstants.HEADER_CONTENT_TYPE);
304 String oldContentType =
305 !ObjectUtils.isEmpty(oldContentTypes) ? oldContentTypes[0] : getVersion().getContentType();
306 StringBuilder builder = new StringBuilder(CONTENT_TYPE_XOP);
307 builder.append(";type=");
308 builder.append('"');
309 builder.append(oldContentType);
310 builder.append('"');
311 saajPart.setMimeHeader(TransportConstants.HEADER_CONTENT_TYPE, builder.toString());
312 }
313
314 public Iterator<Attachment> getAttachments() throws AttachmentException {
315 Iterator<AttachmentPart> iterator = getImplementation().getAttachments(getSaajMessage());
316 return new SaajAttachmentIterator(iterator);
317 }
318
319 public Attachment getAttachment(String contentId) {
320 Assert.hasLength(contentId, "contentId must not be empty");
321 MimeHeaders mimeHeaders = new MimeHeaders();
322 mimeHeaders.setHeader(TransportConstants.HEADER_CONTENT_ID, contentId);
323 Iterator<AttachmentPart> iterator = getImplementation().getAttachment(getSaajMessage(), mimeHeaders);
324 if (!iterator.hasNext()) {
325 return null;
326 }
327 AttachmentPart saajAttachment = iterator.next();
328 return new SaajAttachment(saajAttachment);
329 }
330
331 public Attachment addAttachment(String contentId, DataHandler dataHandler) {
332 Assert.hasLength(contentId, "contentId must not be empty");
333 Assert.notNull(dataHandler, "dataHandler must not be null");
334 AttachmentPart saajAttachment = getImplementation().addAttachmentPart(getSaajMessage(), dataHandler);
335 saajAttachment.setContentId(contentId);
336 saajAttachment.setMimeHeader(TransportConstants.HEADER_CONTENT_TRANSFER_ENCODING, "binary");
337 return new SaajAttachment(saajAttachment);
338 }
339
340 protected final SaajImplementation getImplementation() {
341 if (implementation == null) {
342 int saajVersion = getSaajVersion();
343 if (saajVersion == SaajUtils.SAAJ_13) {
344 implementation = Saaj13Implementation.getInstance();
345 }
346 else if (saajVersion == SaajUtils.SAAJ_12) {
347 implementation = Saaj12Implementation.getInstance();
348 }
349 else if (saajVersion == SaajUtils.SAAJ_11) {
350 implementation = Saaj11Implementation.getInstance();
351 }
352 else {
353 throw new IllegalStateException("Could not find SAAJ on the classpath");
354 }
355 }
356 return implementation;
357 }
358
359 public String toString() {
360 StringBuilder builder = new StringBuilder("SaajSoapMessage");
361 try {
362 SOAPEnvelope envelope = getImplementation().getEnvelope(saajMessage);
363 if (envelope != null) {
364 SOAPBody body = getImplementation().getBody(envelope);
365 if (body != null) {
366 SOAPElement bodyElement = getImplementation().getFirstBodyElement(body);
367 if (bodyElement != null) {
368 builder.append(' ');
369 builder.append(getImplementation().getName(bodyElement));
370 }
371 }
372 }
373 }
374 catch (SOAPException ex) {
375
376 }
377 return builder.toString();
378 }
379
380 private static class SaajAttachmentIterator implements Iterator<Attachment> {
381
382 private final Iterator<AttachmentPart> saajIterator;
383
384 private SaajAttachmentIterator(Iterator<AttachmentPart> saajIterator) {
385 this.saajIterator = saajIterator;
386 }
387
388 public boolean hasNext() {
389 return saajIterator.hasNext();
390 }
391
392 public Attachment next() {
393 AttachmentPart saajAttachment = saajIterator.next();
394 return new SaajAttachment(saajAttachment);
395 }
396
397 public void remove() {
398 saajIterator.remove();
399 }
400 }
401
402 }