View Javadoc

1   /*****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  package org.apache.james.core;
20  
21  import org.apache.avalon.framework.container.ContainerUtil;
22  import org.apache.mailet.Mail;
23  import org.apache.mailet.MailAddress;
24  
25  import javax.mail.MessagingException;
26  import javax.mail.Session;
27  import javax.mail.internet.MimeMessage;
28  import javax.mail.util.SharedByteArrayInputStream;
29  
30  import java.util.ArrayList;
31  import java.util.Properties;
32  
33  public class MimeMessageCopyOnWriteProxyTest extends MimeMessageFromStreamTest {
34  
35      String content = "Subject: foo\r\nContent-Transfer-Encoding2: plain";
36      String sep = "\r\n\r\n";
37      String body = "bar\r\n.\r\n";
38  
39      protected MimeMessage getMessageFromSources(String sources) throws Exception {
40          MimeMessageInputStreamSource mmis = null;
41          try {
42              mmis = new MimeMessageInputStreamSource("test", new SharedByteArrayInputStream(sources.getBytes()));
43          } catch (MessagingException e) {
44          }
45          return new MimeMessageCopyOnWriteProxy(mmis);
46  //        return new MimeMessage(Session.getDefaultInstance(new Properties()),new ByteArrayInputStream(sources.getBytes()));
47      }
48  
49      public void testMessageCloning1() throws Exception {
50          ArrayList r = new ArrayList();
51          r.add(new MailAddress("recipient@test.com"));
52          MimeMessageCopyOnWriteProxy messageFromSources = (MimeMessageCopyOnWriteProxy) getMessageFromSources(content+sep+body);
53          MailImpl mail = new MailImpl("test",new MailAddress("test@test.com"),r,messageFromSources);
54          MailImpl m2 = (MailImpl) mail.duplicate();
55          System.out.println("mail: "+getReferences(mail.getMessage())+" m2: "+getReferences(m2.getMessage()));
56          assertNotSame(m2,mail);
57          assertNotSame(m2.getMessage(),mail.getMessage());
58          // test that the wrapped message is the same
59          assertTrue(isSameMimeMessage(m2.getMessage(),mail.getMessage()));
60          // test it is the same after read only operations!
61          mail.getMessage().getSubject();
62          assertTrue(isSameMimeMessage(m2.getMessage(),mail.getMessage()));
63          mail.getMessage().setText("new body");
64          mail.getMessage().saveChanges();
65          // test it is different after a write operation!
66          mail.getMessage().setSubject("new Subject");
67          assertTrue(!isSameMimeMessage(m2.getMessage(),mail.getMessage()));
68          ContainerUtil.dispose(mail);
69          ContainerUtil.dispose(m2);
70          ContainerUtil.dispose(messageFromSources);
71      }
72  
73      
74      public void testMessageCloning2() throws Exception {
75          ArrayList r = new ArrayList();
76          r.add(new MailAddress("recipient@test.com"));
77          MimeMessageCopyOnWriteProxy messageFromSources = (MimeMessageCopyOnWriteProxy) getMessageFromSources(content+sep+body);
78          MailImpl mail = new MailImpl("test",new MailAddress("test@test.com"),r,messageFromSources);
79          MailImpl m2 = (MailImpl) mail.duplicate();
80          System.out.println("mail: "+getReferences(mail.getMessage())+" m2: "+getReferences(m2.getMessage()));
81          assertNotSame(m2,mail);
82          assertNotSame(m2.getMessage(),mail.getMessage());
83          // test that the wrapped message is the same
84          assertTrue(isSameMimeMessage(m2.getMessage(),mail.getMessage()));
85          // test it is the same after real only operations!
86          m2.getMessage().getSubject();
87          assertTrue(isSameMimeMessage(m2.getMessage(),mail.getMessage()));
88          m2.getMessage().setText("new body");
89          m2.getMessage().saveChanges();
90          // test it is different after a write operation!
91          m2.getMessage().setSubject("new Subject");
92          assertTrue(!isSameMimeMessage(m2.getMessage(),mail.getMessage()));
93          // check that the subjects are correct on both mails!
94          assertEquals(m2.getMessage().getSubject(),"new Subject");
95          assertEquals(mail.getMessage().getSubject(),"foo");
96          // cloning again the messages
97          Mail m2clone = m2.duplicate();
98          assertTrue(isSameMimeMessage(m2clone.getMessage(),m2.getMessage()));
99          MimeMessage mm = getWrappedMessage(m2.getMessage());
100         assertNotSame(m2.getMessage(),m2clone.getMessage());
101         // test that m2clone has a valid wrapped message
102         MimeMessage mm3 = getWrappedMessage(m2clone.getMessage());
103         assertNotNull(mm3);
104         // dispose m2 and check that the clone has still a valid message and it is the same!
105         ((MailImpl) m2).dispose();
106         assertEquals(mm3,getWrappedMessage(m2clone.getMessage()));
107         // change the message that should be not referenced by m2 that has
108         // been disposed, so it should not clone it!
109         m2clone.getMessage().setSubject("new Subject 2");
110         m2clone.getMessage().setText("new Body 3");
111         assertTrue(isSameMimeMessage(m2clone.getMessage(),mm));
112         ContainerUtil.dispose(mail);
113         ContainerUtil.dispose(messageFromSources);
114     }
115     
116     /***
117      * If I create a new MimeMessageCopyOnWriteProxy from another MimeMessageCopyOnWriteProxy,
118      * I remove references to the first and I change the second, then it should not clone
119      */
120     public void testMessageAvoidCloning() throws Exception {
121         ArrayList r = new ArrayList();
122         r.add(new MailAddress("recipient@test.com"));
123         MimeMessageCopyOnWriteProxy messageFromSources = (MimeMessageCopyOnWriteProxy) getMessageFromSources(content+sep+body);
124         MailImpl mail = new MailImpl("test",new MailAddress("test@test.com"),r,messageFromSources);
125         // cloning the message
126         Mail mailClone = mail.duplicate();
127         assertTrue(isSameMimeMessage(mailClone.getMessage(),mail.getMessage()));
128         MimeMessage mm = getWrappedMessage(mail.getMessage());
129         assertNotSame(mail.getMessage(),mailClone.getMessage());
130         // dispose mail and check that the clone has still a valid message and it is the same!
131         ((MailImpl) mail).dispose();
132         ContainerUtil.dispose(messageFromSources);
133         // need to add a gc and a wait, because the original mimemessage should be finalized before the test.
134         System.gc();
135         Thread.sleep(1000);
136         // dumb test
137         assertTrue(isSameMimeMessage(mailClone.getMessage(),mailClone.getMessage()));
138         // change the message that should be not referenced by mail that has
139         // been disposed, so it should not clone it!
140         mailClone.getMessage().setSubject("new Subject 2");
141         mailClone.getMessage().setText("new Body 3");
142         assertTrue(isSameMimeMessage(mailClone.getMessage(),mm));
143         ContainerUtil.dispose(mailClone);
144         ContainerUtil.dispose(mm);
145     }
146 
147     
148     /***
149      * If I create a new MimeMessageCopyOnWriteProxy from a MimeMessage and I change the new 
150      * message, the original should be unaltered and the proxy should clone the message.
151      */
152     public void testMessageCloning3() throws Exception {
153         ArrayList r = new ArrayList();
154         r.add(new MailAddress("recipient@test.com"));
155         MimeMessage m = new MimeMessage(Session.getDefaultInstance(new Properties(null)));
156         m.setText("CIPS");
157         MailImpl mail = new MailImpl("test",new MailAddress("test@test.com"),r,m);
158         assertTrue(isSameMimeMessage(m,mail.getMessage()));
159         // change the message that should be not referenced by mail that has
160         // been disposed, so it should not clone it!
161         System.gc();
162         Thread.sleep(100);
163         mail.getMessage().setSubject("new Subject 2");
164         mail.getMessage().setText("new Body 3");
165         System.gc();
166         Thread.sleep(100);
167         assertFalse(isSameMimeMessage(m,mail.getMessage()));
168         ContainerUtil.dispose(mail);
169         ContainerUtil.dispose(m);
170     }
171 
172     
173     public void testMessageDisposing() throws Exception {
174         ArrayList r = new ArrayList();
175         r.add(new MailAddress("recipient@test.com"));
176         MimeMessageCopyOnWriteProxy messageFromSources = (MimeMessageCopyOnWriteProxy) getMessageFromSources(content+sep+body);
177         MailImpl mail = new MailImpl("test",new MailAddress("test@test.com"),r,messageFromSources);
178         // cloning the message
179         MailImpl mailClone = (MailImpl) mail.duplicate();
180         mail.dispose();
181 
182         assertNotNull(getWrappedMessage(mailClone.getMessage()));
183         assertNull(mail.getMessage());
184 
185         mailClone.dispose();
186         
187         assertNull(mailClone.getMessage());
188         assertNull(mail.getMessage());
189         ContainerUtil.dispose(mail);
190         ContainerUtil.dispose(messageFromSources);
191     }
192     
193     public void testNPE1() throws MessagingException, InterruptedException {
194         ArrayList recipients = new ArrayList();
195         recipients.add(new MailAddress("recipient@test.com"));
196         MimeMessageCopyOnWriteProxy mw = new MimeMessageCopyOnWriteProxy(
197                 new MimeMessageInputStreamSource(
198                         "test",
199                         new SharedByteArrayInputStream(
200                                 ("Return-path: return@test.com\r\n"+
201                                  "Content-Transfer-Encoding: plain\r\n"+
202                                  "Subject: test\r\n\r\n"+
203                                  "Body Text\r\n").getBytes())));
204         
205         MimeMessageCopyOnWriteProxy mw2 = new MimeMessageCopyOnWriteProxy(mw);
206         ContainerUtil.dispose(mw2);
207         mw2 = null;
208         System.gc();
209         Thread.sleep(1000);
210         // the NPE was inside this call
211         mw.getMessageSize();
212         ContainerUtil.dispose(mw);
213     }
214 
215     
216     /***
217      * This test throw a NullPointerException when the original message was created by
218      * a MimeMessageInputStreamSource.
219      */
220     public void testMessageCloningViaCoW3() throws Exception {
221         MimeMessage mmorig = getSimpleMessage();
222         
223         MimeMessage mm = new MimeMessageCopyOnWriteProxy(mmorig);
224         
225         ContainerUtil.dispose(mmorig);
226         mmorig = null;
227         System.gc();
228         Thread.sleep(200);
229 
230         try {
231             mm.writeTo(System.out);
232         } catch (Exception e) {
233             e.printStackTrace();
234             fail("Exception while writing the message to output");
235         }
236         
237         ContainerUtil.dispose(mmorig);
238     }
239 
240     private static String getReferences(MimeMessage m) {
241         StringBuffer ref = new StringBuffer("/");
242         while (m instanceof MimeMessageCopyOnWriteProxy) {
243             ref.append(((MimeMessageCopyOnWriteProxy) m).refCount.getReferenceCount()+"/");
244             m = ((MimeMessageCopyOnWriteProxy) m).getWrappedMessage();
245         }
246         if (m instanceof MimeMessageWrapper) {
247             ref.append("W");
248         } else if (m instanceof MimeMessage) {
249             ref.append("M");
250         } else {
251             ref.append(m.getClass());
252         }
253         return ref.toString();
254     }
255     
256     private static MimeMessage getWrappedMessage(MimeMessage m) {
257         while (m instanceof MimeMessageCopyOnWriteProxy) {
258           m = ((MimeMessageCopyOnWriteProxy) m).getWrappedMessage();
259         }
260         return m;
261     }
262     
263     private static boolean isSameMimeMessage(MimeMessage first, MimeMessage second) {
264         return getWrappedMessage(first) == getWrappedMessage(second);
265         
266     }
267 
268 }