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
26package javax.xml.soap;
27
28import java.io.InputStream;
29import java.util.Iterator;
30
31import 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
119public 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}
527