1. /*
  2. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  3. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  4. */
  5. package javax.mail;
  6. import java.util.Vector;
  7. import java.io.InputStream;
  8. import java.io.OutputStream;
  9. import java.io.IOException;
  10. import javax.activation.DataSource;
  11. /**
  12. * Multipart is a container that holds multiple body parts. Multipart
  13. * provides methods to retrieve and set its subparts. <p>
  14. *
  15. * Multipart also acts as the base class for the content object returned
  16. * by most Multipart DataContentHandlers. For example, invoking getContent()
  17. * on a DataHandler whose source is a "multipart/signed" data source may
  18. * return an appropriate subclass of Multipart. <p>
  19. *
  20. * Some messaging systems provide different subtypes of Multiparts. For
  21. * example, MIME specifies a set of subtypes that include "alternative",
  22. * "mixed", "related", "parallel", "signed", etc. <p>
  23. *
  24. * Multipart is an abstract class. Subclasses provide actual implementations.
  25. *
  26. * @version 1.12, 99/12/06
  27. * @author John Mani
  28. */
  29. public abstract class Multipart {
  30. /**
  31. * Vector of BodyPart objects.
  32. */
  33. protected Vector parts = new Vector(); // Holds BodyParts
  34. /**
  35. * This field specifies the content-type of this multipart
  36. * object. It defaults to "multipart/mixed".
  37. */
  38. protected String contentType = "multipart/mixed" ; // Content-Type
  39. /**
  40. * The <code>Part</code> containing this <code>Multipart</code>,
  41. * if known.
  42. * @since JavaMail 1.1
  43. */
  44. protected Part parent;
  45. /**
  46. * Default constructor. An empty Multipart object is created.
  47. */
  48. protected Multipart() { }
  49. /**
  50. * Setup this Multipart object from the given MultipartDataSource. <p>
  51. *
  52. * The method adds the MultipartDataSource's BodyPart
  53. * objects into this Multipart. This Multipart's contentType is
  54. * set to that of the MultipartDataSource. <p>
  55. *
  56. * This method is typically used in those cases where one
  57. * has a multipart data source that has already been pre-parsed into
  58. * the individual body parts (for example, an IMAP datasource), but
  59. * needs to create an appropriate Multipart subclass that represents
  60. * a specific multipart subtype.
  61. *
  62. * @param mp Multipart datasource
  63. */
  64. protected void setMultipartDataSource(MultipartDataSource mp)
  65. throws MessagingException {
  66. contentType = mp.getContentType();
  67. int count = mp.getCount();
  68. for (int i = 0; i < count; i++)
  69. addBodyPart(mp.getBodyPart(i));
  70. }
  71. /**
  72. * Return the content-type of this Multipart. <p>
  73. *
  74. * This implementation just returns the value of the
  75. * <code>contentType</code> field.
  76. *
  77. * @return content-type
  78. * @see #contentType
  79. */
  80. public String getContentType() {
  81. return contentType;
  82. }
  83. /**
  84. * Return the number of enclosed BodyPart objects. <p>
  85. *
  86. * @return number of parts
  87. * @see #parts
  88. */
  89. public int getCount() throws MessagingException {
  90. if (parts == null)
  91. return 0;
  92. return parts.size();
  93. }
  94. /**
  95. * Get the specified Part. Parts are numbered starting at 0.
  96. *
  97. * @param index the index of the desired Part
  98. * @return the Part
  99. * @exception IndexOutOfBoundsException if the given index
  100. * is out of range.
  101. * @exception MessagingException
  102. */
  103. public BodyPart getBodyPart(int index) throws MessagingException {
  104. if (parts == null)
  105. throw new IndexOutOfBoundsException("No such BodyPart");
  106. return (BodyPart)parts.elementAt(index);
  107. }
  108. /**
  109. * Remove the specified part from the multipart message.
  110. * Shifts all the parts after the removed part down one.
  111. *
  112. * @param part The part to remove
  113. * @return true if part removed, false otherwise
  114. * @exception MessagingException if no such Part exists
  115. * @exception IllegalWriteException if the underlying
  116. * implementation does not support modification
  117. * of existing values
  118. */
  119. public boolean removeBodyPart(BodyPart part) throws MessagingException {
  120. if (parts == null)
  121. throw new MessagingException("No such body part");
  122. boolean ret = parts.removeElement(part);
  123. part.setParent(null);
  124. return ret;
  125. }
  126. /**
  127. * Remove the part at specified location (starting from 0).
  128. * Shifts all the parts after the removed part down one.
  129. *
  130. * @param index Index of the part to remove
  131. * @exception MessagingException
  132. * @exception IndexOutOfBoundsException if the given index
  133. * is out of range.
  134. * @exception IllegalWriteException if the underlying
  135. * implementation does not support modification
  136. * of existing values
  137. */
  138. public void removeBodyPart(int index) throws MessagingException {
  139. if (parts == null)
  140. throw new IndexOutOfBoundsException("No such BodyPart");
  141. BodyPart part = (BodyPart)parts.elementAt(index);
  142. parts.removeElementAt(index);
  143. part.setParent(null);
  144. }
  145. /**
  146. * Adds a Part to the multipart. The BodyPart is appended to
  147. * the list of existing Parts.
  148. *
  149. * @param part The Part to be appended
  150. * @exception MessagingException
  151. * @exception IllegalWriteException if the underlying
  152. * implementation does not support modification
  153. * of existing values
  154. */
  155. public synchronized void addBodyPart(BodyPart part)
  156. throws MessagingException {
  157. if (parts == null)
  158. parts = new Vector();
  159. parts.addElement(part);
  160. part.setParent(this);
  161. }
  162. /**
  163. * Adds a BodyPart at position <code>index</code>.
  164. * If <code>index</code> is not the last one in the list,
  165. * the subsequent parts are shifted up. If <code>index</code>
  166. * is larger than the number of parts present, the
  167. * BodyPart is appended to the end.
  168. *
  169. * @param part The BodyPart to be inserted
  170. * @param index Location where to insert the part
  171. * @exception MessagingException
  172. * @exception IllegalWriteException if the underlying
  173. * implementation does not support modification
  174. * of existing values
  175. */
  176. public synchronized void addBodyPart(BodyPart part, int index)
  177. throws MessagingException {
  178. if (parts == null)
  179. parts = new Vector();
  180. parts.insertElementAt(part, index);
  181. part.setParent(this);
  182. }
  183. /**
  184. * Output an appropriately encoded bytestream to the given
  185. * OutputStream. The implementation subclass decides the
  186. * appropriate encoding algorithm to be used. The bytestream
  187. * is typically used for sending.
  188. *
  189. * @exception IOException if an IO related exception occurs
  190. * @exception MessagingException
  191. */
  192. public abstract void writeTo(OutputStream os)
  193. throws IOException, MessagingException;
  194. /**
  195. * Return the <code>Part</code> that contains this <code>Multipart</code>
  196. * object, or <code>null</code> if not known.
  197. * @since JavaMail 1.1
  198. */
  199. public Part getParent() {
  200. return parent;
  201. }
  202. /**
  203. * Set the parent of this <code>Multipart</code> to be the specified
  204. * <code>Part</code>. Normally called by the <code>Message</code>
  205. * or <code>BodyPart</code> <code>setContent(Multipart)</code> method.
  206. * <code>parent</code> may be <code>null</code> if the
  207. * <code>Multipart</code> is being removed from its containing
  208. * <code>Part</code>.
  209. * @since JavaMail 1.1
  210. */
  211. public void setParent(Part parent) {
  212. this.parent = parent;
  213. }
  214. }