Thu, 31 Aug 2017 15:18:52 +0800
merge
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 */
26 package com.sun.xml.internal.ws.api.message;
28 import com.sun.istack.internal.NotNull;
29 import com.sun.istack.internal.Nullable;
30 import com.sun.xml.internal.stream.buffer.XMLStreamBuffer;
31 import com.sun.xml.internal.ws.api.SOAPVersion;
32 import com.sun.xml.internal.ws.api.WSBinding;
33 import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
34 import com.sun.xml.internal.ws.api.message.saaj.SAAJFactory;
35 import com.sun.xml.internal.ws.api.pipe.Tube;
36 import com.sun.xml.internal.ws.api.pipe.Codecs;
37 import com.sun.xml.internal.ws.fault.SOAPFaultBuilder;
38 import com.sun.xml.internal.ws.message.AttachmentSetImpl;
39 import com.sun.xml.internal.ws.message.DOMMessage;
40 import com.sun.xml.internal.ws.message.EmptyMessageImpl;
41 import com.sun.xml.internal.ws.message.ProblemActionHeader;
42 import com.sun.xml.internal.ws.message.stream.PayloadStreamReaderMessage;
43 import com.sun.xml.internal.ws.message.jaxb.JAXBMessage;
44 import com.sun.xml.internal.ws.message.source.PayloadSourceMessage;
45 import com.sun.xml.internal.ws.message.source.ProtocolSourceMessage;
46 import com.sun.xml.internal.ws.spi.db.BindingContextFactory;
47 import com.sun.xml.internal.ws.streaming.XMLStreamReaderException;
48 import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil;
49 import com.sun.xml.internal.ws.util.DOMUtil;
50 import com.sun.xml.internal.ws.addressing.WsaTubeHelper;
51 import com.sun.xml.internal.ws.addressing.model.MissingAddressingHeaderException;
52 import com.sun.xml.internal.ws.resources.AddressingMessages;
53 import org.w3c.dom.Element;
54 import org.w3c.dom.Node;
56 import javax.xml.bind.JAXBContext;
57 import javax.xml.bind.JAXBElement;
58 import javax.xml.bind.Marshaller;
59 import javax.xml.bind.annotation.XmlRootElement;
60 import javax.xml.namespace.QName;
61 import javax.xml.soap.*;
62 import javax.xml.stream.XMLStreamConstants;
63 import javax.xml.stream.XMLStreamException;
64 import javax.xml.stream.XMLStreamReader;
65 import javax.xml.transform.Source;
66 import javax.xml.transform.sax.SAXSource;
67 import javax.xml.transform.stream.StreamSource;
68 import javax.xml.transform.dom.DOMSource;
69 import javax.xml.ws.ProtocolException;
70 import javax.xml.ws.WebServiceException;
72 /**
73 * Factory methods for various {@link Message} implementations.
74 *
75 * <p>
76 * This class provides various methods to create different
77 * flavors of {@link Message} classes that store data
78 * in different formats.
79 *
80 * <p>
81 * This is a part of the JAX-WS RI internal API so that
82 * {@link Tube} implementations can reuse the implementations
83 * done inside the JAX-WS.
84 *
85 * <p>
86 * If you find some of the useful convenience methods missing
87 * from this class, please talk to us.
88 *
89 *
90 * @author Kohsuke Kawaguchi
91 */
92 public abstract class Messages {
93 private Messages() {}
95 /**
96 * Creates a {@link Message} backed by a JAXB bean.
97 * @deprecated
98 * @param context
99 * The context to be used to produce infoset from the object. Must not be null.
100 * @param jaxbObject
101 * The JAXB object that represents the payload. must not be null. This object
102 * must be bound to an element (which means it either is a {@link JAXBElement} or
103 * an instanceof a class with {@link XmlRootElement}).
104 * @param soapVersion
105 * The SOAP version of the message. Must not be null.
106 */
107 public static Message create(JAXBContext context, Object jaxbObject, SOAPVersion soapVersion) {
108 return JAXBMessage.create(context,jaxbObject,soapVersion);
109 }
111 /**
112 * @deprecated
113 * For use when creating a Dispatch object with an unknown JAXB implementation
114 * for he JAXBContext parameter.
115 *
116 */
117 public static Message createRaw(JAXBContext context, Object jaxbObject, SOAPVersion soapVersion) {
118 return JAXBMessage.createRaw(context,jaxbObject,soapVersion);
119 }
121 /**
122 * @deprecated
123 * Use {@link #create(JAXBRIContext, Object, SOAPVersion)}
124 */
125 public static Message create(Marshaller marshaller, Object jaxbObject, SOAPVersion soapVersion) {
126 return create(BindingContextFactory.getBindingContext(marshaller).getJAXBContext(),jaxbObject,soapVersion);
127 }
129 /**
130 * Creates a {@link Message} backed by a SAAJ {@link SOAPMessage} object.
131 *
132 * <p>
133 * If the {@link SOAPMessage} contains headers and attachments, this method
134 * does the right thing.
135 *
136 * @param saaj
137 * The SOAP message to be represented as a {@link Message}.
138 * Must not be null. Once this method is invoked, the created
139 * {@link Message} will own the {@link SOAPMessage}, so it shall
140 * never be touched directly.
141 */
142 public static Message create(SOAPMessage saaj) {
143 return SAAJFactory.create(saaj);
144 }
146 /**
147 * Creates a {@link Message} using {@link Source} as payload.
148 *
149 * @param payload
150 * Source payload is {@link Message}'s payload
151 * Must not be null. Once this method is invoked, the created
152 * {@link Message} will own the {@link Source}, so it shall
153 * never be touched directly.
154 *
155 * @param ver
156 * The SOAP version of the message. Must not be null.
157 */
158 public static Message createUsingPayload(Source payload, SOAPVersion ver) {
159 if (payload instanceof DOMSource) {
160 if (((DOMSource)payload).getNode() == null) {
161 return new EmptyMessageImpl(ver);
162 }
163 } else if (payload instanceof StreamSource) {
164 StreamSource ss = (StreamSource)payload;
165 if (ss.getInputStream() == null && ss.getReader() == null && ss.getSystemId() == null) {
166 return new EmptyMessageImpl(ver);
167 }
168 } else if (payload instanceof SAXSource) {
169 SAXSource ss = (SAXSource)payload;
170 if (ss.getInputSource() == null && ss.getXMLReader() == null) {
171 return new EmptyMessageImpl(ver);
172 }
173 }
174 return new PayloadSourceMessage(payload, ver);
175 }
177 /**
178 * Creates a {@link Message} using {@link XMLStreamReader} as payload.
179 *
180 * @param payload
181 * XMLStreamReader payload is {@link Message}'s payload
182 * Must not be null. Once this method is invoked, the created
183 * {@link Message} will own the {@link XMLStreamReader}, so it shall
184 * never be touched directly.
185 *
186 * @param ver
187 * The SOAP version of the message. Must not be null.
188 */
189 public static Message createUsingPayload(XMLStreamReader payload, SOAPVersion ver) {
190 return new PayloadStreamReaderMessage(payload, ver);
191 }
193 /**
194 * Creates a {@link Message} from an {@link Element} that represents
195 * a payload.
196 *
197 * @param payload
198 * The element that becomes the child element of the SOAP body.
199 * Must not be null.
200 *
201 * @param ver
202 * The SOAP version of the message. Must not be null.
203 */
204 public static Message createUsingPayload(Element payload, SOAPVersion ver) {
205 return new DOMMessage(ver,payload);
206 }
208 /**
209 * Creates a {@link Message} from an {@link Element} that represents
210 * the whole SOAP message.
211 *
212 * @param soapEnvelope
213 * The SOAP envelope element.
214 */
215 public static Message create(Element soapEnvelope) {
216 SOAPVersion ver = SOAPVersion.fromNsUri(soapEnvelope.getNamespaceURI());
217 // find the headers
218 Element header = DOMUtil.getFirstChild(soapEnvelope, ver.nsUri, "Header");
219 HeaderList headers = null;
220 if(header!=null) {
221 for( Node n=header.getFirstChild(); n!=null; n=n.getNextSibling() ) {
222 if(n.getNodeType()==Node.ELEMENT_NODE) {
223 if(headers==null)
224 headers = new HeaderList(ver);
225 headers.add(Headers.create((Element)n));
226 }
227 }
228 }
230 // find the payload
231 Element body = DOMUtil.getFirstChild(soapEnvelope, ver.nsUri, "Body");
232 if(body==null)
233 throw new WebServiceException("Message doesn't have <S:Body> "+soapEnvelope);
234 Element payload = DOMUtil.getFirstChild(soapEnvelope, ver.nsUri, "Body");
236 if(payload==null) {
237 return new EmptyMessageImpl(headers, new AttachmentSetImpl(), ver);
238 } else {
239 return new DOMMessage(ver,headers,payload);
240 }
241 }
243 /**
244 * Creates a {@link Message} using Source as entire envelope.
245 *
246 * @param envelope
247 * Source envelope is used to create {@link Message}
248 * Must not be null. Once this method is invoked, the created
249 * {@link Message} will own the {@link Source}, so it shall
250 * never be touched directly.
251 *
252 */
253 public static Message create(Source envelope, SOAPVersion soapVersion) {
254 return new ProtocolSourceMessage(envelope, soapVersion);
255 }
258 /**
259 * Creates a {@link Message} that doesn't have any payload.
260 */
261 public static Message createEmpty(SOAPVersion soapVersion) {
262 return new EmptyMessageImpl(soapVersion);
263 }
265 /**
266 * Creates a {@link Message} from {@link XMLStreamReader} that points to
267 * the start of the envelope.
268 *
269 * @param reader
270 * can point to the start document or the start element (of <s:Envelope>)
271 */
272 public static @NotNull Message create(@NotNull XMLStreamReader reader) {
273 // skip until the root element
274 if(reader.getEventType()!=XMLStreamConstants.START_ELEMENT)
275 XMLStreamReaderUtil.nextElementContent(reader);
276 assert reader.getEventType()== XMLStreamConstants.START_ELEMENT :reader.getEventType();
278 SOAPVersion ver = SOAPVersion.fromNsUri(reader.getNamespaceURI());
280 return Codecs.createSOAPEnvelopeXmlCodec(ver).decode(reader);
281 }
283 /**
284 * Creates a {@link Message} from {@link XMLStreamBuffer} that retains the
285 * whole envelope infoset.
286 *
287 * @param xsb
288 * This buffer must contain the infoset of the whole envelope.
289 */
290 public static @NotNull Message create(@NotNull XMLStreamBuffer xsb) {
291 // TODO: we should be able to let Messae know that it's working off from a buffer,
292 // to make some of the operations more efficient.
293 // meanwhile, adding this as an API so that our users can take advantage of it
294 // when we get around to such an implementation later.
295 try {
296 return create(xsb.readAsXMLStreamReader());
297 } catch (XMLStreamException e) {
298 throw new XMLStreamReaderException(e);
299 }
300 }
302 /**
303 * Creates a {@link Message} that represents an exception as a fault. The
304 * created message reflects if t or t.getCause() is SOAPFaultException.
305 *
306 * creates a fault message with default faultCode env:Server if t or t.getCause()
307 * is not SOAPFaultException. Otherwise, it use SOAPFaultException's faultCode
308 *
309 * @return
310 * Always non-null. A message that wraps this {@link Throwable}.
311 *
312 */
313 public static Message create(Throwable t, SOAPVersion soapVersion) {
314 return SOAPFaultBuilder.createSOAPFaultMessage(soapVersion, null, t);
315 }
317 /**
318 * Creates a fault {@link Message}.
319 *
320 * <p>
321 * This method is not designed for efficiency, and we don't expect
322 * to be used for the performance critical codepath.
323 *
324 * @param fault
325 * The populated SAAJ data structure that represents a fault
326 * in detail.
327 *
328 * @return
329 * Always non-null. A message that wraps this {@link SOAPFault}.
330 */
331 public static Message create(SOAPFault fault) {
332 SOAPVersion ver = SOAPVersion.fromNsUri(fault.getNamespaceURI());
333 return new DOMMessage(ver,fault);
334 }
336 /**
337 * @deprecated
338 * Use {@link #createAddressingFaultMessage(WSBinding, Packet, QName)}
339 */
340 public static Message createAddressingFaultMessage(WSBinding binding, QName missingHeader) {
341 return createAddressingFaultMessage(binding,null,missingHeader);
342 }
344 /**
345 * Creates a fault {@link Message} that captures the code/subcode/subsubcode
346 * defined by WS-Addressing if one of the expected WS-Addressing headers is
347 * missing in the message
348 *
349 * @param binding WSBinding
350 * @param p
351 * {@link Packet} that was missing a WS-Addressing header.
352 * @param missingHeader The missing WS-Addressing Header
353 * @return
354 * A message representing SOAPFault that contains the WS-Addressing code/subcode/subsubcode.
355 */
356 public static Message createAddressingFaultMessage(WSBinding binding, Packet p, QName missingHeader) {
357 AddressingVersion av = binding.getAddressingVersion();
358 if(av == null) {
359 // Addressing is not enabled.
360 throw new WebServiceException(AddressingMessages.ADDRESSING_SHOULD_BE_ENABLED());
361 }
362 WsaTubeHelper helper = av.getWsaHelper(null,null,binding);
363 return create(helper.newMapRequiredFault(new MissingAddressingHeaderException(missingHeader,p)));
364 }
365 /**
366 * Creates a fault {@link Message} that captures the code/subcode/subsubcode
367 * defined by WS-Addressing if wsa:Action is not supported.
368 *
369 * @param unsupportedAction The unsupported Action. Must not be null.
370 * @param av The WS-Addressing version of the message. Must not be null.
371 * @param sv The SOAP Version of the message. Must not be null.
372 *
373 * @return
374 * A message representing SOAPFault that contains the WS-Addressing code/subcode/subsubcode.
375 */
376 public static Message create(@NotNull String unsupportedAction, @NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
377 QName subcode = av.actionNotSupportedTag;
378 String faultstring = String.format(av.actionNotSupportedText, unsupportedAction);
380 Message faultMessage;
381 SOAPFault fault;
382 try {
383 if (sv == SOAPVersion.SOAP_12) {
384 fault = SOAPVersion.SOAP_12.getSOAPFactory().createFault();
385 fault.setFaultCode(SOAPConstants.SOAP_SENDER_FAULT);
386 fault.appendFaultSubcode(subcode);
387 Detail detail = fault.addDetail();
388 SOAPElement se = detail.addChildElement(av.problemActionTag);
389 se = se.addChildElement(av.actionTag);
390 se.addTextNode(unsupportedAction);
391 } else {
392 fault = SOAPVersion.SOAP_11.getSOAPFactory().createFault();
393 fault.setFaultCode(subcode);
394 }
395 fault.setFaultString(faultstring);
397 faultMessage = SOAPFaultBuilder.createSOAPFaultMessage(sv, fault);
398 if (sv == SOAPVersion.SOAP_11) {
399 faultMessage.getHeaders().add(new ProblemActionHeader(unsupportedAction, av));
400 }
401 } catch (SOAPException e) {
402 throw new WebServiceException(e);
403 }
405 return faultMessage;
406 }
408 /**
409 * To be called to convert a {@link ProtocolException} and faultcode for a given {@link SOAPVersion} in to a {@link Message}.
410 *
411 * @param soapVersion {@link SOAPVersion#SOAP_11} or {@link SOAPVersion#SOAP_12}
412 * @param pex a ProtocolException
413 * @param faultcode soap faultcode. Its ignored if the {@link ProtocolException} instance is {@link javax.xml.ws.soap.SOAPFaultException} and it has a
414 * faultcode present in the underlying {@link SOAPFault}.
415 * @return {@link Message} representing SOAP fault
416 */
417 public static @NotNull Message create(@NotNull SOAPVersion soapVersion, @NotNull ProtocolException pex, @Nullable QName faultcode){
418 return SOAPFaultBuilder.createSOAPFaultMessage(soapVersion, pex, faultcode);
419 }
420 }