blob: 954d3ba2f95ec6e5bc79a514d651d42dcf6583cc [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.io.InputStream;
import java.nio.charset.Charset;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.james.mime4j.storage.DefaultStorageProvider;
import org.apache.james.mime4j.storage.MultiReferenceStorage;
import org.apache.james.mime4j.storage.Storage;
import org.apache.james.mime4j.storage.StorageProvider;
import org.apache.james.mime4j.util.CharsetUtil;
/**
* Factory for creating message bodies.
*/
public class BodyFactory {
private static Log log = LogFactory.getLog(BodyFactory.class);
private static final Charset FALLBACK_CHARSET = CharsetUtil.DEFAULT_CHARSET;
private StorageProvider storageProvider;
/**
* Creates a new <code>BodyFactory</code> instance that uses the default
* storage provider for creating message bodies from input streams.
*/
public BodyFactory() {
this.storageProvider = DefaultStorageProvider.getInstance();
}
/**
* Creates a new <code>BodyFactory</code> instance that uses the given
* storage provider for creating message bodies from input streams.
*
* @param storageProvider
* a storage provider or <code>null</code> to use the default
* one.
*/
public BodyFactory(StorageProvider storageProvider) {
if (storageProvider == null)
storageProvider = DefaultStorageProvider.getInstance();
this.storageProvider = storageProvider;
}
/**
* Returns the <code>StorageProvider</code> this <code>BodyFactory</code>
* uses to create message bodies from input streams.
*
* @return a <code>StorageProvider</code>.
*/
public StorageProvider getStorageProvider() {
return storageProvider;
}
/**
* Creates a {@link BinaryBody} that holds the content of the given input
* stream.
*
* @param is
* input stream to create a message body from.
* @return a binary body.
* @throws IOException
* if an I/O error occurs.
*/
public BinaryBody binaryBody(InputStream is) throws IOException {
if (is == null)
throw new IllegalArgumentException();
Storage storage = storageProvider.store(is);
return new StorageBinaryBody(new MultiReferenceStorage(storage));
}
/**
* Creates a {@link BinaryBody} that holds the content of the given
* {@link Storage}.
* <p>
* Note that the caller must not invoke {@link Storage#delete() delete()} on
* the given <code>Storage</code> object after it has been passed to this
* method. Instead the message body created by this method takes care of
* deleting the storage when it gets disposed of (see
* {@link Disposable#dispose()}).
*
* @param storage
* storage to create a message body from.
* @return a binary body.
* @throws IOException
* if an I/O error occurs.
*/
public BinaryBody binaryBody(Storage storage) throws IOException {
if (storage == null)
throw new IllegalArgumentException();
return new StorageBinaryBody(new MultiReferenceStorage(storage));
}
/**
* Creates a {@link TextBody} that holds the content of the given input
* stream.
* <p>
* &quot;us-ascii&quot; is used to decode the byte content of the
* <code>Storage</code> into a character stream when calling
* {@link TextBody#getReader() getReader()} on the returned object.
*
* @param is
* input stream to create a message body from.
* @return a text body.
* @throws IOException
* if an I/O error occurs.
*/
public TextBody textBody(InputStream is) throws IOException {
if (is == null)
throw new IllegalArgumentException();
Storage storage = storageProvider.store(is);
return new StorageTextBody(new MultiReferenceStorage(storage),
CharsetUtil.DEFAULT_CHARSET);
}
/**
* Creates a {@link TextBody} that holds the content of the given input
* stream.
* <p>
* The charset corresponding to the given MIME charset name is used to
* decode the byte content of the input stream into a character stream when
* calling {@link TextBody#getReader() getReader()} on the returned object.
* If the MIME charset has no corresponding Java charset or the Java charset
* cannot be used for decoding then &quot;us-ascii&quot; is used instead.
*
* @param is
* input stream to create a message body from.
* @param mimeCharset
* name of a MIME charset.
* @return a text body.
* @throws IOException
* if an I/O error occurs.
*/
public TextBody textBody(InputStream is, String mimeCharset)
throws IOException {
if (is == null)
throw new IllegalArgumentException();
if (mimeCharset == null)
throw new IllegalArgumentException();
Storage storage = storageProvider.store(is);
Charset charset = toJavaCharset(mimeCharset, false);
return new StorageTextBody(new MultiReferenceStorage(storage), charset);
}
/**
* Creates a {@link TextBody} that holds the content of the given
* {@link Storage}.
* <p>
* &quot;us-ascii&quot; is used to decode the byte content of the
* <code>Storage</code> into a character stream when calling
* {@link TextBody#getReader() getReader()} on the returned object.
* <p>
* Note that the caller must not invoke {@link Storage#delete() delete()} on
* the given <code>Storage</code> object after it has been passed to this
* method. Instead the message body created by this method takes care of
* deleting the storage when it gets disposed of (see
* {@link Disposable#dispose()}).
*
* @param storage
* storage to create a message body from.
* @return a text body.
* @throws IOException
* if an I/O error occurs.
*/
public TextBody textBody(Storage storage) throws IOException {
if (storage == null)
throw new IllegalArgumentException();
return new StorageTextBody(new MultiReferenceStorage(storage),
CharsetUtil.DEFAULT_CHARSET);
}
/**
* Creates a {@link TextBody} that holds the content of the given
* {@link Storage}.
* <p>
* The charset corresponding to the given MIME charset name is used to
* decode the byte content of the <code>Storage</code> into a character
* stream when calling {@link TextBody#getReader() getReader()} on the
* returned object. If the MIME charset has no corresponding Java charset or
* the Java charset cannot be used for decoding then &quot;us-ascii&quot; is
* used instead.
* <p>
* Note that the caller must not invoke {@link Storage#delete() delete()} on
* the given <code>Storage</code> object after it has been passed to this
* method. Instead the message body created by this method takes care of
* deleting the storage when it gets disposed of (see
* {@link Disposable#dispose()}).
*
* @param storage
* storage to create a message body from.
* @param mimeCharset
* name of a MIME charset.
* @return a text body.
* @throws IOException
* if an I/O error occurs.
*/
public TextBody textBody(Storage storage, String mimeCharset)
throws IOException {
if (storage == null)
throw new IllegalArgumentException();
if (mimeCharset == null)
throw new IllegalArgumentException();
Charset charset = toJavaCharset(mimeCharset, false);
return new StorageTextBody(new MultiReferenceStorage(storage), charset);
}
/**
* Creates a {@link TextBody} that holds the content of the given string.
* <p>
* &quot;us-ascii&quot; is used to encode the characters of the string into
* a byte stream when calling
* {@link SingleBody#writeTo(java.io.OutputStream) writeTo(OutputStream)} on
* the returned object.
*
* @param text
* text to create a message body from.
* @return a text body.
*/
public TextBody textBody(String text) {
if (text == null)
throw new IllegalArgumentException();
return new StringTextBody(text, CharsetUtil.DEFAULT_CHARSET);
}
/**
* Creates a {@link TextBody} that holds the content of the given string.
* <p>
* The charset corresponding to the given MIME charset name is used to
* encode the characters of the string into a byte stream when calling
* {@link SingleBody#writeTo(java.io.OutputStream) writeTo(OutputStream)} on
* the returned object. If the MIME charset has no corresponding Java
* charset or the Java charset cannot be used for encoding then
* &quot;us-ascii&quot; is used instead.
*
* @param text
* text to create a message body from.
* @param mimeCharset
* name of a MIME charset.
* @return a text body.
*/
public TextBody textBody(String text, String mimeCharset) {
if (text == null)
throw new IllegalArgumentException();
if (mimeCharset == null)
throw new IllegalArgumentException();
Charset charset = toJavaCharset(mimeCharset, true);
return new StringTextBody(text, charset);
}
private static Charset toJavaCharset(String mimeCharset, boolean forEncoding) {
String charset = CharsetUtil.toJavaCharset(mimeCharset);
if (charset == null) {
if (log.isWarnEnabled())
log.warn("MIME charset '" + mimeCharset + "' has no "
+ "corresponding Java charset. Using "
+ FALLBACK_CHARSET + " instead.");
return FALLBACK_CHARSET;
}
if (forEncoding && !CharsetUtil.isEncodingSupported(charset)) {
if (log.isWarnEnabled())
log.warn("MIME charset '" + mimeCharset
+ "' does not support encoding. Using "
+ FALLBACK_CHARSET + " instead.");
return FALLBACK_CHARSET;
}
if (!forEncoding && !CharsetUtil.isDecodingSupported(charset)) {
if (log.isWarnEnabled())
log.warn("MIME charset '" + mimeCharset
+ "' does not support decoding. Using "
+ FALLBACK_CHARSET + " instead.");
return FALLBACK_CHARSET;
}
return Charset.forName(charset);
}
}