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
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
59 assertTrue(isSameMimeMessage(m2.getMessage(),mail.getMessage()));
60
61 mail.getMessage().getSubject();
62 assertTrue(isSameMimeMessage(m2.getMessage(),mail.getMessage()));
63 mail.getMessage().setText("new body");
64 mail.getMessage().saveChanges();
65
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
84 assertTrue(isSameMimeMessage(m2.getMessage(),mail.getMessage()));
85
86 m2.getMessage().getSubject();
87 assertTrue(isSameMimeMessage(m2.getMessage(),mail.getMessage()));
88 m2.getMessage().setText("new body");
89 m2.getMessage().saveChanges();
90
91 m2.getMessage().setSubject("new Subject");
92 assertTrue(!isSameMimeMessage(m2.getMessage(),mail.getMessage()));
93
94 assertEquals(m2.getMessage().getSubject(),"new Subject");
95 assertEquals(mail.getMessage().getSubject(),"foo");
96
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
102 MimeMessage mm3 = getWrappedMessage(m2clone.getMessage());
103 assertNotNull(mm3);
104
105 ((MailImpl) m2).dispose();
106 assertEquals(mm3,getWrappedMessage(m2clone.getMessage()));
107
108
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
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
131 ((MailImpl) mail).dispose();
132 ContainerUtil.dispose(messageFromSources);
133
134 System.gc();
135 Thread.sleep(1000);
136
137 assertTrue(isSameMimeMessage(mailClone.getMessage(),mailClone.getMessage()));
138
139
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
160
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
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
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 }