FileDocCategorySizeDatePackage
MimeMessageCopyOnWriteProxyTest.javaAPI DocApache James 2.3.112318Fri Jan 12 12:56:36 GMT 2007org.apache.james.core

MimeMessageCopyOnWriteProxyTest.java

/****************************************************************
 * 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.avalon.framework.container.ContainerUtil;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;

import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import javax.mail.util.SharedByteArrayInputStream;

import java.util.ArrayList;
import java.util.Properties;

public class MimeMessageCopyOnWriteProxyTest extends MimeMessageFromStreamTest {

    String content = "Subject: foo\r\nContent-Transfer-Encoding2: plain";
    String sep = "\r\n\r\n";
    String body = "bar\r\n.\r\n";

    protected MimeMessage getMessageFromSources(String sources) throws Exception {
        MimeMessageInputStreamSource mmis = null;
        try {
            mmis = new MimeMessageInputStreamSource("test", new SharedByteArrayInputStream(sources.getBytes()));
        } catch (MessagingException e) {
        }
        return new MimeMessageCopyOnWriteProxy(mmis);
//        return new MimeMessage(Session.getDefaultInstance(new Properties()),new ByteArrayInputStream(sources.getBytes()));
    }

    public void testMessageCloning1() throws Exception {
        ArrayList r = new ArrayList();
        r.add(new MailAddress("recipient@test.com"));
        MimeMessageCopyOnWriteProxy messageFromSources = (MimeMessageCopyOnWriteProxy) getMessageFromSources(content+sep+body);
        MailImpl mail = new MailImpl("test",new MailAddress("test@test.com"),r,messageFromSources);
        MailImpl m2 = (MailImpl) mail.duplicate();
        System.out.println("mail: "+getReferences(mail.getMessage())+" m2: "+getReferences(m2.getMessage()));
        assertNotSame(m2,mail);
        assertNotSame(m2.getMessage(),mail.getMessage());
        // test that the wrapped message is the same
        assertTrue(isSameMimeMessage(m2.getMessage(),mail.getMessage()));
        // test it is the same after read only operations!
        mail.getMessage().getSubject();
        assertTrue(isSameMimeMessage(m2.getMessage(),mail.getMessage()));
        mail.getMessage().setText("new body");
        mail.getMessage().saveChanges();
        // test it is different after a write operation!
        mail.getMessage().setSubject("new Subject");
        assertTrue(!isSameMimeMessage(m2.getMessage(),mail.getMessage()));
        ContainerUtil.dispose(mail);
        ContainerUtil.dispose(m2);
        ContainerUtil.dispose(messageFromSources);
    }

    
    public void testMessageCloning2() throws Exception {
        ArrayList r = new ArrayList();
        r.add(new MailAddress("recipient@test.com"));
        MimeMessageCopyOnWriteProxy messageFromSources = (MimeMessageCopyOnWriteProxy) getMessageFromSources(content+sep+body);
        MailImpl mail = new MailImpl("test",new MailAddress("test@test.com"),r,messageFromSources);
        MailImpl m2 = (MailImpl) mail.duplicate();
        System.out.println("mail: "+getReferences(mail.getMessage())+" m2: "+getReferences(m2.getMessage()));
        assertNotSame(m2,mail);
        assertNotSame(m2.getMessage(),mail.getMessage());
        // test that the wrapped message is the same
        assertTrue(isSameMimeMessage(m2.getMessage(),mail.getMessage()));
        // test it is the same after real only operations!
        m2.getMessage().getSubject();
        assertTrue(isSameMimeMessage(m2.getMessage(),mail.getMessage()));
        m2.getMessage().setText("new body");
        m2.getMessage().saveChanges();
        // test it is different after a write operation!
        m2.getMessage().setSubject("new Subject");
        assertTrue(!isSameMimeMessage(m2.getMessage(),mail.getMessage()));
        // check that the subjects are correct on both mails!
        assertEquals(m2.getMessage().getSubject(),"new Subject");
        assertEquals(mail.getMessage().getSubject(),"foo");
        // cloning again the messages
        Mail m2clone = m2.duplicate();
        assertTrue(isSameMimeMessage(m2clone.getMessage(),m2.getMessage()));
        MimeMessage mm = getWrappedMessage(m2.getMessage());
        assertNotSame(m2.getMessage(),m2clone.getMessage());
        // test that m2clone has a valid wrapped message
        MimeMessage mm3 = getWrappedMessage(m2clone.getMessage());
        assertNotNull(mm3);
        // dispose m2 and check that the clone has still a valid message and it is the same!
        ((MailImpl) m2).dispose();
        assertEquals(mm3,getWrappedMessage(m2clone.getMessage()));
        // change the message that should be not referenced by m2 that has
        // been disposed, so it should not clone it!
        m2clone.getMessage().setSubject("new Subject 2");
        m2clone.getMessage().setText("new Body 3");
        assertTrue(isSameMimeMessage(m2clone.getMessage(),mm));
        ContainerUtil.dispose(mail);
        ContainerUtil.dispose(messageFromSources);
    }
    
    /**
     * If I create a new MimeMessageCopyOnWriteProxy from another MimeMessageCopyOnWriteProxy,
     * I remove references to the first and I change the second, then it should not clone
     */
    public void testMessageAvoidCloning() throws Exception {
        ArrayList r = new ArrayList();
        r.add(new MailAddress("recipient@test.com"));
        MimeMessageCopyOnWriteProxy messageFromSources = (MimeMessageCopyOnWriteProxy) getMessageFromSources(content+sep+body);
        MailImpl mail = new MailImpl("test",new MailAddress("test@test.com"),r,messageFromSources);
        // cloning the message
        Mail mailClone = mail.duplicate();
        assertTrue(isSameMimeMessage(mailClone.getMessage(),mail.getMessage()));
        MimeMessage mm = getWrappedMessage(mail.getMessage());
        assertNotSame(mail.getMessage(),mailClone.getMessage());
        // dispose mail and check that the clone has still a valid message and it is the same!
        ((MailImpl) mail).dispose();
        ContainerUtil.dispose(messageFromSources);
        // need to add a gc and a wait, because the original mimemessage should be finalized before the test.
        System.gc();
        Thread.sleep(1000);
        // dumb test
        assertTrue(isSameMimeMessage(mailClone.getMessage(),mailClone.getMessage()));
        // change the message that should be not referenced by mail that has
        // been disposed, so it should not clone it!
        mailClone.getMessage().setSubject("new Subject 2");
        mailClone.getMessage().setText("new Body 3");
        assertTrue(isSameMimeMessage(mailClone.getMessage(),mm));
        ContainerUtil.dispose(mailClone);
        ContainerUtil.dispose(mm);
    }

    
    /**
     * If I create a new MimeMessageCopyOnWriteProxy from a MimeMessage and I change the new 
     * message, the original should be unaltered and the proxy should clone the message.
     */
    public void testMessageCloning3() throws Exception {
        ArrayList r = new ArrayList();
        r.add(new MailAddress("recipient@test.com"));
        MimeMessage m = new MimeMessage(Session.getDefaultInstance(new Properties(null)));
        m.setText("CIPS");
        MailImpl mail = new MailImpl("test",new MailAddress("test@test.com"),r,m);
        assertTrue(isSameMimeMessage(m,mail.getMessage()));
        // change the message that should be not referenced by mail that has
        // been disposed, so it should not clone it!
        System.gc();
        Thread.sleep(100);
        mail.getMessage().setSubject("new Subject 2");
        mail.getMessage().setText("new Body 3");
        System.gc();
        Thread.sleep(100);
        assertFalse(isSameMimeMessage(m,mail.getMessage()));
        ContainerUtil.dispose(mail);
        ContainerUtil.dispose(m);
    }

    
    public void testMessageDisposing() throws Exception {
        ArrayList r = new ArrayList();
        r.add(new MailAddress("recipient@test.com"));
        MimeMessageCopyOnWriteProxy messageFromSources = (MimeMessageCopyOnWriteProxy) getMessageFromSources(content+sep+body);
        MailImpl mail = new MailImpl("test",new MailAddress("test@test.com"),r,messageFromSources);
        // cloning the message
        MailImpl mailClone = (MailImpl) mail.duplicate();
        mail.dispose();

        assertNotNull(getWrappedMessage(mailClone.getMessage()));
        assertNull(mail.getMessage());

        mailClone.dispose();
        
        assertNull(mailClone.getMessage());
        assertNull(mail.getMessage());
        ContainerUtil.dispose(mail);
        ContainerUtil.dispose(messageFromSources);
    }
    
    public void testNPE1() throws MessagingException, InterruptedException {
        ArrayList recipients = new ArrayList();
        recipients.add(new MailAddress("recipient@test.com"));
        MimeMessageCopyOnWriteProxy mw = new MimeMessageCopyOnWriteProxy(
                new MimeMessageInputStreamSource(
                        "test",
                        new SharedByteArrayInputStream(
                                ("Return-path: return@test.com\r\n"+
                                 "Content-Transfer-Encoding: plain\r\n"+
                                 "Subject: test\r\n\r\n"+
                                 "Body Text\r\n").getBytes())));
        
        MimeMessageCopyOnWriteProxy mw2 = new MimeMessageCopyOnWriteProxy(mw);
        ContainerUtil.dispose(mw2);
        mw2 = null;
        System.gc();
        Thread.sleep(1000);
        // the NPE was inside this call
        mw.getMessageSize();
        ContainerUtil.dispose(mw);
    }

    
    /**
     * This test throw a NullPointerException when the original message was created by
     * a MimeMessageInputStreamSource.
     */
    public void testMessageCloningViaCoW3() throws Exception {
        MimeMessage mmorig = getSimpleMessage();
        
        MimeMessage mm = new MimeMessageCopyOnWriteProxy(mmorig);
        
        ContainerUtil.dispose(mmorig);
        mmorig = null;
        System.gc();
        Thread.sleep(200);

        try {
            mm.writeTo(System.out);
        } catch (Exception e) {
            e.printStackTrace();
            fail("Exception while writing the message to output");
        }
        
        ContainerUtil.dispose(mmorig);
    }

    private static String getReferences(MimeMessage m) {
        StringBuffer ref = new StringBuffer("/");
        while (m instanceof MimeMessageCopyOnWriteProxy) {
            ref.append(((MimeMessageCopyOnWriteProxy) m).refCount.getReferenceCount()+"/");
            m = ((MimeMessageCopyOnWriteProxy) m).getWrappedMessage();
        }
        if (m instanceof MimeMessageWrapper) {
            ref.append("W");
        } else if (m instanceof MimeMessage) {
            ref.append("M");
        } else {
            ref.append(m.getClass());
        }
        return ref.toString();
    }
    
    private static MimeMessage getWrappedMessage(MimeMessage m) {
        while (m instanceof MimeMessageCopyOnWriteProxy) {
          m = ((MimeMessageCopyOnWriteProxy) m).getWrappedMessage();
        }
        return m;
    }
    
    private static boolean isSameMimeMessage(MimeMessage first, MimeMessage second) {
        return getWrappedMessage(first) == getWrappedMessage(second);
        
    }

}