1/* 2 * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.xml.internal.messaging.saaj.util.stax; 27 28import java.io.OutputStream; 29import java.util.Arrays; 30import java.util.Iterator; 31import java.util.UUID; 32 33import javax.activation.DataHandler; 34import javax.xml.bind.attachment.AttachmentMarshaller; 35import javax.xml.soap.SOAPException; 36import javax.xml.soap.SOAPMessage; 37import javax.xml.stream.XMLStreamException; 38 39import com.sun.xml.internal.org.jvnet.staxex.Base64Data; 40import com.sun.xml.internal.org.jvnet.staxex.BinaryText; 41import com.sun.xml.internal.org.jvnet.staxex.MtomEnabled; 42import com.sun.xml.internal.org.jvnet.staxex.NamespaceContextEx; 43import com.sun.xml.internal.org.jvnet.staxex.StreamingDataHandler; 44import com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx; 45import com.sun.xml.internal.org.jvnet.staxex.util.MtomStreamWriter; 46// 47//import com.sun.xml.internal.ws.api.message.saaj.SaajStaxWriter; 48//import com.sun.xml.internal.ws.developer.StreamingDataHandler; 49//import com.sun.xml.internal.ws.streaming.MtomStreamWriter; 50 51/** 52 * SaajStaxWriterEx converts XMLStreamWriterEx calls to build an orasaaj SOAPMessage with BinaryTextImpl. 53 * 54 * @author shih-chang.chen@oracle.com 55 */ 56public class SaajStaxWriterEx extends SaajStaxWriter implements XMLStreamWriterEx, MtomStreamWriter { 57 58 static final protected String xopNS = "http://www.w3.org/2004/08/xop/include"; 59 static final protected String Include = "Include"; 60 static final protected String href = "href"; 61 62 private enum State {xopInclude, others}; 63 private State state = State.others; 64 private BinaryText binaryText; 65 66 public SaajStaxWriterEx(SOAPMessage msg, String uri) throws SOAPException { 67 super(msg, uri); 68 } 69 70 @Override 71 public void writeStartElement(String prefix, String ln, String ns) throws XMLStreamException { 72 if (xopNS.equals(ns) && Include.equals(ln)) { 73 state = State.xopInclude; 74 return; 75 } else { 76 super.writeStartElement(prefix, ln, ns); 77 } 78 } 79 80 @Override 81 public void writeEndElement() throws XMLStreamException { 82 if (state.equals(State.xopInclude)) { 83 state = State.others; 84 } else { 85 super.writeEndElement(); 86 } 87 } 88 89 @Override 90 public void writeAttribute(String prefix, String ns, String ln, String value) throws XMLStreamException { 91 if (binaryText != null && href.equals(ln)) { 92 return; 93 } else { 94 super.writeAttribute(prefix, ns, ln, value); 95 } 96 } 97 98// @Override 99// public void writeComment(String data) throws XMLStreamException { 100// ((ElementImpl)currentElement).addCommentNode(data); 101// } 102// 103// @Override 104// public void writeCData(String data) throws XMLStreamException { 105// CDataTextImpl cdt = new CDataTextImpl(soap.getSOAPPart(), data); 106// currentElement.appendChild(cdt); 107// } 108 109 @Override 110 public NamespaceContextEx getNamespaceContext() { 111 return new NamespaceContextEx() { 112 @Override 113 public String getNamespaceURI(String prefix) { 114 return currentElement.getNamespaceURI(prefix); 115 } 116 @Override 117 public String getPrefix(String namespaceURI) { 118 return currentElement.lookupPrefix(namespaceURI); 119 } 120 @Override 121 public Iterator getPrefixes(final String namespaceURI) { 122 return new Iterator<String>() { 123 String prefix = getPrefix(namespaceURI); 124 @Override 125 public boolean hasNext() { 126 return (prefix != null); 127 } 128 @Override 129 public String next() { 130 if (prefix == null) throw new java.util.NoSuchElementException(); 131 String next = prefix; 132 prefix = null; 133 return next; 134 } 135 @Override 136 public void remove() {} 137 }; 138 } 139 @Override 140 public Iterator<Binding> iterator() { 141 return new Iterator<Binding>() { 142 @Override 143 public boolean hasNext() { return false; } 144 @Override 145 public Binding next() { return null; } 146 @Override 147 public void remove() {} 148 }; 149 } 150 }; 151 } 152 153 @Override 154 public void writeBinary(DataHandler data) throws XMLStreamException { 155// binaryText = BinaryTextImpl.createBinaryTextFromDataHandler((MessageImpl)soap, null, currentElement.getOwnerDocument(), data); 156// currentElement.appendChild(binaryText); 157 addBinaryText(data); 158 } 159 160 @Override 161 public OutputStream writeBinary(String arg0) throws XMLStreamException { 162 return null; 163 } 164 165 @Override 166 public void writeBinary(byte[] data, int offset, int length, String contentType) throws XMLStreamException { 167// if (mtomThreshold == -1 || mtomThreshold > length) return null; 168 byte[] bytes = (offset == 0 && length == data.length) ? data : Arrays.copyOfRange(data, offset, offset + length); 169 if (currentElement instanceof MtomEnabled) { 170 binaryText = ((MtomEnabled) currentElement).addBinaryText(bytes); 171 } else { 172 throw new IllegalStateException("The currentElement is not MtomEnabled " + currentElement); 173 } 174 } 175 176 @Override 177 public void writePCDATA(CharSequence arg0) throws XMLStreamException { 178 if (arg0 instanceof Base64Data) { 179 // The fix of StreamReaderBufferCreator preserves this dataHandler 180 addBinaryText(((Base64Data) arg0).getDataHandler()); 181 } else { 182 // We should not normally get here as we expect a DataHandler, 183 // but this is the most general solution. If we do get 184 // something other than a Data Handler, create a Text node with 185 // the data. Another alternative would be to throw an exception, 186 // but in the most general case, we don't know whether this input 187 // is expected. 188 try { 189 currentElement.addTextNode(arg0.toString()); 190 } catch (SOAPException e) { 191 throw new XMLStreamException("Cannot add Text node", e); 192 } 193 } 194 } 195 196 static private String encodeCid() { 197 String cid = "example.jaxws.sun.com"; 198 String name = UUID.randomUUID() + "@"; 199 return name + cid; 200 } 201 202 private String addBinaryText(DataHandler data) { 203 String hrefOrCid = null; 204 if (data instanceof StreamingDataHandler) { 205 hrefOrCid = ((StreamingDataHandler) data).getHrefCid(); 206 } 207 if (hrefOrCid == null) hrefOrCid = encodeCid(); 208 209 String prefixedCid = (hrefOrCid.startsWith("cid:")) ? hrefOrCid : "cid:" + hrefOrCid; 210 // Should we do the threshold processing on DataHandler ? But that would be 211 // expensive as DataHolder need to read the data again from its source 212 //binaryText = BinaryTextImpl.createBinaryTextFromDataHandler((MessageImpl) soap, prefixedCid, currentElement.getOwnerDocument(), data); 213 //currentElement.appendChild(binaryText); 214 if (currentElement instanceof MtomEnabled) { 215 binaryText = ((MtomEnabled) currentElement).addBinaryText(prefixedCid, data); 216 } else { 217 throw new IllegalStateException("The currentElement is not MtomEnabled " + currentElement); 218 } 219 return hrefOrCid; 220 } 221 222 @Override 223 public AttachmentMarshaller getAttachmentMarshaller() { 224 return new AttachmentMarshaller() { 225 @Override 226 public String addMtomAttachment(DataHandler data, String ns, String ln) { 227// if (mtomThreshold == -1) return null; 228 String hrefOrCid = addBinaryText(data); 229// return binaryText.getHref(); 230 return hrefOrCid; 231 } 232 233 @Override 234 public String addMtomAttachment(byte[] data, int offset, int length, String mimeType, String ns, String ln) { 235// if (mtomThreshold == -1 || mtomThreshold > length) return null; 236 byte[] bytes = (offset == 0 && length == data.length) ? data : Arrays.copyOfRange(data, offset, offset + length); 237// binaryText = (BinaryTextImpl) ((ElementImpl) currentElement).addAsBase64TextNode(bytes); 238 if (currentElement instanceof MtomEnabled) { 239 binaryText = ((MtomEnabled) currentElement).addBinaryText(bytes); 240 } else { 241 throw new IllegalStateException("The currentElement is not MtomEnabled " + currentElement); 242 } 243 return binaryText.getHref(); 244 } 245 246 @Override 247 public String addSwaRefAttachment(DataHandler data) { 248 return "cid:"+encodeCid(); 249 } 250 251 @Override 252 public boolean isXOPPackage() { 253 return true; 254 } 255 }; 256 } 257} 258