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 26package com.sun.xml.internal.ws.api.message; 27 28import com.sun.istack.internal.NotNull; 29import com.sun.istack.internal.Nullable; 30import com.sun.xml.internal.stream.buffer.XMLStreamBuffer; 31import com.sun.xml.internal.ws.api.SOAPVersion; 32import com.sun.xml.internal.ws.api.WSBinding; 33import com.sun.xml.internal.ws.api.addressing.AddressingVersion; 34import com.sun.xml.internal.ws.api.message.saaj.SAAJFactory; 35import com.sun.xml.internal.ws.api.pipe.Tube; 36import com.sun.xml.internal.ws.api.pipe.Codecs; 37import com.sun.xml.internal.ws.fault.SOAPFaultBuilder; 38import com.sun.xml.internal.ws.message.AttachmentSetImpl; 39import com.sun.xml.internal.ws.message.DOMMessage; 40import com.sun.xml.internal.ws.message.EmptyMessageImpl; 41import com.sun.xml.internal.ws.message.ProblemActionHeader; 42import com.sun.xml.internal.ws.message.stream.PayloadStreamReaderMessage; 43import com.sun.xml.internal.ws.message.jaxb.JAXBMessage; 44import com.sun.xml.internal.ws.message.source.PayloadSourceMessage; 45import com.sun.xml.internal.ws.message.source.ProtocolSourceMessage; 46import com.sun.xml.internal.ws.spi.db.BindingContextFactory; 47import com.sun.xml.internal.ws.streaming.XMLStreamReaderException; 48import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil; 49import com.sun.xml.internal.ws.util.DOMUtil; 50import com.sun.xml.internal.ws.addressing.WsaTubeHelper; 51import com.sun.xml.internal.ws.addressing.model.MissingAddressingHeaderException; 52import com.sun.xml.internal.ws.resources.AddressingMessages; 53import org.w3c.dom.Element; 54import org.w3c.dom.Node; 55 56import javax.xml.bind.JAXBContext; 57import javax.xml.bind.JAXBElement; 58import javax.xml.bind.Marshaller; 59import javax.xml.bind.annotation.XmlRootElement; 60import javax.xml.namespace.QName; 61import javax.xml.soap.*; 62import javax.xml.stream.XMLStreamConstants; 63import javax.xml.stream.XMLStreamException; 64import javax.xml.stream.XMLStreamReader; 65import javax.xml.transform.Source; 66import javax.xml.transform.sax.SAXSource; 67import javax.xml.transform.stream.StreamSource; 68import javax.xml.transform.dom.DOMSource; 69import javax.xml.ws.ProtocolException; 70import javax.xml.ws.WebServiceException; 71 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 */ 92public abstract class Messages { 93 private Messages() {} 94 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 } 110 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 } 120 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 } 128 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 } 145 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 } 176 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 } 192 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 } 207 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 } 229 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"); 235 236 if(payload==null) { 237 return new EmptyMessageImpl(headers, new AttachmentSetImpl(), ver); 238 } else { 239 return new DOMMessage(ver,headers,payload); 240 } 241 } 242 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 } 256 257 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 } 264 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(); 277 278 SOAPVersion ver = SOAPVersion.fromNsUri(reader.getNamespaceURI()); 279 280 return Codecs.createSOAPEnvelopeXmlCodec(ver).decode(reader); 281 } 282 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 } 301 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 } 316 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 } 335 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 } 343 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); 379 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); 396 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 } 404 405 return faultMessage; 406 } 407 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} 421