001    /*
002     * Copyright 2001-2004 The Apache Software Foundation.
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package javax.xml.soap;
017    
018    import javax.activation.DataHandler;
019    import java.util.Iterator;
020    
021    /**
022     * <P>A single attachment to a <CODE>SOAPMessage</CODE> object. A
023     *   <CODE>SOAPMessage</CODE> object may contain zero, one, or many
024     *   <CODE>AttachmentPart</CODE> objects. Each <CODE>
025     *   AttachmentPart</CODE> object consists of two parts,
026     *   application-specific content and associated MIME headers. The
027     *   MIME headers consists of name/value pairs that can be used to
028     *   identify and describe the content.</P>
029     *
030     *   <P>An <CODE>AttachmentPart</CODE> object must conform to
031     *   certain standards.</P>
032     *
033     *   <OL>
034     *     <LI>It must conform to <A href=
035     *     "http://www.ietf.org/rfc/rfc2045.txt">MIME [RFC2045]
036     *     standards</A></LI>
037     *
038     *     <LI>It MUST contain content</LI>
039     *
040     *     <LI>
041     *       The header portion MUST include the following header:
042     *
043     *       <UL>
044     *         <LI>
045     *           <CODE>Content-Type</CODE><BR>
046     *            This header identifies the type of data in the content
047     *           of an <CODE>AttachmentPart</CODE> object and MUST
048     *           conform to [RFC2045]. The following is an example of a
049     *           Content-Type header:
050     * <PRE>
051     *      Content-Type:  application/xml
052     *
053     * </PRE>
054     *           The following line of code, in which <CODE>ap</CODE> is
055     *           an <CODE>AttachmentPart</CODE> object, sets the header
056     *           shown in the previous example.
057     * <PRE>
058     *      ap.setMimeHeader("Content-Type", "application/xml");
059     *
060     * </PRE>
061     *
062     *           <P></P>
063     *         </LI>
064     *       </UL>
065     *     </LI>
066     *   </OL>
067     *
068     *   <P>There are no restrictions on the content portion of an
069     *   <CODE>AttachmentPart</CODE> object. The content may be anything
070     *   from a simple plain text object to a complex XML document or
071     *   image file.</P>
072     *
073     *   <P>An <CODE>AttachmentPart</CODE> object is created with the
074     *   method <CODE>SOAPMessage.createAttachmentPart</CODE>. After
075     *   setting its MIME headers, the <CODE>AttachmentPart</CODE>
076     *   object is added to the message that created it with the method
077     *   <CODE>SOAPMessage.addAttachmentPart</CODE>.</P>
078     *
079     *   <P>The following code fragment, in which <CODE>m</CODE> is a
080     *   <CODE>SOAPMessage</CODE> object and <CODE>contentStringl</CODE>
081     *   is a <CODE>String</CODE>, creates an instance of <CODE>
082     *   AttachmentPart</CODE>, sets the <CODE>AttachmentPart</CODE>
083     *   object with some content and header information, and adds the
084     *   <CODE>AttachmentPart</CODE> object to the <CODE>
085     *   SOAPMessage</CODE> object.</P>
086     * <PRE>
087     *    AttachmentPart ap1 = m.createAttachmentPart();
088     *    ap1.setContent(contentString1, "text/plain");
089     *    m.addAttachmentPart(ap1);
090     * </PRE>
091     *
092     *   <P>The following code fragment creates and adds a second <CODE>
093     *   AttachmentPart</CODE> instance to the same message. <CODE>
094     *   jpegData</CODE> is a binary byte buffer representing the jpeg
095     *   file.</P>
096     * <PRE>
097     *    AttachmentPart ap2 = m.createAttachmentPart();
098     *    byte[] jpegData =  ...;
099     *    ap2.setContent(new ByteArrayInputStream(jpegData), "image/jpeg");
100     *    m.addAttachmentPart(ap2);
101     * </PRE>
102     *
103     *   <P>The <CODE>getContent</CODE> method retrieves the contents
104     *   and header from an <CODE>AttachmentPart</CODE> object.
105     *   Depending on the <CODE>DataContentHandler</CODE> objects
106     *   present, the returned <CODE>Object</CODE> can either be a typed
107     *   Java object corresponding to the MIME type or an <CODE>
108     *   InputStream</CODE> object that contains the content as
109     *   bytes.</P>
110     * <PRE>
111     *    String content1 = ap1.getContent();
112     *    java.io.InputStream content2 = ap2.getContent();
113     * </PRE>
114     *   The method <CODE>clearContent</CODE> removes all the content
115     *   from an <CODE>AttachmentPart</CODE> object but does not affect
116     *   its header information.
117     * <PRE>
118     *    ap1.clearContent();
119     * </PRE>
120     */
121    public abstract class AttachmentPart {
122    
123        // fixme: should this constructor be protected?
124        /** Create a new AttachmentPart. */
125        public AttachmentPart() {}
126    
127        /**
128         * Returns the number of bytes in this <CODE>
129         * AttachmentPart</CODE> object.
130         * @return the size of this <CODE>AttachmentPart</CODE> object
131         *     in bytes or -1 if the size cannot be determined
132         * @throws  SOAPException  if the content of this
133         *     attachment is corrupted of if there was an exception
134         *     while trying to determine the size.
135         */
136        public abstract int getSize() throws SOAPException;
137    
138        /**
139         * Clears out the content of this <CODE>
140         * AttachmentPart</CODE> object. The MIME header portion is left
141         * untouched.
142         */
143        public abstract void clearContent();
144    
145        /**
146         * Gets the content of this <code>AttachmentPart</code> object as a Java
147         * object. The type of the returned Java object depends on (1) the
148         * <code>DataContentHandler</code> object that is used to interpret the bytes
149         * and (2) the <code>Content-Type</code> given in the header.
150         * <p>
151         * For the MIME content types "text/plain", "text/html" and "text/xml", the
152         * <code>DataContentHandler</code> object does the conversions to and
153         * from the Java types corresponding to the MIME types.
154         * For other MIME types,the <code>DataContentHandler</code> object
155         * can return an <code>InputStream</code> object that contains the content data
156         * as raw bytes.
157         * <p>
158         * A JAXM-compliant implementation must, as a minimum, return a
159         * <code>java.lang.String</code> object corresponding to any content
160         * stream with a <code>Content-Type</code> value of
161         * <code>text/plain</code>, a
162         * <code>javax.xml.transform.StreamSource</code> object corresponding to a
163         * content stream with a <code>Content-Type</code> value of
164         * <code>text/xml</code>, a <code>java.awt.Image</code> object
165         * corresponding to a content stream with a
166         * <code>Content-Type</code> value of <code>image/gif</code> or
167         * <code>image/jpeg</code>.  For those content types that an
168         * installed <code>DataContentHandler</code> object does not understand, the
169         * <code>DataContentHandler</code> object is required to return a
170         * <code>java.io.InputStream</code> object with the raw bytes.
171         *
172         * @return a Java object with the content of this <CODE>
173         *     AttachmentPart</CODE> object
174         * @throws  SOAPException  if there is no content set
175         *     into this <CODE>AttachmentPart</CODE> object or if there
176         *     was a data transformation error
177         */
178        public abstract Object getContent() throws SOAPException;
179    
180        /**
181         * Sets the content of this attachment part to that of the
182         * given <CODE>Object</CODE> and sets the value of the <CODE>
183         * Content-Type</CODE> header to the given type. The type of the
184         * <CODE>Object</CODE> should correspond to the value given for
185         * the <CODE>Content-Type</CODE>. This depends on the particular
186         * set of <CODE>DataContentHandler</CODE> objects in use.
187         * @param  object  the Java object that makes up
188         * the content for this attachment part
189         * @param  contentType the MIME string that
190         * specifies the type of the content
191         * @throws java.lang.IllegalArgumentException if
192         *     the contentType does not match the type of the content
193         *     object, or if there was no <CODE>
194         *     DataContentHandler</CODE> object for this content
195         *     object
196         * @see #getContent() getContent()
197         */
198        public abstract void setContent(Object object, String contentType);
199    
200        /**
201         * Gets the <CODE>DataHandler</CODE> object for this <CODE>
202         * AttachmentPart</CODE> object.
203         * @return the <CODE>DataHandler</CODE> object associated with
204         *     this <CODE>AttachmentPart</CODE> object
205         * @throws  SOAPException  if there is
206         *     no data in this <CODE>AttachmentPart</CODE> object
207         */
208        public abstract DataHandler getDataHandler() throws SOAPException;
209    
210        /**
211         * Sets the given <CODE>DataHandler</CODE> object as the
212         * data handler for this <CODE>AttachmentPart</CODE> object.
213         * Typically, on an incoming message, the data handler is
214         * automatically set. When a message is being created and
215         * populated with content, the <CODE>setDataHandler</CODE>
216         * method can be used to get data from various data sources into
217         * the message.
218         * @param  datahandler  <CODE>DataHandler</CODE> object to
219         *     be set
220         * @throws java.lang.IllegalArgumentException if
221         *     there was a problem with the specified <CODE>
222         *     DataHandler</CODE> object
223         */
224        public abstract void setDataHandler(DataHandler datahandler);
225    
226        /**
227         * Gets the value of the MIME header whose name is
228         * "Content-Id".
229         * @return  a <CODE>String</CODE> giving the value of the
230         *     "Content-Id" header or <CODE>null</CODE> if there is
231         *     none
232         * @see #setContentId(java.lang.String) setContentId(java.lang.String)
233         */
234        public String getContentId() {
235    
236            String as[] = getMimeHeader("Content-Id");
237    
238            if (as != null && as.length > 0) {
239                return as[0];
240            } else {
241                return null;
242            }
243        }
244    
245        /**
246         * Gets the value of the MIME header
247         * "Content-Location".
248         * @return  a <CODE>String</CODE> giving the value of the
249         *     "Content-Location" header or <CODE>null</CODE> if there
250         *     is none
251         */
252        public String getContentLocation() {
253    
254            String as[] = getMimeHeader("Content-Location");
255    
256            if (as != null && as.length > 0) {
257                return as[0];
258            } else {
259                return null;
260            }
261        }
262    
263        /**
264         * Gets the value of the MIME header "Content-Type".
265         * @return  a <CODE>String</CODE> giving the value of the
266         *     "Content-Type" header or <CODE>null</CODE> if there is
267         *     none
268         */
269        public String getContentType() {
270    
271            String as[] = getMimeHeader("Content-Type");
272    
273            if (as != null && as.length > 0) {
274                return as[0];
275            } else {
276                return null;
277            }
278        }
279    
280        /**
281         * Sets the MIME header "Content-Id" with the given
282         * value.
283         * @param  contentId a <CODE>String</CODE> giving
284         *     the value of the "Content-Id" header
285         * @throws java.lang.IllegalArgumentException if
286         *     there was a problem with the specified <CODE>
287         *     contentId</CODE> value
288         * @see #getContentId() getContentId()
289         */
290        public void setContentId(String contentId) {
291            setMimeHeader("Content-Id", contentId);
292        }
293    
294        /**
295         * Sets the MIME header "Content-Location" with the given
296         * value.
297         * @param  contentLocation a <CODE>String</CODE>
298         *     giving the value of the "Content-Location" header
299         * @throws java.lang.IllegalArgumentException if
300         *     there was a problem with the specified content
301         *     location
302         */
303        public void setContentLocation(String contentLocation) {
304            setMimeHeader("Content-Location", contentLocation);
305        }
306    
307        /**
308         * Sets the MIME header "Content-Type" with the given
309         * value.
310         * @param  contentType  a <CODE>String</CODE>
311         *     giving the value of the "Content-Type" header
312         * @throws java.lang.IllegalArgumentException if
313         * there was a problem with the specified content type
314         */
315        public void setContentType(String contentType) {
316            setMimeHeader("Content-Type", contentType);
317        }
318    
319        /**
320         * Removes all MIME headers that match the given name.
321         * @param  header - the string name of the MIME
322         *     header/s to be removed
323         */
324        public abstract void removeMimeHeader(String header);
325    
326        /** Removes all the MIME header entries. */
327        public abstract void removeAllMimeHeaders();
328    
329        /**
330         * Gets all the values of the header identified by the given
331         * <CODE>String</CODE>.
332         * @param   name  the name of the header; example:
333         *     "Content-Type"
334         * @return a <CODE>String</CODE> array giving the value for the
335         *     specified header
336         * @see #setMimeHeader(java.lang.String, java.lang.String) setMimeHeader(java.lang.String, java.lang.String)
337         */
338        public abstract String[] getMimeHeader(String name);
339    
340        /**
341         * Changes the first header entry that matches the given name
342         *   to the given value, adding a new header if no existing
343         *   header matches. This method also removes all matching
344         *   headers but the first.
345         *
346         *   <P>Note that RFC822 headers can only contain US-ASCII
347         *   characters.</P>
348         * @param  name   a <CODE>String</CODE> giving the
349         *     name of the header for which to search
350         * @param  value  a <CODE>String</CODE> giving the
351         *     value to be set for the header whose name matches the
352         *     given name
353         * @throws java.lang.IllegalArgumentException if
354         *     there was a problem with the specified mime header name
355         *     or value
356         */
357        public abstract void setMimeHeader(String name, String value);
358    
359        /**
360         * Adds a MIME header with the specified name and value to
361         *   this <CODE>AttachmentPart</CODE> object.
362         *
363         *   <P>Note that RFC822 headers can contain only US-ASCII
364         *   characters.</P>
365         * @param  name   a <CODE>String</CODE> giving the
366         *     name of the header to be added
367         * @param  value  a <CODE>String</CODE> giving the
368         *     value of the header to be added
369         * @throws java.lang.IllegalArgumentException if
370         *     there was a problem with the specified mime header name
371         *     or value
372         */
373        public abstract void addMimeHeader(String name, String value);
374    
375        /**
376         * Retrieves all the headers for this <CODE>
377         * AttachmentPart</CODE> object as an iterator over the <CODE>
378         * MimeHeader</CODE> objects.
379         * @return  an <CODE>Iterator</CODE> object with all of the Mime
380         *     headers for this <CODE>AttachmentPart</CODE> object
381         */
382        public abstract Iterator getAllMimeHeaders();
383    
384        /**
385         * Retrieves all <CODE>MimeHeader</CODE> objects that match
386         * a name in the given array.
387         * @param   names a <CODE>String</CODE> array with
388         *     the name(s) of the MIME headers to be returned
389         * @return all of the MIME headers that match one of the names
390         *     in the given array as an <CODE>Iterator</CODE>
391         *     object
392         */
393        public abstract Iterator getMatchingMimeHeaders(String names[]);
394    
395        /**
396         * Retrieves all <CODE>MimeHeader</CODE> objects whose name
397         * does not match a name in the given array.
398         * @param   names  a <CODE>String</CODE> array with
399         *     the name(s) of the MIME headers not to be returned
400         * @return all of the MIME headers in this <CODE>
401         *     AttachmentPart</CODE> object except those that match one
402         *     of the names in the given array. The nonmatching MIME
403         *     headers are returned as an <CODE>Iterator</CODE>
404         *     object.
405         */
406        public abstract Iterator getNonMatchingMimeHeaders(String names[]);
407    }