src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MtomCodec.java

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 397
b99d7e355d4b
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 package com.sun.xml.internal.ws.encoding;
aoqi@0 27
aoqi@0 28 import com.sun.istack.internal.NotNull;
aoqi@0 29 import com.sun.xml.internal.bind.DatatypeConverterImpl;
aoqi@0 30 import com.sun.xml.internal.ws.api.SOAPVersion;
aoqi@0 31 import com.sun.xml.internal.ws.api.WSFeatureList;
aoqi@0 32 import com.sun.xml.internal.ws.api.message.Attachment;
aoqi@0 33 import com.sun.xml.internal.ws.api.message.AttachmentSet;
aoqi@0 34 import com.sun.xml.internal.ws.api.message.Packet;
aoqi@0 35 import com.sun.xml.internal.ws.api.pipe.ContentType;
aoqi@0 36 import com.sun.xml.internal.ws.api.pipe.StreamSOAPCodec;
aoqi@0 37 import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory;
aoqi@0 38 import com.sun.xml.internal.ws.api.streaming.XMLStreamWriterFactory;
aoqi@0 39 import com.sun.xml.internal.ws.developer.SerializationFeature;
aoqi@0 40 import com.sun.xml.internal.ws.developer.StreamingDataHandler;
aoqi@0 41 import com.sun.xml.internal.ws.message.MimeAttachmentSet;
aoqi@0 42 import com.sun.xml.internal.ws.streaming.XMLStreamWriterUtil;
aoqi@0 43 import com.sun.xml.internal.ws.util.ByteArrayDataSource;
aoqi@0 44 import com.sun.xml.internal.ws.util.xml.NamespaceContextExAdaper;
aoqi@0 45 import com.sun.xml.internal.ws.util.xml.XMLStreamReaderFilter;
aoqi@0 46 import com.sun.xml.internal.ws.util.xml.XMLStreamWriterFilter;
aoqi@0 47 import com.sun.xml.internal.ws.streaming.MtomStreamWriter;
aoqi@0 48 import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil;
aoqi@0 49 import com.sun.xml.internal.ws.server.UnsupportedMediaException;
aoqi@0 50 import com.sun.xml.internal.org.jvnet.staxex.Base64Data;
aoqi@0 51 import com.sun.xml.internal.org.jvnet.staxex.NamespaceContextEx;
aoqi@0 52 import com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx;
aoqi@0 53 import com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx;
aoqi@0 54
aoqi@0 55 import javax.activation.DataHandler;
aoqi@0 56 import javax.xml.namespace.NamespaceContext;
aoqi@0 57 import javax.xml.stream.XMLStreamConstants;
aoqi@0 58 import javax.xml.stream.XMLStreamException;
aoqi@0 59 import javax.xml.stream.XMLStreamReader;
aoqi@0 60 import javax.xml.stream.XMLStreamWriter;
aoqi@0 61 import javax.xml.ws.WebServiceException;
aoqi@0 62 import javax.xml.ws.soap.MTOMFeature;
aoqi@0 63 import javax.xml.bind.attachment.AttachmentMarshaller;
aoqi@0 64 import java.io.IOException;
aoqi@0 65 import java.io.OutputStream;
aoqi@0 66 import java.io.UnsupportedEncodingException;
aoqi@0 67 import java.net.URLDecoder;
aoqi@0 68 import java.nio.channels.WritableByteChannel;
aoqi@0 69 import java.nio.charset.Charset;
aoqi@0 70 import java.util.ArrayList;
aoqi@0 71 import java.util.Iterator;
aoqi@0 72 import java.util.List;
aoqi@0 73 import java.util.Map;
aoqi@0 74 import java.util.UUID;
aoqi@0 75
aoqi@0 76 /**
aoqi@0 77 * Mtom message Codec. It can be used even for non-soap message's mtom encoding.
aoqi@0 78 *
aoqi@0 79 * @author Vivek Pandey
aoqi@0 80 * @author Jitendra Kotamraju
aoqi@0 81 */
aoqi@0 82 public class MtomCodec extends MimeCodec {
aoqi@0 83
aoqi@0 84 public static final String XOP_XML_MIME_TYPE = "application/xop+xml";
aoqi@0 85 public static final String XOP_LOCALNAME = "Include";
aoqi@0 86 public static final String XOP_NAMESPACEURI = "http://www.w3.org/2004/08/xop/include";
aoqi@0 87
aoqi@0 88 private final StreamSOAPCodec codec;
aoqi@0 89 private final MTOMFeature mtomFeature;
aoqi@0 90 private final SerializationFeature sf;
aoqi@0 91 private final static String DECODED_MESSAGE_CHARSET = "decodedMessageCharset";
aoqi@0 92
aoqi@0 93 MtomCodec(SOAPVersion version, StreamSOAPCodec codec, WSFeatureList features){
aoqi@0 94 super(version, features);
aoqi@0 95 this.codec = codec;
aoqi@0 96 sf = features.get(SerializationFeature.class);
aoqi@0 97 MTOMFeature mtom = features.get(MTOMFeature.class);
aoqi@0 98 if(mtom == null)
aoqi@0 99 this.mtomFeature = new MTOMFeature();
aoqi@0 100 else
aoqi@0 101 this.mtomFeature = mtom;
aoqi@0 102 }
aoqi@0 103
aoqi@0 104 /**
aoqi@0 105 * Return the soap 1.1 and soap 1.2 specific XOP packaged ContentType
aoqi@0 106 *
aoqi@0 107 * @return A non-null content type for soap11 or soap 1.2 content type
aoqi@0 108 */
aoqi@0 109 @Override
aoqi@0 110 public ContentType getStaticContentType(Packet packet) {
aoqi@0 111 return getStaticContentTypeStatic(packet, version);
aoqi@0 112 }
aoqi@0 113
aoqi@0 114 public static ContentType getStaticContentTypeStatic(Packet packet, SOAPVersion version) {
aoqi@0 115 ContentType ct = (ContentType) packet.getInternalContentType();
aoqi@0 116 if ( ct != null ) return ct;
aoqi@0 117
aoqi@0 118 String uuid = UUID.randomUUID().toString();
aoqi@0 119 String boundary = "uuid:" + uuid;
aoqi@0 120 String rootId = "<rootpart*"+uuid+"@example.jaxws.sun.com>";
aoqi@0 121 String soapActionParameter = SOAPVersion.SOAP_11.equals(version) ? null : createActionParameter(packet);
aoqi@0 122
aoqi@0 123 String boundaryParameter = "boundary=\"" + boundary +"\"";
aoqi@0 124 String messageContentType = MULTIPART_RELATED_MIME_TYPE +
aoqi@0 125 ";start=\""+rootId +"\"" +
aoqi@0 126 ";type=\"" + XOP_XML_MIME_TYPE + "\";" +
aoqi@0 127 boundaryParameter +
aoqi@0 128 ";start-info=\"" + version.contentType +
aoqi@0 129 (soapActionParameter == null? "" : soapActionParameter) +
aoqi@0 130 "\"";
aoqi@0 131
aoqi@0 132 ContentTypeImpl ctImpl = SOAPVersion.SOAP_11.equals(version) ?
aoqi@0 133 new ContentTypeImpl(messageContentType, (packet.soapAction == null)?"":packet.soapAction, null) :
aoqi@0 134 new ContentTypeImpl(messageContentType, null, null);
aoqi@0 135 ctImpl.setBoundary(boundary);
aoqi@0 136 ctImpl.setRootId(rootId);
aoqi@0 137 packet.setContentType(ctImpl);
aoqi@0 138 return ctImpl;
aoqi@0 139 }
aoqi@0 140
aoqi@0 141 private static String createActionParameter(Packet packet) {
aoqi@0 142 return packet.soapAction != null? ";action=\\\""+packet.soapAction+"\\\"" : "";
aoqi@0 143 }
aoqi@0 144
aoqi@0 145 @Override
aoqi@0 146 public ContentType encode(Packet packet, OutputStream out) throws IOException {
aoqi@0 147 ContentTypeImpl ctImpl = (ContentTypeImpl) this.getStaticContentType(packet);
aoqi@0 148 String boundary = ctImpl.getBoundary();
aoqi@0 149 String rootId = ctImpl.getRootId();
aoqi@0 150
aoqi@0 151 if(packet.getMessage() != null){
aoqi@0 152 try {
aoqi@0 153 String encoding = getPacketEncoding(packet);
aoqi@0 154 packet.invocationProperties.remove(DECODED_MESSAGE_CHARSET);
aoqi@0 155
aoqi@0 156 String actionParameter = getActionParameter(packet, version);
aoqi@0 157 String soapXopContentType = getSOAPXopContentType(encoding, version, actionParameter);
aoqi@0 158
aoqi@0 159 writeln("--"+boundary, out);
aoqi@0 160 writeMimeHeaders(soapXopContentType, rootId, out);
aoqi@0 161
aoqi@0 162 //mtom attachments that need to be written after the root part
aoqi@0 163 List<ByteArrayBuffer> mtomAttachments = new ArrayList<ByteArrayBuffer>();
aoqi@0 164 MtomStreamWriterImpl writer = new MtomStreamWriterImpl(
aoqi@0 165 XMLStreamWriterFactory.create(out, encoding), mtomAttachments, boundary, mtomFeature);
aoqi@0 166
aoqi@0 167 packet.getMessage().writeTo(writer);
aoqi@0 168 XMLStreamWriterFactory.recycle(writer);
aoqi@0 169 writeln(out);
aoqi@0 170
aoqi@0 171 for(ByteArrayBuffer bos : mtomAttachments){
aoqi@0 172 bos.write(out);
aoqi@0 173 }
aoqi@0 174
aoqi@0 175 // now write out the attachments in the message that weren't
aoqi@0 176 // previously written
aoqi@0 177 writeNonMtomAttachments(packet.getMessage().getAttachments(),
aoqi@0 178 out, boundary);
aoqi@0 179
aoqi@0 180 //write out the end boundary
aoqi@0 181 writeAsAscii("--"+boundary, out);
aoqi@0 182 writeAsAscii("--", out);
aoqi@0 183
aoqi@0 184 } catch (XMLStreamException e) {
aoqi@0 185 throw new WebServiceException(e);
aoqi@0 186 }
aoqi@0 187 }
aoqi@0 188 //now create the boundary for next encode() call
aoqi@0 189 // createConteTypeHeader();
aoqi@0 190 return ctImpl;
aoqi@0 191 }
aoqi@0 192
aoqi@0 193 public static String getSOAPXopContentType(String encoding, SOAPVersion version,
aoqi@0 194 String actionParameter) {
aoqi@0 195 return XOP_XML_MIME_TYPE +";charset="+encoding+";type=\""+version.contentType+ actionParameter + "\"";
aoqi@0 196 }
aoqi@0 197
aoqi@0 198 public static String getActionParameter(Packet packet, SOAPVersion version) {
aoqi@0 199 return (version == SOAPVersion.SOAP_11) ? "" : createActionParameter(packet);
aoqi@0 200 }
aoqi@0 201
aoqi@0 202 public static class ByteArrayBuffer{
aoqi@0 203 final String contentId;
aoqi@0 204
aoqi@0 205 private final DataHandler dh;
aoqi@0 206 private final String boundary;
aoqi@0 207
aoqi@0 208 ByteArrayBuffer(@NotNull DataHandler dh, String b) {
aoqi@0 209 this.dh = dh;
aoqi@0 210 String cid = null;
aoqi@0 211 if (dh instanceof StreamingDataHandler) {
aoqi@0 212 StreamingDataHandler sdh = (StreamingDataHandler) dh;
aoqi@0 213 if (sdh.getHrefCid() != null)
aoqi@0 214 cid = sdh.getHrefCid();
aoqi@0 215 }
aoqi@0 216 this.contentId = cid != null ? cid : encodeCid();
aoqi@0 217 boundary = b;
aoqi@0 218 }
aoqi@0 219
aoqi@0 220 public void write(OutputStream os) throws IOException {
aoqi@0 221 //build attachment frame
aoqi@0 222 writeln("--"+boundary, os);
aoqi@0 223 writeMimeHeaders(dh.getContentType(), contentId, os);
aoqi@0 224 dh.writeTo(os);
aoqi@0 225 writeln(os);
aoqi@0 226 }
aoqi@0 227 }
aoqi@0 228
aoqi@0 229 public static void writeMimeHeaders(String contentType, String contentId, OutputStream out) throws IOException {
aoqi@0 230 String cid = contentId;
aoqi@0 231 if(cid != null && cid.length() >0 && cid.charAt(0) != '<')
aoqi@0 232 cid = '<' + cid + '>';
aoqi@0 233 writeln("Content-Id: " + cid, out);
aoqi@0 234 writeln("Content-Type: " + contentType, out);
aoqi@0 235 writeln("Content-Transfer-Encoding: binary", out);
aoqi@0 236 writeln(out);
aoqi@0 237 }
aoqi@0 238
aoqi@0 239 // Compiler warning for not calling close, but cannot call close,
aoqi@0 240 // will consume attachment bytes.
aoqi@0 241 @SuppressWarnings("resource")
aoqi@0 242 private void writeNonMtomAttachments(AttachmentSet attachments,
aoqi@0 243 OutputStream out, String boundary) throws IOException {
aoqi@0 244
aoqi@0 245 for (Attachment att : attachments) {
aoqi@0 246
aoqi@0 247 DataHandler dh = att.asDataHandler();
aoqi@0 248 if (dh instanceof StreamingDataHandler) {
aoqi@0 249 StreamingDataHandler sdh = (StreamingDataHandler) dh;
aoqi@0 250 // If DataHandler has href Content-ID, it is MTOM, so skip.
aoqi@0 251 if (sdh.getHrefCid() != null)
aoqi@0 252 continue;
aoqi@0 253 }
aoqi@0 254
aoqi@0 255 // build attachment frame
aoqi@0 256 writeln("--" + boundary, out);
aoqi@0 257 writeMimeHeaders(att.getContentType(), att.getContentId(), out);
aoqi@0 258 att.writeTo(out);
aoqi@0 259 writeln(out); // write \r\n
aoqi@0 260 }
aoqi@0 261 }
aoqi@0 262
aoqi@0 263 @Override
aoqi@0 264 public ContentType encode(Packet packet, WritableByteChannel buffer) {
aoqi@0 265 throw new UnsupportedOperationException();
aoqi@0 266 }
aoqi@0 267
aoqi@0 268 @Override
aoqi@0 269 public MtomCodec copy() {
aoqi@0 270 return new MtomCodec(version, (StreamSOAPCodec)codec.copy(), features);
aoqi@0 271 }
aoqi@0 272
aoqi@0 273 private static String encodeCid(){
aoqi@0 274 String cid="example.jaxws.sun.com";
aoqi@0 275 String name = UUID.randomUUID()+"@";
aoqi@0 276 return name + cid;
aoqi@0 277 }
aoqi@0 278
aoqi@0 279 @Override
aoqi@0 280 protected void decode(MimeMultipartParser mpp, Packet packet) throws IOException {
aoqi@0 281 //TODO shouldn't we check for SOAP1.1/SOAP1.2 and throw
aoqi@0 282 //TODO UnsupportedMediaException like StreamSOAPCodec
aoqi@0 283 String charset = null;
aoqi@0 284 String ct = mpp.getRootPart().getContentType();
aoqi@0 285 if (ct != null) {
aoqi@0 286 charset = new ContentTypeImpl(ct).getCharSet();
aoqi@0 287 }
aoqi@0 288 if (charset != null && !Charset.isSupported(charset)) {
aoqi@0 289 throw new UnsupportedMediaException(charset);
aoqi@0 290 }
aoqi@0 291
aoqi@0 292 if (charset != null) {
aoqi@0 293 packet.invocationProperties.put(DECODED_MESSAGE_CHARSET, charset);
aoqi@0 294 } else {
aoqi@0 295 packet.invocationProperties.remove(DECODED_MESSAGE_CHARSET);
aoqi@0 296 }
aoqi@0 297
aoqi@0 298 // we'd like to reuse those reader objects but unfortunately decoder may be reused
aoqi@0 299 // before the decoded message is completely used.
aoqi@0 300 XMLStreamReader mtomReader = new MtomXMLStreamReaderEx( mpp,
aoqi@0 301 XMLStreamReaderFactory.create(null, mpp.getRootPart().asInputStream(), charset, true)
aoqi@0 302 );
aoqi@0 303
aoqi@0 304 packet.setMessage(codec.decode(mtomReader, new MimeAttachmentSet(mpp)));
aoqi@0 305 packet.setMtomFeature(mtomFeature);
aoqi@0 306 packet.setContentType(mpp.getContentType());
aoqi@0 307 }
aoqi@0 308
aoqi@0 309 private String getPacketEncoding(Packet packet) {
aoqi@0 310 // If SerializationFeature is set, just use that encoding
aoqi@0 311 if (sf != null && sf.getEncoding() != null) {
aoqi@0 312 return sf.getEncoding().equals("") ? SOAPBindingCodec.DEFAULT_ENCODING : sf.getEncoding();
aoqi@0 313 }
aoqi@0 314 return determinePacketEncoding(packet);
aoqi@0 315 }
aoqi@0 316
aoqi@0 317 public static String determinePacketEncoding(Packet packet) {
aoqi@0 318 if (packet != null && packet.endpoint != null) {
aoqi@0 319 // Use request message's encoding for Server-side response messages
aoqi@0 320 String charset = (String)packet.invocationProperties.get(DECODED_MESSAGE_CHARSET);
aoqi@0 321 return charset == null
aoqi@0 322 ? SOAPBindingCodec.DEFAULT_ENCODING : charset;
aoqi@0 323 }
aoqi@0 324
aoqi@0 325 // Use default encoding for client-side request messages
aoqi@0 326 return SOAPBindingCodec.DEFAULT_ENCODING;
aoqi@0 327 }
aoqi@0 328
aoqi@0 329 public static class MtomStreamWriterImpl extends XMLStreamWriterFilter implements XMLStreamWriterEx,
aoqi@0 330 MtomStreamWriter, HasEncoding {
aoqi@0 331 private final List<ByteArrayBuffer> mtomAttachments;
aoqi@0 332 private final String boundary;
aoqi@0 333 private final MTOMFeature myMtomFeature;
aoqi@0 334 public MtomStreamWriterImpl(XMLStreamWriter w, List<ByteArrayBuffer> mtomAttachments, String b, MTOMFeature myMtomFeature) {
aoqi@0 335 super(w);
aoqi@0 336 this.mtomAttachments = mtomAttachments;
aoqi@0 337 this.boundary = b;
aoqi@0 338 this.myMtomFeature = myMtomFeature;
aoqi@0 339 }
aoqi@0 340
aoqi@0 341 @Override
aoqi@0 342 public void writeBinary(byte[] data, int start, int len, String contentType) throws XMLStreamException {
aoqi@0 343 //check threshold and if less write as base64encoded value
aoqi@0 344 if(myMtomFeature.getThreshold() > len){
aoqi@0 345 writeCharacters(DatatypeConverterImpl._printBase64Binary(data, start, len));
aoqi@0 346 return;
aoqi@0 347 }
aoqi@0 348 ByteArrayBuffer bab = new ByteArrayBuffer(new DataHandler(new ByteArrayDataSource(data, start, len, contentType)), boundary);
aoqi@0 349 writeBinary(bab);
aoqi@0 350 }
aoqi@0 351
aoqi@0 352 @Override
aoqi@0 353 public void writeBinary(DataHandler dataHandler) throws XMLStreamException {
aoqi@0 354 // TODO how do we check threshold and if less inline the data
aoqi@0 355 writeBinary(new ByteArrayBuffer(dataHandler, boundary));
aoqi@0 356 }
aoqi@0 357
aoqi@0 358 @Override
aoqi@0 359 public OutputStream writeBinary(String contentType) throws XMLStreamException {
aoqi@0 360 throw new UnsupportedOperationException();
aoqi@0 361 }
aoqi@0 362
aoqi@0 363 @Override
aoqi@0 364 public void writePCDATA(CharSequence data) throws XMLStreamException {
aoqi@0 365 if(data == null)
aoqi@0 366 return;
aoqi@0 367 if(data instanceof Base64Data){
aoqi@0 368 Base64Data binaryData = (Base64Data)data;
aoqi@0 369 writeBinary(binaryData.getDataHandler());
aoqi@0 370 return;
aoqi@0 371 }
aoqi@0 372 writeCharacters(data.toString());
aoqi@0 373 }
aoqi@0 374
aoqi@0 375 private void writeBinary(ByteArrayBuffer bab) {
aoqi@0 376 try {
aoqi@0 377 mtomAttachments.add(bab);
aoqi@0 378 String prefix = writer.getPrefix(XOP_NAMESPACEURI);
aoqi@0 379 if (prefix == null || !prefix.equals("xop")) {
aoqi@0 380 writer.setPrefix("xop", XOP_NAMESPACEURI);
aoqi@0 381 writer.writeNamespace("xop", XOP_NAMESPACEURI);
aoqi@0 382 }
aoqi@0 383 writer.writeStartElement(XOP_NAMESPACEURI, XOP_LOCALNAME);
aoqi@0 384 writer.writeAttribute("href", "cid:"+bab.contentId);
aoqi@0 385 writer.writeEndElement();
aoqi@0 386 writer.flush();
aoqi@0 387 } catch (XMLStreamException e) {
aoqi@0 388 throw new WebServiceException(e);
aoqi@0 389 }
aoqi@0 390 }
aoqi@0 391
aoqi@0 392 @Override
aoqi@0 393 public Object getProperty(String name) throws IllegalArgumentException {
aoqi@0 394 // Hack for JDK6's SJSXP
aoqi@0 395 if (name.equals("sjsxp-outputstream") && writer instanceof Map) {
aoqi@0 396 Object obj = ((Map) writer).get("sjsxp-outputstream");
aoqi@0 397 if (obj != null) {
aoqi@0 398 return obj;
aoqi@0 399 }
aoqi@0 400 }
aoqi@0 401 return super.getProperty(name);
aoqi@0 402 }
aoqi@0 403
aoqi@0 404 /**
aoqi@0 405 * JAXBMessage writes envelope directly to the OutputStream(for SJSXP, woodstox).
aoqi@0 406 * While writing, it calls the AttachmentMarshaller methods for adding attachments.
aoqi@0 407 * JAXB writes xop:Include in this case.
aoqi@0 408 */
aoqi@0 409 @Override
aoqi@0 410 public AttachmentMarshaller getAttachmentMarshaller() {
aoqi@0 411 return new AttachmentMarshaller() {
aoqi@0 412
aoqi@0 413 @Override
aoqi@0 414 public String addMtomAttachment(DataHandler data, String elementNamespace, String elementLocalName) {
aoqi@0 415 // Should we do the threshold processing on DataHandler ? But that would be
aoqi@0 416 // expensive as DataHolder need to read the data again from its source
aoqi@0 417 ByteArrayBuffer bab = new ByteArrayBuffer(data, boundary);
aoqi@0 418 mtomAttachments.add(bab);
aoqi@0 419 return "cid:"+bab.contentId;
aoqi@0 420 }
aoqi@0 421
aoqi@0 422 @Override
aoqi@0 423 public String addMtomAttachment(byte[] data, int offset, int length, String mimeType, String elementNamespace, String elementLocalName) {
aoqi@0 424 // inline the data based on the threshold
aoqi@0 425 if (myMtomFeature.getThreshold() > length) {
aoqi@0 426 return null; // JAXB inlines the attachment data
aoqi@0 427 }
aoqi@0 428 ByteArrayBuffer bab = new ByteArrayBuffer(new DataHandler(new ByteArrayDataSource(data, offset, length, mimeType)), boundary);
aoqi@0 429 mtomAttachments.add(bab);
aoqi@0 430 return "cid:"+bab.contentId;
aoqi@0 431 }
aoqi@0 432
aoqi@0 433 @Override
aoqi@0 434 public String addSwaRefAttachment(DataHandler data) {
aoqi@0 435 ByteArrayBuffer bab = new ByteArrayBuffer(data, boundary);
aoqi@0 436 mtomAttachments.add(bab);
aoqi@0 437 return "cid:"+bab.contentId;
aoqi@0 438 }
aoqi@0 439
aoqi@0 440 @Override
aoqi@0 441 public boolean isXOPPackage() {
aoqi@0 442 return true;
aoqi@0 443 }
aoqi@0 444 };
aoqi@0 445 }
aoqi@0 446
aoqi@0 447 public List<ByteArrayBuffer> getMtomAttachments() {
aoqi@0 448 return this.mtomAttachments;
aoqi@0 449 }
aoqi@0 450
aoqi@0 451 @Override
aoqi@0 452 public String getEncoding() {
aoqi@0 453 return XMLStreamWriterUtil.getEncoding(writer);
aoqi@0 454 }
aoqi@0 455
aoqi@0 456 private static class MtomNamespaceContextEx implements NamespaceContextEx {
aoqi@0 457 private final NamespaceContext nsContext;
aoqi@0 458
aoqi@0 459 public MtomNamespaceContextEx(NamespaceContext nsContext) {
aoqi@0 460 this.nsContext = nsContext;
aoqi@0 461 }
aoqi@0 462
aoqi@0 463 @Override
aoqi@0 464 public Iterator<Binding> iterator() {
aoqi@0 465 throw new UnsupportedOperationException();
aoqi@0 466 }
aoqi@0 467
aoqi@0 468 @Override
aoqi@0 469 public String getNamespaceURI(String prefix) {
aoqi@0 470 return nsContext.getNamespaceURI(prefix);
aoqi@0 471 }
aoqi@0 472
aoqi@0 473 @Override
aoqi@0 474 public String getPrefix(String namespaceURI) {
aoqi@0 475 return nsContext.getPrefix(namespaceURI);
aoqi@0 476 }
aoqi@0 477
aoqi@0 478 @Override
aoqi@0 479 public Iterator getPrefixes(String namespaceURI) {
aoqi@0 480 return nsContext.getPrefixes(namespaceURI);
aoqi@0 481 }
aoqi@0 482 }
aoqi@0 483
aoqi@0 484 @Override
aoqi@0 485 public NamespaceContextEx getNamespaceContext() {
aoqi@0 486 NamespaceContext nsContext = writer.getNamespaceContext();
aoqi@0 487 return new MtomNamespaceContextEx(nsContext);
aoqi@0 488 }
aoqi@0 489 }
aoqi@0 490
aoqi@0 491 public static class MtomXMLStreamReaderEx extends XMLStreamReaderFilter implements XMLStreamReaderEx {
aoqi@0 492 /**
aoqi@0 493 * The parser for the outer MIME 'shell'.
aoqi@0 494 */
aoqi@0 495 private final MimeMultipartParser mimeMP;
aoqi@0 496
aoqi@0 497 private boolean xopReferencePresent = false;
aoqi@0 498 private Base64Data base64AttData;
aoqi@0 499
aoqi@0 500 //To be used with #getTextCharacters
aoqi@0 501 private char[] base64EncodedText;
aoqi@0 502
aoqi@0 503 private String xopHref;
aoqi@0 504
aoqi@0 505 public MtomXMLStreamReaderEx(MimeMultipartParser mimeMP, XMLStreamReader reader) {
aoqi@0 506 super(reader);
aoqi@0 507 this.mimeMP = mimeMP;
aoqi@0 508 }
aoqi@0 509
aoqi@0 510 @Override
aoqi@0 511 public CharSequence getPCDATA() throws XMLStreamException {
aoqi@0 512 if(xopReferencePresent){
aoqi@0 513 return base64AttData;
aoqi@0 514 }
aoqi@0 515 return reader.getText();
aoqi@0 516 }
aoqi@0 517
aoqi@0 518 @Override
aoqi@0 519 public NamespaceContextEx getNamespaceContext() {
aoqi@0 520 return new NamespaceContextExAdaper(reader.getNamespaceContext());
aoqi@0 521 }
aoqi@0 522
aoqi@0 523 @Override
aoqi@0 524 public String getElementTextTrim() throws XMLStreamException {
aoqi@0 525 throw new UnsupportedOperationException();
aoqi@0 526 }
aoqi@0 527
aoqi@0 528 @Override
aoqi@0 529 public int getTextLength() {
aoqi@0 530 if (xopReferencePresent) {
aoqi@0 531 return base64AttData.length();
aoqi@0 532 }
aoqi@0 533 return reader.getTextLength();
aoqi@0 534 }
aoqi@0 535
aoqi@0 536 @Override
aoqi@0 537 public int getTextStart() {
aoqi@0 538 if (xopReferencePresent) {
aoqi@0 539 return 0;
aoqi@0 540 }
aoqi@0 541 return reader.getTextStart();
aoqi@0 542 }
aoqi@0 543
aoqi@0 544 @Override
aoqi@0 545 public int getEventType() {
aoqi@0 546 if(xopReferencePresent)
aoqi@0 547 return XMLStreamConstants.CHARACTERS;
aoqi@0 548 return super.getEventType();
aoqi@0 549 }
aoqi@0 550
aoqi@0 551 @Override
aoqi@0 552 public int next() throws XMLStreamException {
aoqi@0 553 int event = reader.next();
aoqi@0 554 if (event == XMLStreamConstants.START_ELEMENT && reader.getLocalName().equals(XOP_LOCALNAME) && reader.getNamespaceURI().equals(XOP_NAMESPACEURI)) {
aoqi@0 555 //its xop reference, take the URI reference
aoqi@0 556 String href = reader.getAttributeValue(null, "href");
aoqi@0 557 try {
aoqi@0 558 xopHref = href;
aoqi@0 559 Attachment att = getAttachment(href);
aoqi@0 560 if(att != null){
aoqi@0 561 DataHandler dh = att.asDataHandler();
aoqi@0 562 if (dh instanceof StreamingDataHandler) {
aoqi@0 563 ((StreamingDataHandler)dh).setHrefCid(att.getContentId());
aoqi@0 564 }
aoqi@0 565 base64AttData = new Base64Data();
aoqi@0 566 base64AttData.set(dh);
aoqi@0 567 }
aoqi@0 568 xopReferencePresent = true;
aoqi@0 569 } catch (IOException e) {
aoqi@0 570 throw new WebServiceException(e);
aoqi@0 571 }
aoqi@0 572 //move to the </xop:Include>
aoqi@0 573 XMLStreamReaderUtil.nextElementContent(reader);
aoqi@0 574 return XMLStreamConstants.CHARACTERS;
aoqi@0 575 }
aoqi@0 576 if(xopReferencePresent){
aoqi@0 577 xopReferencePresent = false;
aoqi@0 578 base64EncodedText = null;
aoqi@0 579 xopHref = null;
aoqi@0 580 }
aoqi@0 581 return event;
aoqi@0 582 }
aoqi@0 583
aoqi@0 584 private String decodeCid(String cid) {
aoqi@0 585 try {
aoqi@0 586 cid = URLDecoder.decode(cid, "utf-8");
aoqi@0 587 } catch (UnsupportedEncodingException e) {
aoqi@0 588 //on recceiving side lets not fail now, try to look for it
aoqi@0 589 }
aoqi@0 590 return cid;
aoqi@0 591 }
aoqi@0 592
aoqi@0 593 private Attachment getAttachment(String cid) throws IOException {
aoqi@0 594 if (cid.startsWith("cid:"))
aoqi@0 595 cid = cid.substring(4, cid.length());
aoqi@0 596 if (cid.indexOf('%') != -1) {
aoqi@0 597 cid = decodeCid(cid);
aoqi@0 598 return mimeMP.getAttachmentPart(cid);
aoqi@0 599 }
aoqi@0 600 return mimeMP.getAttachmentPart(cid);
aoqi@0 601 }
aoqi@0 602
aoqi@0 603 @Override
aoqi@0 604 public char[] getTextCharacters() {
aoqi@0 605 if (xopReferencePresent) {
aoqi@0 606 char[] chars = new char[base64AttData.length()];
aoqi@0 607 base64AttData.writeTo(chars, 0);
aoqi@0 608 return chars;
aoqi@0 609 }
aoqi@0 610 return reader.getTextCharacters();
aoqi@0 611 }
aoqi@0 612
aoqi@0 613 @Override
aoqi@0 614 public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException {
aoqi@0 615 if(xopReferencePresent){
aoqi@0 616 if(target == null){
aoqi@0 617 throw new NullPointerException("target char array can't be null") ;
aoqi@0 618 }
aoqi@0 619
aoqi@0 620 if(targetStart < 0 || length < 0 || sourceStart < 0 || targetStart >= target.length ||
aoqi@0 621 (targetStart + length ) > target.length) {
aoqi@0 622 throw new IndexOutOfBoundsException();
aoqi@0 623 }
aoqi@0 624
aoqi@0 625 int textLength = base64AttData.length();
aoqi@0 626 if(sourceStart > textLength)
aoqi@0 627 throw new IndexOutOfBoundsException();
aoqi@0 628
aoqi@0 629 if(base64EncodedText == null){
aoqi@0 630 base64EncodedText = new char[base64AttData.length()];
aoqi@0 631 base64AttData.writeTo(base64EncodedText, 0);
aoqi@0 632 }
aoqi@0 633
aoqi@0 634 int copiedLength = Math.min(textLength - sourceStart, length);
aoqi@0 635 System.arraycopy(base64EncodedText, sourceStart , target, targetStart, copiedLength);
aoqi@0 636 return copiedLength;
aoqi@0 637 }
aoqi@0 638 return reader.getTextCharacters(sourceStart, target, targetStart, length);
aoqi@0 639 }
aoqi@0 640
aoqi@0 641 @Override
aoqi@0 642 public String getText() {
aoqi@0 643 if (xopReferencePresent) {
aoqi@0 644 return base64AttData.toString();
aoqi@0 645 }
aoqi@0 646 return reader.getText();
aoqi@0 647 }
aoqi@0 648
aoqi@0 649 protected boolean isXopReference() throws XMLStreamException {
aoqi@0 650 return xopReferencePresent;
aoqi@0 651 }
aoqi@0 652
aoqi@0 653 protected String getXopHref() {
aoqi@0 654 return xopHref;
aoqi@0 655 }
aoqi@0 656
aoqi@0 657 public MimeMultipartParser getMimeMultipartParser() {
aoqi@0 658 return mimeMP;
aoqi@0 659 }
aoqi@0 660 }
aoqi@0 661
aoqi@0 662 }

mercurial