src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeMultipart.java

Tue, 06 Mar 2012 16:09:35 -0800

author
ohair
date
Tue, 06 Mar 2012 16:09:35 -0800
changeset 286
f50545b5e2f1
child 368
0989ad8c0860
permissions
-rw-r--r--

7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom

ohair@286 1 /*
ohair@286 2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
ohair@286 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ohair@286 4 *
ohair@286 5 * This code is free software; you can redistribute it and/or modify it
ohair@286 6 * under the terms of the GNU General Public License version 2 only, as
ohair@286 7 * published by the Free Software Foundation. Oracle designates this
ohair@286 8 * particular file as subject to the "Classpath" exception as provided
ohair@286 9 * by Oracle in the LICENSE file that accompanied this code.
ohair@286 10 *
ohair@286 11 * This code is distributed in the hope that it will be useful, but WITHOUT
ohair@286 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ohair@286 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
ohair@286 14 * version 2 for more details (a copy is included in the LICENSE file that
ohair@286 15 * accompanied this code).
ohair@286 16 *
ohair@286 17 * You should have received a copy of the GNU General Public License version
ohair@286 18 * 2 along with this work; if not, write to the Free Software Foundation,
ohair@286 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ohair@286 20 *
ohair@286 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@286 22 * or visit www.oracle.com if you need additional information or have any
ohair@286 23 * questions.
ohair@286 24 */
ohair@286 25
ohair@286 26 /*
ohair@286 27 * @(#)MimeMultipart.java 1.31 03/01/29
ohair@286 28 */
ohair@286 29
ohair@286 30
ohair@286 31
ohair@286 32 package com.sun.xml.internal.messaging.saaj.packaging.mime.internet;
ohair@286 33
ohair@286 34 import java.io.*;
ohair@286 35
ohair@286 36 import javax.activation.DataSource;
ohair@286 37
ohair@286 38 import com.sun.xml.internal.messaging.saaj.packaging.mime.*;
ohair@286 39 import com.sun.xml.internal.messaging.saaj.packaging.mime.util.*;
ohair@286 40 import com.sun.xml.internal.messaging.saaj.util.FinalArrayList;
ohair@286 41 import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
ohair@286 42 import com.sun.xml.internal.messaging.saaj.util.SAAJUtil;
ohair@286 43
ohair@286 44 /**
ohair@286 45 * The MimeMultipart class is an implementation
ohair@286 46 * that uses MIME conventions for the multipart data. <p>
ohair@286 47 *
ohair@286 48 * A MimeMultipart is obtained from a MimeBodyPart whose primary type
ohair@286 49 * is "multipart" (by invoking the part's <code>getContent()</code> method)
ohair@286 50 * or it can be created by a client as part of creating a new MimeMessage. <p>
ohair@286 51 *
ohair@286 52 * The default multipart subtype is "mixed". The other multipart
ohair@286 53 * subtypes, such as "alternative", "related", and so on, can be
ohair@286 54 * implemented as subclasses of MimeMultipart with additional methods
ohair@286 55 * to implement the additional semantics of that type of multipart
ohair@286 56 * content. The intent is that service providers, mail JavaBean writers
ohair@286 57 * and mail clients will write many such subclasses and their Command
ohair@286 58 * Beans, and will install them into the JavaBeans Activation
ohair@286 59 * Framework, so that any JavaMail implementation and its clients can
ohair@286 60 * transparently find and use these classes. Thus, a MIME multipart
ohair@286 61 * handler is treated just like any other type handler, thereby
ohair@286 62 * decoupling the process of providing multipart handlers from the
ohair@286 63 * JavaMail API. Lacking these additional MimeMultipart subclasses,
ohair@286 64 * all subtypes of MIME multipart data appear as MimeMultipart objects. <p>
ohair@286 65 *
ohair@286 66 * An application can directly construct a MIME multipart object of any
ohair@286 67 * subtype by using the <code>MimeMultipart(String subtype)</code>
ohair@286 68 * constructor. For example, to create a "multipart/alternative" object,
ohair@286 69 * use <code>new MimeMultipart("alternative")</code>.
ohair@286 70 *
ohair@286 71 * @version 1.31, 03/01/29
ohair@286 72 * @author John Mani
ohair@286 73 * @author Bill Shannon
ohair@286 74 * @author Max Spivak
ohair@286 75 */
ohair@286 76
ohair@286 77 //BM MimeMultipart can extend this
ohair@286 78 public class MimeMultipart {
ohair@286 79
ohair@286 80 /**
ohair@286 81 * The DataSource supplying our InputStream.
ohair@286 82 */
ohair@286 83 protected DataSource ds = null;
ohair@286 84
ohair@286 85 /**
ohair@286 86 * Have we parsed the data from our InputStream yet?
ohair@286 87 * Defaults to true; set to false when our constructor is
ohair@286 88 * given a DataSource with an InputStream that we need to
ohair@286 89 * parse.
ohair@286 90 */
ohair@286 91 protected boolean parsed = true;
ohair@286 92
ohair@286 93 /**
ohair@286 94 * Vector of MimeBodyPart objects.
ohair@286 95 */
ohair@286 96 protected FinalArrayList parts = new FinalArrayList(); // Holds BodyParts
ohair@286 97
ohair@286 98 /**
ohair@286 99 * This field specifies the content-type of this multipart
ohair@286 100 * object. It defaults to "multipart/mixed".
ohair@286 101 */
ohair@286 102 protected ContentType contentType;
ohair@286 103
ohair@286 104 /**
ohair@286 105 * The <code>MimeBodyPart</code> containing this <code>MimeMultipart</code>,
ohair@286 106 * if known.
ohair@286 107 * @since JavaMail 1.1
ohair@286 108 */
ohair@286 109 protected MimeBodyPart parent;
ohair@286 110
ohair@286 111 protected static boolean ignoreMissingEndBoundary = true;
ohair@286 112
ohair@286 113 static {
ohair@286 114 ignoreMissingEndBoundary = SAAJUtil.getSystemBoolean("saaj.mime.multipart.ignoremissingendboundary");
ohair@286 115 }
ohair@286 116 /**
ohair@286 117 * Default constructor. An empty MimeMultipart object
ohair@286 118 * is created. Its content type is set to "multipart/mixed".
ohair@286 119 * A unique boundary string is generated and this string is
ohair@286 120 * setup as the "boundary" parameter for the
ohair@286 121 * <code>contentType</code> field. <p>
ohair@286 122 *
ohair@286 123 * MimeBodyParts may be added later.
ohair@286 124 */
ohair@286 125 public MimeMultipart() {
ohair@286 126 this("mixed");
ohair@286 127 }
ohair@286 128
ohair@286 129 /**
ohair@286 130 * Construct a MimeMultipart object of the given subtype.
ohair@286 131 * A unique boundary string is generated and this string is
ohair@286 132 * setup as the "boundary" parameter for the
ohair@286 133 * <code>contentType</code> field. <p>
ohair@286 134 *
ohair@286 135 * MimeBodyParts may be added later.
ohair@286 136 */
ohair@286 137 public MimeMultipart(String subtype) {
ohair@286 138 //super();
ohair@286 139 /*
ohair@286 140 * Compute a boundary string.
ohair@286 141 */
ohair@286 142 String boundary = UniqueValue.getUniqueBoundaryValue();
ohair@286 143 contentType = new ContentType("multipart", subtype, null);
ohair@286 144 contentType.setParameter("boundary", boundary);
ohair@286 145 }
ohair@286 146
ohair@286 147 /**
ohair@286 148 * Constructs a MimeMultipart object and its bodyparts from the
ohair@286 149 * given DataSource. <p>
ohair@286 150 *
ohair@286 151 * This constructor handles as a special case the situation where the
ohair@286 152 * given DataSource is a MultipartDataSource object.
ohair@286 153 *
ohair@286 154 * Otherwise, the DataSource is assumed to provide a MIME multipart
ohair@286 155 * byte stream. The <code>parsed</code> flag is set to false. When
ohair@286 156 * the data for the body parts are needed, the parser extracts the
ohair@286 157 * "boundary" parameter from the content type of this DataSource,
ohair@286 158 * skips the 'preamble' and reads bytes till the terminating
ohair@286 159 * boundary and creates MimeBodyParts for each part of the stream.
ohair@286 160 *
ohair@286 161 * @param ds DataSource, can be a MultipartDataSource
ohair@286 162 * @param ct
ohair@286 163 * This must be the same information as {@link DataSource#getContentType()}.
ohair@286 164 * All the callers of this method seem to have this object handy, so
ohair@286 165 * for performance reason this method accepts it. Can be null.
ohair@286 166 */
ohair@286 167 public MimeMultipart(DataSource ds, ContentType ct) throws MessagingException {
ohair@286 168 // 'ds' was not a MultipartDataSource, we have
ohair@286 169 // to parse this ourself.
ohair@286 170 parsed = false;
ohair@286 171 this.ds = ds;
ohair@286 172 if (ct==null)
ohair@286 173 contentType = new ContentType(ds.getContentType());
ohair@286 174 else
ohair@286 175 contentType = ct;
ohair@286 176 }
ohair@286 177
ohair@286 178 /**
ohair@286 179 * Set the subtype. This method should be invoked only on a new
ohair@286 180 * MimeMultipart object created by the client. The default subtype
ohair@286 181 * of such a multipart object is "mixed". <p>
ohair@286 182 *
ohair@286 183 * @param subtype Subtype
ohair@286 184 */
ohair@286 185 public void setSubType(String subtype) {
ohair@286 186 contentType.setSubType(subtype);
ohair@286 187 }
ohair@286 188
ohair@286 189 /**
ohair@286 190 * Return the number of enclosed MimeBodyPart objects.
ohair@286 191 *
ohair@286 192 * @return number of parts
ohair@286 193 */
ohair@286 194 public int getCount() throws MessagingException {
ohair@286 195 parse();
ohair@286 196 if (parts == null)
ohair@286 197 return 0;
ohair@286 198
ohair@286 199 return parts.size();
ohair@286 200 }
ohair@286 201
ohair@286 202 /**
ohair@286 203 * Get the specified MimeBodyPart. BodyParts are numbered starting at 0.
ohair@286 204 *
ohair@286 205 * @param index the index of the desired MimeBodyPart
ohair@286 206 * @return the MimeBodyPart
ohair@286 207 * @exception MessagingException if no such MimeBodyPart exists
ohair@286 208 */
ohair@286 209 public MimeBodyPart getBodyPart(int index)
ohair@286 210 throws MessagingException {
ohair@286 211 parse();
ohair@286 212 if (parts == null)
ohair@286 213 throw new IndexOutOfBoundsException("No such BodyPart");
ohair@286 214
ohair@286 215 return (MimeBodyPart)parts.get(index);
ohair@286 216 }
ohair@286 217
ohair@286 218 /**
ohair@286 219 * Get the MimeBodyPart referred to by the given ContentID (CID).
ohair@286 220 * Returns null if the part is not found.
ohair@286 221 *
ohair@286 222 * @param CID the ContentID of the desired part
ohair@286 223 * @return the MimeBodyPart
ohair@286 224 */
ohair@286 225 public MimeBodyPart getBodyPart(String CID)
ohair@286 226 throws MessagingException {
ohair@286 227 parse();
ohair@286 228
ohair@286 229 int count = getCount();
ohair@286 230 for (int i = 0; i < count; i++) {
ohair@286 231 MimeBodyPart part = getBodyPart(i);
ohair@286 232 String s = part.getContentID();
ohair@286 233 // Old versions of AXIS2 put angle brackets around the content
ohair@286 234 // id but not the start param
ohair@286 235 String sNoAngle = (s!= null) ? s.replaceFirst("^<", "").replaceFirst(">$", "")
ohair@286 236 :null;
ohair@286 237 if (s != null && (s.equals(CID) || CID.equals(sNoAngle)))
ohair@286 238 return part;
ohair@286 239 }
ohair@286 240 return null;
ohair@286 241 }
ohair@286 242
ohair@286 243 /**
ohair@286 244 * Update headers. The default implementation here just
ohair@286 245 * calls the <code>updateHeaders</code> method on each of its
ohair@286 246 * children BodyParts. <p>
ohair@286 247 *
ohair@286 248 * Note that the boundary parameter is already set up when
ohair@286 249 * a new and empty MimeMultipart object is created. <p>
ohair@286 250 *
ohair@286 251 * This method is called when the <code>saveChanges</code>
ohair@286 252 * method is invoked on the Message object containing this
ohair@286 253 * MimeMultipart. This is typically done as part of the Message
ohair@286 254 * send process, however note that a client is free to call
ohair@286 255 * it any number of times. So if the header updating process is
ohair@286 256 * expensive for a specific MimeMultipart subclass, then it
ohair@286 257 * might itself want to track whether its internal state actually
ohair@286 258 * did change, and do the header updating only if necessary.
ohair@286 259 */
ohair@286 260 protected void updateHeaders() throws MessagingException {
ohair@286 261 for (int i = 0; i < parts.size(); i++)
ohair@286 262 ((MimeBodyPart)parts.get(i)).updateHeaders();
ohair@286 263 }
ohair@286 264
ohair@286 265 /**
ohair@286 266 * Iterates through all the parts and outputs each Mime part
ohair@286 267 * separated by a boundary.
ohair@286 268 */
ohair@286 269 public void writeTo(OutputStream os)
ohair@286 270 throws IOException, MessagingException {
ohair@286 271 parse();
ohair@286 272
ohair@286 273 String boundary = "--" + contentType.getParameter("boundary");
ohair@286 274
ohair@286 275 for (int i = 0; i < parts.size(); i++) {
ohair@286 276 OutputUtil.writeln(boundary, os); // put out boundary
ohair@286 277 getBodyPart(i).writeTo(os);
ohair@286 278 OutputUtil.writeln(os); // put out empty line
ohair@286 279 }
ohair@286 280
ohair@286 281 // put out last boundary
ohair@286 282 OutputUtil.writeAsAscii(boundary, os);
ohair@286 283 OutputUtil.writeAsAscii("--", os);
ohair@286 284 os.flush();
ohair@286 285 }
ohair@286 286
ohair@286 287 /**
ohair@286 288 * Parse the InputStream from our DataSource, constructing the
ohair@286 289 * appropriate MimeBodyParts. The <code>parsed</code> flag is
ohair@286 290 * set to true, and if true on entry nothing is done. This
ohair@286 291 * method is called by all other methods that need data for
ohair@286 292 * the body parts, to make sure the data has been parsed.
ohair@286 293 *
ohair@286 294 * @since JavaMail 1.2
ohair@286 295 */
ohair@286 296 protected void parse() throws MessagingException {
ohair@286 297 if (parsed)
ohair@286 298 return;
ohair@286 299
ohair@286 300 InputStream in;
ohair@286 301 SharedInputStream sin = null;
ohair@286 302 long start = 0, end = 0;
ohair@286 303 boolean foundClosingBoundary = false;
ohair@286 304
ohair@286 305 try {
ohair@286 306 in = ds.getInputStream();
ohair@286 307 if (!(in instanceof ByteArrayInputStream) &&
ohair@286 308 !(in instanceof BufferedInputStream) &&
ohair@286 309 !(in instanceof SharedInputStream))
ohair@286 310 in = new BufferedInputStream(in);
ohair@286 311 } catch (Exception ex) {
ohair@286 312 throw new MessagingException("No inputstream from datasource");
ohair@286 313 }
ohair@286 314 if (in instanceof SharedInputStream)
ohair@286 315 sin = (SharedInputStream)in;
ohair@286 316
ohair@286 317 String boundary = "--" + contentType.getParameter("boundary");
ohair@286 318 byte[] bndbytes = ASCIIUtility.getBytes(boundary);
ohair@286 319 int bl = bndbytes.length;
ohair@286 320
ohair@286 321 try {
ohair@286 322 // Skip the preamble
ohair@286 323 LineInputStream lin = new LineInputStream(in);
ohair@286 324 String line;
ohair@286 325 while ((line = lin.readLine()) != null) {
ohair@286 326 /*
ohair@286 327 * Strip trailing whitespace. Can't use trim method
ohair@286 328 * because it's too aggressive. Some bogus MIME
ohair@286 329 * messages will include control characters in the
ohair@286 330 * boundary string.
ohair@286 331 */
ohair@286 332 int i;
ohair@286 333 for (i = line.length() - 1; i >= 0; i--) {
ohair@286 334 char c = line.charAt(i);
ohair@286 335 if (!(c == ' ' || c == '\t'))
ohair@286 336 break;
ohair@286 337 }
ohair@286 338 line = line.substring(0, i + 1);
ohair@286 339 if (line.equals(boundary))
ohair@286 340 break;
ohair@286 341 }
ohair@286 342 if (line == null)
ohair@286 343 throw new MessagingException("Missing start boundary");
ohair@286 344
ohair@286 345 /*
ohair@286 346 * Read and process body parts until we see the
ohair@286 347 * terminating boundary line (or EOF).
ohair@286 348 */
ohair@286 349 boolean done = false;
ohair@286 350 getparts:
ohair@286 351 while (!done) {
ohair@286 352 InternetHeaders headers = null;
ohair@286 353 if (sin != null) {
ohair@286 354 start = sin.getPosition();
ohair@286 355 // skip headers
ohair@286 356 while ((line = lin.readLine()) != null && line.length() > 0)
ohair@286 357 ;
ohair@286 358 if (line == null) {
ohair@286 359 if (!ignoreMissingEndBoundary) {
ohair@286 360 throw new MessagingException("Missing End Boundary for Mime Package : EOF while skipping headers");
ohair@286 361 }
ohair@286 362 // assume there's just a missing end boundary
ohair@286 363 break getparts;
ohair@286 364 }
ohair@286 365 } else {
ohair@286 366 // collect the headers for this body part
ohair@286 367 headers = createInternetHeaders(in);
ohair@286 368 }
ohair@286 369
ohair@286 370 if (!in.markSupported())
ohair@286 371 throw new MessagingException("Stream doesn't support mark");
ohair@286 372
ohair@286 373 ByteOutputStream buf = null;
ohair@286 374 // if we don't have a shared input stream, we copy the data
ohair@286 375 if (sin == null)
ohair@286 376 buf = new ByteOutputStream();
ohair@286 377 int b;
ohair@286 378 boolean bol = true; // beginning of line flag
ohair@286 379 // the two possible end of line characters
ohair@286 380 int eol1 = -1, eol2 = -1;
ohair@286 381
ohair@286 382 /*
ohair@286 383 * Read and save the content bytes in buf.
ohair@286 384 */
ohair@286 385 for (;;) {
ohair@286 386 if (bol) {
ohair@286 387 /*
ohair@286 388 * At the beginning of a line, check whether the
ohair@286 389 * next line is a boundary.
ohair@286 390 */
ohair@286 391 int i;
ohair@286 392 in.mark(bl + 4 + 1000); // bnd + "--\r\n" + lots of LWSP
ohair@286 393 // read bytes, matching against the boundary
ohair@286 394 for (i = 0; i < bl; i++)
ohair@286 395 if (in.read() != bndbytes[i])
ohair@286 396 break;
ohair@286 397 if (i == bl) {
ohair@286 398 // matched the boundary, check for last boundary
ohair@286 399 int b2 = in.read();
ohair@286 400 if (b2 == '-') {
ohair@286 401 if (in.read() == '-') {
ohair@286 402 done = true;
ohair@286 403 foundClosingBoundary = true;
ohair@286 404 break; // ignore trailing text
ohair@286 405 }
ohair@286 406 }
ohair@286 407 // skip linear whitespace
ohair@286 408 while (b2 == ' ' || b2 == '\t')
ohair@286 409 b2 = in.read();
ohair@286 410 // check for end of line
ohair@286 411 if (b2 == '\n')
ohair@286 412 break; // got it! break out of the loop
ohair@286 413 if (b2 == '\r') {
ohair@286 414 in.mark(1);
ohair@286 415 if (in.read() != '\n')
ohair@286 416 in.reset();
ohair@286 417 break; // got it! break out of the loop
ohair@286 418 }
ohair@286 419 }
ohair@286 420 // failed to match, reset and proceed normally
ohair@286 421 in.reset();
ohair@286 422
ohair@286 423 // if this is not the first line, write out the
ohair@286 424 // end of line characters from the previous line
ohair@286 425 if (buf != null && eol1 != -1) {
ohair@286 426 buf.write(eol1);
ohair@286 427 if (eol2 != -1)
ohair@286 428 buf.write(eol2);
ohair@286 429 eol1 = eol2 = -1;
ohair@286 430 }
ohair@286 431 }
ohair@286 432
ohair@286 433 // read the next byte
ohair@286 434 if ((b = in.read()) < 0) {
ohair@286 435 done = true;
ohair@286 436 break;
ohair@286 437 }
ohair@286 438
ohair@286 439 /*
ohair@286 440 * If we're at the end of the line, save the eol characters
ohair@286 441 * to be written out before the beginning of the next line.
ohair@286 442 */
ohair@286 443 if (b == '\r' || b == '\n') {
ohair@286 444 bol = true;
ohair@286 445 if (sin != null)
ohair@286 446 end = sin.getPosition() - 1;
ohair@286 447 eol1 = b;
ohair@286 448 if (b == '\r') {
ohair@286 449 in.mark(1);
ohair@286 450 if ((b = in.read()) == '\n')
ohair@286 451 eol2 = b;
ohair@286 452 else
ohair@286 453 in.reset();
ohair@286 454 }
ohair@286 455 } else {
ohair@286 456 bol = false;
ohair@286 457 if (buf != null)
ohair@286 458 buf.write(b);
ohair@286 459 }
ohair@286 460 }
ohair@286 461
ohair@286 462 /*
ohair@286 463 * Create a MimeBody element to represent this body part.
ohair@286 464 */
ohair@286 465 MimeBodyPart part;
ohair@286 466 if (sin != null)
ohair@286 467 part = createMimeBodyPart(sin.newStream(start, end));
ohair@286 468 else
ohair@286 469 part = createMimeBodyPart(headers, buf.getBytes(), buf.getCount());
ohair@286 470 addBodyPart(part);
ohair@286 471 }
ohair@286 472 } catch (IOException ioex) {
ohair@286 473 throw new MessagingException("IO Error", ioex);
ohair@286 474 }
ohair@286 475
ohair@286 476 if (!ignoreMissingEndBoundary && !foundClosingBoundary && sin== null) {
ohair@286 477 throw new MessagingException("Missing End Boundary for Mime Package : EOF while skipping headers");
ohair@286 478 }
ohair@286 479 parsed = true;
ohair@286 480 }
ohair@286 481
ohair@286 482 /**
ohair@286 483 * Create and return an InternetHeaders object that loads the
ohair@286 484 * headers from the given InputStream. Subclasses can override
ohair@286 485 * this method to return a subclass of InternetHeaders, if
ohair@286 486 * necessary. This implementation simply constructs and returns
ohair@286 487 * an InternetHeaders object.
ohair@286 488 *
ohair@286 489 * @param is the InputStream to read the headers from
ohair@286 490 * @exception MessagingException
ohair@286 491 * @since JavaMail 1.2
ohair@286 492 */
ohair@286 493 protected InternetHeaders createInternetHeaders(InputStream is)
ohair@286 494 throws MessagingException {
ohair@286 495 return new InternetHeaders(is);
ohair@286 496 }
ohair@286 497
ohair@286 498 /**
ohair@286 499 * Create and return a MimeBodyPart object to represent a
ohair@286 500 * body part parsed from the InputStream. Subclasses can override
ohair@286 501 * this method to return a subclass of MimeBodyPart, if
ohair@286 502 * necessary. This implementation simply constructs and returns
ohair@286 503 * a MimeBodyPart object.
ohair@286 504 *
ohair@286 505 * @param headers the headers for the body part
ohair@286 506 * @param content the content of the body part
ohair@286 507 * @since JavaMail 1.2
ohair@286 508 */
ohair@286 509 protected MimeBodyPart createMimeBodyPart(InternetHeaders headers, byte[] content, int len) {
ohair@286 510 return new MimeBodyPart(headers, content,len);
ohair@286 511 }
ohair@286 512
ohair@286 513 /**
ohair@286 514 * Create and return a MimeBodyPart object to represent a
ohair@286 515 * body part parsed from the InputStream. Subclasses can override
ohair@286 516 * this method to return a subclass of MimeBodyPart, if
ohair@286 517 * necessary. This implementation simply constructs and returns
ohair@286 518 * a MimeBodyPart object.
ohair@286 519 *
ohair@286 520 * @param is InputStream containing the body part
ohair@286 521 * @exception MessagingException
ohair@286 522 * @since JavaMail 1.2
ohair@286 523 */
ohair@286 524 protected MimeBodyPart createMimeBodyPart(InputStream is) throws MessagingException {
ohair@286 525 return new MimeBodyPart(is);
ohair@286 526 }
ohair@286 527
ohair@286 528 /**
ohair@286 529 * Setup this MimeMultipart object from the given MultipartDataSource. <p>
ohair@286 530 *
ohair@286 531 * The method adds the MultipartDataSource's MimeBodyPart
ohair@286 532 * objects into this MimeMultipart. This MimeMultipart's contentType is
ohair@286 533 * set to that of the MultipartDataSource. <p>
ohair@286 534 *
ohair@286 535 * This method is typically used in those cases where one
ohair@286 536 * has a multipart data source that has already been pre-parsed into
ohair@286 537 * the individual body parts (for example, an IMAP datasource), but
ohair@286 538 * needs to create an appropriate MimeMultipart subclass that represents
ohair@286 539 * a specific multipart subtype.
ohair@286 540 *
ohair@286 541 * @param mp MimeMultipart datasource
ohair@286 542 */
ohair@286 543
ohair@286 544 protected void setMultipartDataSource(MultipartDataSource mp)
ohair@286 545 throws MessagingException {
ohair@286 546 contentType = new ContentType(mp.getContentType());
ohair@286 547
ohair@286 548 int count = mp.getCount();
ohair@286 549 for (int i = 0; i < count; i++)
ohair@286 550 addBodyPart(mp.getBodyPart(i));
ohair@286 551 }
ohair@286 552
ohair@286 553 /**
ohair@286 554 * Return the content-type of this MimeMultipart. <p>
ohair@286 555 *
ohair@286 556 * This implementation just returns the value of the
ohair@286 557 * <code>contentType</code> field.
ohair@286 558 *
ohair@286 559 * @return content-type
ohair@286 560 * @see #contentType
ohair@286 561 */
ohair@286 562 public ContentType getContentType() {
ohair@286 563 return contentType;
ohair@286 564 }
ohair@286 565
ohair@286 566 /**
ohair@286 567 * Remove the specified part from the multipart message.
ohair@286 568 * Shifts all the parts after the removed part down one.
ohair@286 569 *
ohair@286 570 * @param part The part to remove
ohair@286 571 * @return true if part removed, false otherwise
ohair@286 572 * @exception MessagingException if no such MimeBodyPart exists
ohair@286 573 */
ohair@286 574 public boolean removeBodyPart(MimeBodyPart part) throws MessagingException {
ohair@286 575 if (parts == null)
ohair@286 576 throw new MessagingException("No such body part");
ohair@286 577
ohair@286 578 boolean ret = parts.remove(part);
ohair@286 579 part.setParent(null);
ohair@286 580 return ret;
ohair@286 581 }
ohair@286 582
ohair@286 583 /**
ohair@286 584 * Remove the part at specified location (starting from 0).
ohair@286 585 * Shifts all the parts after the removed part down one.
ohair@286 586 *
ohair@286 587 * @param index Index of the part to remove
ohair@286 588 * @exception IndexOutOfBoundsException if the given index
ohair@286 589 * is out of range.
ohair@286 590 */
ohair@286 591 public void removeBodyPart(int index) {
ohair@286 592 if (parts == null)
ohair@286 593 throw new IndexOutOfBoundsException("No such BodyPart");
ohair@286 594
ohair@286 595 MimeBodyPart part = (MimeBodyPart)parts.get(index);
ohair@286 596 parts.remove(index);
ohair@286 597 part.setParent(null);
ohair@286 598 }
ohair@286 599
ohair@286 600 /**
ohair@286 601 * Adds a MimeBodyPart to the multipart. The MimeBodyPart is appended to
ohair@286 602 * the list of existing Parts.
ohair@286 603 *
ohair@286 604 * @param part The MimeBodyPart to be appended
ohair@286 605 */
ohair@286 606 public synchronized void addBodyPart(MimeBodyPart part) {
ohair@286 607 if (parts == null)
ohair@286 608 parts = new FinalArrayList();
ohair@286 609
ohair@286 610 parts.add(part);
ohair@286 611 part.setParent(this);
ohair@286 612 }
ohair@286 613
ohair@286 614 /**
ohair@286 615 * Adds a MimeBodyPart at position <code>index</code>.
ohair@286 616 * If <code>index</code> is not the last one in the list,
ohair@286 617 * the subsequent parts are shifted up. If <code>index</code>
ohair@286 618 * is larger than the number of parts present, the
ohair@286 619 * MimeBodyPart is appended to the end.
ohair@286 620 *
ohair@286 621 * @param part The MimeBodyPart to be inserted
ohair@286 622 * @param index Location where to insert the part
ohair@286 623 */
ohair@286 624 public synchronized void addBodyPart(MimeBodyPart part, int index) {
ohair@286 625 if (parts == null)
ohair@286 626 parts = new FinalArrayList();
ohair@286 627
ohair@286 628 parts.add(index,part);
ohair@286 629 part.setParent(this);
ohair@286 630 }
ohair@286 631
ohair@286 632 /**
ohair@286 633 * Return the <code>MimeBodyPart</code> that contains this <code>MimeMultipart</code>
ohair@286 634 * object, or <code>null</code> if not known.
ohair@286 635 * @since JavaMail 1.1
ohair@286 636 */
ohair@286 637 MimeBodyPart getParent() {
ohair@286 638 return parent;
ohair@286 639 }
ohair@286 640
ohair@286 641 /**
ohair@286 642 * Set the parent of this <code>MimeMultipart</code> to be the specified
ohair@286 643 * <code>MimeBodyPart</code>. Normally called by the <code>Message</code>
ohair@286 644 * or <code>MimeBodyPart</code> <code>setContent(MimeMultipart)</code> method.
ohair@286 645 * <code>parent</code> may be <code>null</code> if the
ohair@286 646 * <code>MimeMultipart</code> is being removed from its containing
ohair@286 647 * <code>MimeBodyPart</code>.
ohair@286 648 * @since JavaMail 1.1
ohair@286 649 */
ohair@286 650 void setParent(MimeBodyPart parent) {
ohair@286 651 this.parent = parent;
ohair@286 652 }
ohair@286 653 }

mercurial