| /**************************************************************** |
| * 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> |
| * "us-ascii" 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 "us-ascii" 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> |
| * "us-ascii" 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 "us-ascii" 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> |
| * "us-ascii" 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 |
| * "us-ascii" 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); |
| } |
| |
| } |