All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.xml.ws.encoding.xml.XMLMessage Maven / Gradle / Ivy

There is a newer version: 4.0.2
Show newest version
/*
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the License).  You may not use this file except in
 * compliance with the License.
 * 
 * You can obtain a copy of the license at
 * https://glassfish.dev.java.net/public/CDDLv1.0.html.
 * See the License for the specific language governing
 * permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL
 * Header Notice in each file and include the License file
 * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
 * If applicable, add the following below the CDDL Header,
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
 */

package com.sun.xml.ws.encoding.xml;

import com.sun.istack.NotNull;
import com.sun.xml.messaging.saaj.packaging.mime.internet.ContentType;
import com.sun.xml.messaging.saaj.packaging.mime.internet.MimeMultipart;
import com.sun.xml.messaging.saaj.util.ByteOutputStream;
import com.sun.xml.ws.api.SOAPVersion;
import com.sun.xml.ws.api.message.Attachment;
import com.sun.xml.ws.api.message.AttachmentSet;
import com.sun.xml.ws.api.message.HeaderList;
import com.sun.xml.ws.api.message.Message;
import com.sun.xml.ws.api.message.Messages;
import com.sun.xml.ws.api.message.Packet;
import com.sun.xml.ws.api.model.wsdl.WSDLPort;
import com.sun.xml.ws.api.pipe.Codec;
import com.sun.xml.ws.api.streaming.XMLStreamReaderFactory;
import com.sun.xml.ws.api.streaming.XMLStreamWriterFactory;
import com.sun.xml.ws.encoding.MimeMultipartParser;
import com.sun.xml.ws.encoding.XMLHTTPBindingCodec;
import com.sun.xml.ws.message.AbstractMessageImpl;
import com.sun.xml.ws.message.EmptyMessageImpl;
import com.sun.xml.ws.util.xml.XMLStreamReaderToXMLStreamWriter;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;

import javax.activation.DataSource;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.WebServiceException;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 *
 * @author Jitendra Kotamraju
 */
public final class XMLMessage {

    // So that SAAJ registers DCHs for MIME types
    static {
        new com.sun.xml.messaging.saaj.soap.AttachmentPartImpl();
    }

    private static final int PLAIN_XML_FLAG      = 1;       // 00001
    private static final int MIME_MULTIPART_FLAG = 2;       // 00010
    private static final int FI_ENCODED_FLAG     = 16;      // 10000


    /**
     * Finds if the stream has some content or not
     *
     * @return null if there is no data
     *         else stream to be used
     */
    private static InputStream hasSomeData(InputStream in) throws IOException {
        if (in != null) {
            if (in.available() < 1) {
                if (!in.markSupported()) {
                    in = new BufferedInputStream(in);
                }
                in.mark(1);
                if (in.read() != -1) {
                    in.reset();
                } else {
                    in = null;          // No data
                }
            }
        }
        return in;
    }


    /**
     * Construct a message given a content type and an input stream.
     */
    public static Message create(final String ct, InputStream in) {
        Message data;
        try {
            in = hasSomeData(in);
            if (in == null) {
                data = Messages.createEmpty(SOAPVersion.SOAP_11);
                return data;
            }

            if (ct != null) {
                final ContentType contentType = new ContentType(ct);
                final int contentTypeId = identifyContentType(contentType);
                if ((contentTypeId & MIME_MULTIPART_FLAG) != 0) {
                    data = new XMLMultiPart(ct, in);
                } else if ((contentTypeId & PLAIN_XML_FLAG) != 0) {
                    data = Messages.createUsingPayload(new StreamSource(in),
                            SOAPVersion.SOAP_11);
                } else {
                    data = new UnknownContent(ct, in);
                }
            } else {
                data = Messages.createEmpty(SOAPVersion.SOAP_11);
            }
        } catch(Exception ex) {
            throw new WebServiceException(ex);
        }
        return data;
    }


    public static Message create(Source source) {
        return (source == null) ? 
            Messages.createEmpty(SOAPVersion.SOAP_11) : 
            Messages.createUsingPayload(source, SOAPVersion.SOAP_11);
    }

    public static Message create(DataSource ds) {
        try {
            return (ds == null) ? 
                Messages.createEmpty(SOAPVersion.SOAP_11) : 
                create(ds.getContentType(), ds.getInputStream());
        } catch(IOException ioe) {
            throw new WebServiceException(ioe);
        }
    }

    public static Message create(Exception e) {
        return new FaultMessage(SOAPVersion.SOAP_11);
    }

    /**
     * Get the content type ID from the content type.
     */
    private static int getContentId(String ct) {    
        try {
            final ContentType contentType = new ContentType(ct);
            return identifyContentType(contentType);
        } catch(Exception ex) {
            throw new WebServiceException(ex);
        }
    }
    
    /**
     * Return true if the content uses fast infoset.
     */
    public static boolean isFastInfoset(String ct) {    
        return (getContentId(ct) & FI_ENCODED_FLAG) != 0;
    }
    
    /**
     * Verify a contentType.
     *
     * @return
     * MIME_MULTIPART_FLAG | PLAIN_XML_FLAG
     * MIME_MULTIPART_FLAG | FI_ENCODED_FLAG;
     * PLAIN_XML_FLAG
     * FI_ENCODED_FLAG
     *
     */
    public static int identifyContentType(ContentType contentType) {
        String primary = contentType.getPrimaryType();
        String sub = contentType.getSubType();

        if (primary.equalsIgnoreCase("multipart") && sub.equalsIgnoreCase("related")) {
            String type = contentType.getParameter("type");
            if (type != null) {
                if (isXMLType(type)) {
                    return MIME_MULTIPART_FLAG | PLAIN_XML_FLAG;
                } else if (isFastInfosetType(type)) {
                    return MIME_MULTIPART_FLAG | FI_ENCODED_FLAG;
                }
            }
            return 0;
        } else if (isXMLType(primary, sub)) {
            return PLAIN_XML_FLAG;
        } else if (isFastInfosetType(primary, sub)) {
            return FI_ENCODED_FLAG;
        }
        return 0;
    }

    protected static boolean isXMLType(@NotNull String primary, @NotNull String sub) {
        return (primary.equalsIgnoreCase("text") && sub.equalsIgnoreCase("xml"))
                || (primary.equalsIgnoreCase("application") && sub.equalsIgnoreCase("xml"))
                || (primary.equalsIgnoreCase("application") && sub.toLowerCase().endsWith("+xml"));
    }

    protected static boolean isXMLType(String type) {
        String lowerType = type.toLowerCase();
        return lowerType.startsWith("text/xml")
                || lowerType.startsWith("application/xml")
                || (lowerType.startsWith("application/") && (lowerType.indexOf("+xml") != -1));
    }

    protected static boolean isFastInfosetType(String primary, String sub) {
        return primary.equalsIgnoreCase("application") && sub.equalsIgnoreCase("fastinfoset");
    }

    protected static boolean isFastInfosetType(String type) {
        return type.toLowerCase().startsWith("application/fastinfoset");
    }
    
    
    /**
     * Access a {@link Message} as a {@link DataSource}.
     * 

* A {@link Message} implementation will implement this if the * messages is to be access as data source. *

* TODO: consider putting as part of the API. */ public static interface MessageDataSource { /** * Check if the data source has been consumed. * @return true of the data source has been consumed, otherwise false. */ boolean hasUnconsumedDataSource(); /** * Get the data source. * @return the data source. */ DataSource getDataSource(); } /** * Data represented as a multi-part MIME message. *

* The root part may be an XML or an FI document. * * This class parses {@link MimeMultipart} lazily. */ public static final class XMLMultiPart extends AbstractMessageImpl implements MessageDataSource { private final DataSource dataSource; private MimeMultipartParser mpp; public XMLMultiPart(final String contentType, final InputStream is) { super(SOAPVersion.SOAP_11); dataSource = createDataSource(contentType, is); } public XMLMultiPart(DataSource dataSource) { super(SOAPVersion.SOAP_11); this.dataSource = dataSource; } public DataSource getDataSource() { assert dataSource != null; return dataSource; } private void convertDataSourceToMessage() { if (mpp == null) { try { mpp = new MimeMultipartParser( dataSource.getInputStream(), dataSource.getContentType()); } catch(IOException ioe) { throw new WebServiceException(ioe); } } } @Override public boolean isOneWay(@NotNull WSDLPort port) { return false; } public boolean isFault() { return false; } public boolean hasHeaders() { return false; } public HeaderList getHeaders() { return new HeaderList(); } @Override public AttachmentSet getAttachments() { convertDataSourceToMessage(); return new XMLAttachmentSet(mpp); } public String getPayloadLocalPart() { throw new UnsupportedOperationException(); } public String getPayloadNamespaceURI() { throw new UnsupportedOperationException(); } public boolean hasPayload() { return true; } public Source readPayloadAsSource() { convertDataSourceToMessage(); return mpp.getRootPart().asSource(); } public XMLStreamReader readPayload() throws XMLStreamException { convertDataSourceToMessage(); return XMLStreamReaderFactory.create( null, mpp.getRootPart().asInputStream(), true); } public void writePayloadTo(XMLStreamWriter sw) { XMLStreamReaderToXMLStreamWriter c = new XMLStreamReaderToXMLStreamWriter(); try { XMLStreamReader r = readPayload(); c.bridge(r, sw); XMLStreamReaderFactory.recycle(r); } catch(Exception e) { throw new RuntimeException(e); } } protected void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment){ throw new UnsupportedOperationException(); } public Message copy() { throw new UnsupportedOperationException(); } public boolean hasUnconsumedDataSource() { return mpp == null; } } private static final class XMLAttachmentSet implements AttachmentSet { private final Map attMap; public XMLAttachmentSet(MimeMultipartParser mpp) { // TODO attMap = new HashMap(); attMap.putAll(mpp.getAttachmentParts()); } /** * Gets the attachment by the content ID. * * @return null * if no such attachment exist. */ public Attachment get(String contentId) { return attMap.get(contentId); } public boolean isEmpty() { return attMap.isEmpty(); } /** * Returns an iterator over a set of elements of type T. * * @return an Iterator. */ public Iterator iterator() { return attMap.values().iterator(); } public void add(Attachment att) { attMap.put(att.getContentId(), att); } } private static class FaultMessage extends EmptyMessageImpl { public FaultMessage(SOAPVersion version) { super(version); } @Override public boolean isFault() { return true; } } /** * Don't know about this content. It's conent-type is NOT the XML types * we recognize(text/xml, application/xml, multipart/related;text/xml etc). * * This could be used to represent image/jpeg etc */ public static class UnknownContent extends AbstractMessageImpl implements MessageDataSource { private final DataSource ds; private final HeaderList headerList; public UnknownContent(final String ct, final InputStream in) { this(createDataSource(ct,in)); } public UnknownContent(DataSource ds) { super(SOAPVersion.SOAP_11); this.ds = ds; this.headerList = new HeaderList(); } /** * Copy constructor. */ private UnknownContent(UnknownContent that) { super(that.soapVersion); this.ds = that.ds; this.headerList = HeaderList.copy(that.headerList); } public boolean hasUnconsumedDataSource() { return true; } public DataSource getDataSource() { assert ds != null; return ds; } protected void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException { throw new UnsupportedOperationException(); } public boolean hasHeaders() { return false; } public boolean isFault() { return false; } public HeaderList getHeaders() { return headerList; } public String getPayloadLocalPart() { throw new UnsupportedOperationException(); } public String getPayloadNamespaceURI() { throw new UnsupportedOperationException(); } public boolean hasPayload() { return false; } public Source readPayloadAsSource() { return null; } public XMLStreamReader readPayload() throws XMLStreamException { throw new WebServiceException("There isn't XML payload. Shouldn't come here."); } public void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException { // No XML. Nothing to do } public Message copy() { return new UnknownContent(this); } } public static DataSource getDataSource(Message msg) { if (msg instanceof MessageDataSource) { return ((MessageDataSource)msg).getDataSource(); } else { AttachmentSet atts = msg.getAttachments(); if (atts != null && !atts.isEmpty()) { final ByteOutputStream bos = new ByteOutputStream(); try { Codec codec = new XMLHTTPBindingCodec(); com.sun.xml.ws.api.pipe.ContentType ct = codec.getStaticContentType(new Packet(msg)); codec.encode(new Packet(msg), bos); return createDataSource(ct.getContentType(), bos.newInputStream()); } catch(IOException ioe) { throw new WebServiceException(ioe); } } else { final ByteOutputStream bos = new ByteOutputStream(); XMLStreamWriter writer = XMLStreamWriterFactory.create(bos); try { msg.writePayloadTo(writer); writer.flush(); } catch (XMLStreamException e) { throw new WebServiceException(e); } return XMLMessage.createDataSource("text/xml", bos.newInputStream()); } } } public static DataSource createDataSource(final String contentType, final InputStream is) { return new DataSource() { public InputStream getInputStream() { return is; } public OutputStream getOutputStream() { return null; } public String getContentType() { return contentType; } public String getName() { return ""; } }; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy