325N/A/*
325N/A * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
325N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
325N/A *
325N/A * This code is free software; you can redistribute it and/or modify it
325N/A * under the terms of the GNU General Public License version 2 only, as
325N/A * published by the Free Software Foundation. Oracle designates this
325N/A * particular file as subject to the "Classpath" exception as provided
325N/A * by Oracle in the LICENSE file that accompanied this code.
325N/A *
325N/A * This code is distributed in the hope that it will be useful, but WITHOUT
325N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
325N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
325N/A * version 2 for more details (a copy is included in the LICENSE file that
325N/A * accompanied this code).
325N/A *
325N/A * You should have received a copy of the GNU General Public License version
325N/A * 2 along with this work; if not, write to the Free Software Foundation,
325N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
325N/A *
325N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
325N/A * or visit www.oracle.com if you need additional information or have any
325N/A * questions.
325N/A */
325N/A
325N/Apackage com.sun.xml.internal.ws.message.saaj;
325N/A
325N/Aimport com.sun.istack.internal.NotNull;
325N/Aimport com.sun.istack.internal.XMLStreamException2;
325N/Aimport com.sun.istack.internal.Nullable;
325N/Aimport com.sun.istack.internal.FragmentContentHandler;
325N/Aimport com.sun.xml.internal.bind.api.Bridge;
325N/Aimport com.sun.xml.internal.bind.unmarshaller.DOMScanner;
325N/Aimport com.sun.xml.internal.ws.api.SOAPVersion;
325N/Aimport com.sun.xml.internal.ws.api.message.*;
325N/Aimport com.sun.xml.internal.ws.message.AttachmentUnmarshallerImpl;
325N/Aimport com.sun.xml.internal.ws.message.AbstractMessageImpl;
325N/Aimport com.sun.xml.internal.ws.message.AttachmentSetImpl;
325N/Aimport com.sun.xml.internal.ws.streaming.DOMStreamReader;
325N/Aimport com.sun.xml.internal.ws.util.DOMUtil;
325N/Aimport org.w3c.dom.Element;
325N/Aimport org.w3c.dom.Node;
325N/Aimport org.w3c.dom.NamedNodeMap;
325N/Aimport org.w3c.dom.Attr;
325N/Aimport org.xml.sax.ContentHandler;
325N/Aimport org.xml.sax.ErrorHandler;
325N/Aimport org.xml.sax.SAXException;
325N/Aimport org.xml.sax.helpers.AttributesImpl;
325N/Aimport org.xml.sax.helpers.LocatorImpl;
325N/A
325N/Aimport javax.activation.DataHandler;
325N/Aimport javax.xml.bind.JAXBException;
325N/Aimport javax.xml.bind.Unmarshaller;
325N/Aimport javax.xml.soap.AttachmentPart;
325N/Aimport javax.xml.soap.SOAPBody;
325N/Aimport javax.xml.soap.SOAPEnvelope;
325N/Aimport javax.xml.soap.SOAPException;
325N/Aimport javax.xml.soap.SOAPHeader;
325N/Aimport javax.xml.soap.SOAPHeaderElement;
325N/Aimport javax.xml.soap.SOAPMessage;
325N/Aimport javax.xml.stream.XMLStreamException;
325N/Aimport javax.xml.stream.XMLStreamReader;
325N/Aimport javax.xml.stream.XMLStreamWriter;
325N/Aimport javax.xml.transform.Source;
325N/Aimport javax.xml.transform.dom.DOMSource;
325N/Aimport javax.xml.transform.stream.StreamSource;
325N/Aimport javax.xml.ws.WebServiceException;
325N/Aimport javax.xml.ws.soap.SOAPFaultException;
325N/Aimport java.io.IOException;
325N/Aimport java.io.InputStream;
325N/Aimport java.io.OutputStream;
325N/Aimport java.util.HashMap;
325N/Aimport java.util.Iterator;
325N/Aimport java.util.List;
325N/Aimport java.util.Map;
325N/A
325N/A/**
325N/A * {@link Message} implementation backed by {@link SOAPMessage}.
325N/A *
325N/A * @author Vivek Pandey
325N/A * @author Rama Pulavarthi
325N/A */
325N/Apublic class SAAJMessage extends Message {
325N/A // flag to switch between representations
325N/A private boolean parsedMessage;
325N/A // flag to check if Message API is exercised;
325N/A private boolean accessedMessage;
325N/A private final SOAPMessage sm;
325N/A
325N/A private HeaderList headers;
325N/A private List<Element> bodyParts;
325N/A private Element payload;
325N/A
325N/A private String payloadLocalName;
325N/A private String payloadNamespace;
325N/A private SOAPVersion soapVersion;
325N/A
325N/A //Collect the attrbutes on the enclosing elements so that the same message can be reproduced without loss of any
325N/A // valuable info
325N/A private NamedNodeMap bodyAttrs, headerAttrs, envelopeAttrs;
325N/A
325N/A public SAAJMessage(SOAPMessage sm) {
325N/A this.sm = sm;
325N/A }
325N/A
325N/A /**
325N/A * This constructor is a convenience and called by the {@link #copy}
325N/A *
325N/A * @param headers
325N/A * @param sm
325N/A */
325N/A private SAAJMessage(HeaderList headers, AttachmentSet as, SOAPMessage sm) {
325N/A this.sm = sm;
325N/A this.parse();
325N/A if(headers == null)
325N/A headers = new HeaderList();
325N/A this.headers = headers;
325N/A this.attachmentSet = as;
325N/A }
325N/A
325N/A private void parse() {
325N/A if (!parsedMessage) {
325N/A try {
325N/A access();
325N/A if (headers == null)
325N/A headers = new HeaderList();
325N/A SOAPHeader header = sm.getSOAPHeader();
325N/A if (header != null) {
325N/A headerAttrs = header.getAttributes();
325N/A Iterator iter = header.examineAllHeaderElements();
325N/A while (iter.hasNext()) {
325N/A headers.add(new SAAJHeader((SOAPHeaderElement) iter.next()));
325N/A }
325N/A }
325N/A attachmentSet = new SAAJAttachmentSet(sm);
325N/A
325N/A parsedMessage = true;
325N/A } catch (SOAPException e) {
325N/A throw new WebServiceException(e);
325N/A }
325N/A }
325N/A }
325N/A
325N/A private void access() {
325N/A if (!accessedMessage) {
325N/A try {
325N/A envelopeAttrs = sm.getSOAPPart().getEnvelope().getAttributes();
325N/A Node body = sm.getSOAPBody();
325N/A bodyAttrs = body.getAttributes();
325N/A soapVersion = SOAPVersion.fromNsUri(body.getNamespaceURI());
325N/A //cature all the body elements
325N/A bodyParts = DOMUtil.getChildElements(body);
325N/A //we treat payload as the first body part
325N/A payload = bodyParts.size() > 0 ? bodyParts.get(0) : null;
325N/A // hope this is correct. Caching the localname and namespace of the payload should be fine
325N/A // but what about if a Handler replaces the payload with something else? Weel, may be it
325N/A // will be error condition anyway
325N/A if (payload != null) {
325N/A payloadLocalName = payload.getLocalName();
325N/A payloadNamespace = payload.getNamespaceURI();
325N/A }
325N/A accessedMessage = true;
325N/A } catch (SOAPException e) {
325N/A throw new WebServiceException(e);
325N/A }
325N/A }
325N/A }
325N/A
325N/A public boolean hasHeaders() {
325N/A parse();
325N/A return headers.size() > 0;
325N/A }
325N/A
325N/A public @NotNull HeaderList getHeaders() {
325N/A parse();
325N/A return headers;
325N/A }
325N/A /**
325N/A * Gets the attachments of this message
325N/A * (attachments live outside a message.)
325N/A */
325N/A @Override
325N/A public @NotNull AttachmentSet getAttachments() {
325N/A parse();
325N/A return attachmentSet;
325N/A }
325N/A
325N/A /**
325N/A * Optimization hint for the derived class to check
325N/A * if we may have some attachments.
325N/A */
325N/A @Override
325N/A protected boolean hasAttachments() {
325N/A parse();
325N/A return attachmentSet!=null;
325N/A }
325N/A
325N/A public @Nullable String getPayloadLocalPart() {
325N/A access();
325N/A return payloadLocalName;
325N/A }
325N/A
325N/A public String getPayloadNamespaceURI() {
325N/A access();
325N/A return payloadNamespace;
325N/A }
325N/A
325N/A public boolean hasPayload() {
325N/A access();
325N/A return payloadNamespace != null;
325N/A }
325N/A
325N/A private void addAttributes(Element e, NamedNodeMap attrs) {
325N/A if(attrs == null)
325N/A return;
325N/A String elPrefix = e.getPrefix();
325N/A for(int i=0; i < attrs.getLength();i++) {
325N/A Attr a = (Attr)attrs.item(i);
325N/A //check if attr is ns declaration
325N/A if("xmlns".equals(a.getPrefix()) || a.getLocalName().equals("xmlns")) {
325N/A if(elPrefix == null && a.getLocalName().equals("xmlns")) {
325N/A // the target element has already default ns declaration, dont' override it
325N/A continue;
325N/A } else if(elPrefix != null && "xmlns".equals(a.getPrefix()) && elPrefix.equals(a.getLocalName())) {
325N/A //dont bind the prefix to ns again, its already in the target element.
325N/A continue;
325N/A }
325N/A e.setAttributeNS(a.getNamespaceURI(),a.getName(),a.getValue());
325N/A continue;
325N/A }
325N/A e.setAttributeNS(a.getNamespaceURI(),a.getName(),a.getValue());
325N/A }
325N/A }
325N/A
325N/A public Source readEnvelopeAsSource() {
325N/A try {
325N/A if (!parsedMessage) {
325N/A SOAPEnvelope se = sm.getSOAPPart().getEnvelope();
325N/A return new DOMSource(se);
325N/A
325N/A } else {
325N/A SOAPMessage msg = soapVersion.saajMessageFactory.createMessage();
325N/A addAttributes(msg.getSOAPPart().getEnvelope(),envelopeAttrs);
325N/A SOAPBody newBody = msg.getSOAPPart().getEnvelope().getBody();
325N/A addAttributes(newBody, bodyAttrs);
325N/A for (Element part : bodyParts) {
325N/A Node n = newBody.getOwnerDocument().importNode(part, true);
325N/A newBody.appendChild(n);
325N/A }
325N/A addAttributes(msg.getSOAPHeader(),headerAttrs);
325N/A for (Header header : headers) {
325N/A header.writeTo(msg);
325N/A }
325N/A SOAPEnvelope se = msg.getSOAPPart().getEnvelope();
325N/A return new DOMSource(se);
325N/A }
325N/A } catch (SOAPException e) {
325N/A throw new WebServiceException(e);
325N/A }
325N/A }
325N/A
325N/A public SOAPMessage readAsSOAPMessage() throws SOAPException {
325N/A if (!parsedMessage) {
325N/A return sm;
325N/A } else {
325N/A SOAPMessage msg = soapVersion.saajMessageFactory.createMessage();
325N/A addAttributes(msg.getSOAPPart().getEnvelope(),envelopeAttrs);
325N/A SOAPBody newBody = msg.getSOAPPart().getEnvelope().getBody();
325N/A addAttributes(newBody, bodyAttrs);
325N/A for (Element part : bodyParts) {
325N/A Node n = newBody.getOwnerDocument().importNode(part, true);
325N/A newBody.appendChild(n);
325N/A }
325N/A addAttributes(msg.getSOAPHeader(),headerAttrs);
325N/A for (Header header : headers) {
325N/A header.writeTo(msg);
325N/A }
325N/A for (Attachment att : getAttachments()) {
325N/A AttachmentPart part = msg.createAttachmentPart();
325N/A part.setDataHandler(att.asDataHandler());
325N/A part.setContentId('<' + att.getContentId() + '>');
325N/A msg.addAttachmentPart(part);
325N/A }
325N/A msg.saveChanges();
325N/A return msg;
325N/A }
325N/A }
325N/A
325N/A public Source readPayloadAsSource() {
325N/A access();
325N/A return (payload != null) ? new DOMSource(payload) : null;
325N/A }
325N/A
325N/A public <T> T readPayloadAsJAXB(Unmarshaller unmarshaller) throws JAXBException {
325N/A access();
325N/A if (payload != null) {
325N/A if(hasAttachments())
325N/A unmarshaller.setAttachmentUnmarshaller(new AttachmentUnmarshallerImpl(getAttachments()));
325N/A return (T) unmarshaller.unmarshal(payload);
325N/A
325N/A }
325N/A return null;
325N/A }
325N/A
325N/A public <T> T readPayloadAsJAXB(Bridge<T> bridge) throws JAXBException {
325N/A access();
325N/A if (payload != null)
325N/A return bridge.unmarshal(payload,hasAttachments()? new AttachmentUnmarshallerImpl(getAttachments()) : null);
325N/A return null;
325N/A }
325N/A
325N/A public XMLStreamReader readPayload() throws XMLStreamException {
325N/A access();
325N/A if (payload != null) {
325N/A DOMStreamReader dss = new DOMStreamReader();
325N/A dss.setCurrentNode(payload);
325N/A dss.nextTag();
325N/A assert dss.getEventType() == XMLStreamReader.START_ELEMENT;
325N/A return dss;
325N/A }
325N/A return null;
325N/A }
325N/A
325N/A public void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException {
325N/A access();
325N/A try {
325N/A for (Element part : bodyParts)
325N/A DOMUtil.serializeNode(part, sw);
325N/A } catch (XMLStreamException e) {
325N/A throw new WebServiceException(e);
325N/A }
325N/A }
325N/A
325N/A public void writeTo(XMLStreamWriter writer) throws XMLStreamException {
325N/A try {
325N/A writer.writeStartDocument();
325N/A if (!parsedMessage) {
325N/A DOMUtil.serializeNode(sm.getSOAPPart().getEnvelope(), writer);
325N/A } else {
325N/A SOAPEnvelope env = sm.getSOAPPart().getEnvelope();
325N/A DOMUtil.writeTagWithAttributes(env, writer);
325N/A if (hasHeaders()) {
325N/A if(env.getHeader() != null) {
325N/A DOMUtil.writeTagWithAttributes(env.getHeader(), writer);
325N/A } else {
325N/A writer.writeStartElement(env.getPrefix(), "Header", env.getNamespaceURI());
325N/A }
325N/A int len = headers.size();
325N/A for (int i = 0; i < len; i++) {
325N/A headers.get(i).writeTo(writer);
325N/A }
325N/A writer.writeEndElement();
325N/A }
325N/A
325N/A DOMUtil.serializeNode(sm.getSOAPBody(), writer);
325N/A writer.writeEndElement();
325N/A }
325N/A writer.writeEndDocument();
325N/A writer.flush();
325N/A } catch (SOAPException ex) {
325N/A throw new XMLStreamException2(ex);
325N/A //for now. ask jaxws team what to do.
325N/A }
325N/A }
325N/A
325N/A public void writeTo(ContentHandler contentHandler, ErrorHandler errorHandler) throws SAXException {
325N/A String soapNsUri = soapVersion.nsUri;
325N/A if (!parsedMessage) {
325N/A DOMScanner ds = new DOMScanner();
325N/A ds.setContentHandler(contentHandler);
325N/A ds.scan(sm.getSOAPPart());
325N/A } else {
325N/A contentHandler.setDocumentLocator(NULL_LOCATOR);
325N/A contentHandler.startDocument();
325N/A contentHandler.startPrefixMapping("S", soapNsUri);
325N/A startPrefixMapping(contentHandler, envelopeAttrs,"S");
325N/A contentHandler.startElement(soapNsUri, "Envelope", "S:Envelope", getAttributes(envelopeAttrs));
325N/A if (hasHeaders()) {
325N/A startPrefixMapping(contentHandler, headerAttrs,"S");
325N/A contentHandler.startElement(soapNsUri, "Header", "S:Header", getAttributes(headerAttrs));
325N/A HeaderList headers = getHeaders();
325N/A int len = headers.size();
325N/A for (int i = 0; i < len; i++) {
325N/A // shouldn't JDK be smart enough to use array-style indexing for this foreach!?
325N/A headers.get(i).writeTo(contentHandler, errorHandler);
325N/A }
325N/A endPrefixMapping(contentHandler, headerAttrs,"S");
325N/A contentHandler.endElement(soapNsUri, "Header", "S:Header");
325N/A
325N/A }
325N/A startPrefixMapping(contentHandler, bodyAttrs,"S");
325N/A // write the body
325N/A contentHandler.startElement(soapNsUri, "Body", "S:Body", getAttributes(bodyAttrs));
325N/A writePayloadTo(contentHandler, errorHandler, true);
325N/A endPrefixMapping(contentHandler, bodyAttrs,"S");
325N/A contentHandler.endElement(soapNsUri, "Body", "S:Body");
325N/A endPrefixMapping(contentHandler, envelopeAttrs,"S");
325N/A contentHandler.endElement(soapNsUri, "Envelope", "S:Envelope");
325N/A }
325N/A }
325N/A /**
325N/A * Gets the Attributes that are not namesapce declarations
325N/A * @param attrs
325N/A * @return
325N/A */
325N/A private AttributesImpl getAttributes(NamedNodeMap attrs) {
325N/A AttributesImpl atts = new AttributesImpl();
325N/A if(attrs == null)
325N/A return EMPTY_ATTS;
325N/A for(int i=0; i < attrs.getLength();i++) {
325N/A Attr a = (Attr)attrs.item(i);
325N/A //check if attr is ns declaration
325N/A if("xmlns".equals(a.getPrefix()) || a.getLocalName().equals("xmlns")) {
325N/A continue;
325N/A }
325N/A atts.addAttribute(fixNull(a.getNamespaceURI()),a.getLocalName(),a.getName(),a.getSchemaTypeInfo().getTypeName(),a.getValue());
325N/A }
325N/A return atts;
325N/A }
325N/A
325N/A /**
325N/A * Collects the ns declarations and starts the prefix mapping, consequently the associated endPrefixMapping needs to be called.
325N/A * @param contentHandler
325N/A * @param attrs
325N/A * @param excludePrefix , this is to excldue the global prefix mapping "S" used at the start
325N/A * @throws SAXException
325N/A */
325N/A private void startPrefixMapping(ContentHandler contentHandler, NamedNodeMap attrs, String excludePrefix) throws SAXException {
325N/A if(attrs == null)
325N/A return;
325N/A for(int i=0; i < attrs.getLength();i++) {
325N/A Attr a = (Attr)attrs.item(i);
325N/A //check if attr is ns declaration
325N/A if("xmlns".equals(a.getPrefix()) || a.getLocalName().equals("xmlns")) {
325N/A if(!fixNull(a.getPrefix()).equals(excludePrefix)) {
325N/A contentHandler.startPrefixMapping(fixNull(a.getPrefix()), a.getNamespaceURI());
325N/A }
325N/A }
325N/A }
325N/A }
325N/A
325N/A private void endPrefixMapping(ContentHandler contentHandler, NamedNodeMap attrs, String excludePrefix) throws SAXException {
325N/A if(attrs == null)
325N/A return;
325N/A for(int i=0; i < attrs.getLength();i++) {
325N/A Attr a = (Attr)attrs.item(i);
325N/A //check if attr is ns declaration
325N/A if("xmlns".equals(a.getPrefix()) || a.getLocalName().equals("xmlns")) {
325N/A if(!fixNull(a.getPrefix()).equals(excludePrefix)) {
325N/A contentHandler.endPrefixMapping(fixNull(a.getPrefix()));
325N/A }
325N/A }
325N/A }
325N/A }
325N/A
325N/A private static String fixNull(String s) {
325N/A if(s==null) return "";
325N/A else return s;
325N/A }
325N/A
325N/A private void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException {
325N/A if(fragment)
325N/A contentHandler = new FragmentContentHandler(contentHandler);
325N/A DOMScanner ds = new DOMScanner();
325N/A ds.setContentHandler(contentHandler);
325N/A ds.scan(payload);
325N/A }
325N/A
325N/A /**
325N/A * Creates a copy of a {@link com.sun.xml.internal.ws.api.message.Message}.
325N/A * <p/>
325N/A * <p/>
325N/A * This method creates a new {@link com.sun.xml.internal.ws.api.message.Message} whose header/payload/attachments/properties
325N/A * are identical to this {@link com.sun.xml.internal.ws.api.message.Message}. Once created, the created {@link com.sun.xml.internal.ws.api.message.Message}
325N/A * and the original {@link com.sun.xml.internal.ws.api.message.Message} behaves independently --- adding header/
325N/A * attachment to one {@link com.sun.xml.internal.ws.api.message.Message} doesn't affect another {@link com.sun.xml.internal.ws.api.message.Message}
325N/A * at all.
325N/A * <p/>
325N/A * <h3>Design Rationale</h3>
325N/A * <p/>
325N/A * Since a {@link com.sun.xml.internal.ws.api.message.Message} body is read-once, sometimes
325N/A * (such as when you do fail-over, or WS-RM) you need to
325N/A * create an idential copy of a {@link com.sun.xml.internal.ws.api.message.Message}.
325N/A * <p/>
325N/A * <p/>
325N/A * The actual copy operation depends on the layout
325N/A * of the data in memory, hence it's best to be done by
325N/A * the {@link com.sun.xml.internal.ws.api.message.Message} implementation itself.
325N/A */
325N/A public Message copy() {
325N/A try {
325N/A if (!parsedMessage) {
325N/A return new SAAJMessage(readAsSOAPMessage());
325N/A } else {
325N/A SOAPMessage msg = soapVersion.saajMessageFactory.createMessage();
325N/A SOAPBody newBody = msg.getSOAPPart().getEnvelope().getBody();
325N/A for (Element part : bodyParts) {
325N/A Node n = newBody.getOwnerDocument().importNode(part, true);
325N/A newBody.appendChild(n);
325N/A }
325N/A return new SAAJMessage(getHeaders(), getAttachments(), msg);
325N/A }
325N/A } catch (SOAPException e) {
325N/A throw new WebServiceException(e);
325N/A }
325N/A }
325N/A private static final AttributesImpl EMPTY_ATTS = new AttributesImpl();
325N/A private static final LocatorImpl NULL_LOCATOR = new LocatorImpl();
325N/A
325N/A private class SAAJAttachment implements Attachment {
325N/A
325N/A final AttachmentPart ap;
325N/A
325N/A public SAAJAttachment(AttachmentPart part) {
325N/A this.ap = part;
325N/A }
325N/A
325N/A /**
325N/A * Content ID of the attachment. Uniquely identifies an attachment.
325N/A */
325N/A public String getContentId() {
325N/A return ap.getContentId();
325N/A }
325N/A
325N/A /**
325N/A * Gets the MIME content-type of this attachment.
325N/A */
325N/A public String getContentType() {
325N/A return ap.getContentType();
325N/A }
325N/A
325N/A /**
325N/A * Gets the attachment as an exact-length byte array.
325N/A */
325N/A public byte[] asByteArray() {
325N/A try {
325N/A return ap.getRawContentBytes();
325N/A } catch (SOAPException e) {
325N/A throw new WebServiceException(e);
325N/A }
325N/A }
325N/A
325N/A /**
325N/A * Gets the attachment as a {@link javax.activation.DataHandler}.
325N/A */
325N/A public DataHandler asDataHandler() {
325N/A try {
325N/A return ap.getDataHandler();
325N/A } catch (SOAPException e) {
325N/A throw new WebServiceException(e);
325N/A }
325N/A }
325N/A
325N/A /**
325N/A * Gets the attachment as a {@link javax.xml.transform.Source}.
325N/A * Note that there's no guarantee that the attachment is actually an XML.
325N/A */
325N/A public Source asSource() {
325N/A try {
325N/A return new StreamSource(ap.getRawContent());
325N/A } catch (SOAPException e) {
325N/A throw new WebServiceException(e);
325N/A }
325N/A }
325N/A
325N/A /**
325N/A * Obtains this attachment as an {@link java.io.InputStream}.
325N/A */
325N/A public InputStream asInputStream() {
325N/A try {
325N/A return ap.getRawContent();
325N/A } catch (SOAPException e) {
325N/A throw new WebServiceException(e);
325N/A }
325N/A }
325N/A
325N/A /**
325N/A * Writes the contents of the attachment into the given stream.
325N/A */
325N/A public void writeTo(OutputStream os) throws IOException {
325N/A os.write(asByteArray());
325N/A }
325N/A
325N/A /**
325N/A * Writes this attachment to the given {@link javax.xml.soap.SOAPMessage}.
325N/A */
325N/A public void writeTo(SOAPMessage saaj) {
325N/A saaj.addAttachmentPart(ap);
325N/A }
325N/A
325N/A AttachmentPart asAttachmentPart(){
325N/A return ap;
325N/A }
325N/A }
325N/A
325N/A /**
325N/A * {@link AttachmentSet} for SAAJ.
325N/A *
325N/A * SAAJ wants '&lt;' and '>' for the content ID, but {@link AttachmentSet}
325N/A * doesn't. S this class also does the conversion between them.
325N/A */
325N/A private class SAAJAttachmentSet implements AttachmentSet {
325N/A
325N/A private Map<String, Attachment> attMap;
325N/A private Iterator attIter;
325N/A
325N/A public SAAJAttachmentSet(SOAPMessage sm) {
325N/A attIter = sm.getAttachments();
325N/A }
325N/A
325N/A /**
325N/A * Gets the attachment by the content ID.
325N/A *
325N/A * @return null
325N/A * if no such attachment exist.
325N/A */
325N/A public Attachment get(String contentId) {
325N/A // if this is the first time then create the attachment Map
325N/A if (attMap == null) {
325N/A if (!attIter.hasNext())
325N/A return null;
325N/A attMap = createAttachmentMap();
325N/A }
325N/A if(contentId.charAt(0) != '<'){
325N/A return attMap.get('<'+contentId+'>');
325N/A }
325N/A return attMap.get(contentId);
325N/A }
325N/A
325N/A public boolean isEmpty() {
325N/A if(attMap!=null)
325N/A return attMap.isEmpty();
325N/A else
325N/A return !attIter.hasNext();
325N/A }
325N/A
325N/A /**
325N/A * Returns an iterator over a set of elements of type T.
325N/A *
325N/A * @return an Iterator.
325N/A */
325N/A public Iterator<Attachment> iterator() {
325N/A if (attMap == null) {
325N/A attMap = createAttachmentMap();
325N/A }
325N/A return attMap.values().iterator();
325N/A }
325N/A
325N/A private Map<String, Attachment> createAttachmentMap() {
325N/A HashMap<String, Attachment> map = new HashMap<String, Attachment>();
325N/A while (attIter.hasNext()) {
325N/A AttachmentPart ap = (AttachmentPart) attIter.next();
325N/A map.put(ap.getContentId(), new SAAJAttachment(ap));
325N/A }
325N/A return map;
325N/A }
325N/A
325N/A public void add(Attachment att) {
325N/A attMap.put('<'+att.getContentId()+'>', att);
325N/A }
325N/A }
325N/A
325N/A}