JavaMail Вопрос или Ошибка? - PullRequest
0 голосов
/ 01 марта 2009

У меня вопрос по поводу Java Mail и как он работает с потоками. В Java Mail 1.4.1 есть конструктор MimeMessage, который принимает поток . Насколько я понимаю, я мог бы передать поток в этот конструктор, и он перевел бы меня в MimeMessage Я написал 2 теста, чтобы доказать это. Первый тест отправляет поток, который содержит только частичное сообщение MIME из нескольких частей. Второй тест отправляет в потоке, который содержит 2 полных составных сообщения MIME. Ни одна из них не работает так, как я ожидал. Первый не генерирует исключение, а второй как-то считывает весь поток в одно сообщение. Это ошибка в Java Mail или я использую неправильный вид потоков? Или мне не хватает чего-то большего?

Это немного долго, но вот код теста:

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.BodyPart;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;

import junit.framework.TestCase;


public class mimeTest extends TestCase {

    public void testPartialMulitpartMessage() throws MessagingException, IOException 
    {
        Properties props = new Properties();
        Session session = Session.getInstance(props, null);
        String testMsg1 = "test";
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

        // Step 1 - Create first MIME message
        MimeMessage mesg = new MimeMessage(session);
        Multipart mp = new MimeMultipart("mixed");
        //create a child part
        BodyPart bodyPart = new MimeBodyPart();
        bodyPart.setContent(testMsg1, "application/x-special");
        bodyPart.setHeader("Content-Length", String.valueOf(testMsg1.length()));
        DataSource ds = new ByteArrayDataSource(testMsg1, "application/x-special");
        bodyPart.setDataHandler(new DataHandler(ds));
        bodyPart.setHeader("Content-Transfer-Encoding", "8bit");
        // Add the child part to the multipart
        mp.addBodyPart(bodyPart);
        // Put the MultiPart into the Message
        mesg.setContent(mp);

        // Step 2 - write to a stream
        mesg.writeTo(byteArrayOutputStream);

        byte bytes[] = byteArrayOutputStream.toByteArray();
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes, 0, 10);
        BufferedInputStream bufferedInputStream = new BufferedInputStream(byteArrayInputStream);
        boolean thrown = false;
        try
        {
            //Why does this not throw a messageexception.
            MimeMessage mesg2 = new MimeMessage(session, bufferedInputStream);
        }
        catch(MessagingException me){
            thrown = true;
        }

        if(!thrown) {
            assertTrue("Expected exception not thrown.", false);
        }
    }

    public void testMulitpleMulitpartMessages() throws MessagingException, IOException {
        Properties props = new Properties();
        Session session = Session.getInstance(props, null);
        String testMsg1 = "test";
        String testMsg2 = "test1";
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

        // Step 1 - Create first MIME message
        MimeMessage mesg = new MimeMessage(session);
        Multipart mp = new MimeMultipart("mixed");
        //create a child part
        BodyPart bodyPart = new MimeBodyPart();
        bodyPart.setContent(testMsg1, "application/x-special");
        bodyPart.setHeader("Content-Length", String.valueOf(testMsg1.length()));
        DataSource ds = new ByteArrayDataSource(testMsg1, "application/x-special");
        bodyPart.setDataHandler(new DataHandler(ds));
        bodyPart.setHeader("Content-Transfer-Encoding", "8bit");
        // Add the child part to the multipart
        mp.addBodyPart(bodyPart);
        // Put the MultiPart into the Message
        mesg.setContent(mp);

        // Step 2 - write to a stream
        mesg.writeTo(byteArrayOutputStream);

        // Step 3 - Create second MIME message
        MimeMessage mesg2 = new MimeMessage(session);
        mp = new MimeMultipart("mixed");
        //create a child part
        bodyPart = new MimeBodyPart();
        bodyPart.setContent(testMsg2, "application/x-special");
        bodyPart.setHeader("Content-Length", String.valueOf(testMsg2.length()));
        ds = new ByteArrayDataSource(testMsg2, "application/x-special");
        bodyPart.setDataHandler(new DataHandler(ds));
        bodyPart.setHeader("Content-Transfer-Encoding", "8bit");
        // Add the child part to the multipart 
        mp.addBodyPart(bodyPart);
        // Put the MultiPart into the Message
        mesg2.setContent(mp);

        // Step 4 - write to the same stream
        mesg2.writeTo(byteArrayOutputStream);

        // Step 6 - read the two messages back
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        BufferedInputStream bufferedInputStream = new BufferedInputStream(byteArrayInputStream);
        List<MimeMessage> listMessages = new ArrayList<MimeMessage>();
        while (bufferedInputStream.available() > 0) {
            //http://java.sun.com/products/javamail/javadocs/javax/mail/internet/MimeMessage.html#MimeMessage(javax.mail.Session,%20java.io.InputStream)
            //The InputStream will be left positioned at the end of the data for the message.
            //WHY does this not work?  It reads the whole stream.
            mesg = new MimeMessage(session, bufferedInputStream);
            //output the message
            listMessages.add(mesg);
        }

        assertEquals(2, listMessages.size());

        assertTrue(listMessages.get(0).equals(mesg));
        assertTrue(listMessages.get(1).equals(mesg2));
    }
}

Ответы [ 2 ]

4 голосов
/ 01 марта 2009

JavaMail API - это свинарник, и его использование в сыром виде - неблагодарное занятие, в целом потому, что оно не ведет себя так, как вы ожидаете.

Я бы порекомендовал использовать вокруг него слой API Spring, это гораздо менее напряженно. Он не полностью скрывает JavaMail, он делает его более предсказуемым и удобным для тестирования.

1 голос
/ 18 июня 2009

JavaMail будет читать весь поток, возможно, буферизуя его. Я согласен с @skaffman, однако моя точка зрения такова, что он просто сильно оптимизирован без комментариев относительно того, почему, и это затрудняет использование.

Метод MimeMessage.parse (InputStream) - это то, с чем вы имеете дело. Он читает весь поток, не закрывая его, если только вы не используете SharedInputStream. Он оставит InputStream позиционированным в конце, как вы видите.

MimeMessage мало что делает для интерпретации данных в потоке, поэтому я думаю, что вам «не хватает чего-то большего», чтобы использовать ваши слова. Почему вы ожидаете, что он будет интерпретировать данные? Вы можете просто отправить составные сообщения, которые вы используете для создания своих потоков?

...