1 /* 2 * Copyright (c) 1997, 2014, 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 26 package com.sun.xml.internal.messaging.saaj.soap; 27 28 import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; 29 30 import com.sun.xml.internal.messaging.saaj.packaging.mime.util.ASCIIUtility; 31 32 import com.sun.xml.internal.messaging.saaj.packaging.mime.Header; 33 import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimePartDataSource; 34 import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.InternetHeaders; 35 import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimeBodyPart; 36 import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimeUtility; 37 import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream; 38 import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants; 39 40 import java.io.IOException; 41 import java.io.InputStream; 42 import java.io.ByteArrayOutputStream; 43 import java.io.ByteArrayInputStream; 44 import java.io.OutputStream; 45 import java.util.Iterator; 46 import java.util.List; 47 import java.util.logging.Level; 48 import java.util.logging.Logger; 49 50 import javax.activation.*; 51 import javax.xml.soap.*; 52 import com.sun.xml.internal.org.jvnet.mimepull.MIMEPart; 53 54 /** 55 * Implementation of attachments. 56 * 57 * @author Anil Vijendran (akv@eng.sun.com) 58 */ 59 public class AttachmentPartImpl extends AttachmentPart { 60 61 protected static final Logger log = 62 Logger.getLogger(LogDomainConstants.SOAP_DOMAIN, 63 "com.sun.xml.internal.messaging.saaj.soap.LocalStrings"); 64 65 static { 66 try { 67 CommandMap map = CommandMap.getDefaultCommandMap(); 68 if (map instanceof MailcapCommandMap) { 69 MailcapCommandMap mailMap = (MailcapCommandMap) map; 70 String hndlrStr = ";;x-java-content-handler="; 71 mailMap.addMailcap( 72 "text/xml" 73 + hndlrStr 74 + "com.sun.xml.internal.messaging.saaj.soap.XmlDataContentHandler"); 75 mailMap.addMailcap( 76 "application/xml" 77 + hndlrStr 78 + "com.sun.xml.internal.messaging.saaj.soap.XmlDataContentHandler"); 79 mailMap.addMailcap( 80 "application/fastinfoset" 81 + hndlrStr 82 + "com.sun.xml.internal.messaging.saaj.soap.FastInfosetDataContentHandler"); 83 /* Image DataContentHandler handles all image types 84 mailMap.addMailcap( 85 "image/jpeg" 86 + hndlrStr 87 + "com.sun.xml.internal.messaging.saaj.soap.JpegDataContentHandler"); 88 mailMap.addMailcap( 89 "image/gif" 90 + hndlrStr 91 + "com.sun.xml.internal.messaging.saaj.soap.GifDataContentHandler"); */ 92 /*mailMap.addMailcap( 93 "multipart/*" 94 + hndlrStr 95 + "com.sun.xml.internal.messaging.saaj.soap.MultipartDataContentHandler");*/ 96 mailMap.addMailcap( 97 "image/*" 98 + hndlrStr 99 + "com.sun.xml.internal.messaging.saaj.soap.ImageDataContentHandler"); 100 mailMap.addMailcap( 101 "text/plain" 102 + hndlrStr 103 + "com.sun.xml.internal.messaging.saaj.soap.StringDataContentHandler"); 104 } else { 105 throw new SOAPExceptionImpl("Default CommandMap is not a MailcapCommandMap"); 106 } 107 } catch (Throwable t) { 108 log.log( 109 Level.SEVERE, 110 "SAAJ0508.soap.cannot.register.handlers", 111 t); 112 if (t instanceof RuntimeException) { 113 throw (RuntimeException) t; 114 } else { 115 throw new RuntimeException(t.getLocalizedMessage()); 116 } 117 } 118 }; 119 120 private final MimeHeaders headers; 121 private MimeBodyPart rawContent = null; 122 private DataHandler dataHandler = null; 123 124 //alternate impl that uses a MIMEPart 125 private MIMEPart mimePart = null; 126 127 public AttachmentPartImpl() { 128 headers = new MimeHeaders(); 129 } 130 131 public AttachmentPartImpl(MIMEPart part) { 132 headers = new MimeHeaders(); 133 mimePart = part; 134 List<? extends com.sun.xml.internal.org.jvnet.mimepull.Header> hdrs = part.getAllHeaders(); 135 for (com.sun.xml.internal.org.jvnet.mimepull.Header hd : hdrs) { 136 headers.addHeader(hd.getName(), hd.getValue()); 137 } 138 } 139 140 public int getSize() throws SOAPException { 141 if (mimePart != null) { 142 try { 143 return mimePart.read().available(); 144 } catch (IOException e) { 145 return -1; 146 } 147 } 148 if ((rawContent == null) && (dataHandler == null)) 149 return 0; 150 151 if (rawContent != null) { 152 try { 153 return rawContent.getSize(); 154 } catch (Exception ex) { 155 log.log( 156 Level.SEVERE, 157 "SAAJ0573.soap.attachment.getrawbytes.ioexception", 158 new String[] { ex.getLocalizedMessage()}); 159 throw new SOAPExceptionImpl("Raw InputStream Error: " + ex); 160 } 161 } else { 162 ByteOutputStream bout = new ByteOutputStream(); 163 try { 164 dataHandler.writeTo(bout); 165 } catch (IOException ex) { 166 log.log( 167 Level.SEVERE, 168 "SAAJ0501.soap.data.handler.err", 169 new String[] { ex.getLocalizedMessage()}); 170 throw new SOAPExceptionImpl("Data handler error: " + ex); 171 } 172 return bout.size(); 173 } 174 } 175 176 public void clearContent() { 177 if (mimePart != null) { 178 mimePart.close(); 179 mimePart = null; 180 } 181 dataHandler = null; 182 rawContent = null; 183 } 184 185 public Object getContent() throws SOAPException { 186 try { 187 if (mimePart != null) { 188 //return an inputstream 189 return mimePart.read(); 190 } 191 if (dataHandler != null) { 192 return getDataHandler().getContent(); 193 } else if (rawContent != null) { 194 return rawContent.getContent(); 195 } else { 196 log.severe("SAAJ0572.soap.no.content.for.attachment"); 197 throw new SOAPExceptionImpl("No data handler/content associated with this attachment"); 198 } 199 } catch (Exception ex) { 200 log.log(Level.SEVERE, "SAAJ0575.soap.attachment.getcontent.exception", ex); 201 throw new SOAPExceptionImpl(ex.getLocalizedMessage()); 202 } 203 } 204 205 public void setContent(Object object, String contentType) 206 throws IllegalArgumentException { 207 if (mimePart != null) { 208 mimePart.close(); 209 mimePart = null; 210 } 211 DataHandler dh = new DataHandler(object, contentType); 212 213 setDataHandler(dh); 214 } 215 216 217 public DataHandler getDataHandler() throws SOAPException { 218 if (mimePart != null) { 219 //return an inputstream 220 return new DataHandler(new DataSource() { 221 222 public InputStream getInputStream() throws IOException { 223 return mimePart.read(); 224 } 225 226 public OutputStream getOutputStream() throws IOException { 227 throw new UnsupportedOperationException("getOutputStream cannot be supported : You have enabled LazyAttachments Option"); 228 } 229 230 public String getContentType() { 231 return mimePart.getContentType(); 232 } 233 234 public String getName() { 235 return "MIMEPart Wrapper DataSource"; 236 } 237 }); 238 } 239 if (dataHandler == null) { 240 if (rawContent != null) { 241 return new DataHandler(new MimePartDataSource(rawContent)); 242 } 243 log.severe("SAAJ0502.soap.no.handler.for.attachment"); 244 throw new SOAPExceptionImpl("No data handler associated with this attachment"); 245 } 246 return dataHandler; 247 } 248 249 public void setDataHandler(DataHandler dataHandler) 250 throws IllegalArgumentException { 251 if (mimePart != null) { 252 mimePart.close(); 253 mimePart = null; 254 } 255 if (dataHandler == null) { 256 log.severe("SAAJ0503.soap.no.null.to.dataHandler"); 257 throw new IllegalArgumentException("Null dataHandler argument to setDataHandler"); 258 } 259 this.dataHandler = dataHandler; 260 rawContent = null; 261 262 if (log.isLoggable(Level.FINE)) 263 log.log(Level.FINE, "SAAJ0580.soap.set.Content-Type", 264 new String[] { dataHandler.getContentType() }); 265 setMimeHeader("Content-Type", dataHandler.getContentType()); 266 } 267 268 public void removeAllMimeHeaders() { 269 headers.removeAllHeaders(); 270 } 271 272 public void removeMimeHeader(String header) { 273 headers.removeHeader(header); 274 } 275 276 public String[] getMimeHeader(String name) { 277 return headers.getHeader(name); 278 } 279 280 public void setMimeHeader(String name, String value) { 281 headers.setHeader(name, value); 282 } 283 284 public void addMimeHeader(String name, String value) { 285 headers.addHeader(name, value); 286 } 287 288 public Iterator getAllMimeHeaders() { 289 return headers.getAllHeaders(); 290 } 291 292 public Iterator getMatchingMimeHeaders(String[] names) { 293 return headers.getMatchingHeaders(names); 294 } 295 296 public Iterator getNonMatchingMimeHeaders(String[] names) { 297 return headers.getNonMatchingHeaders(names); 298 } 299 300 boolean hasAllHeaders(MimeHeaders hdrs) { 301 if (hdrs != null) { 302 Iterator i = hdrs.getAllHeaders(); 303 while (i.hasNext()) { 304 MimeHeader hdr = (MimeHeader) i.next(); 305 String[] values = headers.getHeader(hdr.getName()); 306 boolean found = false; 307 308 if (values != null) { 309 for (int j = 0; j < values.length; j++) 310 if (hdr.getValue().equalsIgnoreCase(values[j])) { 311 found = true; 312 break; 313 } 314 } 315 316 if (!found) { 317 return false; 318 } 319 } 320 } 321 return true; 322 } 323 324 MimeBodyPart getMimePart() throws SOAPException { 325 try { 326 if (this.mimePart != null) { 327 return new MimeBodyPart(mimePart); 328 } 329 if (rawContent != null) { 330 copyMimeHeaders(headers, rawContent); 331 return rawContent; 332 } 333 334 MimeBodyPart envelope = new MimeBodyPart(); 335 336 envelope.setDataHandler(dataHandler); 337 copyMimeHeaders(headers, envelope); 338 339 return envelope; 340 } catch (Exception ex) { 341 log.severe("SAAJ0504.soap.cannot.externalize.attachment"); 342 throw new SOAPExceptionImpl("Unable to externalize attachment", ex); 343 } 344 } 345 346 public static void copyMimeHeaders(MimeHeaders headers, MimeBodyPart mbp) 347 throws SOAPException { 348 349 Iterator i = headers.getAllHeaders(); 350 351 while (i.hasNext()) 352 try { 353 MimeHeader mh = (MimeHeader) i.next(); 354 355 mbp.setHeader(mh.getName(), mh.getValue()); 356 } catch (Exception ex) { 357 log.severe("SAAJ0505.soap.cannot.copy.mime.hdr"); 358 throw new SOAPExceptionImpl("Unable to copy MIME header", ex); 359 } 360 } 361 362 public static void copyMimeHeaders(MimeBodyPart mbp, AttachmentPartImpl ap) 363 throws SOAPException { 364 try { 365 List hdr = mbp.getAllHeaders(); 366 int sz = hdr.size(); 367 for( int i=0; i<sz; i++ ) { 368 Header h = (Header)hdr.get(i); 369 if(h.getName().equalsIgnoreCase("Content-Type")) 370 continue; // skip 371 ap.addMimeHeader(h.getName(), h.getValue()); 372 } 373 } catch (Exception ex) { 374 log.severe("SAAJ0506.soap.cannot.copy.mime.hdrs.into.attachment"); 375 throw new SOAPExceptionImpl( 376 "Unable to copy MIME headers into attachment", 377 ex); 378 } 379 } 380 381 public void setBase64Content(InputStream content, String contentType) 382 throws SOAPException { 383 384 if (mimePart != null) { 385 mimePart.close(); 386 mimePart = null; 387 } 388 dataHandler = null; 389 InputStream decoded = null; 390 ByteOutputStream bos = null; 391 try { 392 decoded = MimeUtility.decode(content, "base64"); 393 InternetHeaders hdrs = new InternetHeaders(); 394 hdrs.setHeader("Content-Type", contentType); 395 //TODO: reading the entire attachment here is ineffcient. Somehow the MimeBodyPart 396 // Ctor with inputStream causes problems based on the InputStream 397 // has markSupported()==true 398 bos = new ByteOutputStream(); 399 bos.write(decoded); 400 rawContent = new MimeBodyPart(hdrs, bos.getBytes(), bos.getCount()); 401 setMimeHeader("Content-Type", contentType); 402 } catch (Exception e) { 403 log.log(Level.SEVERE, "SAAJ0578.soap.attachment.setbase64content.exception", e); 404 throw new SOAPExceptionImpl(e.getLocalizedMessage()); 405 } finally { 406 if (bos != null) 407 bos.close(); 408 try { 409 if (decoded != null) 410 decoded.close(); 411 } catch (IOException ex) { 412 throw new SOAPException(ex); 413 } 414 } 415 } 416 417 public InputStream getBase64Content() throws SOAPException { 418 InputStream stream; 419 if (mimePart != null) { 420 stream = mimePart.read(); 421 } else if (rawContent != null) { 422 try { 423 stream = rawContent.getInputStream(); 424 } catch (Exception e) { 425 log.log(Level.SEVERE,"SAAJ0579.soap.attachment.getbase64content.exception", e); 426 throw new SOAPExceptionImpl(e.getLocalizedMessage()); 427 } 428 } else if (dataHandler != null) { 429 try { 430 stream = dataHandler.getInputStream(); 431 } catch (IOException e) { 432 log.severe("SAAJ0574.soap.attachment.datahandler.ioexception"); 433 throw new SOAPExceptionImpl("DataHandler error" + e); 434 } 435 } else { 436 log.severe("SAAJ0572.soap.no.content.for.attachment"); 437 throw new SOAPExceptionImpl("No data handler/content associated with this attachment"); 438 } 439 440 //TODO: Write a BASE64EncoderInputStream instead, 441 // this code below is inefficient 442 // where we are trying to read the whole attachment first 443 int len; 444 int size = 1024; 445 byte [] buf; 446 if (stream != null) { 447 try { 448 ByteArrayOutputStream bos = new ByteArrayOutputStream(size); 449 //TODO: try and optimize this on the same lines as 450 // ByteOutputStream : to eliminate the temp buffer here 451 OutputStream ret = MimeUtility.encode(bos, "base64"); 452 buf = new byte[size]; 453 while ((len = stream.read(buf, 0, size)) != -1) { 454 ret.write(buf, 0, len); 455 } 456 ret.flush(); 457 buf = bos.toByteArray(); 458 return new ByteArrayInputStream(buf); 459 } catch (Exception e) { 460 // throw new SOAPException 461 log.log(Level.SEVERE,"SAAJ0579.soap.attachment.getbase64content.exception", e); 462 throw new SOAPExceptionImpl(e.getLocalizedMessage()); 463 } finally { 464 try { 465 stream.close(); 466 } catch (IOException ex) { 467 //close the stream 468 } 469 } 470 } else { 471 //throw new SOAPException 472 log.log(Level.SEVERE,"SAAJ0572.soap.no.content.for.attachment"); 473 throw new SOAPExceptionImpl("No data handler/content associated with this attachment"); 474 } 475 } 476 477 public void setRawContent(InputStream content, String contentType) 478 throws SOAPException { 479 if (mimePart != null) { 480 mimePart.close(); 481 mimePart = null; 482 } 483 dataHandler = null; 484 ByteOutputStream bos = null; 485 try { 486 InternetHeaders hdrs = new InternetHeaders(); 487 hdrs.setHeader("Content-Type", contentType); 488 //TODO: reading the entire attachment here is ineffcient. Somehow the MimeBodyPart 489 // Ctor with inputStream causes problems based on whether the InputStream has 490 // markSupported()==true or false 491 bos = new ByteOutputStream(); 492 bos.write(content); 493 rawContent = new MimeBodyPart(hdrs, bos.getBytes(), bos.getCount()); 494 setMimeHeader("Content-Type", contentType); 495 } catch (Exception e) { 496 log.log(Level.SEVERE, "SAAJ0576.soap.attachment.setrawcontent.exception", e); 497 throw new SOAPExceptionImpl(e.getLocalizedMessage()); 498 } finally { 499 if (bos != null) 500 bos.close(); 501 try { 502 content.close(); 503 } catch (IOException ex) { 504 throw new SOAPException(ex); 505 } 506 } 507 } 508 509 /* 510 public void setRawContentBytes(byte[] content, String contentType) 511 throws SOAPException { 512 if (content == null) { 513 throw new SOAPExceptionImpl("Null content passed to setRawContentBytes"); 514 } 515 dataHandler = null; 516 try { 517 InternetHeaders hdrs = new InternetHeaders(); 518 hdrs.setHeader("Content-Type", contentType); 519 rawContent = new MimeBodyPart(hdrs, content, content.length); 520 setMimeHeader("Content-Type", contentType); 521 } catch (Exception e) { 522 log.log(Level.SEVERE, "SAAJ0576.soap.attachment.setrawcontent.exception", e); 523 throw new SOAPExceptionImpl(e.getLocalizedMessage()); 524 } 525 } */ 526 527 public void setRawContentBytes( 528 byte[] content, int off, int len, String contentType) 529 throws SOAPException { 530 if (mimePart != null) { 531 mimePart.close(); 532 mimePart = null; 533 } 534 if (content == null) { 535 throw new SOAPExceptionImpl("Null content passed to setRawContentBytes"); 536 } 537 dataHandler = null; 538 try { 539 InternetHeaders hdrs = new InternetHeaders(); 540 hdrs.setHeader("Content-Type", contentType); 541 rawContent = new MimeBodyPart(hdrs, content, off, len); 542 setMimeHeader("Content-Type", contentType); 543 } catch (Exception e) { 544 log.log(Level.SEVERE, 545 "SAAJ0576.soap.attachment.setrawcontent.exception", e); 546 throw new SOAPExceptionImpl(e.getLocalizedMessage()); 547 } 548 } 549 550 public InputStream getRawContent() throws SOAPException { 551 if (mimePart != null) { 552 return mimePart.read(); 553 } 554 if (rawContent != null) { 555 try { 556 return rawContent.getInputStream(); 557 } catch (Exception e) { 558 log.log(Level.SEVERE,"SAAJ0577.soap.attachment.getrawcontent.exception", e); 559 throw new SOAPExceptionImpl(e.getLocalizedMessage()); 560 } 561 } else if (dataHandler != null) { 562 try { 563 return dataHandler.getInputStream(); 564 } catch (IOException e) { 565 log.severe("SAAJ0574.soap.attachment.datahandler.ioexception"); 566 throw new SOAPExceptionImpl("DataHandler error" + e); 567 } 568 } else { 569 log.severe("SAAJ0572.soap.no.content.for.attachment"); 570 throw new SOAPExceptionImpl("No data handler/content associated with this attachment"); 571 } 572 } 573 574 public byte[] getRawContentBytes() throws SOAPException { 575 InputStream ret; 576 if (mimePart != null) { 577 try { 578 ret = mimePart.read(); 579 return ASCIIUtility.getBytes(ret); 580 } catch (IOException ex) { 581 log.log(Level.SEVERE,"SAAJ0577.soap.attachment.getrawcontent.exception", ex); 582 throw new SOAPExceptionImpl(ex); 583 } 584 } 585 if (rawContent != null) { 586 try { 587 ret = rawContent.getInputStream(); 588 return ASCIIUtility.getBytes(ret); 589 } catch (Exception e) { 590 log.log(Level.SEVERE,"SAAJ0577.soap.attachment.getrawcontent.exception", e); 591 throw new SOAPExceptionImpl(e); 592 } 593 } else if (dataHandler != null) { 594 try { 595 ret = dataHandler.getInputStream(); 596 return ASCIIUtility.getBytes(ret); 597 } catch (IOException e) { 598 log.severe("SAAJ0574.soap.attachment.datahandler.ioexception"); 599 throw new SOAPExceptionImpl("DataHandler error" + e); 600 } 601 } else { 602 log.severe("SAAJ0572.soap.no.content.for.attachment"); 603 throw new SOAPExceptionImpl("No data handler/content associated with this attachment"); 604 } 605 } 606 607 // attachments are equal if they are the same reference 608 public boolean equals(Object o) { 609 return (this == o); 610 } 611 612 // In JDK 8 we get a warning if we implement equals() but not hashCode(). 613 // There is no intuitive value for this, the default one in Object is fine. 614 public int hashCode() { 615 return super.hashCode(); 616 } 617 618 public MimeHeaders getMimeHeaders() { 619 return headers; 620 } 621 622 }