All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.james.mailrepository.jdbc.MessageInputStream Maven / Gradle / Ivy

/****************************************************************
 * 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.mailrepository.jdbc;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.apache.james.repository.api.StreamRepository;
import org.apache.james.server.core.MimeMessageUtil;
import org.apache.james.server.core.MimeMessageWrapper;
import org.apache.mailet.Mail;

/**
 * This class provides an inputStream for a Mail object.
* If the Mail is larger than 4KB it uses Piped streams and a worker thread, * otherwise it simply creates a temporary byte buffer and does not create the * worker thread. * * Note: Javamail (or the Activation Framework) already uses a * worker thread when asked for an inputstream. * @Deprecated Will be dropped in 3.9.0. See https://www.mail-archive.com/[email protected]/msg72460.html */ @Deprecated final class MessageInputStream extends InputStream { /** * The size of the current message */ private long size = -1; /** * The wrapped stream (Piped or Binary) */ private InputStream wrapped; /** * If an excaption happens in the worker threads it's stored here */ private Exception caughtException; /** * Stream repository used for dbfiles (null otherwise) */ private final StreamRepository streamRep; /** * Main constructor. If srep is not null than we are using dbfiles and we * stream the body to file and only the header to db. * * @param mc * the Mail * @param srep * the StreamRepository the StreamRepository used for dbfiles. * @param sizeLimit * the sizeLimit which set the limit after which the streaming * will be disabled * @throws IOException * get thrown if an IO error detected * @throws MessagingException * get thrown if an error detected while reading information of * the mail */ public MessageInputStream(Mail mc, StreamRepository srep, int sizeLimit, final boolean update) throws IOException, MessagingException { super(); caughtException = null; streamRep = srep; size = mc.getMessageSize(); // we use the pipes only when streamRep is null and the message size is // greater than 4096 // Otherwise we should calculate the header size and not the message // size when streamRep is not null (JAMES-475) if (streamRep == null && size > sizeLimit) { PipedOutputStream headerOut = new PipedOutputStream(); new Thread() { private Mail mail; private PipedOutputStream out; @Override public void run() { try { writeStream(mail, out, update); } catch (IOException | MessagingException e) { caughtException = e; } } public Thread setParam(Mail mc, PipedOutputStream headerOut) { this.mail = mc; this.out = headerOut; return this; } }.setParam(mc, (PipedOutputStream) headerOut).start(); wrapped = new PipedInputStream(headerOut); } else { ByteArrayOutputStream headerOut = new ByteArrayOutputStream(); writeStream(mc, headerOut, update); wrapped = new ByteArrayInputStream(headerOut.toByteArray()); size = headerOut.size(); } } /** * Returns the size of the full message * * @return size the full message size */ public long getSize() { return size; } /** * Write the full mail to the stream This can be used by this object or by * the worker threads. * * @param mail * the Mail used as source * @param out * the OutputStream writting the mail to * @throws IOException * get thrown if an IO error detected * @throws MessagingException * get thrown if an error detected while reading information of * the mail */ private void writeStream(Mail mail, OutputStream out, boolean update) throws IOException, MessagingException { MimeMessage msg = mail.getMessage(); if (update && msg instanceof MimeMessageWrapper) { MimeMessageWrapper wrapper = (MimeMessageWrapper) msg; wrapper.loadMessage(); } OutputStream bodyOut = null; try { if (streamRep == null) { // If there is no filestore, use the byte array to store headers // and the body bodyOut = out; } else { // Store the body in the stream repository bodyOut = streamRep.put(mail.getName()); } if (msg instanceof MimeMessageWrapper) { ((MimeMessageWrapper) msg).writeTo(out, bodyOut, null, true); } else { // Write the message to the headerOut and bodyOut. bodyOut goes // straight to the file MimeMessageUtil.writeTo(mail.getMessage(), out, bodyOut); } out.flush(); bodyOut.flush(); } finally { closeOutputStreams(out, bodyOut); } } private void throwException() throws IOException { try { if (wrapped == null) { throw new IOException("wrapped stream does not exists anymore"); } else if (caughtException instanceof IOException) { throw (IOException) caughtException; } else { throw new IOException("Exception caugth in worker thread " + caughtException.getMessage()) { @Override public Throwable getCause() { return caughtException; } }; } } finally { caughtException = null; wrapped = null; } } /** * Closes output streams used to update message * * @param headerStream * the stream containing header information - potentially the * same as the body stream * @param bodyStream * the stream containing body information * @throws IOException */ private void closeOutputStreams(OutputStream headerStream, OutputStream bodyStream) throws IOException { try { // If the header stream is not the same as the body stream, // close the header stream here. if ((headerStream != null) && (headerStream != bodyStream)) { headerStream.close(); } } finally { if (bodyStream != null) { bodyStream.close(); } } } // wrapper methods @Override public int available() throws IOException { if (caughtException != null || wrapped == null) { throwException(); } return wrapped.available(); } @Override public void close() throws IOException { if (caughtException != null || wrapped == null) { throwException(); } wrapped.close(); wrapped = null; } @Override public synchronized void mark(int readLimit) { wrapped.mark(readLimit); } @Override public boolean markSupported() { return wrapped.markSupported(); } @Override public int read(byte[] b, int off, int len) throws IOException { if (caughtException != null || wrapped == null) { throwException(); } return wrapped.read(b, off, len); } @Override public int read(byte[] b) throws IOException { if (caughtException != null || wrapped == null) { throwException(); } return wrapped.read(b); } @Override public synchronized void reset() throws IOException { if (caughtException != null || wrapped == null) { throwException(); } wrapped.reset(); } @Override public long skip(long n) throws IOException { if (caughtException != null || wrapped == null) { throwException(); } return wrapped.skip(n); } @Override public int read() throws IOException { if (caughtException != null || wrapped == null) { throwException(); } return wrapped.read(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy