blob: 34beca606f0a82b557bc4856c98f61cb6ff81977 [file] [log] [blame]
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
package org.apache.james.mime4j.message;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.apache.james.mime4j.Charsets;
import org.apache.james.mime4j.dom.BinaryBody;
import org.apache.james.mime4j.dom.Body;
import org.apache.james.mime4j.dom.Entity;
import org.apache.james.mime4j.dom.Header;
import org.apache.james.mime4j.dom.Message;
import org.apache.james.mime4j.dom.Multipart;
import org.apache.james.mime4j.dom.SingleBody;
import org.apache.james.mime4j.dom.TextBody;
import org.apache.james.mime4j.io.InputStreams;
import org.apache.james.mime4j.stream.Field;
import org.apache.james.mime4j.stream.NameValuePair;
/**
* {@link org.apache.james.mime4j.dom.Multipart} builder.
*/
public class MultipartBuilder {
private final List<Entity> bodyParts;
private String subType;
private String preamble;
private String epilogue;
private BodyFactory bodyFactory;
public static MultipartBuilder create(String subType) {
return new MultipartBuilder().setSubType(subType);
}
public static MultipartBuilder createCopy(Multipart other) {
return new MultipartBuilder().copy(other);
}
public static MultipartBuilder create() {
return new MultipartBuilder();
}
private MultipartBuilder() {
this.bodyParts = new LinkedList<Entity>();
}
public MultipartBuilder use(final BodyFactory bodyFactory) {
this.bodyFactory = bodyFactory;
return this;
}
/**
* Gets the multipart sub-type. E.g. <code>alternative</code> (the
* default) or <code>parallel</code>. See RFC 2045 for common sub-types
* and their meaning.
*
* @return the multipart sub-type.
*/
public String getSubType() {
return subType;
}
/**
* Sets the multipart sub-type. E.g. <code>alternative</code> or
* <code>parallel</code>. See RFC 2045 for common sub-types and their
* meaning.
*
* @param subType
* the sub-type.
*/
public MultipartBuilder setSubType(String subType) {
this.subType = subType;
return this;
}
/**
* Returns the number of body parts.
*
* @return number of <code>Entity</code> objects.
*/
public int getCount() {
return bodyParts.size();
}
/**
* Gets the list of body parts. The list is immutable.
*
* @return the list of <code>Entity</code> objects.
*/
public List<Entity> getBodyParts() {
return Collections.unmodifiableList(bodyParts);
}
/**
* Adds a body part to the end of the list of body parts.
*
* @param bodyPart
* the body part.
*/
public MultipartBuilder addBodyPart(Entity bodyPart) {
if (bodyPart == null) {
throw new IllegalArgumentException();
}
bodyParts.add(bodyPart);
return this;
}
/**
* Inserts a body part at the specified position in the list of body parts.
*
* @param bodyPart
* the body part.
* @param index
* index at which the specified body part is to be inserted.
*/
public MultipartBuilder addBodyPart(Entity bodyPart, int index) {
if (bodyPart == null) {
throw new IllegalArgumentException();
}
bodyParts.add(index, bodyPart);
return this;
}
/**
* Removes the body part at the specified position in the list of body
* parts.
*
* @param index
* index of the body part to be removed.
* @return the removed body part.
*/
public MultipartBuilder removeBodyPart(int index) {
bodyParts.remove(index);
return this;
}
/**
* Replaces the body part at the specified position in the list of body
* parts with the specified body part.
*
* @param bodyPart
* body part to be stored at the specified position.
* @param index
* index of body part to replace.
* @return the replaced body part.
* @throws IndexOutOfBoundsException
* if the index is out of range (index &lt; 0 || index &gt;=
* getCount()).
*/
public MultipartBuilder replaceBodyPart(Entity bodyPart, int index) {
if (bodyPart == null) {
throw new IllegalArgumentException();
}
bodyParts.set(index, bodyPart);
return this;
}
/**
* Returns preamble.
*
* @return the preamble.
*/
public String getPreamble() {
return preamble;
}
/**
* Sets the preamble.
*
* @param preamble
* the preamble.
*/
public MultipartBuilder setPreamble(String preamble) {
this.preamble = preamble;
return this;
}
/**
* Returns epilogue.
*
* @return the epilogue.
*/
public String getEpilogue() {
return epilogue;
}
/**
* Sets the epilogue.
*
* @param epilogue
* the epilogue.
*/
public MultipartBuilder setEpilogue(String epilogue) {
this.epilogue = epilogue;
return this;
}
public MultipartBuilder addTextPart(String text, Charset charset) throws IOException {
Charset cs = charset != null ? charset : Charsets.ISO_8859_1;
TextBody body = bodyFactory != null ? bodyFactory.textBody(
InputStreams.create(text, cs), cs.name()) : BasicBodyFactory.INSTANCE.textBody(text, cs);
BodyPart bodyPart = BodyPartBuilder.create()
.setBody(body)
.setContentType("text/plain", new NameValuePair("charset", cs.name()))
.setContentTransferEncoding("quoted-printable")
.build();
return addBodyPart(bodyPart);
}
public MultipartBuilder addBinaryPart(byte[] bin, String mimeType) throws IOException {
BinaryBody body = bodyFactory != null ? bodyFactory.binaryBody(InputStreams.create(bin)) :
BasicBodyFactory.INSTANCE.binaryBody(bin);
BodyPart bodyPart = BodyPartBuilder.create()
.setBody(body)
.setContentType(mimeType)
.setContentTransferEncoding("base64")
.build();
return addBodyPart(bodyPart);
}
public MultipartBuilder copy(Multipart other) {
if (other == null) {
return this;
}
subType = other.getSubType();
bodyParts.clear();
final List<Entity> otherParts = other.getBodyParts();
for (Entity otherPart: otherParts) {
BodyPart bodyPart = new BodyPart();
Header otherHeader = otherPart.getHeader();
if (otherHeader != null) {
HeaderImpl header = new HeaderImpl();
for (Field otherField : otherHeader.getFields()) {
header.addField(otherField);
}
bodyPart.setHeader(header);
}
final Body otherBody = otherPart.getBody();
if (otherBody != null) {
Body body = null;
if (otherBody instanceof Message) {
body = MessageBuilder.createCopy((Message) otherBody).build();
} else if (otherBody instanceof Multipart) {
body = MultipartBuilder.createCopy((Multipart) otherBody).build();
} else if (otherBody instanceof SingleBody) {
body = ((SingleBody) otherBody).copy();
}
bodyPart.setBody(body);
}
bodyParts.add(bodyPart);
}
preamble = other.getPreamble();
epilogue = other.getEpilogue();
return this;
}
public Multipart build() {
MultipartImpl multipart = new MultipartImpl(subType);
for (Entity part : bodyParts) {
multipart.addBodyPart(part);
}
multipart.setPreamble(preamble);
multipart.setEpilogue(epilogue);
return multipart;
}
}