/*
 * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.xml.internal.messaging.saaj.util.stax;

import java.io.OutputStream;
import java.util.Arrays;
import java.util.Iterator;
import java.util.UUID;

import javax.activation.DataHandler;
import javax.xml.bind.attachment.AttachmentMarshaller;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.stream.XMLStreamException;

import com.sun.xml.internal.org.jvnet.staxex.Base64Data;
import com.sun.xml.internal.org.jvnet.staxex.BinaryText;
import com.sun.xml.internal.org.jvnet.staxex.MtomEnabled;
import com.sun.xml.internal.org.jvnet.staxex.NamespaceContextEx;
import com.sun.xml.internal.org.jvnet.staxex.StreamingDataHandler;
import com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx;
import com.sun.xml.internal.org.jvnet.staxex.util.MtomStreamWriter;
//
//import com.sun.xml.internal.ws.api.message.saaj.SaajStaxWriter;
//import com.sun.xml.internal.ws.developer.StreamingDataHandler;
//import com.sun.xml.internal.ws.streaming.MtomStreamWriter;

SaajStaxWriterEx converts XMLStreamWriterEx calls to build an orasaaj SOAPMessage with BinaryTextImpl.
Author:shih-chang.chen@oracle.com
/** * SaajStaxWriterEx converts XMLStreamWriterEx calls to build an orasaaj SOAPMessage with BinaryTextImpl. * * @author shih-chang.chen@oracle.com */
public class SaajStaxWriterEx extends SaajStaxWriter implements XMLStreamWriterEx, MtomStreamWriter { static final protected String xopNS = "http://www.w3.org/2004/08/xop/include"; static final protected String Include = "Include"; static final protected String href = "href"; private enum State {xopInclude, others}; private State state = State.others; private BinaryText binaryText; public SaajStaxWriterEx(SOAPMessage msg, String uri) throws SOAPException { super(msg, uri); } @Override public void writeStartElement(String prefix, String ln, String ns) throws XMLStreamException { if (xopNS.equals(ns) && Include.equals(ln)) { state = State.xopInclude; return; } else { super.writeStartElement(prefix, ln, ns); } } @Override public void writeEndElement() throws XMLStreamException { if (state.equals(State.xopInclude)) { state = State.others; } else { super.writeEndElement(); } } @Override public void writeAttribute(String prefix, String ns, String ln, String value) throws XMLStreamException { if (binaryText != null && href.equals(ln)) { return; } else { super.writeAttribute(prefix, ns, ln, value); } } // @Override // public void writeComment(String data) throws XMLStreamException { // ((ElementImpl)currentElement).addCommentNode(data); // } // // @Override // public void writeCData(String data) throws XMLStreamException { // CDataTextImpl cdt = new CDataTextImpl(soap.getSOAPPart(), data); // currentElement.appendChild(cdt); // } @Override public NamespaceContextEx getNamespaceContext() { return new NamespaceContextEx() { @Override public String getNamespaceURI(String prefix) { return currentElement.getNamespaceURI(prefix); } @Override public String getPrefix(String namespaceURI) { return currentElement.lookupPrefix(namespaceURI); } @Override public Iterator getPrefixes(final String namespaceURI) { return new Iterator<String>() { String prefix = getPrefix(namespaceURI); @Override public boolean hasNext() { return (prefix != null); } @Override public String next() { if (prefix == null) throw new java.util.NoSuchElementException(); String next = prefix; prefix = null; return next; } @Override public void remove() {} }; } @Override public Iterator<Binding> iterator() { return new Iterator<Binding>() { @Override public boolean hasNext() { return false; } @Override public Binding next() { return null; } @Override public void remove() {} }; } }; } @Override public void writeBinary(DataHandler data) throws XMLStreamException { // binaryText = BinaryTextImpl.createBinaryTextFromDataHandler((MessageImpl)soap, null, currentElement.getOwnerDocument(), data); // currentElement.appendChild(binaryText); addBinaryText(data); } @Override public OutputStream writeBinary(String arg0) throws XMLStreamException { return null; } @Override public void writeBinary(byte[] data, int offset, int length, String contentType) throws XMLStreamException { // if (mtomThreshold == -1 || mtomThreshold > length) return null; byte[] bytes = (offset == 0 && length == data.length) ? data : Arrays.copyOfRange(data, offset, offset + length); if (currentElement instanceof MtomEnabled) { binaryText = ((MtomEnabled) currentElement).addBinaryText(bytes); } else { throw new IllegalStateException("The currentElement is not MtomEnabled " + currentElement); } } @Override public void writePCDATA(CharSequence arg0) throws XMLStreamException { if (arg0 instanceof Base64Data) { // The fix of StreamReaderBufferCreator preserves this dataHandler addBinaryText(((Base64Data) arg0).getDataHandler()); } else { // We should not normally get here as we expect a DataHandler, // but this is the most general solution. If we do get // something other than a Data Handler, create a Text node with // the data. Another alternative would be to throw an exception, // but in the most general case, we don't know whether this input // is expected. try { currentElement.addTextNode(arg0.toString()); } catch (SOAPException e) { throw new XMLStreamException("Cannot add Text node", e); } } } static private String encodeCid() { String cid = "example.jaxws.sun.com"; String name = UUID.randomUUID() + "@"; return name + cid; } private String addBinaryText(DataHandler data) { String hrefOrCid = null; if (data instanceof StreamingDataHandler) { hrefOrCid = ((StreamingDataHandler) data).getHrefCid(); } if (hrefOrCid == null) hrefOrCid = encodeCid(); String prefixedCid = (hrefOrCid.startsWith("cid:")) ? hrefOrCid : "cid:" + hrefOrCid; // Should we do the threshold processing on DataHandler ? But that would be // expensive as DataHolder need to read the data again from its source //binaryText = BinaryTextImpl.createBinaryTextFromDataHandler((MessageImpl) soap, prefixedCid, currentElement.getOwnerDocument(), data); //currentElement.appendChild(binaryText); if (currentElement instanceof MtomEnabled) { binaryText = ((MtomEnabled) currentElement).addBinaryText(prefixedCid, data); } else { throw new IllegalStateException("The currentElement is not MtomEnabled " + currentElement); } return hrefOrCid; } @Override public AttachmentMarshaller getAttachmentMarshaller() { return new AttachmentMarshaller() { @Override public String addMtomAttachment(DataHandler data, String ns, String ln) { // if (mtomThreshold == -1) return null; String hrefOrCid = addBinaryText(data); // return binaryText.getHref(); return hrefOrCid; } @Override public String addMtomAttachment(byte[] data, int offset, int length, String mimeType, String ns, String ln) { // if (mtomThreshold == -1 || mtomThreshold > length) return null; byte[] bytes = (offset == 0 && length == data.length) ? data : Arrays.copyOfRange(data, offset, offset + length); // binaryText = (BinaryTextImpl) ((ElementImpl) currentElement).addAsBase64TextNode(bytes); if (currentElement instanceof MtomEnabled) { binaryText = ((MtomEnabled) currentElement).addBinaryText(bytes); } else { throw new IllegalStateException("The currentElement is not MtomEnabled " + currentElement); } return binaryText.getHref(); } @Override public String addSwaRefAttachment(DataHandler data) { return "cid:"+encodeCid(); } @Override public boolean isXOPPackage() { return true; } }; } }