View Javadoc
1   /*
2    * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.xml.internal.ws.message.jaxb;
27  
28  import com.sun.xml.internal.ws.api.SOAPVersion;
29  import com.sun.xml.internal.ws.api.message.Message;
30  import com.sun.xml.internal.ws.api.message.MessageHeaders;
31  import com.sun.xml.internal.ws.encoding.SOAPBindingCodec;
32  import com.sun.xml.internal.ws.message.AbstractMessageImpl;
33  import com.sun.xml.internal.ws.message.PayloadElementSniffer;
34  import com.sun.xml.internal.ws.spi.db.BindingContext;
35  import com.sun.xml.internal.ws.spi.db.XMLBridge;
36  import com.sun.xml.internal.ws.streaming.MtomStreamWriter;
37  import com.sun.xml.internal.ws.streaming.XMLStreamWriterUtil;
38  import org.xml.sax.ContentHandler;
39  import org.xml.sax.ErrorHandler;
40  import org.xml.sax.SAXException;
41  
42  import javax.xml.bind.JAXBContext;
43  import javax.xml.bind.JAXBException;
44  import javax.xml.bind.Marshaller;
45  import javax.xml.bind.attachment.AttachmentMarshaller;
46  import javax.xml.namespace.QName;
47  import javax.xml.stream.XMLStreamException;
48  import javax.xml.stream.XMLStreamReader;
49  import javax.xml.stream.XMLStreamWriter;
50  import javax.xml.transform.Source;
51  import javax.xml.ws.WebServiceException;
52  import java.io.OutputStream;
53  
54  /**
55   * {@link Message} backed by a JAXB bean; this implementation is used when client uses
56   * Dispatch mechanism in JAXB/MESSAGE mode; difference from {@link JAXBMessage} is
57   * that {@code jaxbObject} holds whole SOAP message including SOAP envelope;
58   * it's the client who is responsible for preparing message content.
59   *
60   * @author Miroslav Kos (miroslav.kos at oracle.com)
61   */
62  public class JAXBDispatchMessage extends AbstractMessageImpl {
63  
64      private final Object jaxbObject;
65  
66      private final XMLBridge bridge;
67  
68      /**
69       * For the use case of a user-supplied JAXB context that is not
70       * a known JAXB type, as when creating a Disaptch object with a
71       * JAXB object parameter, we will marshal and unmarshal directly with
72       * the context object, as there is no Bond available.  In this case,
73       * swaRef is not supported.
74       */
75      private final JAXBContext rawContext;
76  
77      /**
78       * Lazily sniffed payload element name
79       */
80      private QName payloadQName;
81  
82      /**
83       * Copy constructor.
84       */
85      private JAXBDispatchMessage(JAXBDispatchMessage that) {
86          super(that);
87          jaxbObject = that.jaxbObject;
88          rawContext = that.rawContext;
89          bridge = that.bridge;
90      }
91  
92      public JAXBDispatchMessage(JAXBContext rawContext, Object jaxbObject, SOAPVersion soapVersion) {
93          super(soapVersion);
94          this.bridge = null;
95          this.rawContext = rawContext;
96          this.jaxbObject = jaxbObject;
97      }
98  
99      public JAXBDispatchMessage(BindingContext context, Object jaxbObject, SOAPVersion soapVersion) {
100         super(soapVersion);
101         this.bridge = context.createFragmentBridge();
102         this.rawContext = null;
103         this.jaxbObject = jaxbObject;
104     }
105 
106     @Override
107     protected void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException {
108         throw new UnsupportedOperationException();
109     }
110 
111     @Override
112     public boolean hasHeaders() {
113         return false;
114     }
115 
116     @Override
117     public MessageHeaders getHeaders() {
118         return null;
119     }
120 
121     @Override
122     public String getPayloadLocalPart() {
123         if (payloadQName == null) {
124             readPayloadElement();
125         }
126         return payloadQName.getLocalPart();
127     }
128 
129     @Override
130     public String getPayloadNamespaceURI() {
131         if (payloadQName == null) {
132             readPayloadElement();
133         }
134         return payloadQName.getNamespaceURI();
135     }
136 
137     private void readPayloadElement() {
138         PayloadElementSniffer sniffer = new PayloadElementSniffer();
139         try {
140             if (rawContext != null) {
141                 Marshaller m = rawContext.createMarshaller();
142                 m.setProperty("jaxb.fragment", Boolean.FALSE);
143                 m.marshal(jaxbObject, sniffer);
144             } else {
145                 bridge.marshal(jaxbObject, sniffer, null);
146             }
147 
148         } catch (JAXBException e) {
149             // if it's due to us aborting the processing after the first element,
150             // we can safely ignore this exception.
151             //
152             // if it's due to error in the object, the same error will be reported
153             // when the readHeader() method is used, so we don't have to report
154             // an error right now.
155             payloadQName = sniffer.getPayloadQName();
156         }
157     }
158 
159     @Override
160     public boolean hasPayload() {
161         return true;
162     }
163 
164     @Override
165     public Source readPayloadAsSource() {
166         throw new UnsupportedOperationException();
167     }
168 
169     @Override
170     public XMLStreamReader readPayload() throws XMLStreamException {
171         throw new UnsupportedOperationException();
172     }
173 
174     @Override
175     public void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException {
176         throw new UnsupportedOperationException();
177     }
178 
179     @Override
180     public Message copy() {
181         return new JAXBDispatchMessage(this);
182     }
183 
184     @Override
185     @SuppressWarnings("unchecked")
186     public void writeTo(XMLStreamWriter sw) throws XMLStreamException {
187         try {
188             // MtomCodec sets its own AttachmentMarshaller
189             AttachmentMarshaller am = (sw instanceof MtomStreamWriter)
190                     ? ((MtomStreamWriter) sw).getAttachmentMarshaller()
191                     : new AttachmentMarshallerImpl(attachmentSet);
192 
193             // Get the encoding of the writer
194             String encoding = XMLStreamWriterUtil.getEncoding(sw);
195 
196             // Get output stream and use JAXB UTF-8 writer
197             OutputStream os = bridge.supportOutputStream() ? XMLStreamWriterUtil.getOutputStream(sw) : null;
198             if (rawContext != null) {
199                 Marshaller m = rawContext.createMarshaller();
200                 m.setProperty("jaxb.fragment", Boolean.FALSE);
201                 m.setAttachmentMarshaller(am);
202                 if (os != null) {
203                     m.marshal(jaxbObject, os);
204                 } else {
205                     m.marshal(jaxbObject, sw);
206                 }
207 
208             } else {
209 
210                 if (os != null && encoding != null && encoding.equalsIgnoreCase(SOAPBindingCodec.UTF8_ENCODING)) {
211                     bridge.marshal(jaxbObject, os, sw.getNamespaceContext(), am);
212                 } else {
213                     bridge.marshal(jaxbObject, sw, am);
214                 }
215             }
216             //cleanup() is not needed since JAXB doesn't keep ref to AttachmentMarshaller
217         } catch (JAXBException e) {
218             // bug 6449684, spec 4.3.4
219             throw new WebServiceException(e);
220         }
221     }
222 }