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: package com.sun.xml.ws.message;
037:
038: import com.sun.xml.bind.api.Bridge;
039: import com.sun.xml.bind.marshaller.SAX2DOMEx;
040: import com.sun.xml.ws.api.SOAPVersion;
041: import com.sun.xml.ws.api.message.Attachment;
042: import com.sun.xml.ws.api.message.HeaderList;
043: import com.sun.xml.ws.api.message.Message;
044: import com.sun.xml.ws.api.message.Packet;
045: import com.sun.xml.ws.util.xml.XmlUtil;
046: import javax.xml.soap.AttachmentPart;
047: import org.xml.sax.ContentHandler;
048: import org.xml.sax.ErrorHandler;
049: import org.xml.sax.SAXException;
050: import org.xml.sax.helpers.AttributesImpl;
051: import org.xml.sax.helpers.LocatorImpl;
052:
053: import javax.xml.bind.JAXBException;
054: import javax.xml.bind.Unmarshaller;
055: import javax.xml.soap.SOAPException;
056: import javax.xml.soap.SOAPMessage;
057: import javax.xml.soap.MimeHeader;
058: import javax.xml.stream.XMLStreamException;
059: import javax.xml.stream.XMLStreamWriter;
060: import javax.xml.transform.Source;
061: import javax.xml.transform.sax.SAXSource;
062: import java.util.List;
063: import java.util.Map;
064:
065: /**
066: * Partial {@link Message} implementation.
067: *
068: * <p>
069: * This class implements some of the {@link Message} methods.
070: * The idea is that those implementations may be non-optimal but
071: * it may save effort in implementing {@link Message} and reduce
072: * the code size.
073: *
074: * <p>
075: * {@link Message} classes that are used more commonly should
076: * examine carefully which method can be implemented faster,
077: * and override them accordingly.
078: *
079: * @author Kohsuke Kawaguchi
080: */
081: public abstract class AbstractMessageImpl extends Message {
082: /**
083: * SOAP version of this message.
084: * Used to implement some of the methods, but nothing more than that.
085: *
086: * <p>
087: * So if you aren't using those methods that use this field,
088: * this can be null.
089: */
090: protected final SOAPVersion soapVersion;
091:
092: protected AbstractMessageImpl(SOAPVersion soapVersion) {
093: this .soapVersion = soapVersion;
094: }
095:
096: /**
097: * Copy constructor.
098: */
099: protected AbstractMessageImpl(AbstractMessageImpl that) {
100: this .soapVersion = that.soapVersion;
101: }
102:
103: public Source readEnvelopeAsSource() {
104: return new SAXSource(new XMLReaderImpl(this ),
105: XMLReaderImpl.THE_SOURCE);
106: }
107:
108: public <T> T readPayloadAsJAXB(Unmarshaller unmarshaller)
109: throws JAXBException {
110: if (hasAttachments())
111: unmarshaller
112: .setAttachmentUnmarshaller(new AttachmentUnmarshallerImpl(
113: getAttachments()));
114: try {
115: return (T) unmarshaller.unmarshal(readPayloadAsSource());
116: } finally {
117: unmarshaller.setAttachmentUnmarshaller(null);
118: }
119: }
120:
121: public <T> T readPayloadAsJAXB(Bridge<T> bridge)
122: throws JAXBException {
123: return bridge.unmarshal(readPayloadAsSource(),
124: hasAttachments() ? new AttachmentUnmarshallerImpl(
125: getAttachments()) : null);
126: }
127:
128: /**
129: * Default implementation that relies on {@link #writePayloadTo(XMLStreamWriter)}
130: */
131: public void writeTo(XMLStreamWriter w) throws XMLStreamException {
132: String soapNsUri = soapVersion.nsUri;
133: w.writeStartDocument();
134: w.writeStartElement("S", "Envelope", soapNsUri);
135: w.writeNamespace("S", soapNsUri);
136: if (hasHeaders()) {
137: w.writeStartElement("S", "Header", soapNsUri);
138: HeaderList headers = getHeaders();
139: int len = headers.size();
140: for (int i = 0; i < len; i++) {
141: headers.get(i).writeTo(w);
142: }
143: w.writeEndElement();
144: }
145: // write the body
146: w.writeStartElement("S", "Body", soapNsUri);
147:
148: writePayloadTo(w);
149:
150: w.writeEndElement();
151: w.writeEndElement();
152: w.writeEndDocument();
153: }
154:
155: /**
156: * Writes the whole envelope as SAX events.
157: */
158: public void writeTo(ContentHandler contentHandler,
159: ErrorHandler errorHandler) throws SAXException {
160: String soapNsUri = soapVersion.nsUri;
161:
162: contentHandler.setDocumentLocator(NULL_LOCATOR);
163: contentHandler.startDocument();
164: contentHandler.startPrefixMapping("S", soapNsUri);
165: contentHandler.startElement(soapNsUri, "Envelope",
166: "S:Envelope", EMPTY_ATTS);
167: if (hasHeaders()) {
168: contentHandler.startElement(soapNsUri, "Header",
169: "S:Header", EMPTY_ATTS);
170: HeaderList headers = getHeaders();
171: int len = headers.size();
172: for (int i = 0; i < len; i++) {
173: // shouldn't JDK be smart enough to use array-style indexing for this foreach!?
174: headers.get(i).writeTo(contentHandler, errorHandler);
175: }
176: contentHandler.endElement(soapNsUri, "Header", "S:Header");
177: }
178: // write the body
179: contentHandler.startElement(soapNsUri, "Body", "S:Body",
180: EMPTY_ATTS);
181: writePayloadTo(contentHandler, errorHandler, true);
182: contentHandler.endElement(soapNsUri, "Body", "S:Body");
183: contentHandler.endElement(soapNsUri, "Envelope", "S:Envelope");
184: }
185:
186: /**
187: * Writes the payload to SAX events.
188: *
189: * @param fragment
190: * if true, this method will fire SAX events without start/endDocument events,
191: * suitable for embedding this into a bigger SAX event sequence.
192: * if false, this method generaets a completely SAX event sequence on its own.
193: */
194: protected abstract void writePayloadTo(
195: ContentHandler contentHandler, ErrorHandler errorHandler,
196: boolean fragment) throws SAXException;
197:
198: /**
199: * Default implementation that uses {@link #writeTo(ContentHandler, ErrorHandler)}
200: */
201: public SOAPMessage readAsSOAPMessage() throws SOAPException {
202: SOAPMessage msg = soapVersion.saajMessageFactory
203: .createMessage();
204: SAX2DOMEx s2d = new SAX2DOMEx(msg.getSOAPPart());
205: try {
206: writeTo(s2d, XmlUtil.DRACONIAN_ERROR_HANDLER);
207: } catch (SAXException e) {
208: throw new SOAPException(e);
209: }
210: for (Attachment att : getAttachments()) {
211: AttachmentPart part = msg.createAttachmentPart();
212: part.setDataHandler(att.asDataHandler());
213: part.setContentId('<' + att.getContentId() + '>');
214: msg.addAttachmentPart(part);
215: }
216: return msg;
217: }
218:
219: /**
220: *
221: */
222: public SOAPMessage readAsSOAPMessage(Packet packet, boolean inbound)
223: throws SOAPException {
224: SOAPMessage msg = readAsSOAPMessage();
225: Map<String, List<String>> headers = null;
226: String key = inbound ? Packet.INBOUND_TRANSPORT_HEADERS
227: : Packet.OUTBOUND_TRANSPORT_HEADERS;
228: if (packet.supports(key)) {
229: headers = (Map<String, List<String>>) packet.get(key);
230: }
231: if (headers != null) {
232: for (Map.Entry<String, List<String>> e : headers.entrySet()) {
233: if (!e.getKey().equalsIgnoreCase("Content-Type")) {
234: for (String value : e.getValue()) {
235: msg.getMimeHeaders().addHeader(e.getKey(),
236: value);
237: }
238: }
239: }
240: }
241: msg.saveChanges();
242: return msg;
243: }
244:
245: protected static final AttributesImpl EMPTY_ATTS = new AttributesImpl();
246: protected static final LocatorImpl NULL_LOCATOR = new LocatorImpl();
247: }
|