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