You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ba...@apache.org on 2006/01/03 01:58:28 UTC
svn commit: r365502 - in /james/server/trunk/src:
java/org/apache/james/core/ java/org/apache/james/mailrepository/
test/org/apache/james/core/ test/org/apache/james/transport/
Author: bago
Date: Mon Jan 2 16:58:17 2006
New Revision: 365502
URL: http://svn.apache.org/viewcvs?rev=365502&view=rev
Log:
Implementation of a CopyOnWrite proxy over the MimeMessages. Now James always try to wrap a MimeMessage in this proxy counting references and cloning the message on write operations if shared. This should fix JAMES-421 without performance loss.
Also added a few tests of the new classes. The previous LinearProcessorTest now passes!
Added:
james/server/trunk/src/java/org/apache/james/core/MimeMessageCopyOnWriteProxy.java
james/server/trunk/src/java/org/apache/james/core/MimeMessageUtil.java
james/server/trunk/src/test/org/apache/james/core/MimeMessageCopyOnWriteProxyTest.java
Modified:
james/server/trunk/src/java/org/apache/james/core/MailImpl.java
james/server/trunk/src/java/org/apache/james/core/MimeMessageWrapper.java
james/server/trunk/src/java/org/apache/james/mailrepository/AvalonMailRepository.java
james/server/trunk/src/java/org/apache/james/mailrepository/JDBCMailRepository.java
james/server/trunk/src/test/org/apache/james/transport/LinearProcessorTest.java
Modified: james/server/trunk/src/java/org/apache/james/core/MailImpl.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/core/MailImpl.java?rev=365502&r1=365501&r2=365502&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/core/MailImpl.java (original)
+++ james/server/trunk/src/java/org/apache/james/core/MailImpl.java Mon Jan 2 16:58:17 2006
@@ -133,7 +133,7 @@
}
}
}
-
+
/**
* @param mail
* @param newName
@@ -177,8 +177,7 @@
throws MessagingException {
this(name, sender, recipients);
MimeMessageSource source = new MimeMessageInputStreamSource(name, messageIn);
- MimeMessageWrapper wrapper = new MimeMessageWrapper(source);
- this.setMessage(wrapper);
+ this.setMessage(new MimeMessageCopyOnWriteProxy(source));
}
/**
@@ -190,9 +189,9 @@
* @param recipients the collection of recipients of this MailImpl
* @param message the MimeMessage associated with this MailImpl
*/
- public MailImpl(String name, MailAddress sender, Collection recipients, MimeMessage message) {
+ public MailImpl(String name, MailAddress sender, Collection recipients, MimeMessage message) throws MessagingException {
this(name, sender, recipients);
- this.setMessage(message);
+ this.setMessage(new MimeMessageCopyOnWriteProxy(message));
}
/**
@@ -289,6 +288,7 @@
public MimeMessage getMessage() throws MessagingException {
return message;
}
+
/**
* Set the name of this MailImpl.
*
@@ -372,6 +372,10 @@
MimeMessageWrapper wrapper = (MimeMessageWrapper) message;
return wrapper.getMessageSize();
}
+ if (message instanceof MimeMessageCopyOnWriteProxy) {
+ MimeMessageCopyOnWriteProxy wrapper = (MimeMessageCopyOnWriteProxy) message;
+ return wrapper.getMessageSize();
+ }
//SK: Should probably eventually store this as a locally
// maintained value (so we don't have to load and reparse
// messages each time).
@@ -535,12 +539,8 @@
* @see org.apache.avalon.framework.activity.Disposable#dispose()
*/
public void dispose() {
- try {
- MimeMessage wrapper = getMessage();
- ContainerUtil.dispose(wrapper);
- } catch (MessagingException me) {
- // Ignored
- }
+ ContainerUtil.dispose(message);
+ message = null;
}
/**
Added: james/server/trunk/src/java/org/apache/james/core/MimeMessageCopyOnWriteProxy.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/core/MimeMessageCopyOnWriteProxy.java?rev=365502&view=auto
==============================================================================
--- james/server/trunk/src/java/org/apache/james/core/MimeMessageCopyOnWriteProxy.java (added)
+++ james/server/trunk/src/java/org/apache/james/core/MimeMessageCopyOnWriteProxy.java Mon Jan 2 16:58:17 2006
@@ -0,0 +1,818 @@
+/***********************************************************************
+ * Copyright (c) 2000-2005 The Apache Software Foundation. *
+ * All rights reserved. *
+ * ------------------------------------------------------------------- *
+ * Licensed 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.activity.Disposable;
+
+import javax.activation.DataHandler;
+import javax.mail.Address;
+import javax.mail.Flags;
+import javax.mail.Folder;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Multipart;
+import javax.mail.Session;
+import javax.mail.Flags.Flag;
+import javax.mail.internet.MimeMessage;
+import javax.mail.search.SearchTerm;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Date;
+import java.util.Enumeration;
+
+/**
+ * This object wraps a "possibly shared" MimeMessage tracking copies and
+ * automatically cloning it (if shared) when a write operation is invoked.
+ */
+public class MimeMessageCopyOnWriteProxy extends MimeMessage implements
+ Disposable {
+
+ /**
+ * Used internally to track the reference count
+ */
+ class ReferenceCounter {
+
+ /**
+ * reference counter
+ */
+ private int referenceCount = 1;
+
+ /**
+ * @param original
+ * MimeMessageWrapper
+ * @throws MessagingException
+ */
+ public ReferenceCounter() throws MessagingException {
+ this(0);
+ }
+
+ /**
+ * @param original
+ * MimeMessage to wrap
+ * @param writable
+ * if true we can alter the message itself, otherwise copy on
+ * write it.
+ * @throws MessagingException
+ */
+ public ReferenceCounter(int startCounter) throws MessagingException {
+ referenceCount = startCounter;
+ }
+
+ protected synchronized void incrementReferenceCount() {
+ referenceCount++;
+ }
+
+ protected synchronized void decrementReferenceCount() {
+ referenceCount--;
+ }
+
+ protected synchronized int getReferenceCount() {
+ return referenceCount;
+ }
+
+ }
+
+ ReferenceCounter refCount;
+
+ /**
+ * @param original
+ * MimeMessageWrapper
+ * @throws MessagingException
+ */
+ public MimeMessageCopyOnWriteProxy(MimeMessage original)
+ throws MessagingException {
+ this(original, false);
+ }
+
+ /**
+ * @param original
+ * MimeMessageSource
+ * @throws MessagingException
+ */
+ public MimeMessageCopyOnWriteProxy(MimeMessageSource original)
+ throws MessagingException {
+ this(new MimeMessageWrapper(original), true);
+ }
+
+ /**
+ * Private constructor providing an external reference counter.
+ *
+ * @param original
+ * @param refCount
+ * @throws MessagingException
+ */
+ private MimeMessageCopyOnWriteProxy(MimeMessage original,
+ boolean writeable)
+ throws MessagingException {
+ super(Session.getDefaultInstance(System.getProperties(), null));
+
+ this.wrapped = original;
+ if (wrapped instanceof MimeMessageCopyOnWriteProxy) {
+ refCount = ((MimeMessageCopyOnWriteProxy) wrapped).refCount;
+ wrapped = ((MimeMessageCopyOnWriteProxy) wrapped).getWrappedMessage();
+ } else {
+ refCount = new ReferenceCounter();
+ }
+
+ if (!writeable) {
+ refCount.incrementReferenceCount();
+ }
+ }
+
+ /**
+ * Check the number of references over the MimeMessage and clone it if
+ * needed.
+ *
+ * @throws MessagingException
+ * exception
+ */
+ protected void checkCopyOnWrite() throws MessagingException {
+ synchronized (refCount) {
+ if (refCount.getReferenceCount() > 1) {
+ refCount.decrementReferenceCount();
+
+ refCount = new ReferenceCounter(1);
+ if (wrapped instanceof MimeMessageWrapper) {
+ MimeMessageWrapper mmw = (MimeMessageWrapper) wrapped;
+ if (!mmw.isModified()) {
+ wrapped = new MimeMessageWrapper(mmw.source);
+ } else {
+ wrapped = new MimeMessage(wrapped);
+ }
+ } else {
+ // Not sure this will really clone the MimeMessage!
+ wrapped = new MimeMessage(wrapped);
+ }
+ }
+ }
+ }
+
+ /**
+ * The mime message in memory
+ */
+ protected MimeMessage wrapped = null;
+
+ /**
+ * Rewritten for optimization purposes
+ */
+ public void writeTo(OutputStream os) throws IOException, MessagingException {
+ wrapped.writeTo(os);
+ }
+
+ /**
+ * Rewritten for optimization purposes
+ */
+ public void writeTo(OutputStream os, String[] ignoreList)
+ throws IOException, MessagingException {
+ wrapped.writeTo(os, ignoreList);
+ }
+
+ /**
+ * Various reader methods
+ */
+
+ /**
+ * @see javax.mail.Message#getFrom()
+ */
+ public Address[] getFrom() throws MessagingException {
+ return wrapped.getFrom();
+ }
+
+ /**
+ * @see javax.mail.Message#getRecipients(javax.mail.Message.RecipientType)
+ */
+ public Address[] getRecipients(Message.RecipientType type)
+ throws MessagingException {
+ return wrapped.getRecipients(type);
+ }
+
+ /**
+ * @see javax.mail.Message#getAllRecipients()
+ */
+ public Address[] getAllRecipients() throws MessagingException {
+ return wrapped.getAllRecipients();
+ }
+
+ /**
+ * @see javax.mail.Message#getReplyTo()
+ */
+ public Address[] getReplyTo() throws MessagingException {
+ return wrapped.getReplyTo();
+ }
+
+ /**
+ * @see javax.mail.Message#getSubject()
+ */
+ public String getSubject() throws MessagingException {
+ return wrapped.getSubject();
+ }
+
+ /**
+ * @see javax.mail.Message#getSentDate()
+ */
+ public Date getSentDate() throws MessagingException {
+ return wrapped.getSentDate();
+ }
+
+ /**
+ * @see javax.mail.Message#getReceivedDate()
+ */
+ public Date getReceivedDate() throws MessagingException {
+ return wrapped.getReceivedDate();
+ }
+
+ /**
+ * @see javax.mail.Part#getSize()
+ */
+ public int getSize() throws MessagingException {
+ return wrapped.getSize();
+ }
+
+ /**
+ * @see javax.mail.Part#getLineCount()
+ */
+ public int getLineCount() throws MessagingException {
+ return wrapped.getLineCount();
+ }
+
+ /**
+ * @see javax.mail.Part#getContentType()
+ */
+ public String getContentType() throws MessagingException {
+ return wrapped.getContentType();
+ }
+
+ /**
+ * @see javax.mail.Part#isMimeType(java.lang.String)
+ */
+ public boolean isMimeType(String mimeType) throws MessagingException {
+ return wrapped.isMimeType(mimeType);
+ }
+
+ /**
+ * @see javax.mail.Part#getDisposition()
+ */
+ public String getDisposition() throws MessagingException {
+ return wrapped.getDisposition();
+ }
+
+ /**
+ * @see javax.mail.internet.MimePart#getEncoding()
+ */
+ public String getEncoding() throws MessagingException {
+ return wrapped.getEncoding();
+ }
+
+ /**
+ * @see javax.mail.internet.MimePart#getContentID()
+ */
+ public String getContentID() throws MessagingException {
+ return wrapped.getContentID();
+ }
+
+ /**
+ * @see javax.mail.internet.MimePart#getContentMD5()
+ */
+ public String getContentMD5() throws MessagingException {
+ return wrapped.getContentMD5();
+ }
+
+ /**
+ * @see javax.mail.Part#getDescription()
+ */
+ public String getDescription() throws MessagingException {
+ return wrapped.getDescription();
+ }
+
+ /**
+ * @see javax.mail.internet.MimePart#getContentLanguage()
+ */
+ public String[] getContentLanguage() throws MessagingException {
+ return wrapped.getContentLanguage();
+ }
+
+ /**
+ * @see javax.mail.internet.MimeMessage#getMessageID()
+ */
+ public String getMessageID() throws MessagingException {
+ return wrapped.getMessageID();
+ }
+
+ /**
+ * @see javax.mail.Part#getFileName()
+ */
+ public String getFileName() throws MessagingException {
+ return wrapped.getFileName();
+ }
+
+ /**
+ * @see javax.mail.Part#getInputStream()
+ */
+ public InputStream getInputStream() throws IOException, MessagingException {
+ return wrapped.getInputStream();
+ }
+
+ /**
+ * @see javax.mail.Part#getDataHandler()
+ */
+ public DataHandler getDataHandler() throws MessagingException {
+ return wrapped.getDataHandler();
+ }
+
+ /**
+ * @see javax.mail.Part#getContent()
+ */
+ public Object getContent() throws IOException, MessagingException {
+ return wrapped.getContent();
+ }
+
+ /**
+ * @see javax.mail.Part#getHeader(java.lang.String)
+ */
+ public String[] getHeader(String name) throws MessagingException {
+ return wrapped.getHeader(name);
+ }
+
+ /**
+ * @see javax.mail.internet.MimePart#getHeader(java.lang.String, java.lang.String)
+ */
+ public String getHeader(String name, String delimiter)
+ throws MessagingException {
+ return wrapped.getHeader(name, delimiter);
+ }
+
+ /**
+ * @see javax.mail.Part#getAllHeaders()
+ */
+ public Enumeration getAllHeaders() throws MessagingException {
+ return wrapped.getAllHeaders();
+ }
+
+ /**
+ * @see javax.mail.Part#getMatchingHeaders(java.lang.String[])
+ */
+ public Enumeration getMatchingHeaders(String[] names)
+ throws MessagingException {
+ return wrapped.getMatchingHeaders(names);
+ }
+
+ /**
+ * @see javax.mail.Part#getNonMatchingHeaders(java.lang.String[])
+ */
+ public Enumeration getNonMatchingHeaders(String[] names)
+ throws MessagingException {
+ return wrapped.getNonMatchingHeaders(names);
+ }
+
+ /**
+ * @see javax.mail.internet.MimePart#getAllHeaderLines()
+ */
+ public Enumeration getAllHeaderLines() throws MessagingException {
+ return wrapped.getAllHeaderLines();
+ }
+
+ /**
+ * @see javax.mail.internet.MimePart#getMatchingHeaderLines(java.lang.String[])
+ */
+ public Enumeration getMatchingHeaderLines(String[] names)
+ throws MessagingException {
+ return wrapped.getMatchingHeaderLines(names);
+ }
+
+ /**
+ * @see javax.mail.internet.MimePart#getNonMatchingHeaderLines(java.lang.String[])
+ */
+ public Enumeration getNonMatchingHeaderLines(String[] names)
+ throws MessagingException {
+ return wrapped.getNonMatchingHeaderLines(names);
+ }
+
+ /**
+ * @see javax.mail.Message#getFlags()
+ */
+ public Flags getFlags() throws MessagingException {
+ return wrapped.getFlags();
+ }
+
+ /**
+ * @see javax.mail.Message#isSet(javax.mail.Flags.Flag)
+ */
+ public boolean isSet(Flags.Flag flag) throws MessagingException {
+ return wrapped.isSet(flag);
+ }
+
+ /**
+ * @see javax.mail.internet.MimeMessage#getSender()
+ */
+ public Address getSender() throws MessagingException {
+ return wrapped.getSender();
+ }
+
+ /**
+ * @see javax.mail.Message#match(javax.mail.search.SearchTerm)
+ */
+ public boolean match(SearchTerm arg0) throws MessagingException {
+ return wrapped.match(arg0);
+ }
+
+ /**
+ * @see javax.mail.internet.MimeMessage#getRawInputStream()
+ */
+ public InputStream getRawInputStream() throws MessagingException {
+ return wrapped.getRawInputStream();
+ }
+
+ /**
+ * @see javax.mail.Message#getFolder()
+ */
+ public Folder getFolder() {
+ return wrapped.getFolder();
+ }
+
+ /**
+ * @see javax.mail.Message#getMessageNumber()
+ */
+ public int getMessageNumber() {
+ return wrapped.getMessageNumber();
+ }
+
+ /**
+ * @see javax.mail.Message#isExpunged()
+ */
+ public boolean isExpunged() {
+ return wrapped.isExpunged();
+ }
+
+ /**
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object arg0) {
+ return wrapped.equals(arg0);
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ return wrapped.hashCode();
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ return wrapped.toString();
+ }
+
+ /*
+ * Various writer methods
+ */
+
+ /**
+ * @see javax.mail.Message#setFrom(javax.mail.Address)
+ */
+ public void setFrom(Address address) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setFrom(address);
+ }
+
+ /**
+ * @see javax.mail.Message#setFrom()
+ */
+ public void setFrom() throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setFrom();
+ }
+
+ /**
+ * @see javax.mail.Message#addFrom(javax.mail.Address[])
+ */
+ public void addFrom(Address[] addresses) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.addFrom(addresses);
+ }
+
+ /**
+ * @see javax.mail.Message#setRecipients(javax.mail.Message.RecipientType, javax.mail.Address[])
+ */
+ public void setRecipients(Message.RecipientType type, Address[] addresses)
+ throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setRecipients(type, addresses);
+ }
+
+ /**
+ * @see javax.mail.Message#addRecipients(javax.mail.Message.RecipientType, javax.mail.Address[])
+ */
+ public void addRecipients(Message.RecipientType type, Address[] addresses)
+ throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.addRecipients(type, addresses);
+ }
+
+ /**
+ * @see javax.mail.Message#setReplyTo(javax.mail.Address[])
+ */
+ public void setReplyTo(Address[] addresses) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setReplyTo(addresses);
+ }
+
+ /**
+ * @see javax.mail.Message#setSubject(java.lang.String)
+ */
+ public void setSubject(String subject) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setSubject(subject);
+ }
+
+ /**
+ * @see javax.mail.internet.MimeMessage#setSubject(java.lang.String, java.lang.String)
+ */
+ public void setSubject(String subject, String charset)
+ throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setSubject(subject, charset);
+ }
+
+ /**
+ * @see javax.mail.Message#setSentDate(java.util.Date)
+ */
+ public void setSentDate(Date d) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setSentDate(d);
+ }
+
+ /**
+ * @see javax.mail.Part#setDisposition(java.lang.String)
+ */
+ public void setDisposition(String disposition) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setDisposition(disposition);
+ }
+
+ /**
+ * @see javax.mail.internet.MimeMessage#setContentID(java.lang.String)
+ */
+ public void setContentID(String cid) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setContentID(cid);
+ }
+
+ /**
+ * @see javax.mail.internet.MimePart#setContentMD5(java.lang.String)
+ */
+ public void setContentMD5(String md5) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setContentMD5(md5);
+ }
+
+ /**
+ * @see javax.mail.Part#setDescription(java.lang.String)
+ */
+ public void setDescription(String description) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setDescription(description);
+ }
+
+ /**
+ * @see javax.mail.internet.MimeMessage#setDescription(java.lang.String, java.lang.String)
+ */
+ public void setDescription(String description, String charset)
+ throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setDescription(description, charset);
+ }
+
+ /**
+ * @see javax.mail.internet.MimePart#setContentLanguage(java.lang.String[])
+ */
+ public void setContentLanguage(String[] languages)
+ throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setContentLanguage(languages);
+ }
+
+ /**
+ * @see javax.mail.Part#setFileName(java.lang.String)
+ */
+ public void setFileName(String filename) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setFileName(filename);
+ }
+
+ /**
+ * @see javax.mail.Part#setDataHandler(javax.activation.DataHandler)
+ */
+ public void setDataHandler(DataHandler dh) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setDataHandler(dh);
+ }
+
+ /**
+ * @see javax.mail.Part#setContent(java.lang.Object, java.lang.String)
+ */
+ public void setContent(Object o, String type) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setContent(o, type);
+ }
+
+ /**
+ * @see javax.mail.Part#setText(java.lang.String)
+ */
+ public void setText(String text) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setText(text);
+ }
+
+ /**
+ * @see javax.mail.internet.MimePart#setText(java.lang.String, java.lang.String)
+ */
+ public void setText(String text, String charset) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setText(text, charset);
+ }
+
+ /**
+ * @see javax.mail.Part#setContent(javax.mail.Multipart)
+ */
+ public void setContent(Multipart mp) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setContent(mp);
+ }
+
+ public Message reply(boolean replyToAll) throws MessagingException {
+ checkCopyOnWrite();
+ return wrapped.reply(replyToAll);
+ }
+
+ /**
+ * @see javax.mail.Part#setHeader(java.lang.String, java.lang.String)
+ */
+ public void setHeader(String name, String value) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setHeader(name, value);
+ }
+
+ /**
+ * @see javax.mail.Part#addHeader(java.lang.String, java.lang.String)
+ */
+ public void addHeader(String name, String value) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.addHeader(name, value);
+ }
+
+ /**
+ * @see javax.mail.Part#removeHeader(java.lang.String)
+ */
+ public void removeHeader(String name) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.removeHeader(name);
+ }
+
+ /**
+ * @see javax.mail.internet.MimePart#addHeaderLine(java.lang.String)
+ */
+ public void addHeaderLine(String line) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.addHeaderLine(line);
+ }
+
+ /**
+ * @see javax.mail.Message#setFlags(javax.mail.Flags, boolean)
+ */
+ public void setFlags(Flags flag, boolean set) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setFlags(flag, set);
+ }
+
+ /**
+ * @see javax.mail.Message#saveChanges()
+ */
+ public void saveChanges() throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.saveChanges();
+ }
+
+ /*
+ * Since JavaMail 1.2
+ */
+
+ /**
+ * @see javax.mail.internet.MimeMessage#addRecipients(javax.mail.Message.RecipientType, java.lang.String)
+ */
+ public void addRecipients(Message.RecipientType type, String addresses)
+ throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.addRecipients(type, addresses);
+ }
+
+ /**
+ * @see javax.mail.internet.MimeMessage#setRecipients(javax.mail.Message.RecipientType, java.lang.String)
+ */
+ public void setRecipients(Message.RecipientType type, String addresses)
+ throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setRecipients(type, addresses);
+ }
+
+ /**
+ * @see javax.mail.internet.MimeMessage#setSender(javax.mail.Address)
+ */
+ public void setSender(Address arg0) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setSender(arg0);
+ }
+
+ /**
+ * @see javax.mail.Message#addRecipient(javax.mail.Message.RecipientType, javax.mail.Address)
+ */
+ public void addRecipient(RecipientType arg0, Address arg1)
+ throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.addRecipient(arg0, arg1);
+ }
+
+ /**
+ * @see javax.mail.Message#setFlag(javax.mail.Flags.Flag, boolean)
+ */
+ public void setFlag(Flag arg0, boolean arg1) throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setFlag(arg0, arg1);
+ }
+
+ /**
+ * @see javax.mail.Message#setRecipient(javax.mail.Message.RecipientType, javax.mail.Address)
+ */
+ public void setRecipient(RecipientType arg0, Address arg1)
+ throws MessagingException {
+ checkCopyOnWrite();
+ wrapped.setRecipient(arg0, arg1);
+ }
+
+ /**
+ * @see org.apache.avalon.framework.activity.Disposable#dispose()
+ */
+ public synchronized void dispose() {
+ if (wrapped != null) {
+ refCount.decrementReferenceCount();
+ System.out.println(System.identityHashCode(this)+System.identityHashCode(wrapped)+" => "+refCount.getReferenceCount());
+ if (refCount.getReferenceCount()<=0) {
+ if (wrapped instanceof Disposable) {
+ ((Disposable) wrapped).dispose();
+ }
+ }
+ wrapped = null;
+ }
+ }
+
+ /**
+ * @see java.lang.Object#finalize()
+ */
+ protected void finalize() throws Throwable {
+ dispose();
+ super.finalize();
+ }
+
+ /**
+ * @return the message size
+ * @throws MessagingException
+ */
+ public long getMessageSize() throws MessagingException {
+ if (wrapped instanceof MimeMessageWrapper) {
+ return ((MimeMessageWrapper) wrapped).getMessageSize();
+ } else {
+ long size = wrapped.getSize();
+ Enumeration e = wrapped.getAllHeaderLines();
+ while (e.hasMoreElements()) {
+ size += ((String) e.nextElement()).length();
+ }
+ return size;
+ }
+ }
+
+ /**
+ * @return
+ */
+ public MimeMessage getWrappedMessage() {
+ return wrapped;
+ }
+
+}
Added: james/server/trunk/src/java/org/apache/james/core/MimeMessageUtil.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/core/MimeMessageUtil.java?rev=365502&view=auto
==============================================================================
--- james/server/trunk/src/java/org/apache/james/core/MimeMessageUtil.java (added)
+++ james/server/trunk/src/java/org/apache/james/core/MimeMessageUtil.java Mon Jan 2 16:58:17 2006
@@ -0,0 +1,179 @@
+/***********************************************************************
+ * Copyright (c) 2000-2005 The Apache Software Foundation. *
+ * All rights reserved. *
+ * ------------------------------------------------------------------- *
+ * Licensed 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.james.util.InternetPrintWriter;
+import org.apache.james.util.io.IOUtil;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeUtility;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+
+/**
+ * Utility class to provide optimized write methods for the various MimeMessage
+ * implementations.
+ */
+public class MimeMessageUtil {
+
+ /**
+ * Convenience method to take any MimeMessage and write the headers and body to two
+ * different output streams
+ */
+ public static void writeTo(MimeMessage message, OutputStream headerOs, OutputStream bodyOs) throws IOException, MessagingException {
+ writeTo(message, headerOs, bodyOs, null);
+ }
+
+ /**
+ * Convenience method to take any MimeMessage and write the headers and body to two
+ * different output streams, with an ignore list
+ */
+ public static void writeTo(MimeMessage message, OutputStream headerOs, OutputStream bodyOs, String[] ignoreList) throws IOException, MessagingException {
+ if (message instanceof MimeMessageCopyOnWriteProxy) {
+ MimeMessageCopyOnWriteProxy wr = (MimeMessageCopyOnWriteProxy) message;
+ MimeMessage m = wr.getWrappedMessage();
+ if (m instanceof MimeMessageWrapper) {
+ MimeMessageWrapper wrapper = (MimeMessageWrapper)m;
+ wrapper.writeTo(headerOs, bodyOs, ignoreList);
+ return;
+ }
+ } else if (message instanceof MimeMessageWrapper) {
+ MimeMessageWrapper wrapper = (MimeMessageWrapper)message;
+ wrapper.writeTo(headerOs, bodyOs, ignoreList);
+ return;
+ }
+ if(message.getMessageID() == null) {
+ message.saveChanges();
+ }
+
+ //Write the headers (minus ignored ones)
+ Enumeration headers = message.getNonMatchingHeaderLines(ignoreList);
+ PrintWriter hos = new InternetPrintWriter(new BufferedWriter(new OutputStreamWriter(headerOs), 512), true);
+ while (headers.hasMoreElements()) {
+ hos.println((String)headers.nextElement());
+ }
+ // Print header/data separator
+ hos.println();
+ hos.flush();
+
+ InputStream bis;
+ OutputStream bos;
+ // Write the body to the output stream
+
+ /*
+ try {
+ bis = message.getRawInputStream();
+ bos = bodyOs;
+ } catch(javax.mail.MessagingException me) {
+ // we may get a "No content" exception
+ // if that happens, try it the hard way
+
+ // Why, you ask? In JavaMail v1.3, when you initially
+ // create a message using MimeMessage APIs, there is no
+ // raw content available. getInputStream() works, but
+ // getRawInputStream() throws an exception.
+
+ bos = MimeUtility.encode(bodyOs, message.getEncoding());
+ bis = message.getInputStream();
+ }
+ */
+
+ try {
+ // Get the message as a stream. This will encode
+ // objects as necessary, and we have some input from
+ // decoding an re-encoding the stream. I'd prefer the
+ // raw stream, but see
+ bos = MimeUtility.encode(bodyOs, message.getEncoding());
+ bis = message.getInputStream();
+ } catch(javax.activation.UnsupportedDataTypeException udte) {
+ /* If we get an UnsupportedDataTypeException try using
+ * the raw input stream as a "best attempt" at rendering
+ * a message.
+ *
+ * WARNING: JavaMail v1.3 getRawInputStream() returns
+ * INVALID (unchanged) content for a changed message.
+ * getInputStream() works properly, but in this case
+ * has failed due to a missing DataHandler.
+ *
+ * MimeMessage.getRawInputStream() may throw a "no
+ * content" MessagingException. In JavaMail v1.3, when
+ * you initially create a message using MimeMessage
+ * APIs, there is no raw content available.
+ * getInputStream() works, but getRawInputStream()
+ * throws an exception. If we catch that exception,
+ * throw the UDTE. It should mean that someone has
+ * locally constructed a message part for which JavaMail
+ * doesn't have a DataHandler.
+ */
+
+ try {
+ bis = message.getRawInputStream();
+ bos = bodyOs;
+ } catch(javax.mail.MessagingException _) {
+ throw udte;
+ }
+ }
+ catch(javax.mail.MessagingException me) {
+ /* This could be another kind of MessagingException
+ * thrown by MimeMessage.getInputStream(), such as a
+ * javax.mail.internet.ParseException.
+ *
+ * The ParseException is precisely one of the reasons
+ * why the getRawInputStream() method exists, so that we
+ * can continue to stream the content, even if we cannot
+ * handle it. Again, if we get an exception, we throw
+ * the one that caused us to call getRawInputStream().
+ */
+ try {
+ bis = message.getRawInputStream();
+ bos = bodyOs;
+ } catch(javax.mail.MessagingException _) {
+ throw me;
+ }
+ }
+
+ try {
+ copyStream(bis, bos);
+ }
+ finally {
+ IOUtil.shutdownStream(bis);
+ }
+ }
+
+ /**
+ * Convenience method to copy streams
+ */
+ public static void copyStream(InputStream in, OutputStream out) throws IOException {
+ // TODO: This is really a bad way to do this sort of thing. A shared buffer to
+ // allow simultaneous read/writes would be a substantial improvement
+ byte[] block = new byte[1024];
+ int read = 0;
+ while ((read = in.read(block)) > -1) {
+ out.write(block, 0, read);
+ }
+ out.flush();
+ }
+
+
+}
Modified: james/server/trunk/src/java/org/apache/james/core/MimeMessageWrapper.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/core/MimeMessageWrapper.java?rev=365502&r1=365501&r2=365502&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/core/MimeMessageWrapper.java (original)
+++ james/server/trunk/src/java/org/apache/james/core/MimeMessageWrapper.java Mon Jan 2 16:58:17 2006
@@ -230,7 +230,7 @@
// and write to this outputstream
InputStream in = source.getInputStream();
try {
- copyStream(in, os);
+ MimeMessageUtil.copyStream(in, os);
} finally {
IOUtil.shutdownStream(in);
}
@@ -269,128 +269,12 @@
}
pos.println();
pos.flush();
- copyStream(in, bodyOs);
+ MimeMessageUtil.copyStream(in, bodyOs);
} finally {
IOUtil.shutdownStream(in);
}
} else {
- writeTo(message, headerOs, bodyOs, ignoreList);
- }
- }
-
- /**
- * Convenience method to take any MimeMessage and write the headers and body to two
- * different output streams
- */
- public static void writeTo(MimeMessage message, OutputStream headerOs, OutputStream bodyOs) throws IOException, MessagingException {
- writeTo(message, headerOs, bodyOs, null);
- }
-
- /**
- * Convenience method to take any MimeMessage and write the headers and body to two
- * different output streams, with an ignore list
- */
- public static void writeTo(MimeMessage message, OutputStream headerOs, OutputStream bodyOs, String[] ignoreList) throws IOException, MessagingException {
- if (message instanceof MimeMessageWrapper) {
- MimeMessageWrapper wrapper = (MimeMessageWrapper)message;
- wrapper.writeTo(headerOs, bodyOs, ignoreList);
- } else {
- if(message.getMessageID() == null) {
- message.saveChanges();
- }
-
- //Write the headers (minus ignored ones)
- Enumeration headers = message.getNonMatchingHeaderLines(ignoreList);
- PrintWriter hos = new InternetPrintWriter(new BufferedWriter(new OutputStreamWriter(headerOs), 512), true);
- while (headers.hasMoreElements()) {
- hos.println((String)headers.nextElement());
- }
- // Print header/data separator
- hos.println();
- hos.flush();
-
- InputStream bis = null;
- OutputStream bos = null;
- // Write the body to the output stream
-
- /*
- try {
- bis = message.getRawInputStream();
- bos = bodyOs;
- } catch(javax.mail.MessagingException me) {
- // we may get a "No content" exception
- // if that happens, try it the hard way
-
- // Why, you ask? In JavaMail v1.3, when you initially
- // create a message using MimeMessage APIs, there is no
- // raw content available. getInputStream() works, but
- // getRawInputStream() throws an exception.
-
- bos = MimeUtility.encode(bodyOs, message.getEncoding());
- bis = message.getInputStream();
- }
- */
-
- try {
- // Get the message as a stream. This will encode
- // objects as necessary, and we have some input from
- // decoding an re-encoding the stream. I'd prefer the
- // raw stream, but see
- bos = MimeUtility.encode(bodyOs, message.getEncoding());
- bis = message.getInputStream();
- } catch(javax.activation.UnsupportedDataTypeException udte) {
- /* If we get an UnsupportedDataTypeException try using
- * the raw input stream as a "best attempt" at rendering
- * a message.
- *
- * WARNING: JavaMail v1.3 getRawInputStream() returns
- * INVALID (unchanged) content for a changed message.
- * getInputStream() works properly, but in this case
- * has failed due to a missing DataHandler.
- *
- * MimeMessage.getRawInputStream() may throw a "no
- * content" MessagingException. In JavaMail v1.3, when
- * you initially create a message using MimeMessage
- * APIs, there is no raw content available.
- * getInputStream() works, but getRawInputStream()
- * throws an exception. If we catch that exception,
- * throw the UDTE. It should mean that someone has
- * locally constructed a message part for which JavaMail
- * doesn't have a DataHandler.
- */
-
- try {
- bis = message.getRawInputStream();
- bos = bodyOs;
- } catch(javax.mail.MessagingException _) {
- throw udte;
- }
- }
- catch(javax.mail.MessagingException me) {
- /* This could be another kind of MessagingException
- * thrown by MimeMessage.getInputStream(), such as a
- * javax.mail.internet.ParseException.
- *
- * The ParseException is precisely one of the reasons
- * why the getRawInputStream() method exists, so that we
- * can continue to stream the content, even if we cannot
- * handle it. Again, if we get an exception, we throw
- * the one that caused us to call getRawInputStream().
- */
- try {
- bis = message.getRawInputStream();
- bos = bodyOs;
- } catch(javax.mail.MessagingException _) {
- throw me;
- }
- }
-
- try {
- copyStream(bis, bos);
- }
- finally {
- IOUtil.shutdownStream(bis);
- }
+ MimeMessageUtil.writeTo(message, headerOs, bodyOs, ignoreList);
}
}
@@ -755,24 +639,10 @@
}
InputStream in = getContentStream();
try {
- copyStream(in, outs);
+ MimeMessageUtil.copyStream(in, outs);
} finally {
IOUtil.shutdownStream(in);
}
- }
-
- /**
- * Convenience method to copy streams
- */
- private static void copyStream(InputStream in, OutputStream out) throws IOException {
- // TODO: This is really a bad way to do this sort of thing. A shared buffer to
- // allow simultaneous read/writes would be a substantial improvement
- byte[] block = new byte[1024];
- int read = 0;
- while ((read = in.read(block)) > -1) {
- out.write(block, 0, read);
- }
- out.flush();
}
/*
Modified: james/server/trunk/src/java/org/apache/james/mailrepository/AvalonMailRepository.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/mailrepository/AvalonMailRepository.java?rev=365502&r1=365501&r2=365502&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/mailrepository/AvalonMailRepository.java (original)
+++ james/server/trunk/src/java/org/apache/james/mailrepository/AvalonMailRepository.java Mon Jan 2 16:58:17 2006
@@ -29,12 +29,14 @@
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
+import org.apache.james.core.MimeMessageCopyOnWriteProxy;
import org.apache.james.core.MimeMessageWrapper;
import org.apache.james.services.MailRepository;
import org.apache.james.util.Lock;
import org.apache.mailet.Mail;
import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
import java.io.OutputStream;
import java.util.ArrayList;
@@ -260,8 +262,15 @@
}
boolean saveStream = true;
- if (mc.getMessage() instanceof MimeMessageWrapper) {
- MimeMessageWrapper wrapper = (MimeMessageWrapper) mc.getMessage();
+ MimeMessage message = mc.getMessage();
+ // if the message is a Copy on Write proxy we check the wrapped message
+ // to optimize the behaviour in case of MimeMessageWrapper
+ if (message instanceof MimeMessageCopyOnWriteProxy) {
+ MimeMessageCopyOnWriteProxy messageCow = (MimeMessageCopyOnWriteProxy) message;
+ message = messageCow.getWrappedMessage();
+ }
+ if (message instanceof MimeMessageWrapper) {
+ MimeMessageWrapper wrapper = (MimeMessageWrapper) message;
if (DEEP_DEBUG) {
System.out.println("Retrieving from: " + wrapper.getSourceId());
StringBuffer debugBuffer =
@@ -352,7 +361,7 @@
return null;
}
MimeMessageAvalonSource source = new MimeMessageAvalonSource(sr, destination, key);
- mc.setMessage(new MimeMessageWrapper(source));
+ mc.setMessage(new MimeMessageCopyOnWriteProxy(source));
return mc;
} catch (Exception me) {
Modified: james/server/trunk/src/java/org/apache/james/mailrepository/JDBCMailRepository.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/mailrepository/JDBCMailRepository.java?rev=365502&r1=365501&r2=365502&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/mailrepository/JDBCMailRepository.java (original)
+++ james/server/trunk/src/java/org/apache/james/mailrepository/JDBCMailRepository.java Mon Jan 2 16:58:17 2006
@@ -35,6 +35,8 @@
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.james.context.AvalonContextUtilities;
import org.apache.james.core.MailImpl;
+import org.apache.james.core.MimeMessageCopyOnWriteProxy;
+import org.apache.james.core.MimeMessageUtil;
import org.apache.james.core.MimeMessageWrapper;
import org.apache.james.services.MailRepository;
import org.apache.james.util.JDBCUtil;
@@ -612,7 +614,7 @@
ObjectOutputStream oos = new ObjectOutputStream(baos);
try {
if (mc instanceof MailImpl) {
- oos.writeObject(((MailImpl)mc).getAttributesRaw());
+ oos.writeObject(((MailImpl)mc).getAttributesRaw());
} else {
HashMap temp = new HashMap();
for (Iterator i = mc.getAttributeNames(); i.hasNext(); ) {
@@ -649,6 +651,11 @@
// updating the database.
MimeMessage messageBody = mc.getMessage();
boolean saveBody = false;
+ // if the message is a CopyOnWrite proxy we check the modified wrapped object.
+ if (messageBody instanceof MimeMessageCopyOnWriteProxy) {
+ MimeMessageCopyOnWriteProxy messageCow = (MimeMessageCopyOnWriteProxy) messageBody;
+ messageBody = messageCow.getWrappedMessage();
+ }
if (messageBody instanceof MimeMessageWrapper) {
MimeMessageWrapper message = (MimeMessageWrapper)messageBody;
saveBody = message.isModified();
@@ -673,7 +680,7 @@
}
//Write the message to the headerOut and bodyOut. bodyOut goes straight to the file
- MimeMessageWrapper.writeTo(messageBody, headerOut, bodyOut);
+ MimeMessageUtil.writeTo(mc.getMessage(), headerOut, bodyOut);
//Store the headers in the database
ByteArrayInputStream headerInputStream =
@@ -732,7 +739,7 @@
}
//Write the message to the headerOut and bodyOut. bodyOut goes straight to the file
- MimeMessageWrapper.writeTo(messageBody, headerOut, bodyOut);
+ MimeMessageUtil.writeTo(messageBody, headerOut, bodyOut);
ByteArrayInputStream headerInputStream =
new ByteArrayInputStream(headerOut.toByteArray());
@@ -748,7 +755,7 @@
ObjectOutputStream oos = new ObjectOutputStream(baos);
try {
if (mc instanceof MailImpl) {
- oos.writeObject(((MailImpl)mc).getAttributesRaw());
+ oos.writeObject(((MailImpl)mc).getAttributesRaw());
} else {
HashMap temp = new HashMap();
for (Iterator i = mc.getAttributeNames(); i.hasNext(); ) {
@@ -925,7 +932,7 @@
mc.setLastUpdated(rsMessage.getTimestamp(7));
MimeMessageJDBCSource source = new MimeMessageJDBCSource(this, key, sr);
- MimeMessageWrapper message = new MimeMessageWrapper(source);
+ MimeMessageCopyOnWriteProxy message = new MimeMessageCopyOnWriteProxy(source);
mc.setMessage(message);
return mc;
} catch (SQLException sqle) {
Added: james/server/trunk/src/test/org/apache/james/core/MimeMessageCopyOnWriteProxyTest.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/test/org/apache/james/core/MimeMessageCopyOnWriteProxyTest.java?rev=365502&view=auto
==============================================================================
--- james/server/trunk/src/test/org/apache/james/core/MimeMessageCopyOnWriteProxyTest.java (added)
+++ james/server/trunk/src/test/org/apache/james/core/MimeMessageCopyOnWriteProxyTest.java Mon Jan 2 16:58:17 2006
@@ -0,0 +1,184 @@
+/***********************************************************************
+ * Copyright (c) 1999-2005 The Apache Software Foundation. *
+ * All rights reserved. *
+ * ------------------------------------------------------------------- *
+ * Licensed 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.mailet.Mail;
+import org.apache.mailet.MailAddress;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import junit.framework.TestCase;
+
+public class MimeMessageCopyOnWriteProxyTest extends TestCase {
+
+ MimeMessageWrapper mw = null;
+ String content = "Subject: foo\r\nContent-Transfer-Encoding2: plain";
+ String sep = "\r\n\r\n";
+ String body = "bar\r\n.\r\n";
+ MailImpl mail;
+
+ public MimeMessageCopyOnWriteProxyTest(String arg0) throws MessagingException {
+ super(arg0);
+
+ MimeMessageInputStreamSource mmis = null;
+ try {
+ mmis = new MimeMessageInputStreamSource("test", new ByteArrayInputStream((content+sep+body).getBytes()));
+ } catch (MessagingException e) {
+ }
+ mw = new MimeMessageWrapper(mmis);
+ }
+
+ public void testMessageCloning1() throws MessagingException, IOException {
+ ArrayList r = new ArrayList();
+ r.add(new MailAddress("recipient@test.com"));
+ mail = new MailImpl("test",new MailAddress("test@test.com"),r,mw);
+ 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!
+ 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()));
+ }
+
+
+ public void testMessageCloning2() throws MessagingException, IOException {
+ ArrayList r = new ArrayList();
+ r.add(new MailAddress("recipient@test.com"));
+ mail = new MailImpl("test",new MailAddress("test@test.com"),r,mw);
+ 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));
+ }
+
+ public void testMessageAvoidCloning() throws MessagingException, IOException {
+ ArrayList r = new ArrayList();
+ r.add(new MailAddress("recipient@test.com"));
+ mail = new MailImpl("test",new MailAddress("test@test.com"),r,mw);
+ // 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();
+ // 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));
+ }
+
+
+ public void testMessageDisposing() throws MessagingException, IOException {
+ ArrayList r = new ArrayList();
+ r.add(new MailAddress("recipient@test.com"));
+ mail = new MailImpl("test",new MailAddress("test@test.com"),r,mw);
+ // 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());
+ }
+
+ 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);
+
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+}
Modified: james/server/trunk/src/test/org/apache/james/transport/LinearProcessorTest.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/test/org/apache/james/transport/LinearProcessorTest.java?rev=365502&r1=365501&r2=365502&view=diff
==============================================================================
--- james/server/trunk/src/test/org/apache/james/transport/LinearProcessorTest.java (original)
+++ james/server/trunk/src/test/org/apache/james/transport/LinearProcessorTest.java Mon Jan 2 16:58:17 2006
@@ -106,6 +106,7 @@
System.err.println("Setting body to "+newText);
message.addHeader("x-Header", newText);
message.setText(newText);
+ message.setSubject(newText);
message.saveChanges();
} catch (javax.mail.MessagingException me) {
log (me.getMessage());
@@ -151,6 +152,8 @@
MimeMessage m1 = ((Mail) a.get(0)).getMessage();
MimeMessage m2 = ((Mail) a.get(1)).getMessage();
assertNotSame(m1,m2);
+ assertEquals(m1.getSubject(),"new text 1");
+ assertEquals(m2.getSubject(),"new text 2");
} catch (MessagingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org