001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.ws.api.message;
038:
039: import com.sun.istack.NotNull;
040: import com.sun.istack.Nullable;
041: import com.sun.xml.bind.api.JAXBRIContext;
042: import com.sun.xml.bind.v2.runtime.MarshallerImpl;
043: import com.sun.xml.stream.buffer.XMLStreamBuffer;
044: import com.sun.xml.ws.api.SOAPVersion;
045: import com.sun.xml.ws.api.addressing.AddressingVersion;
046: import com.sun.xml.ws.api.pipe.Tube;
047: import com.sun.xml.ws.api.pipe.Codecs;
048: import com.sun.xml.ws.encoding.StreamSOAPCodec;
049: import com.sun.xml.ws.fault.SOAPFaultBuilder;
050: import com.sun.xml.ws.message.AttachmentSetImpl;
051: import com.sun.xml.ws.message.DOMMessage;
052: import com.sun.xml.ws.message.EmptyMessageImpl;
053: import com.sun.xml.ws.message.ProblemActionHeader;
054: import com.sun.xml.ws.message.stream.PayloadStreamReaderMessage;
055: import com.sun.xml.ws.message.jaxb.JAXBMessage;
056: import com.sun.xml.ws.message.saaj.SAAJMessage;
057: import com.sun.xml.ws.message.source.PayloadSourceMessage;
058: import com.sun.xml.ws.message.source.ProtocolSourceMessage;
059: import com.sun.xml.ws.streaming.XMLStreamReaderException;
060: import com.sun.xml.ws.streaming.XMLStreamReaderUtil;
061: import com.sun.xml.ws.util.DOMUtil;
062: import org.w3c.dom.Element;
063: import org.w3c.dom.Node;
064:
065: import javax.xml.bind.JAXBElement;
066: import javax.xml.bind.Marshaller;
067: import javax.xml.bind.annotation.XmlRootElement;
068: import javax.xml.namespace.QName;
069: import javax.xml.soap.*;
070: import javax.xml.stream.XMLStreamConstants;
071: import javax.xml.stream.XMLStreamException;
072: import javax.xml.stream.XMLStreamReader;
073: import javax.xml.transform.Source;
074: import javax.xml.ws.ProtocolException;
075: import javax.xml.ws.WebServiceException;
076:
077: /**
078: * Factory methods for various {@link Message} implementations.
079: *
080: * <p>
081: * This class provides various methods to create different
082: * flavors of {@link Message} classes that store data
083: * in different formats.
084: *
085: * <p>
086: * This is a part of the JAX-WS RI internal API so that
087: * {@link Tube} implementations can reuse the implementations
088: * done inside the JAX-WS.
089: *
090: * <p>
091: * If you find some of the useful convenience methods missing
092: * from this class, please talk to us.
093: *
094: *
095: * @author Kohsuke Kawaguchi
096: */
097: public abstract class Messages {
098: private Messages() {
099: }
100:
101: /**
102: * Creates a {@link Message} backed by a JAXB bean.
103: *
104: * @param context
105: * The context to be used to produce infoset from the object. Must not be null.
106: * @param jaxbObject
107: * The JAXB object that represents the payload. must not be null. This object
108: * must be bound to an element (which means it either is a {@link JAXBElement} or
109: * an instanceof a class with {@link XmlRootElement}).
110: * @param soapVersion
111: * The SOAP version of the message. Must not be null.
112: */
113: public static Message create(JAXBRIContext context,
114: Object jaxbObject, SOAPVersion soapVersion) {
115: return JAXBMessage.create(context, jaxbObject, soapVersion);
116: }
117:
118: /**
119: * @deprecated
120: * Use {@link #create(JAXBRIContext, Object, SOAPVersion)}
121: */
122: public static Message create(Marshaller marshaller,
123: Object jaxbObject, SOAPVersion soapVersion) {
124: return create(((MarshallerImpl) marshaller).getContext(),
125: jaxbObject, soapVersion);
126: }
127:
128: /**
129: * Creates a {@link Message} backed by a SAAJ {@link SOAPMessage} object.
130: *
131: * <p>
132: * If the {@link SOAPMessage} contains headers and attachments, this method
133: * does the right thing.
134: *
135: * @param saaj
136: * The SOAP message to be represented as a {@link Message}.
137: * Must not be null. Once this method is invoked, the created
138: * {@link Message} will own the {@link SOAPMessage}, so it shall
139: * never be touched directly.
140: */
141: public static Message create(SOAPMessage saaj) {
142: return new SAAJMessage(saaj);
143: }
144:
145: /**
146: * Creates a {@link Message} using {@link Source} as payload.
147: *
148: * @param payload
149: * Source payload is {@link Message}'s payload
150: * Must not be null. Once this method is invoked, the created
151: * {@link Message} will own the {@link Source}, so it shall
152: * never be touched directly.
153: *
154: * @param ver
155: * The SOAP version of the message. Must not be null.
156: */
157: public static Message createUsingPayload(Source payload,
158: SOAPVersion ver) {
159: return new PayloadSourceMessage(payload, ver);
160: }
161:
162: /**
163: * Creates a {@link Message} using {@link XMLStreamReader} as payload.
164: *
165: * @param payload
166: * XMLStreamReader payload is {@link Message}'s payload
167: * Must not be null. Once this method is invoked, the created
168: * {@link Message} will own the {@link XMLStreamReader}, so it shall
169: * never be touched directly.
170: *
171: * @param ver
172: * The SOAP version of the message. Must not be null.
173: */
174: public static Message createUsingPayload(XMLStreamReader payload,
175: SOAPVersion ver) {
176: return new PayloadStreamReaderMessage(payload, ver);
177: }
178:
179: /**
180: * Creates a {@link Message} from an {@link Element} that represents
181: * a payload.
182: *
183: * @param payload
184: * The element that becomes the child element of the SOAP body.
185: * Must not be null.
186: *
187: * @param ver
188: * The SOAP version of the message. Must not be null.
189: */
190: public static Message createUsingPayload(Element payload,
191: SOAPVersion ver) {
192: return new DOMMessage(ver, payload);
193: }
194:
195: /**
196: * Creates a {@link Message} from an {@link Element} that represents
197: * the whole SOAP message.
198: *
199: * @param soapEnvelope
200: * The SOAP envelope element.
201: */
202: public static Message create(Element soapEnvelope) {
203: SOAPVersion ver = SOAPVersion.fromNsUri(soapEnvelope
204: .getNamespaceURI());
205: // find the headers
206: Element header = DOMUtil.getFirstChild(soapEnvelope, ver.nsUri,
207: "Header");
208: HeaderList headers = null;
209: if (header != null) {
210: for (Node n = header.getFirstChild(); n != null; n = n
211: .getNextSibling()) {
212: if (n.getNodeType() == Node.ELEMENT_NODE) {
213: if (headers == null)
214: headers = new HeaderList();
215: headers.add(Headers.create((Element) n));
216: }
217: }
218: }
219:
220: // find the payload
221: Element body = DOMUtil.getFirstChild(soapEnvelope, ver.nsUri,
222: "Body");
223: if (body == null)
224: throw new WebServiceException(
225: "Message doesn't have <S:Body> " + soapEnvelope);
226: Element payload = DOMUtil.getFirstChild(soapEnvelope,
227: ver.nsUri, "Body");
228:
229: if (payload == null) {
230: return new EmptyMessageImpl(headers,
231: new AttachmentSetImpl(), ver);
232: } else {
233: return new DOMMessage(ver, headers, payload);
234: }
235: }
236:
237: /**
238: * Creates a {@link Message} using Source as entire envelope.
239: *
240: * @param envelope
241: * Source envelope is used to create {@link Message}
242: * Must not be null. Once this method is invoked, the created
243: * {@link Message} will own the {@link Source}, so it shall
244: * never be touched directly.
245: *
246: */
247: public static Message create(Source envelope,
248: SOAPVersion soapVersion) {
249: return new ProtocolSourceMessage(envelope, soapVersion);
250: }
251:
252: /**
253: * Creates a {@link Message} that doesn't have any payload.
254: */
255: public static Message createEmpty(SOAPVersion soapVersion) {
256: return new EmptyMessageImpl(soapVersion);
257: }
258:
259: /**
260: * Creates a {@link Message} from {@link XMLStreamReader} that points to
261: * the start of the envelope.
262: *
263: * @param reader
264: * can point to the start document or the start element (of <s:Envelope>)
265: */
266: public static @NotNull
267: Message create(@NotNull
268: XMLStreamReader reader) {
269: // skip until the root element
270: if (reader.getEventType() != XMLStreamConstants.START_ELEMENT)
271: XMLStreamReaderUtil.nextElementContent(reader);
272: assert reader.getEventType() == XMLStreamConstants.START_ELEMENT : reader
273: .getEventType();
274:
275: SOAPVersion ver = SOAPVersion.fromNsUri(reader
276: .getNamespaceURI());
277:
278: return Codecs.createSOAPEnvelopeXmlCodec(ver).decode(reader);
279: }
280:
281: /**
282: * Creates a {@link Message} from {@link XMLStreamBuffer} that retains the
283: * whole envelope infoset.
284: *
285: * @param xsb
286: * This buffer must contain the infoset of the whole envelope.
287: */
288: public static @NotNull
289: Message create(@NotNull
290: 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,
315: null, t);
316: }
317:
318: /**
319: * Creates a fault {@link Message}.
320: *
321: * <p>
322: * This method is not designed for efficiency, and we don't expect
323: * to be used for the performance critical codepath.
324: *
325: * @param fault
326: * The populated SAAJ data structure that represents a fault
327: * in detail.
328: *
329: * @return
330: * Always non-null. A message that wraps this {@link SOAPFault}.
331: */
332: public static Message create(SOAPFault fault) {
333: SOAPVersion ver = SOAPVersion
334: .fromNsUri(fault.getNamespaceURI());
335: return new DOMMessage(ver, fault);
336: }
337:
338: /**
339: * Creates a fault {@link Message} that captures the code/subcode/subsubcode
340: * defined by WS-Addressing if wsa:Action is not supported.
341: *
342: * @param unsupportedAction The unsupported Action. Must not be null.
343: * @param av The WS-Addressing version of the message. Must not be null.
344: * @param sv The SOAP Version of the message. Must not be null.
345: *
346: * @return
347: * A message representing SOAPFault that contains the WS-Addressing code/subcode/subsubcode.
348: */
349: public static Message create(@NotNull
350: String unsupportedAction, @NotNull
351: AddressingVersion av, @NotNull
352: SOAPVersion sv) {
353: QName subcode = av.actionNotSupportedTag;
354: String faultstring = String.format(av.actionNotSupportedText,
355: unsupportedAction);
356:
357: Message faultMessage;
358: SOAPFault fault;
359: try {
360: if (sv == SOAPVersion.SOAP_12) {
361: fault = SOAPVersion.SOAP_12.saajSoapFactory
362: .createFault();
363: fault.setFaultCode(SOAPConstants.SOAP_SENDER_FAULT);
364: fault.appendFaultSubcode(subcode);
365: Detail detail = fault.addDetail();
366: SOAPElement se = detail
367: .addChildElement(av.problemActionTag);
368: se = se.addChildElement(av.actionTag);
369: se.addTextNode(unsupportedAction);
370: } else {
371: fault = SOAPVersion.SOAP_11.saajSoapFactory
372: .createFault();
373: fault.setFaultCode(subcode);
374: }
375: fault.setFaultString(faultstring);
376:
377: faultMessage = SOAPFaultBuilder.createSOAPFaultMessage(sv,
378: fault);
379: if (sv == SOAPVersion.SOAP_11) {
380: faultMessage.getHeaders().add(
381: new ProblemActionHeader(unsupportedAction, av));
382: }
383: } catch (SOAPException e) {
384: throw new WebServiceException(e);
385: }
386:
387: return faultMessage;
388: }
389:
390: /**
391: * To be called to convert a {@link ProtocolException} and faultcode for a given {@link SOAPVersion} in to a {@link Message}.
392: *
393: * @param soapVersion {@link SOAPVersion#SOAP_11} or {@link SOAPVersion#SOAP_12}
394: * @param pex a ProtocolException
395: * @param faultcode soap faultcode. Its ignored if the {@link ProtocolException} instance is {@link javax.xml.ws.soap.SOAPFaultException} and it has a
396: * faultcode present in the underlying {@link SOAPFault}.
397: * @return {@link Message} representing SOAP fault
398: */
399: public static @NotNull
400: Message create(@NotNull
401: SOAPVersion soapVersion, @NotNull
402: ProtocolException pex, @Nullable
403: QName faultcode) {
404: return SOAPFaultBuilder.createSOAPFaultMessage(soapVersion,
405: pex, faultcode);
406: }
407: }
|