1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
5 *
6 * The contents of this file are subject to the terms of either the GNU
7 * General Public License Version 2 only ("GPL") or the Common Development
8 * and Distribution License("CDDL") (collectively, the "License"). You
9 * may not use this file except in compliance with the License. You can obtain
10 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
11 * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
12 * language governing permissions and limitations under the License.
13 *
14 * When distributing the software, include this License Header Notice in each
15 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
16 * Sun designates this particular file as subject to the "Classpath" exception
17 * as provided by Sun in the GPL Version 2 section of the License file that
18 * accompanied this code. If applicable, add the following below the License
19 * Header, with the fields enclosed by brackets [] replaced by your own
20 * identifying information: "Portions Copyrighted [year]
21 * [name of copyright owner]"
22 *
23 * Contributor(s):
24 *
25 * If you wish your version of this file to be governed by only the CDDL or
26 * only the GPL Version 2, indicate your decision by adding "[Contributor]
27 * elects to include this software in this distribution under the [CDDL or GPL
28 * Version 2] license." If you don't indicate a single choice of license, a
29 * recipient has the option to distribute your version of this file under
30 * either the CDDL, the GPL Version 2 or to extend the choice of license to
31 * its licensees as provided above. However, if you add GPL Version 2 code
32 * and therefore, elected the GPL Version 2 license, then the option applies
33 * only if the new code is made subject to such option by the copyright
34 * holder.
35 */
36
37 /*
38 * @(#)Multipart.java 1.16 07/05/04
39 */
40
41 package javax.mail;
42
43 import java.util.Vector;
44 import java.io.InputStream;
45 import java.io.OutputStream;
46 import java.io.IOException;
47 import javax.activation.DataSource;
48
49 /**
50 * Multipart is a container that holds multiple body parts. Multipart
51 * provides methods to retrieve and set its subparts. <p>
52 *
53 * Multipart also acts as the base class for the content object returned
54 * by most Multipart DataContentHandlers. For example, invoking getContent()
55 * on a DataHandler whose source is a "multipart/signed" data source may
56 * return an appropriate subclass of Multipart. <p>
57 *
58 * Some messaging systems provide different subtypes of Multiparts. For
59 * example, MIME specifies a set of subtypes that include "alternative",
60 * "mixed", "related", "parallel", "signed", etc. <p>
61 *
62 * Multipart is an abstract class. Subclasses provide actual implementations.
63 *
64 * @version 1.16, 07/05/04
65 * @author John Mani
66 */
67
68 public abstract class Multipart {
69
70 /**
71 * Vector of BodyPart objects.
72 */
73 protected Vector parts = new Vector(); // Holds BodyParts
74
75 /**
76 * This field specifies the content-type of this multipart
77 * object. It defaults to "multipart/mixed".
78 */
79 protected String contentType = "multipart/mixed"; // Content-Type
80
81 /**
82 * The <code>Part</code> containing this <code>Multipart</code>,
83 * if known.
84 * @since JavaMail 1.1
85 */
86 protected Part parent;
87
88 /**
89 * Default constructor. An empty Multipart object is created.
90 */
91 protected Multipart() { }
92
93 /**
94 * Setup this Multipart object from the given MultipartDataSource. <p>
95 *
96 * The method adds the MultipartDataSource's BodyPart
97 * objects into this Multipart. This Multipart's contentType is
98 * set to that of the MultipartDataSource. <p>
99 *
100 * This method is typically used in those cases where one
101 * has a multipart data source that has already been pre-parsed into
102 * the individual body parts (for example, an IMAP datasource), but
103 * needs to create an appropriate Multipart subclass that represents
104 * a specific multipart subtype.
105 *
106 * @param mp Multipart datasource
107 */
108 protected synchronized void setMultipartDataSource(MultipartDataSource mp)
109 throws MessagingException {
110 contentType = mp.getContentType();
111
112 int count = mp.getCount();
113 for (int i = 0; i < count; i++)
114 addBodyPart(mp.getBodyPart(i));
115 }
116
117 /**
118 * Return the content-type of this Multipart. <p>
119 *
120 * This implementation just returns the value of the
121 * <code>contentType</code> field.
122 *
123 * @return content-type
124 * @see #contentType
125 */
126 public String getContentType() {
127 return contentType;
128 }
129
130 /**
131 * Return the number of enclosed BodyPart objects. <p>
132 *
133 * @return number of parts
134 * @see #parts
135 */
136 public synchronized int getCount() throws MessagingException {
137 if (parts == null)
138 return 0;
139
140 return parts.size();
141 }
142
143 /**
144 * Get the specified Part. Parts are numbered starting at 0.
145 *
146 * @param index the index of the desired Part
147 * @return the Part
148 * @exception IndexOutOfBoundsException if the given index
149 * is out of range.
150 * @exception MessagingException
151 */
152 public synchronized BodyPart getBodyPart(int index)
153 throws MessagingException {
154 if (parts == null)
155 throw new IndexOutOfBoundsException("No such BodyPart");
156
157 return (BodyPart)parts.elementAt(index);
158 }
159
160 /**
161 * Remove the specified part from the multipart message.
162 * Shifts all the parts after the removed part down one.
163 *
164 * @param part The part to remove
165 * @return true if part removed, false otherwise
166 * @exception MessagingException if no such Part exists
167 * @exception IllegalWriteException if the underlying
168 * implementation does not support modification
169 * of existing values
170 */
171 public synchronized boolean removeBodyPart(BodyPart part)
172 throws MessagingException {
173 if (parts == null)
174 throw new MessagingException("No such body part");
175
176 boolean ret = parts.removeElement(part);
177 part.setParent(null);
178 return ret;
179 }
180
181 /**
182 * Remove the part at specified location (starting from 0).
183 * Shifts all the parts after the removed part down one.
184 *
185 * @param index Index of the part to remove
186 * @exception MessagingException
187 * @exception IndexOutOfBoundsException if the given index
188 * is out of range.
189 * @exception IllegalWriteException if the underlying
190 * implementation does not support modification
191 * of existing values
192 */
193 public synchronized void removeBodyPart(int index)
194 throws MessagingException {
195 if (parts == null)
196 throw new IndexOutOfBoundsException("No such BodyPart");
197
198 BodyPart part = (BodyPart)parts.elementAt(index);
199 parts.removeElementAt(index);
200 part.setParent(null);
201 }
202
203 /**
204 * Adds a Part to the multipart. The BodyPart is appended to
205 * the list of existing Parts.
206 *
207 * @param part The Part to be appended
208 * @exception MessagingException
209 * @exception IllegalWriteException if the underlying
210 * implementation does not support modification
211 * of existing values
212 */
213 public synchronized void addBodyPart(BodyPart part)
214 throws MessagingException {
215 if (parts == null)
216 parts = new Vector();
217
218 parts.addElement(part);
219 part.setParent(this);
220 }
221
222 /**
223 * Adds a BodyPart at position <code>index</code>.
224 * If <code>index</code> is not the last one in the list,
225 * the subsequent parts are shifted up. If <code>index</code>
226 * is larger than the number of parts present, the
227 * BodyPart is appended to the end.
228 *
229 * @param part The BodyPart to be inserted
230 * @param index Location where to insert the part
231 * @exception MessagingException
232 * @exception IllegalWriteException if the underlying
233 * implementation does not support modification
234 * of existing values
235 */
236 public synchronized void addBodyPart(BodyPart part, int index)
237 throws MessagingException {
238 if (parts == null)
239 parts = new Vector();
240
241 parts.insertElementAt(part, index);
242 part.setParent(this);
243 }
244
245 /**
246 * Output an appropriately encoded bytestream to the given
247 * OutputStream. The implementation subclass decides the
248 * appropriate encoding algorithm to be used. The bytestream
249 * is typically used for sending.
250 *
251 * @exception IOException if an IO related exception occurs
252 * @exception MessagingException
253 */
254 public abstract void writeTo(OutputStream os)
255 throws IOException, MessagingException;
256
257 /**
258 * Return the <code>Part</code> that contains this <code>Multipart</code>
259 * object, or <code>null</code> if not known.
260 * @since JavaMail 1.1
261 */
262 public synchronized Part getParent() {
263 return parent;
264 }
265
266 /**
267 * Set the parent of this <code>Multipart</code> to be the specified
268 * <code>Part</code>. Normally called by the <code>Message</code>
269 * or <code>BodyPart</code> <code>setContent(Multipart)</code> method.
270 * <code>parent</code> may be <code>null</code> if the
271 * <code>Multipart</code> is being removed from its containing
272 * <code>Part</code>.
273 * @since JavaMail 1.1
274 */
275 public synchronized void setParent(Part parent) {
276 this.parent = parent;
277 }
278 }