View Javadoc

1   /*
2    * Copyright 2002-2009 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.soap.saaj;
18  
19  import java.io.IOException;
20  import java.io.OutputStream;
21  import java.util.Iterator;
22  import javax.activation.DataHandler;
23  import javax.xml.soap.AttachmentPart;
24  import javax.xml.soap.MimeHeaders;
25  import javax.xml.soap.SOAPBody;
26  import javax.xml.soap.SOAPElement;
27  import javax.xml.soap.SOAPEnvelope;
28  import javax.xml.soap.SOAPException;
29  import javax.xml.soap.SOAPMessage;
30  import javax.xml.soap.SOAPPart;
31  
32  import org.springframework.util.Assert;
33  import org.springframework.util.ObjectUtils;
34  import org.springframework.ws.mime.Attachment;
35  import org.springframework.ws.mime.AttachmentException;
36  import org.springframework.ws.soap.AbstractSoapMessage;
37  import org.springframework.ws.soap.SoapEnvelope;
38  import org.springframework.ws.soap.SoapMessage;
39  import org.springframework.ws.soap.SoapVersion;
40  import org.springframework.ws.soap.saaj.support.SaajUtils;
41  import org.springframework.ws.soap.support.SoapUtils;
42  import org.springframework.ws.transport.TransportConstants;
43  
44  /**
45   * SAAJ-specific implementation of the {@link SoapMessage} interface. Created via the {@link SaajSoapMessageFactory},
46   * wraps a {@link SOAPMessage}.
47   *
48   * @author Arjen Poutsma
49   * @see SOAPMessage
50   * @since 1.0.0
51   */
52  public class SaajSoapMessage extends AbstractSoapMessage {
53  
54      private static final String CONTENT_TYPE_XOP = "application/xop+xml";
55  
56      private SOAPMessage saajMessage;
57  
58      private SoapEnvelope envelope;
59  
60      private final boolean langAttributeOnSoap11FaultString;
61  
62      private SaajImplementation implementation;
63  
64      /**
65       * Create a new <code>SaajSoapMessage</code> based on the given SAAJ <code>SOAPMessage</code>.
66       *
67       * @param soapMessage the SAAJ SOAPMessage
68       */
69      public SaajSoapMessage(SOAPMessage soapMessage) {
70          this(soapMessage, true);
71      }
72  
73      /**
74       * Create a new <code>SaajSoapMessage</code> based on the given SAAJ <code>SOAPMessage</code>.
75       *
76       * @param soapMessage the SAAJ SOAPMessage
77       * @param langAttributeOnSoap11FaultString
78       *                    whether a {@code xml:lang} attribute is allowed on SOAP 1.1 {@code <faultstring>} elements
79       */
80      public SaajSoapMessage(SOAPMessage soapMessage, boolean langAttributeOnSoap11FaultString) {
81          Assert.notNull(soapMessage, "soapMessage must not be null");
82          saajMessage = soapMessage;
83          this.langAttributeOnSoap11FaultString = langAttributeOnSoap11FaultString;
84          MimeHeaders headers = getImplementation().getMimeHeaders(soapMessage);
85          if (ObjectUtils.isEmpty(headers.getHeader(TransportConstants.HEADER_SOAP_ACTION))) {
86              headers.addHeader(TransportConstants.HEADER_SOAP_ACTION, "\"\"");
87          }
88      }
89  
90      /** Return the SAAJ <code>SOAPMessage</code> that this <code>SaajSoapMessage</code> is based on. */
91      public SOAPMessage getSaajMessage() {
92          return saajMessage;
93      }
94  
95      /** Sets the SAAJ <code>SOAPMessage</code> that this <code>SaajSoapMessage</code> is based on. */
96      public void setSaajMessage(SOAPMessage soapMessage) {
97          Assert.notNull(soapMessage, "soapMessage must not be null");
98          saajMessage = soapMessage;
99          envelope = null;
100     }
101 
102     public SoapEnvelope getEnvelope() {
103         if (envelope == null) {
104             try {
105                 SOAPEnvelope saajEnvelope = getImplementation().getEnvelope(getSaajMessage());
106                 envelope = new SaajSoapEnvelope(saajEnvelope, langAttributeOnSoap11FaultString);
107             }
108             catch (SOAPException ex) {
109                 throw new SaajSoapEnvelopeException(ex);
110             }
111         }
112         return envelope;
113     }
114 
115     public String getSoapAction() {
116         MimeHeaders mimeHeaders = getImplementation().getMimeHeaders(getSaajMessage());
117         if (SoapVersion.SOAP_11 == getVersion()) {
118             String[] actions = mimeHeaders.getHeader(TransportConstants.HEADER_SOAP_ACTION);
119             return ObjectUtils.isEmpty(actions) ? TransportConstants.EMPTY_SOAP_ACTION : actions[0];
120         }
121         else if (SoapVersion.SOAP_12 == getVersion()) {
122             String[] contentTypes = mimeHeaders.getHeader(TransportConstants.HEADER_CONTENT_TYPE);
123             return !ObjectUtils.isEmpty(contentTypes) ? SoapUtils.extractActionFromContentType(contentTypes[0]) :
124                     TransportConstants.EMPTY_SOAP_ACTION;
125         }
126         else {
127             throw new IllegalStateException("Unsupported SOAP version: " + getVersion());
128         }
129     }
130 
131     public void setSoapAction(String soapAction) {
132         MimeHeaders mimeHeaders = getImplementation().getMimeHeaders(getSaajMessage());
133         soapAction = SoapUtils.escapeAction(soapAction);
134         if (SoapVersion.SOAP_11 == getVersion()) {
135             mimeHeaders.setHeader(TransportConstants.HEADER_SOAP_ACTION, soapAction);
136         }
137         else if (SoapVersion.SOAP_12 == getVersion()) {
138             // force save of Content Type header
139             if (saajMessage.saveRequired()) {
140                 try {
141                     saajMessage.saveChanges();
142                 }
143                 catch (SOAPException ex) {
144                     throw new SaajSoapMessageException("Could not save message", ex);
145                 }
146             }
147             String[] contentTypes = mimeHeaders.getHeader(TransportConstants.HEADER_CONTENT_TYPE);
148             String contentType = !ObjectUtils.isEmpty(contentTypes) ? contentTypes[0] : getVersion().getContentType();
149             contentType = SoapUtils.setActionInContentType(contentType, soapAction);
150             mimeHeaders.setHeader(TransportConstants.HEADER_CONTENT_TYPE, contentType);
151             mimeHeaders.removeHeader(TransportConstants.HEADER_SOAP_ACTION);
152         }
153         else {
154             throw new IllegalStateException("Unsupported SOAP version: " + getVersion());
155         }
156 
157     }
158 
159     public void writeTo(OutputStream outputStream) throws IOException {
160         MimeHeaders mimeHeaders = getImplementation().getMimeHeaders(getSaajMessage());
161         if (ObjectUtils.isEmpty(mimeHeaders.getHeader(TransportConstants.HEADER_ACCEPT))) {
162             mimeHeaders.setHeader(TransportConstants.HEADER_ACCEPT, getVersion().getContentType());
163         }
164         try {
165             getImplementation().writeTo(getSaajMessage(), outputStream);
166             outputStream.flush();
167         }
168         catch (SOAPException ex) {
169             throw new SaajSoapMessageException("Could not write message to OutputStream: " + ex.getMessage(), ex);
170         }
171     }
172 
173     public boolean isXopPackage() {
174         if (SaajUtils.getSaajVersion(saajMessage) >= SaajUtils.SAAJ_13) {
175             SOAPPart saajPart = saajMessage.getSOAPPart();
176             String[] contentTypes = saajPart.getMimeHeader(TransportConstants.HEADER_CONTENT_TYPE);
177             for (int i = 0; i < contentTypes.length; i++) {
178                 if (contentTypes[i].indexOf(CONTENT_TYPE_XOP) != -1) {
179                     return true;
180                 }
181             }
182         }
183         return false;
184     }
185 
186     public boolean convertToXopPackage() {
187         if (SaajUtils.getSaajVersion(saajMessage) >= SaajUtils.SAAJ_13) {
188             convertMessageToXop();
189             convertPartToXop();
190             return true;
191         }
192         else {
193             return false;
194         }
195     }
196 
197     private void convertMessageToXop() {
198         MimeHeaders mimeHeaders = saajMessage.getMimeHeaders();
199         String[] oldContentTypes = mimeHeaders.getHeader(TransportConstants.HEADER_CONTENT_TYPE);
200         String oldContentType =
201                 !ObjectUtils.isEmpty(oldContentTypes) ? oldContentTypes[0] : getVersion().getContentType();
202         StringBuffer buffer = new StringBuffer(CONTENT_TYPE_XOP);
203         buffer.append(";type=");
204         buffer.append('"');
205         buffer.append(oldContentType);
206         buffer.append('"');
207         mimeHeaders.setHeader(TransportConstants.HEADER_CONTENT_TYPE, buffer.toString());
208     }
209 
210     private void convertPartToXop() {
211         SOAPPart saajPart = saajMessage.getSOAPPart();
212         String[] oldContentTypes = saajPart.getMimeHeader(TransportConstants.HEADER_CONTENT_TYPE);
213         String oldContentType =
214                 !ObjectUtils.isEmpty(oldContentTypes) ? oldContentTypes[0] : getVersion().getContentType();
215         StringBuffer buffer = new StringBuffer(CONTENT_TYPE_XOP);
216         buffer.append(";type=");
217         buffer.append('"');
218         buffer.append(oldContentType);
219         buffer.append('"');
220         saajPart.setMimeHeader(TransportConstants.HEADER_CONTENT_TYPE, buffer.toString());
221     }
222 
223     public Iterator getAttachments() throws AttachmentException {
224         Iterator iterator = getImplementation().getAttachments(getSaajMessage());
225         return new SaajAttachmentIterator(iterator);
226     }
227 
228     public Attachment getAttachment(String contentId) {
229         Assert.hasLength(contentId, "contentId must not be empty");
230         MimeHeaders mimeHeaders = new MimeHeaders();
231         mimeHeaders.setHeader(TransportConstants.HEADER_CONTENT_ID, contentId);
232         Iterator iterator = getImplementation().getAttachment(getSaajMessage(), mimeHeaders);
233         if (!iterator.hasNext()) {
234             return null;
235         }
236         AttachmentPart saajAttachment = (AttachmentPart) iterator.next();
237         return new SaajAttachment(saajAttachment);
238     }
239 
240     public Attachment addAttachment(String contentId, DataHandler dataHandler) {
241         Assert.hasLength(contentId, "contentId must not be empty");
242         Assert.notNull(dataHandler, "dataHandler must not be null");
243         AttachmentPart saajAttachment = getImplementation().addAttachmentPart(getSaajMessage(), dataHandler);
244         saajAttachment.setContentId(contentId);
245         saajAttachment.setMimeHeader(TransportConstants.HEADER_CONTENT_TRANSFER_ENCODING, "binary");
246         return new SaajAttachment(saajAttachment);
247     }
248 
249     protected final SaajImplementation getImplementation() {
250         if (implementation == null) {
251             if (SaajUtils.getSaajVersion(saajMessage) == SaajUtils.SAAJ_13) {
252                 implementation = Saaj13Implementation.getInstance();
253             }
254             else if (SaajUtils.getSaajVersion(saajMessage) == SaajUtils.SAAJ_12) {
255                 implementation = Saaj12Implementation.getInstance();
256             }
257             else if (SaajUtils.getSaajVersion(saajMessage) == SaajUtils.SAAJ_11) {
258                 implementation = Saaj11Implementation.getInstance();
259             }
260             else {
261                 throw new IllegalStateException("Could not find SAAJ on the classpath");
262             }
263         }
264         return implementation;
265     }
266 
267     public String toString() {
268         StringBuffer buffer = new StringBuffer("SaajSoapMessage");
269         try {
270             SOAPEnvelope envelope = getImplementation().getEnvelope(saajMessage);
271             if (envelope != null) {
272                 SOAPBody body = getImplementation().getBody(envelope);
273                 if (body != null) {
274                     SOAPElement bodyElement = getImplementation().getFirstBodyElement(body);
275                     if (bodyElement != null) {
276                         buffer.append(' ');
277                         buffer.append(getImplementation().getName(bodyElement));
278                     }
279                 }
280             }
281         }
282         catch (SOAPException ex) {
283             // ignore
284         }
285         return buffer.toString();
286     }
287 
288     private static class SaajAttachmentIterator implements Iterator {
289 
290         private final Iterator saajIterator;
291 
292         private SaajAttachmentIterator(Iterator saajIterator) {
293             this.saajIterator = saajIterator;
294         }
295 
296         public boolean hasNext() {
297             return saajIterator.hasNext();
298         }
299 
300         public Object next() {
301             AttachmentPart saajAttachment = (AttachmentPart) saajIterator.next();
302             return new SaajAttachment(saajAttachment);
303         }
304 
305         public void remove() {
306             saajIterator.remove();
307         }
308     }
309 
310 }