001/****************************************************************
002 * Licensed to the Apache Software Foundation (ASF) under one   *
003 * or more contributor license agreements.  See the NOTICE file *
004 * distributed with this work for additional information        *
005 * regarding copyright ownership.  The ASF licenses this file   *
006 * to you under the Apache License, Version 2.0 (the            *
007 * "License"); you may not use this file except in compliance   *
008 * with the License.  You may obtain a copy of the License at   *
009 *                                                              *
010 *   http://www.apache.org/licenses/LICENSE-2.0                 *
011 *                                                              *
012 * Unless required by applicable law or agreed to in writing,   *
013 * software distributed under the License is distributed on an  *
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015 * KIND, either express or implied.  See the License for the    *
016 * specific language governing permissions and limitations      *
017 * under the License.                                           *
018 ****************************************************************/
019
020package org.apache.james.mime4j.message;
021
022import java.util.Collections;
023import java.util.LinkedList;
024import java.util.List;
025
026import org.apache.james.mime4j.dom.Entity;
027import org.apache.james.mime4j.dom.Multipart;
028
029/**
030 * Abstract MIME multipart body.
031 */
032public abstract class AbstractMultipart implements Multipart {
033
034    protected List<Entity> bodyParts = new LinkedList<Entity>();
035    private Entity parent = null;
036
037    private String subType;
038
039    /**
040     * Creates a new empty <code>Multipart</code> instance.
041     */
042    public AbstractMultipart(String subType) {
043        this.subType = subType;
044    }
045
046    /**
047     * Gets the multipart sub-type. E.g. <code>alternative</code> (the
048     * default) or <code>parallel</code>. See RFC 2045 for common sub-types
049     * and their meaning.
050     *
051     * @return the multipart sub-type.
052     */
053    public String getSubType() {
054        return subType;
055    }
056
057    /**
058     * Sets the multipart sub-type. E.g. <code>alternative</code> or
059     * <code>parallel</code>. See RFC 2045 for common sub-types and their
060     * meaning.
061     *
062     * @param subType
063     *            the sub-type.
064     */
065    public void setSubType(String subType) {
066        this.subType = subType;
067    }
068
069    /**
070     * @see org.apache.james.mime4j.dom.Body#getParent()
071     */
072    public Entity getParent() {
073        return parent;
074    }
075
076    /**
077     * @see org.apache.james.mime4j.dom.Body#setParent(org.apache.james.mime4j.dom.Entity)
078     */
079    public void setParent(Entity parent) {
080        this.parent = parent;
081        for (Entity bodyPart : bodyParts) {
082            bodyPart.setParent(parent);
083        }
084    }
085
086    /**
087     * Returns the number of body parts.
088     *
089     * @return number of <code>Entity</code> objects.
090     */
091    public int getCount() {
092        return bodyParts.size();
093    }
094
095    /**
096     * Gets the list of body parts. The list is immutable.
097     *
098     * @return the list of <code>Entity</code> objects.
099     */
100    public List<Entity> getBodyParts() {
101        return Collections.unmodifiableList(bodyParts);
102    }
103
104    /**
105     * Sets the list of body parts.
106     *
107     * @param bodyParts
108     *            the new list of <code>Entity</code> objects.
109     */
110    public void setBodyParts(List<Entity> bodyParts) {
111        this.bodyParts = bodyParts;
112        for (Entity bodyPart : bodyParts) {
113            bodyPart.setParent(parent);
114        }
115    }
116
117    /**
118     * Adds a body part to the end of the list of body parts.
119     *
120     * @param bodyPart
121     *            the body part.
122     */
123    public void addBodyPart(Entity bodyPart) {
124        if (bodyPart == null)
125            throw new IllegalArgumentException();
126
127        bodyParts.add(bodyPart);
128        bodyPart.setParent(parent);
129    }
130
131    /**
132     * Inserts a body part at the specified position in the list of body parts.
133     *
134     * @param bodyPart
135     *            the body part.
136     * @param index
137     *            index at which the specified body part is to be inserted.
138     * @throws IndexOutOfBoundsException
139     *             if the index is out of range (index &lt; 0 || index &gt;
140     *             getCount()).
141     */
142    public void addBodyPart(Entity bodyPart, int index) {
143        if (bodyPart == null)
144            throw new IllegalArgumentException();
145
146        bodyParts.add(index, bodyPart);
147        bodyPart.setParent(parent);
148    }
149
150    /**
151     * Removes the body part at the specified position in the list of body
152     * parts.
153     *
154     * @param index
155     *            index of the body part to be removed.
156     * @return the removed body part.
157     * @throws IndexOutOfBoundsException
158     *             if the index is out of range (index &lt; 0 || index &gt;=
159     *             getCount()).
160     */
161    public Entity removeBodyPart(int index) {
162        Entity bodyPart = bodyParts.remove(index);
163        bodyPart.setParent(null);
164        return bodyPart;
165    }
166
167    /**
168     * Replaces the body part at the specified position in the list of body
169     * parts with the specified body part.
170     *
171     * @param bodyPart
172     *            body part to be stored at the specified position.
173     * @param index
174     *            index of body part to replace.
175     * @return the replaced body part.
176     * @throws IndexOutOfBoundsException
177     *             if the index is out of range (index &lt; 0 || index &gt;=
178     *             getCount()).
179     */
180    public Entity replaceBodyPart(Entity bodyPart, int index) {
181        if (bodyPart == null)
182            throw new IllegalArgumentException();
183
184        Entity replacedEntity = bodyParts.set(index, bodyPart);
185        if (bodyPart == replacedEntity)
186            throw new IllegalArgumentException(
187                    "Cannot replace body part with itself");
188
189        bodyPart.setParent(parent);
190        replacedEntity.setParent(null);
191
192        return replacedEntity;
193    }
194
195    /**
196     * Gets the preamble or null if the message has no preamble.
197     *
198     * @return the preamble.
199     */
200    public abstract String getPreamble();
201
202    /**
203     * Sets the preamble with a value or null to remove the preamble.
204     *
205     * @param preamble
206     *            the preamble.
207     */
208    public abstract void setPreamble(String preamble);
209
210    /**
211     * Gets the epilogue or null if the message has no epilogue
212     *
213     * @return the epilogue.
214     */
215    public abstract String getEpilogue();
216
217    /**
218     * Sets the epilogue value, or remove it if the value passed is null.
219     *
220     * @param epilogue
221     *            the epilogue.
222     */
223    public abstract void setEpilogue(String epilogue);
224
225    /**
226     * Disposes of the BodyParts of this Multipart. Note that the dispose call
227     * does not get forwarded to the parent entity of this Multipart.
228     *
229     * @see org.apache.james.mime4j.dom.Disposable#dispose()
230     */
231    public void dispose() {
232        for (Entity bodyPart : bodyParts) {
233            bodyPart.dispose();
234        }
235    }
236
237}