/****************************************************************
* 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.core;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.DeferredFileOutputStream;
import org.apache.james.lifecycle.api.Disposable;
import javax.mail.MessagingException;
import javax.mail.util.SharedByteArrayInputStream;
import javax.mail.util.SharedFileInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
/**
* Takes an input stream and creates a repeatable input stream source for a
* MimeMessageWrapper. It does this by completely reading the input stream and
* saving that to data to an {@link DeferredFileOutputStream} with its threshold set to 100kb
*/
public class MimeMessageInputStreamSource extends MimeMessageSource implements Disposable {
private final List<InputStream> streams = new ArrayList<InputStream>();
/**
* A temporary file used to hold the message stream
*/
private DeferredFileOutputStream out;
/**
* The full path of the temporary file
*/
private String sourceId;
/**
* 100kb threshold for the stream.
*/
private final static int THRESHOLD = 1024 * 100;
/**
* Temporary directory to use
*/
private final static File TMPDIR = new File(System.getProperty("java.io.tmpdir"));
/**
* Construct a new MimeMessageInputStreamSource from an
* <code>InputStream</code> that contains the bytes of a MimeMessage.
*
* @param key the prefix for the name of the temp file
* @param in the stream containing the MimeMessage
* @throws MessagingException if an error occurs while trying to store the stream
*/
public MimeMessageInputStreamSource(String key, InputStream in) throws MessagingException {
super();
// We want to immediately read this into a temporary file
// Create a temp file and channel the input stream into it
try {
out = new DeferredFileOutputStream(THRESHOLD, key, ".m64", TMPDIR);
IOUtils.copy(in, out);
sourceId = key;
} catch (IOException ioe) {
throw new MessagingException("Unable to retrieve the data: " + ioe.getMessage(), ioe);
} finally {
try {
if (out != null) {
out.close();
File file = out.getFile();
if (file != null) {
file.delete();
}
}
} catch (IOException ioe) {
// Ignored - logging unavailable to log this non-fatal error.
}
try {
if (in != null) {
in.close();
}
} catch (IOException ioe) {
// Ignored - logging unavailable to log this non-fatal error.
}
}
}
public MimeMessageInputStreamSource(String key) {
super();
out = new DeferredFileOutputStream(THRESHOLD, key, ".m64", TMPDIR);
sourceId = key;
}
/**
* Returns the unique identifier of this input stream source
*
* @return the unique identifier for this MimeMessageInputStreamSource
*/
public String getSourceId() {
return sourceId;
}
/**
* Get an input stream to retrieve the data stored in the temporary file
*
* @return a <code>BufferedInputStream</code> containing the data
*/
public synchronized InputStream getInputStream() throws IOException {
InputStream in;
if (out.isInMemory()) {
in = new SharedByteArrayInputStream(out.getData());
} else {
in = new SharedFileInputStream(out.getFile());
}
streams.add(in);
return in;
}
/**
* Get the size of the temp file
*
* @return the size of the temp file
* @throws IOException if an error is encoutered while computing the size of the
* message
*/
@Override
public long getMessageSize() throws IOException {
return out.getByteCount();
}
public OutputStream getWritableOutputStream() {
return out;
}
@Override
public void dispose() {
// explicit close all streams
for (InputStream stream : streams) {
IOUtils.closeQuietly(stream);
}
if (out != null) {
IOUtils.closeQuietly(out);
File file = out.getFile();
if (file != null) {
FileUtils.deleteQuietly(file);
file = null;
}
out = null;
}
}
}