1 /*
   2  * Copyright (c) 2004, 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 
  26 package javax.xml.soap;
  27 
  28 import java.io.InputStream;
  29 import java.util.Iterator;
  30 
  31 import javax.activation.DataHandler;
  32 
  33 /**
  34  * A single attachment to a {@code SOAPMessage} object. A {@code SOAPMessage}
  35  * object may contain zero, one, or many {@code AttachmentPart} objects.
  36  * Each {@code AttachmentPart} object consists of two parts,
  37  * application-specific content and associated MIME headers. The
  38  * MIME headers consists of name/value pairs that can be used to
  39  * identify and describe the content.
  40  * <p>
  41  * An {@code AttachmentPart} object must conform to certain standards.
  42  * <OL>
  43  * <LI>It must conform to <a href="http://www.ietf.org/rfc/rfc2045.txt">
  44  *     MIME [RFC2045] standards</a>
  45  * <LI>It MUST contain content
  46  * <LI>The header portion MUST include the following header:
  47  *  <UL>
  48  *   <LI>{@code Content-Type}<br>
  49  *       This header identifies the type of data in the content of an
  50  *       {@code AttachmentPart} object and MUST conform to [RFC2045].
  51  *       The following is an example of a Content-Type header:
  52  *       <PRE>
  53  *       Content-Type:  application/xml
  54  *       </PRE>
  55  *       The following line of code, in which {@code ap} is an
  56  *       {@code AttachmentPart} object, sets the header shown in
  57  *       the previous example.
  58  *       <PRE>
  59  *       ap.setMimeHeader("Content-Type", "application/xml");
  60  *       </PRE>
  61  *  </UL>
  62  * </OL>
  63  * <p>
  64  * There are no restrictions on the content portion of an {@code
  65  * AttachmentPart} object. The content may be anything from a
  66  * simple plain text object to a complex XML document or image file.
  67  *
  68  * <p>
  69  * An {@code AttachmentPart} object is created with the method
  70  * {@code SOAPMessage.createAttachmentPart}. After setting its MIME headers,
  71  *  the {@code AttachmentPart} object is added to the message
  72  * that created it with the method {@code SOAPMessage.addAttachmentPart}.
  73  *
  74  * <p>
  75  * The following code fragment, in which {@code m} is a
  76  * {@code SOAPMessage} object and {@code contentStringl} is a
  77  * {@code String}, creates an instance of {@code AttachmentPart},
  78  * sets the {@code AttachmentPart} object with some content and
  79  * header information, and adds the {@code AttachmentPart} object to
  80  * the {@code SOAPMessage} object.
  81  * <PRE>
  82  *     AttachmentPart ap1 = m.createAttachmentPart();
  83  *     ap1.setContent(contentString1, "text/plain");
  84  *     m.addAttachmentPart(ap1);
  85  * </PRE>
  86  *
  87  *
  88  * <p>
  89  * The following code fragment creates and adds a second
  90  * {@code AttachmentPart} instance to the same message. {@code jpegData}
  91  * is a binary byte buffer representing the jpeg file.
  92  * <PRE>
  93  *     AttachmentPart ap2 = m.createAttachmentPart();
  94  *     byte[] jpegData =  ...;
  95  *     ap2.setContent(new ByteArrayInputStream(jpegData), "image/jpeg");
  96  *     m.addAttachmentPart(ap2);
  97  * </PRE>
  98  * <p>
  99  * The {@code getContent} method retrieves the contents and header from
 100  * an {@code AttachmentPart} object. Depending on the
 101  * {@code DataContentHandler} objects present, the returned
 102  * {@code Object} can either be a typed Java object corresponding
 103  * to the MIME type or an {@code InputStream} object that contains the
 104  * content as bytes.
 105  * <PRE>
 106  *     String content1 = ap1.getContent();
 107  *     java.io.InputStream content2 = ap2.getContent();
 108  * </PRE>
 109  *
 110  * The method {@code clearContent} removes all the content from an
 111  * {@code AttachmentPart} object but does not affect its header information.
 112  * <PRE>
 113  *     ap1.clearContent();
 114  * </PRE>
 115  *
 116  * @since 1.6
 117  */
 118 
 119 public abstract class AttachmentPart {
 120     /**
 121      * Returns the number of bytes in this {@code AttachmentPart}
 122      * object.
 123      *
 124      * @return the size of this {@code AttachmentPart} object in bytes
 125      *         or -1 if the size cannot be determined
 126      * @exception SOAPException if the content of this attachment is
 127      *            corrupted of if there was an exception while trying
 128      *            to determine the size.
 129      */
 130     public abstract int getSize() throws SOAPException;
 131 
 132     /**
 133      * Clears out the content of this {@code AttachmentPart} object.
 134      * The MIME header portion is left untouched.
 135      */
 136     public abstract void clearContent();
 137 
 138     /**
 139      * Gets the content of this {@code AttachmentPart} object as a Java
 140      * object. The type of the returned Java object depends on (1) the
 141      * {@code DataContentHandler} object that is used to interpret the bytes
 142      * and (2) the {@code Content-Type} given in the header.
 143      * <p>
 144      * For the MIME content types "text/plain", "text/html" and "text/xml", the
 145      * {@code DataContentHandler} object does the conversions to and
 146      * from the Java types corresponding to the MIME types.
 147      * For other MIME types,the {@code DataContentHandler} object
 148      * can return an {@code InputStream} object that contains the content data
 149      * as raw bytes.
 150      * <p>
 151      * A SAAJ-compliant implementation must, as a minimum, return a
 152      * {@code java.lang.String} object corresponding to any content
 153      * stream with a {@code Content-Type} value of
 154      * {@code text/plain}, a
 155      * {@code javax.xml.transform.stream.StreamSource} object corresponding to a
 156      * content stream with a {@code Content-Type} value of
 157      * {@code text/xml}, a {@code java.awt.Image} object
 158      * corresponding to a content stream with a
 159      * {@code Content-Type} value of {@code image/gif} or
 160      * {@code image/jpeg}.  For those content types that an
 161      * installed {@code DataContentHandler} object does not understand, the
 162      * {@code DataContentHandler} object is required to return a
 163      * {@code java.io.InputStream} object with the raw bytes.
 164      *
 165      * @return a Java object with the content of this {@code AttachmentPart}
 166      *         object
 167      *
 168      * @exception SOAPException if there is no content set into this
 169      *            {@code AttachmentPart} object or if there was a data
 170      *            transformation error
 171      */
 172     public abstract Object getContent() throws SOAPException;
 173 
 174     /**
 175      * Gets the content of this {@code AttachmentPart} object as an
 176      * InputStream as if a call had been made to {@code getContent} and no
 177      * {@code DataContentHandler} had been registered for the
 178      * {@code content-type} of this {@code AttachmentPart}.
 179      *<p>
 180      * Note that reading from the returned InputStream would result in consuming
 181      * the data in the stream. It is the responsibility of the caller to reset
 182      * the InputStream appropriately before calling a Subsequent API. If a copy
 183      * of the raw attachment content is required then the {@link #getRawContentBytes} API
 184      * should be used instead.
 185      *
 186      * @return an {@code InputStream} from which the raw data contained by
 187      *      the {@code AttachmentPart} can be accessed.
 188      *
 189      * @throws SOAPException if there is no content set into this
 190      *      {@code AttachmentPart} object or if there was a data
 191      *      transformation error.
 192      *
 193      * @since 1.6, SAAJ 1.3
 194      * @see #getRawContentBytes
 195      */
 196     public abstract InputStream getRawContent() throws SOAPException;
 197 
 198     /**
 199      * Gets the content of this {@code AttachmentPart} object as a
 200      * byte[] array as if a call had been made to {@code getContent} and no
 201      * {@code DataContentHandler} had been registered for the
 202      * {@code content-type} of this {@code AttachmentPart}.
 203      *
 204      * @return a {@code byte[]} array containing the raw data of the
 205      *      {@code AttachmentPart}.
 206      *
 207      * @throws SOAPException if there is no content set into this
 208      *      {@code AttachmentPart} object or if there was a data
 209      *      transformation error.
 210      *
 211      * @since 1.6, SAAJ 1.3
 212      */
 213     public abstract byte[] getRawContentBytes() throws SOAPException;
 214 
 215     /**
 216      * Returns an {@code InputStream} which can be used to obtain the
 217      * content of {@code AttachmentPart}  as Base64 encoded
 218      * character data, this method would base64 encode the raw bytes
 219      * of the attachment and return.
 220      *
 221      * @return an {@code InputStream} from which the Base64 encoded
 222      *       {@code AttachmentPart} can be read.
 223      *
 224      * @throws SOAPException if there is no content set into this
 225      *      {@code AttachmentPart} object or if there was a data
 226      *      transformation error.
 227      *
 228      * @since 1.6, SAAJ 1.3
 229      */
 230     public abstract InputStream getBase64Content() throws SOAPException;
 231 
 232     /**
 233      * Sets the content of this attachment part to that of the given
 234      * {@code Object} and sets the value of the {@code Content-Type}
 235      * header to the given type. The type of the
 236      * {@code Object} should correspond to the value given for the
 237      * {@code Content-Type}. This depends on the particular
 238      * set of {@code DataContentHandler} objects in use.
 239      *
 240      *
 241      * @param object the Java object that makes up the content for
 242      *               this attachment part
 243      * @param contentType the MIME string that specifies the type of
 244      *                  the content
 245      *
 246      * @exception IllegalArgumentException may be thrown if the contentType
 247      *            does not match the type of the content object, or if there
 248      *            was no {@code DataContentHandler} object for this
 249      *            content object
 250      *
 251      * @see #getContent
 252      */
 253     public abstract void setContent(Object object, String contentType);
 254 
 255     /**
 256      * Sets the content of this attachment part to that contained by the
 257      * {@code InputStream} {@code content} and sets the value of the
 258      * {@code Content-Type} header to the value contained in
 259      * {@code contentType}.
 260      * <P>
 261      *  A subsequent call to getSize() may not be an exact measure
 262      *  of the content size.
 263      *
 264      * @param content the raw data to add to the attachment part
 265      * @param contentType the value to set into the {@code Content-Type}
 266      * header
 267      *
 268      * @exception SOAPException if an there is an error in setting the content
 269      * @exception NullPointerException if {@code content} is null
 270      * @since 1.6, SAAJ 1.3
 271      */
 272     public abstract void setRawContent(InputStream content, String contentType) throws SOAPException;
 273 
 274     /**
 275      * Sets the content of this attachment part to that contained by the
 276      * {@code byte[]} array {@code content} and sets the value of the
 277      * {@code Content-Type} header to the value contained in
 278      * {@code contentType}.
 279      *
 280      * @param content the raw data to add to the attachment part
 281      * @param contentType the value to set into the {@code Content-Type}
 282      * header
 283      * @param offset the offset in the byte array of the content
 284      * @param len the number of bytes that form the content
 285      *
 286      * @exception SOAPException if an there is an error in setting the content
 287      * or content is null
 288      * @since 1.6, SAAJ 1.3
 289      */
 290     public abstract void setRawContentBytes(
 291         byte[] content, int offset, int len,  String contentType)
 292         throws SOAPException;
 293 
 294 
 295     /**
 296      * Sets the content of this attachment part from the Base64 source
 297      * {@code InputStream}  and sets the value of the
 298      * {@code Content-Type} header to the value contained in
 299      * {@code contentType}, This method would first decode the base64
 300      * input and write the resulting raw bytes to the attachment.
 301      * <P>
 302      *  A subsequent call to getSize() may not be an exact measure
 303      *  of the content size.
 304      *
 305      * @param content the base64 encoded data to add to the attachment part
 306      * @param contentType the value to set into the {@code Content-Type}
 307      * header
 308      *
 309      * @exception SOAPException if an there is an error in setting the content
 310      * @exception NullPointerException if {@code content} is null
 311      *
 312      * @since 1.6, SAAJ 1.3
 313      */
 314     public abstract void setBase64Content(
 315         InputStream content, String contentType) throws SOAPException;
 316 
 317 
 318     /**
 319      * Gets the {@code DataHandler} object for this {@code AttachmentPart}
 320      * object.
 321      *
 322      * @return the {@code DataHandler} object associated with this
 323      *         {@code AttachmentPart} object
 324      *
 325      * @exception SOAPException if there is no data in
 326      * this {@code AttachmentPart} object
 327      */
 328     public abstract DataHandler getDataHandler()
 329         throws SOAPException;
 330 
 331     /**
 332      * Sets the given {@code DataHandler} object as the data handler
 333      * for this {@code AttachmentPart} object. Typically, on an incoming
 334      * message, the data handler is automatically set. When
 335      * a message is being created and populated with content, the
 336      * {@code setDataHandler} method can be used to get data from
 337      * various data sources into the message.
 338      *
 339      * @param dataHandler the {@code DataHandler} object to be set
 340      *
 341      * @exception IllegalArgumentException if there was a problem with
 342      *            the specified {@code DataHandler} object
 343      */
 344     public abstract void setDataHandler(DataHandler dataHandler);
 345 
 346 
 347     /**
 348      * Gets the value of the MIME header whose name is "Content-ID".
 349      *
 350      * @return a {@code String} giving the value of the
 351      *          "Content-ID" header or {@code null} if there
 352      *          is none
 353      * @see #setContentId
 354      */
 355     public String getContentId() {
 356         String[] values = getMimeHeader("Content-ID");
 357         if (values != null && values.length > 0)
 358             return values[0];
 359         return null;
 360     }
 361 
 362     /**
 363      * Gets the value of the MIME header whose name is "Content-Location".
 364      *
 365      * @return a {@code String} giving the value of the
 366      *          "Content-Location" header or {@code null} if there
 367      *          is none
 368      */
 369     public String getContentLocation() {
 370         String[] values = getMimeHeader("Content-Location");
 371         if (values != null && values.length > 0)
 372             return values[0];
 373         return null;
 374     }
 375 
 376     /**
 377      * Gets the value of the MIME header whose name is "Content-Type".
 378      *
 379      * @return a {@code String} giving the value of the
 380      *          "Content-Type" header or {@code null} if there
 381      *          is none
 382      */
 383     public String getContentType() {
 384         String[] values = getMimeHeader("Content-Type");
 385         if (values != null && values.length > 0)
 386             return values[0];
 387         return null;
 388     }
 389 
 390     /**
 391      * Sets the MIME header whose name is "Content-ID" with the given value.
 392      *
 393      * @param contentId a {@code String} giving the value of the
 394      *          "Content-ID" header
 395      *
 396      * @exception IllegalArgumentException if there was a problem with
 397      *            the specified {@code contentId} value
 398      * @see #getContentId
 399      */
 400     public void setContentId(String contentId)
 401     {
 402         setMimeHeader("Content-ID", contentId);
 403     }
 404 
 405 
 406     /**
 407      * Sets the MIME header whose name is "Content-Location" with the given value.
 408      *
 409      *
 410      * @param contentLocation a {@code String} giving the value of the
 411      *          "Content-Location" header
 412      * @exception IllegalArgumentException if there was a problem with
 413      *            the specified content location
 414      */
 415     public void setContentLocation(String contentLocation)
 416     {
 417         setMimeHeader("Content-Location", contentLocation);
 418     }
 419 
 420     /**
 421      * Sets the MIME header whose name is "Content-Type" with the given value.
 422      *
 423      * @param contentType a {@code String} giving the value of the
 424      *          "Content-Type" header
 425      *
 426      * @exception IllegalArgumentException if there was a problem with
 427      *            the specified content type
 428      */
 429     public void setContentType(String contentType)
 430     {
 431         setMimeHeader("Content-Type", contentType);
 432     }
 433 
 434     /**
 435      * Removes all MIME headers that match the given name.
 436      *
 437      * @param header the string name of the MIME header/s to
 438      *               be removed
 439      */
 440     public abstract void removeMimeHeader(String header);
 441 
 442     /**
 443      * Removes all the MIME header entries.
 444      */
 445     public abstract void removeAllMimeHeaders();
 446 
 447 
 448     /**
 449      * Gets all the values of the header identified by the given
 450      * {@code String}.
 451      *
 452      * @param name the name of the header; example: "Content-Type"
 453      * @return a {@code String} array giving the value for the
 454      *         specified header
 455      * @see #setMimeHeader
 456      */
 457     public abstract String[] getMimeHeader(String name);
 458 
 459 
 460     /**
 461      * Changes the first header entry that matches the given name
 462      * to the given value, adding a new header if no existing header
 463      * matches. This method also removes all matching headers but the first. <p>
 464      *
 465      * Note that RFC822 headers can only contain US-ASCII characters.
 466      *
 467      * @param   name    a {@code String} giving the name of the header
 468      *                  for which to search
 469      * @param   value   a {@code String} giving the value to be set for
 470      *                  the header whose name matches the given name
 471      *
 472      * @exception IllegalArgumentException if there was a problem with
 473      *            the specified mime header name or value
 474      */
 475     public abstract void setMimeHeader(String name, String value);
 476 
 477 
 478     /**
 479      * Adds a MIME header with the specified name and value to this
 480      * {@code AttachmentPart} object.
 481      * <p>
 482      * Note that RFC822 headers can contain only US-ASCII characters.
 483      *
 484      * @param   name    a {@code String} giving the name of the header
 485      *                  to be added
 486      * @param   value   a {@code String} giving the value of the header
 487      *                  to be added
 488      *
 489      * @exception IllegalArgumentException if there was a problem with
 490      *            the specified mime header name or value
 491      */
 492     public abstract void addMimeHeader(String name, String value);
 493 
 494     /**
 495      * Retrieves all the headers for this {@code AttachmentPart} object
 496      * as an iterator over the {@code MimeHeader} objects.
 497      *
 498      * @return  an {@code Iterator} object with all of the Mime
 499      *          headers for this {@code AttachmentPart} object
 500      */
 501     public abstract Iterator<MimeHeader> getAllMimeHeaders();
 502 
 503     /**
 504      * Retrieves all {@code MimeHeader} objects that match a name in
 505      * the given array.
 506      *
 507      * @param names a {@code String} array with the name(s) of the
 508      *        MIME headers to be returned
 509      * @return  all of the MIME headers that match one of the names in the
 510      *           given array as an {@code Iterator} object
 511      */
 512     public abstract Iterator<MimeHeader> getMatchingMimeHeaders(String[] names);
 513 
 514     /**
 515      * Retrieves all {@code MimeHeader} objects whose name does
 516      * not match a name in the given array.
 517      *
 518      * @param names a {@code String} array with the name(s) of the
 519      *        MIME headers not to be returned
 520      * @return  all of the MIME headers in this {@code AttachmentPart} object
 521      *          except those that match one of the names in the
 522      *           given array.  The nonmatching MIME headers are returned as an
 523      *           {@code Iterator} object.
 524      */
 525     public abstract Iterator<MimeHeader> getNonMatchingMimeHeaders(String[] names);
 526 }