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/03/11 16:19:34 UTC

svn commit: r385090 - in /james/server/trunk/src: java/org/apache/james/core/ java/org/apache/james/mailrepository/filepair/ java/org/apache/james/transport/mailets/ test/org/apache/james/core/

Author: bago
Date: Sat Mar 11 07:19:33 2006
New Revision: 385090

URL: http://svn.apache.org/viewcvs?rev=385090&view=rev
Log:
Removed wrapping from MimeMessageWrapper: now it is a simple MimeMessage extension (thanks to latest javamail providing much more protected methods than earlier releases)
Updated a few file/stream handling objects to use SharedFileInputStream so that javamail will not load the full message in memory when cloning the message. (Related to JAMES-134)
Added a bunch of tests to check consistency of the various MimeMessage implementation/constructors.
(Sorry, no "streaming support" for db repositories in this commit: still working on it)

Added:
    james/server/trunk/src/test/org/apache/james/core/MimeMessageFromMimeMessageTest.java
    james/server/trunk/src/test/org/apache/james/core/MimeMessageFromSharedStreamTest.java
    james/server/trunk/src/test/org/apache/james/core/MimeMessageFromStreamTest.java
    james/server/trunk/src/test/org/apache/james/core/MimeMessageTest.java
    james/server/trunk/src/test/org/apache/james/core/MimeMessageUtilTest.java
Modified:
    james/server/trunk/src/java/org/apache/james/core/MimeMessageCopyOnWriteProxy.java
    james/server/trunk/src/java/org/apache/james/core/MimeMessageInputStreamSource.java
    james/server/trunk/src/java/org/apache/james/core/MimeMessageUtil.java
    james/server/trunk/src/java/org/apache/james/core/MimeMessageWrapper.java
    james/server/trunk/src/java/org/apache/james/mailrepository/filepair/AbstractFileRepository.java
    james/server/trunk/src/java/org/apache/james/mailrepository/filepair/File_Persistent_Stream_Repository.java
    james/server/trunk/src/java/org/apache/james/transport/mailets/AbstractRedirect.java
    james/server/trunk/src/java/org/apache/james/transport/mailets/AddHeader.java
    james/server/trunk/src/test/org/apache/james/core/MimeMessageCopyOnWriteProxyTest.java
    james/server/trunk/src/test/org/apache/james/core/MimeMessageWrapperTest.java

Modified: 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=385090&r1=385089&r2=385090&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/core/MimeMessageCopyOnWriteProxy.java (original)
+++ james/server/trunk/src/java/org/apache/james/core/MimeMessageCopyOnWriteProxy.java Sat Mar 11 07:19:33 2006
@@ -89,7 +89,7 @@
 
     }
 
-    ReferenceCounter refCount;
+    protected ReferenceCounter refCount;
 
     /**
      * @param original
@@ -756,15 +756,6 @@
     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);
     }
 
     /**

Modified: james/server/trunk/src/java/org/apache/james/core/MimeMessageInputStreamSource.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/core/MimeMessageInputStreamSource.java?rev=385090&r1=385089&r2=385090&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/core/MimeMessageInputStreamSource.java (original)
+++ james/server/trunk/src/java/org/apache/james/core/MimeMessageInputStreamSource.java Sat Mar 11 07:19:33 2006
@@ -19,10 +19,8 @@
 
 import javax.mail.MessagingException;
 
-import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -30,6 +28,8 @@
 
 import org.apache.avalon.framework.activity.Disposable;
 
+import com.sun.mail.util.SharedFileInputStream;
+
 /**
  * Takes an input stream and creates a repeatable input stream source
  * for a MimeMessageWrapper.  It does this by completely reading the
@@ -116,7 +116,7 @@
      * @return a <code>BufferedInputStream</code> containing the data
      */
     public synchronized InputStream getInputStream() throws IOException {
-        return new BufferedInputStream(new FileInputStream(file));
+        return new SharedFileInputStream(file.getAbsolutePath());
     }
 
     /**

Modified: 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=385090&r1=385089&r2=385090&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/core/MimeMessageUtil.java (original)
+++ james/server/trunk/src/java/org/apache/james/core/MimeMessageUtil.java Sat Mar 11 07:19:33 2006
@@ -25,6 +25,8 @@
 import javax.mail.internet.MimeUtility;
 
 import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -51,38 +53,29 @@
      * different output streams, with an ignore list
      */
     public static void writeTo(MimeMessage message, OutputStream headerOs, OutputStream bodyOs, String[] ignoreList) throws IOException, MessagingException {
+        MimeMessage testMessage = message;
         if (message instanceof MimeMessageCopyOnWriteProxy) {
             MimeMessageCopyOnWriteProxy wr = (MimeMessageCopyOnWriteProxy) message;
-            MimeMessage m = wr.getWrappedMessage();
-            if (m instanceof MimeMessageWrapper) {
-                MimeMessageWrapper wrapper = (MimeMessageWrapper)m;
+            testMessage = wr.getWrappedMessage();
+        }
+        if (testMessage instanceof MimeMessageWrapper) {
+            MimeMessageWrapper wrapper = (MimeMessageWrapper)testMessage;
+            if (!wrapper.isModified()) {
                 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();
+        writeHeadersTo(message, headerOs, ignoreList);
 
         // Write the body to the output stream
-        writeMessageTo(message, bodyOs);
+        writeMessageBodyTo(message, bodyOs);
     }
 
-    public static void writeMessageTo(MimeMessage message, OutputStream bodyOs) throws IOException, UnsupportedDataTypeException, MessagingException {
+    public static void writeMessageBodyTo(MimeMessage message, OutputStream bodyOs) throws IOException, UnsupportedDataTypeException, MessagingException {
         OutputStream bos;
         InputStream bis;
 
@@ -160,6 +153,39 @@
             out.write(block, 0, read);
         }
         out.flush();
+    }
+
+
+    /**
+     * Write the message headers to the given outputstream
+     * 
+     * @param message
+     * @param headerOs
+     * @param ignoreList
+     * @throws MessagingException
+     */
+    private static void writeHeadersTo(MimeMessage message, OutputStream headerOs, String[] ignoreList) throws MessagingException {
+        //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();
+    }
+    
+    /**
+     * @param message
+     * @param ignoreList
+     * @return
+     * @throws MessagingException
+     */
+    public static InputStream getHeadersInputStream(MimeMessage message, String[] ignoreList) throws MessagingException {
+        ByteArrayOutputStream bo = new ByteArrayOutputStream();
+        writeHeadersTo(message,bo,ignoreList);
+        return new ByteArrayInputStream(bo.toByteArray());
     }
 
 

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=385090&r1=385089&r2=385090&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 Sat Mar 11 07:19:33 2006
@@ -18,43 +18,29 @@
 package org.apache.james.core;
 
 import javax.activation.DataHandler;
-import javax.mail.Address;
-import javax.mail.Flags;
-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.InternetAddress;
 import javax.mail.internet.InternetHeaders;
 import javax.mail.internet.MimeMessage;
-import javax.mail.internet.MimeUtility;
-import javax.mail.internet.NewsAddress;
-import javax.mail.search.SearchTerm;
 
-import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.IOException;
 import java.io.LineNumberReader;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
-import java.io.SequenceInputStream;
-import java.io.StringReader;
-import java.io.UnsupportedEncodingException;
-import java.text.ParseException;
-import java.util.Date;
 import java.util.Enumeration;
 
+import org.apache.avalon.framework.activity.Disposable;
 import org.apache.james.util.InternetPrintWriter;
 import org.apache.james.util.io.IOUtil;
 import org.apache.mailet.RFC2822Headers;
-import org.apache.mailet.dates.RFC822DateFormat;
 
-import org.apache.avalon.framework.activity.Disposable;
+import com.sun.mail.util.SharedByteArrayInputStream;
 
 /**
  * This object wraps a MimeMessage, only loading the underlying MimeMessage
@@ -68,33 +54,90 @@
     /**
      * Can provide an input stream to the data
      */
-    MimeMessageSource source = null;
+    protected MimeMessageSource source = null;
+    
     /**
-     * The Internet headers in memory
+     * This is false until we parse the message 
      */
-    MailHeaders headers = null;
+    protected boolean messageParsed = false;
+    
     /**
-     * The mime message in memory
+     * This is false until we parse the message 
      */
-    MimeMessage message = null;
+    protected boolean headersModified = false;
+    
     /**
-     * Record whether a change was made to this message
+     * This is false until we parse the message 
      */
-    boolean modified = false;
+    protected boolean bodyModified = false;
+
+    
     /**
-     * How to format a mail date
+     * A constructor that instantiates a MimeMessageWrapper based on
+     * a MimeMessageSource
+     *
+     * @param source the MimeMessageSource
+     * @throws MessagingException 
      */
-    RFC822DateFormat mailDateFormat = new RFC822DateFormat();
+    public MimeMessageWrapper(Session session, MimeMessageSource source) throws MessagingException {
+        super(session);
+        this.headers = null;
+        this.modified = false;
+        this.headersModified = false;
+        this.bodyModified = false;
+        this.source = source;
+    }
 
     /**
      * A constructor that instantiates a MimeMessageWrapper based on
      * a MimeMessageSource
      *
      * @param source the MimeMessageSource
+     * @throws MessagingException 
+     * @throws MessagingException 
      */
-    public MimeMessageWrapper(MimeMessageSource source) {
-        super(Session.getDefaultInstance(System.getProperties(), null));
-        this.source = source;
+    public MimeMessageWrapper(MimeMessageSource source) throws MessagingException {
+        this(Session.getDefaultInstance(System.getProperties()),source);
+    }
+    
+    public MimeMessageWrapper(MimeMessage original) throws MessagingException {
+        super(Session.getDefaultInstance(System.getProperties()));
+        flags = original.getFlags();
+        
+        // if the original is an unmodified MimeMessageWrapped we clone the headers and
+        // take its source.
+        if (original instanceof MimeMessageWrapper && !((MimeMessageWrapper) original).bodyModified) {
+            source = ((MimeMessageWrapper) original).source;
+            // this probably speed up things
+            if (((MimeMessageWrapper) original).headers != null) {
+                ByteArrayOutputStream temp = new ByteArrayOutputStream();
+                ((MailHeaders) ((MimeMessageWrapper) original).headers).writeTo(temp);
+                headers = createInternetHeaders(new ByteArrayInputStream(temp.toByteArray()));
+                headersModified = ((MimeMessageWrapper) original).headersModified;
+            }
+        }
+        
+        if (source == null) {
+            ByteArrayOutputStream bos;
+            int size = original.getSize();
+            if (size > 0)
+                bos = new ByteArrayOutputStream(size);
+            else
+                bos = new ByteArrayOutputStream();
+            try {
+                original.writeTo(bos);
+                bos.close();
+                SharedByteArrayInputStream bis =
+                        new SharedByteArrayInputStream(bos.toByteArray());
+                parse(bis);
+                bis.close();
+                saved = true;
+            } catch (IOException ex) {
+                // should never happen, but just in case...
+                throw new MessagingException("IOException while copying message",
+                                ex);
+            }
+        }
     }
     
     /**
@@ -106,34 +149,13 @@
         return source.getSourceId();
     }
 
-    private synchronized MailHeaders loadHeaders(InputStream is) throws MessagingException {
-
-        /* InternetHeaders can be a bit awkward to work with due to
-         * its own internal handling of header order.  This hack may
-         * not always be necessary, but for now we are trying to
-         * ensure that there is a Return-Path header, even if just a
-         * placeholder, so that later, e.g., in LocalDelivery, when we
-         * call setHeader, it will remove any other Return-Path
-         * headers, and ensure that ours is on the top. addHeader
-         * handles header order, but not setHeader. This may change in
-         * future JavaMail.  But if there are other Return-Path header
-         * values, let's drop our placeholder. */
-
-        headers = new MailHeaders(new ByteArrayInputStream((RFC2822Headers.RETURN_PATH + ": placeholder").getBytes()));
-        headers.setHeader(RFC2822Headers.RETURN_PATH, null);
-        headers.load(is);
-        String[] returnPathHeaders = headers.getHeader(RFC2822Headers.RETURN_PATH);
-        if (returnPathHeaders.length > 1) headers.setHeader(RFC2822Headers.RETURN_PATH, returnPathHeaders[1]);
-        return headers;
-    }
-
     /**
      * Load the message headers from the internal source.
      *
      * @throws MessagingException if an error is encountered while
      *                            loading the headers
      */
-    private synchronized void loadHeaders() throws MessagingException {
+    protected synchronized void loadHeaders() throws MessagingException {
         if (headers != null) {
             //Another thread has already loaded these headers
             return;
@@ -141,7 +163,7 @@
         try {
             InputStream in = source.getInputStream();
             try {
-                headers = loadHeaders(in);
+                headers = createInternetHeaders(in);
             } finally {
                 IOUtil.shutdownStream(in);
             }
@@ -156,21 +178,18 @@
      * @throws MessagingException if an error is encountered while
      *                            loading the message
      */
-    private synchronized void loadMessage() throws MessagingException {
-        if (message != null) {
+    protected synchronized void loadMessage() throws MessagingException {
+        if (messageParsed) {
             //Another thread has already loaded this message
             return;
         }
         InputStream in = null;
         try {
             in = source.getInputStream();
-            headers = loadHeaders(in);
 
-            ByteArrayInputStream headersIn
-                    = new ByteArrayInputStream(headers.toByteArray());
-            in = new SequenceInputStream(headersIn, in);
-
-            message = new MimeMessage(session, in);
+            parse(in);
+            // TODO is it ok?
+            saved = true;
             
         } catch (IOException ioe) {
             throw new MessagingException("Unable to parse stream: " + ioe.getMessage(), ioe);
@@ -180,52 +199,19 @@
     }
 
     /**
-     * Internal implementation to get InternetAddress headers
-     */
-    private Address[] getAddressHeader(String name) throws MessagingException {
-        String addr = getHeader(name, ",");
-        if (addr == null) {
-            return null;
-        } else {
-            return InternetAddress.parse(addr);
-        }
-    }
-
-
-    /**
-     * Internal implementation to find headers
-     */
-    private String getHeaderName(Message.RecipientType recipienttype) throws MessagingException {
-        String s;
-        if (recipienttype == Message.RecipientType.TO) {
-            s = RFC2822Headers.TO;
-        } else if (recipienttype == Message.RecipientType.CC) {
-            s = RFC2822Headers.CC;
-        } else if (recipienttype == Message.RecipientType.BCC) {
-            s = RFC2822Headers.BCC;
-        } else if (recipienttype == RecipientType.NEWSGROUPS) {
-            s = "Newsgroups";
-        } else {
-            throw new MessagingException("Invalid Recipient Type");
-        }
-        return s;
-    }
-
-
-    /**
      * Get whether the message has been modified.
      *
      * @return whether the message has been modified
      */
     public boolean isModified() {
-        return modified;
+        return headersModified || bodyModified || modified;
     }
 
     /**
      * Rewritten for optimization purposes
      */
     public void writeTo(OutputStream os) throws IOException, MessagingException {
-        if (message == null || !isModified()) {
+        if (!isModified()) {
             // We do not want to instantiate the message... just read from source
             // and write to this outputstream
             InputStream in = source.getInputStream();
@@ -254,7 +240,7 @@
     }
 
     public void writeTo(OutputStream headerOs, OutputStream bodyOs, String[] ignoreList) throws IOException, MessagingException {
-        if (message == null || !isModified()) {
+        if (!isModified()) {
             //We do not want to instantiate the message... just read from source
             //  and write to this outputstream
 
@@ -274,140 +260,20 @@
                 IOUtil.shutdownStream(in);
             }
         } else {
-            MimeMessageUtil.writeTo(message, headerOs, bodyOs, ignoreList);
-        }
-    }
-
-    /**
-     * Various reader methods
-     */
-    public Address[] getFrom() throws MessagingException {
-        if (headers == null) {
-            loadHeaders();
-        }
-        Address from[] = getAddressHeader(RFC2822Headers.FROM);
-        if(from == null) {
-            from = getAddressHeader(RFC2822Headers.SENDER);
-        }
-        return from;
-    }
-
-    public Address[] getRecipients(Message.RecipientType type) throws MessagingException {
-        if (headers == null) {
-            loadHeaders();
-        }
-        if (type == RecipientType.NEWSGROUPS) {
-            String s = headers.getHeader("Newsgroups", ",");
-            if(s == null) {
-                return null;
-            } else {
-                return NewsAddress.parse(s);
-            }
-        } else {
-            return getAddressHeader(getHeaderName(type));
-        }
-    }
-
-    public Address[] getAllRecipients() throws MessagingException {
-        if (headers == null) {
-            loadHeaders();
-        }
-        Address toAddresses[] = getRecipients(RecipientType.TO);
-        Address ccAddresses[] = getRecipients(RecipientType.CC);
-        Address bccAddresses[] = getRecipients(RecipientType.BCC);
-        Address newsAddresses[] = getRecipients(RecipientType.NEWSGROUPS);
-        if(ccAddresses == null && bccAddresses == null && newsAddresses == null) {
-            return toAddresses;
-        }
-        int i = (toAddresses == null ? 0 : toAddresses.length)
-                + (ccAddresses == null ? 0 : ccAddresses.length)
-                + (bccAddresses == null ? 0 : bccAddresses.length)
-                + (newsAddresses == null ? 0 : newsAddresses.length);
-        Address allAddresses[] = new Address[i];
-        int j = 0;
-        if (toAddresses != null) {
-            System.arraycopy(toAddresses, 0, allAddresses, j, toAddresses.length);
-            j += toAddresses.length;
-        }
-        if(ccAddresses != null) {
-            System.arraycopy(ccAddresses, 0, allAddresses, j, ccAddresses.length);
-            j += ccAddresses.length;
-        }
-        if(bccAddresses != null) {
-            System.arraycopy(bccAddresses, 0, allAddresses, j, bccAddresses.length);
-            j += bccAddresses.length;
-        }
-        if(newsAddresses != null) {
-            System.arraycopy(newsAddresses, 0, allAddresses, j, newsAddresses.length);
-            j += newsAddresses.length;
-        }
-        return allAddresses;
-    }
-
-    public Address[] getReplyTo() throws MessagingException {
-        if (headers == null) {
-            loadHeaders();
-        }
-        Address replyTo[] = getAddressHeader(RFC2822Headers.REPLY_TO);
-        if(replyTo == null) {
-            replyTo = getFrom();
-        }
-        return replyTo;
-    }
-
-    public String getSubject() throws MessagingException {
-        if (headers == null) {
-            loadHeaders();
-        }
-        String subject = getHeader(RFC2822Headers.SUBJECT, null);
-        if (subject == null) {
-            return null;
-        }
-        try {
-            return MimeUtility.decodeText(unfold(subject));
-        } catch(UnsupportedEncodingException _ex) {
-            return subject;
-        }
-    }
-
-    public Date getSentDate() throws MessagingException {
-        if (headers == null) {
-            loadHeaders();
-        }
-        String header = getHeader(RFC2822Headers.DATE, null);
-        if(header != null) {
-            try {
-                return mailDateFormat.parse(header);
-            } catch(ParseException _ex) {
-                return null;
-            }
-        } else {
-            return null;
+            MimeMessageUtil.writeTo(this, headerOs, bodyOs, ignoreList);
         }
     }
 
     /**
-     * We do not attempt to define the received date, although in theory this is the last
-     * most date in the Received: headers.  For now we return null, which means we are
-     * not implementing it.
-     */
-    public Date getReceivedDate() throws MessagingException {
-        if (headers == null) {
-            loadHeaders();
-        }
-        return null;
-    }
-
-    /**
      * This is the MimeMessage implementation - this should return ONLY the
      * body, not the entire message (should not count headers).  Will have
      * to parse the message.
      */
     public int getSize() throws MessagingException {
-        if (message == null) {
+        if (!messageParsed) {
             loadMessage();
         }
-        return message.getSize();
+        return super.getSize();
     }
 
     /**
@@ -454,108 +320,13 @@
             throw new MessagingException("Error retrieving message size", ioe);
         }
     }
-
-    public String getContentType() throws MessagingException {
-        if (headers == null) {
-            loadHeaders();
-        }
-        String value = getHeader(RFC2822Headers.CONTENT_TYPE, null);
-        if (value == null) {
-            return "text/plain";
-        } else {
-            return value;
-        }
-    }
-
-    public boolean isMimeType(String mimeType) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        return message.isMimeType(mimeType);
-    }
-
-    public String getDisposition() throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        return message.getDisposition();
-    }
-
-    public String getEncoding() throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        return message.getEncoding();
-    }
-
-    public String getContentID() throws MessagingException {
-        if (headers == null) {
-            loadHeaders();
-        }
-        return getHeader("Content-Id", null);
-    }
-
-    public String getContentMD5() throws MessagingException {
-        if (headers == null) {
-            loadHeaders();
-        }
-        return getHeader("Content-MD5", null);
-    }
-
-    public String getDescription() throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        return message.getDescription();
-    }
-
-    public String[] getContentLanguage() throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        return message.getContentLanguage();
-    }
-
-    public String getMessageID() throws MessagingException {
-        if (headers == null) {
-            loadHeaders();
-        }
-        return getHeader(RFC2822Headers.MESSAGE_ID, null);
-    }
-
-    public String getFileName() throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        return message.getFileName();
-    }
-
-    public InputStream getInputStream() throws IOException, MessagingException {
-        if (message == null) {
-            //This is incorrect... supposed to return a decoded inputstream of
-            //  the message body
-            //return source.getInputStream();
-            loadMessage();
-            return message.getInputStream();
-        } else {
-            return message.getInputStream();
-        }
-    }
-
-    public DataHandler getDataHandler() throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        return message.getDataHandler();
-    }
-
-    public Object getContent() throws IOException, MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        return message.getContent();
-    }
-
+    
+    
+    /**
+     * We override all the "headers" access methods to be sure that we
+     * loaded the headers 
+     */
+    
     public String[] getHeader(String name) throws MessagingException {
         if (headers == null) {
             loadHeaders();
@@ -612,398 +383,115 @@
         return headers.getNonMatchingHeaderLines(names);
     }
 
-    public Flags getFlags() throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        return message.getFlags();
-    }
-
-    public boolean isSet(Flags.Flag flag) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        return message.isSet(flag);
-    }
-
-
-    /**
-     * Writes content only, ie not headers, to the specified OutputStream.
-     *
-     * @param outs the OutputStream to which the content is written
-     */
-    public void writeContentTo(OutputStream outs)
-            throws java.io.IOException, MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        InputStream in = getContentStream();
-        try {
-            MimeMessageUtil.copyStream(in, outs);
-        } finally {
-            IOUtil.shutdownStream(in);
-        }
-    }
-
-    /*
-     * Various writer methods
-     */
 
-    public void setFrom(Address address) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setFrom(address);
-    }
-
-    public void setFrom() throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setFrom();
-    }
-
-    public void addFrom(Address[] addresses) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.addFrom(addresses);
-    }
-
-    public void setRecipients(Message.RecipientType type, Address[] addresses) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setRecipients(type, addresses);
-    }
-
-    public void addRecipients(Message.RecipientType type, Address[] addresses) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.addRecipients(type, addresses);
-    }
-
-    public void setReplyTo(Address[] addresses) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setReplyTo(addresses);
-    }
-
-    public void setSubject(String subject) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        headers.setHeader(RFC2822Headers.SUBJECT, subject);
-        message.setSubject(subject);
-    }
-
-    public void setSubject(String subject, String charset) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        // is this correct?
-        try {
-            headers.setHeader(RFC2822Headers.SUBJECT, new String(subject.getBytes(charset)));
-        }
-        catch (java.io.UnsupportedEncodingException _) { /* TODO */ }
-        message.setSubject(subject, charset);
-    }
-
-    public void setSentDate(Date d) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        headers.setHeader(RFC2822Headers.DATE, mailDateFormat.format(d));
-        message.setSentDate(d);
-    }
-
-    public void setDisposition(String disposition) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setDisposition(disposition);
-    }
-
-    public void setContentID(String cid) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setContentID(cid);
-    }
-
-    public void setContentMD5(String md5) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setContentMD5(md5);
-    }
-
-    public void setDescription(String description) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setDescription(description);
-    }
-
-    public void setDescription(String description, String charset) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setDescription(description, charset);
-    }
-
-    public void setContentLanguage(String[] languages) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setContentLanguage(languages);
-    }
-
-    public void setFileName(String filename) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setFileName(filename);
-    }
-
-    public void setDataHandler(DataHandler dh) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setDataHandler(dh);
-    }
-
-    public void setContent(Object o, String type) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setContent(o, type);
-    }
-
-    public void setText(String text) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setText(text);
-    }
-
-    public void setText(String text, String charset) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setText(text, charset);
-    }
-
-    public void setContent(Multipart mp) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setContent(mp);
-    }
-
-    public Message reply(boolean replyToAll) throws MessagingException {
-        if (message == null) {
-            loadMessage();
+    private void checkModifyHeaders() throws MessagingException {
+        if (headers == null) {
+            loadHeaders();
         }
         modified = true;
-        return message.reply(replyToAll);
+        headersModified = true;
     }
 
     public void setHeader(String name, String value) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        headers.setHeader(name, value);
-        message.setHeader(name, value);
+        checkModifyHeaders();
+        super.setHeader(name, value);
     }
 
     public void addHeader(String name, String value) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        headers.addHeader(name, value);
-        message.addHeader(name, value);
+        checkModifyHeaders();
+        super.addHeader(name, value);
     }
 
     public void removeHeader(String name) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        headers.removeHeader(name);
-        message.removeHeader(name);
+        checkModifyHeaders();
+        super.removeHeader(name);
     }
 
     public void addHeaderLine(String line) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        headers.addHeaderLine(line);
-        message.addHeaderLine(line);
-    }
-
-    public void setFlags(Flags flag, boolean set) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setFlags(flag, set);
+        checkModifyHeaders();
+        super.addHeaderLine(line);
     }
 
-    public void saveChanges() throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.saveChanges();
-    }
 
-    /*
-     * Since JavaMail 1.2
+    /**
+     * The message is changed when working with headers and when altering the content.
+     * Every method that alter the content will fallback to this one.
+     * 
+     * @see javax.mail.Part#setDataHandler(javax.activation.DataHandler)
      */
-    public InputStream getRawInputStream() throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        return message.getRawInputStream();
-    }
-
-    public void addRecipients(Message.RecipientType type, String addresses) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
+    public synchronized void setDataHandler(DataHandler arg0) throws MessagingException {
         modified = true;
-        message.addRecipients(type, addresses);
+        bodyModified = true;
+        super.setDataHandler(arg0);
     }
 
-    public void setRecipients(Message.RecipientType type, String addresses) throws MessagingException {
-        if (message == null) {
-            loadMessage();
+    /**
+     * @see org.apache.avalon.framework.activity.Disposable#dispose()
+     */
+    public void dispose() {
+        if (source instanceof Disposable) {
+            ((Disposable)source).dispose();
         }
-        modified = true;
-        message.setRecipients(type, addresses);
     }
 
-    /*
-     * Since JavaMail 1.3
+    /**
+     * TODO fixme
+     * @see javax.mail.internet.MimeMessage#parse(java.io.InputStream)
      */
-    public Address getSender() throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        return message.getSender();
+    protected void parse(InputStream is) throws MessagingException {
+        // the super implementation calls
+        // headers = createInternetHeaders(is);
+        super.parse(is);
+        messageParsed = true;
     }
 
-    public void setSender(Address arg0) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setSender(arg0);
-    }
+    /**
+     * If we already parsed the headers then we simply return the updated ones.
+     * Otherwise we parse
+     * 
+     * @see javax.mail.internet.MimeMessage#createInternetHeaders(java.io.InputStream)
+     */
+    protected InternetHeaders createInternetHeaders(InputStream is) throws MessagingException {
 
-    public void addRecipient(RecipientType arg0, Address arg1) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.addRecipient(arg0,arg1);
-    }
+        // Keep this: skip the headers from the stream
+        // we could put that code in the else and simple write an "header" skipping
+        // reader for the others.
 
-    public boolean match(SearchTerm arg0) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        return message.match(arg0);
-    }
+        
+        /* InternetHeaders can be a bit awkward to work with due to
+         * its own internal handling of header order.  This hack may
+         * not always be necessary, but for now we are trying to
+         * ensure that there is a Return-Path header, even if just a
+         * placeholder, so that later, e.g., in LocalDelivery, when we
+         * call setHeader, it will remove any other Return-Path
+         * headers, and ensure that ours is on the top. addHeader
+         * handles header order, but not setHeader. This may change in
+         * future JavaMail.  But if there are other Return-Path header
+         * values, let's drop our placeholder. */
 
-    public void setFlag(Flag arg0, boolean arg1) throws MessagingException {
-        if (message == null) {
-            loadMessage();
+        MailHeaders newHeaders = new MailHeaders(new ByteArrayInputStream((RFC2822Headers.RETURN_PATH + ": placeholder").getBytes()));
+        newHeaders.setHeader(RFC2822Headers.RETURN_PATH, null);
+        newHeaders.load(is);
+        String[] returnPathHeaders = newHeaders.getHeader(RFC2822Headers.RETURN_PATH);
+        if (returnPathHeaders.length > 1) newHeaders.setHeader(RFC2822Headers.RETURN_PATH, returnPathHeaders[1]);
+        
+        if (headers != null) {
+            return headers;
+        } else {
+            return newHeaders;
         }
-        modified = true;
-        message.setFlag(arg0,arg1);
     }
 
-    public void setRecipient(RecipientType arg0, Address arg1) throws MessagingException {
-        if (message == null) {
-            loadMessage();
-        }
-        modified = true;
-        message.setRecipient(arg0,arg1);
-    }
-    
     /**
-     * @see org.apache.avalon.framework.activity.Disposable#dispose()
+     * @see javax.mail.internet.MimeMessage#getContentStream()
      */
-    public void dispose() {
-        if (source instanceof Disposable) {
-            ((Disposable)source).dispose();
+    protected InputStream getContentStream() throws MessagingException {
+        if (!messageParsed) {
+            loadMessage();
         }
+        return super.getContentStream();
     }
 
-    /**
-     * To be optimized.
-     * Starting from Javamail 1.3.3/1.4.0 we could use the unfold code 
-     * from the javamail.MimeMessage
-     * 
-     * @param s
-     * @return
-     */
-    static String unfold(String message) {
-        if (message == null) return null;
-
-        BufferedReader read = new BufferedReader(new StringReader(message));
-        StringBuffer result = new StringBuffer();
-        boolean unfolded = false;
-        String line;
-        boolean firstLine = true;
-        try {
-            while ((line = read.readLine())!= null && !line.equals("")) {
-              if (line.startsWith("\t") || line.startsWith(" ")) {
-                  result.append(" "+line.trim());
-                  unfolded = true;
-              } else {
-                  if (firstLine) {
-                    firstLine = false;
-                  } else {
-                    result.append("\r\n");
-                  }
-                  result.append(line);
-              }
-            }
-        } catch (IOException e) {
-            // This should never happen as we read from a String.
-          unfolded = false;
-        }
-        if (unfolded) {
-            return result.toString();
-        } else return message;
-    }
-
+    
+    
 }

Modified: james/server/trunk/src/java/org/apache/james/mailrepository/filepair/AbstractFileRepository.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/mailrepository/filepair/AbstractFileRepository.java?rev=385090&r1=385089&r2=385090&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/mailrepository/filepair/AbstractFileRepository.java (original)
+++ james/server/trunk/src/java/org/apache/james/mailrepository/filepair/AbstractFileRepository.java Sat Mar 11 07:19:33 2006
@@ -18,7 +18,6 @@
 package org.apache.james.mailrepository.filepair;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.FilenameFilter;
 import java.io.IOException;
@@ -40,6 +39,8 @@
 import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.avalon.framework.service.Serviceable;
 
+import com.sun.mail.util.SharedFileInputStream;
+
 /**
  * This an abstract class implementing functionality for creating a file-store.
  *
@@ -257,7 +258,7 @@
     protected InputStream getInputStream( final String key )
         throws IOException
     {
-        return new FileInputStream( getFile( key ) );
+        return new SharedFileInputStream( encode( key ) );
     }
 
     protected OutputStream getOutputStream( final String key )

Modified: james/server/trunk/src/java/org/apache/james/mailrepository/filepair/File_Persistent_Stream_Repository.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/mailrepository/filepair/File_Persistent_Stream_Repository.java?rev=385090&r1=385089&r2=385090&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/mailrepository/filepair/File_Persistent_Stream_Repository.java (original)
+++ james/server/trunk/src/java/org/apache/james/mailrepository/filepair/File_Persistent_Stream_Repository.java Sat Mar 11 07:19:33 2006
@@ -23,9 +23,9 @@
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
+
 import org.apache.avalon.cornerstone.services.store.StreamRepository;
 import org.apache.james.util.io.IOUtil;
-import org.apache.james.util.io.ResettableFileInputStream;
 
 /**
  * Implementation of a StreamRepository to a File.
@@ -52,8 +52,7 @@
     {
         try
         {
-            final ResettableFileInputStream stream =
-                new ResettableFileInputStream( getFile( key ) );
+            InputStream stream = getInputStream( key );
 
             final Object o = m_inputs.get( key );
             if( null == o )

Modified: james/server/trunk/src/java/org/apache/james/transport/mailets/AbstractRedirect.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/transport/mailets/AbstractRedirect.java?rev=385090&r1=385089&r2=385090&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/transport/mailets/AbstractRedirect.java (original)
+++ james/server/trunk/src/java/org/apache/james/transport/mailets/AbstractRedirect.java Sat Mar 11 07:19:33 2006
@@ -1177,7 +1177,7 @@
      */
     private String getMessageBody(MimeMessage message) throws Exception {
         java.io.ByteArrayOutputStream bodyOs = new java.io.ByteArrayOutputStream();
-        MimeMessageUtil.writeMessageTo(message,bodyOs);
+        MimeMessageUtil.writeMessageBodyTo(message,bodyOs);
         return bodyOs.toString();
     }
 

Modified: james/server/trunk/src/java/org/apache/james/transport/mailets/AddHeader.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/transport/mailets/AddHeader.java?rev=385090&r1=385089&r2=385090&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/transport/mailets/AddHeader.java (original)
+++ james/server/trunk/src/java/org/apache/james/transport/mailets/AddHeader.java Sat Mar 11 07:19:33 2006
@@ -19,7 +19,6 @@
 
 import javax.mail.internet.MimeMessage ;
 
-import org.apache.james.core.MailImpl ;
 import org.apache.mailet.GenericMailet ;
 import org.apache.mailet.Mail ;
 

Modified: 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=385090&r1=385089&r2=385090&view=diff
==============================================================================
--- james/server/trunk/src/test/org/apache/james/core/MimeMessageCopyOnWriteProxyTest.java (original)
+++ james/server/trunk/src/test/org/apache/james/core/MimeMessageCopyOnWriteProxyTest.java Sat Mar 11 07:19:33 2006
@@ -19,16 +19,15 @@
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailAddress;
 
+import com.sun.mail.util.SharedByteArrayInputStream;
+
 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 {
+public class MimeMessageCopyOnWriteProxyTest extends MimeMessageFromStreamTest {
 
     MimeMessageWrapper mw = null;
     String content = "Subject: foo\r\nContent-Transfer-Encoding2: plain";
@@ -36,16 +35,20 @@
     String body = "bar\r\n.\r\n";
     MailImpl mail;
 
-    public MimeMessageCopyOnWriteProxyTest(String arg0) throws MessagingException {
-        super(arg0);
-
+    protected MimeMessage getMessageFromSources(String sources) throws Exception {
         MimeMessageInputStreamSource mmis = null;
         try {
-            mmis = new MimeMessageInputStreamSource("test", new ByteArrayInputStream((content+sep+body).getBytes()));
+            mmis = new MimeMessageInputStreamSource("test", new SharedByteArrayInputStream(sources.getBytes()));
         } catch (MessagingException e) {
         }
-        mw = new MimeMessageWrapper(mmis);
+        return new MimeMessageWrapper(mmis);
+//        return new MimeMessage(Session.getDefaultInstance(new Properties()),new ByteArrayInputStream(sources.getBytes()));
+    }
+
+    protected void setUp() throws Exception {
+        mw = (MimeMessageWrapper) getMessageFromSources(content+sep+body);
     }
+
     
     public void testMessageCloning1() throws MessagingException, IOException {
         ArrayList r = new ArrayList();
@@ -171,14 +174,6 @@
     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();
     }
 
 }

Added: james/server/trunk/src/test/org/apache/james/core/MimeMessageFromMimeMessageTest.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/test/org/apache/james/core/MimeMessageFromMimeMessageTest.java?rev=385090&view=auto
==============================================================================
--- james/server/trunk/src/test/org/apache/james/core/MimeMessageFromMimeMessageTest.java (added)
+++ james/server/trunk/src/test/org/apache/james/core/MimeMessageFromMimeMessageTest.java Sat Mar 11 07:19:33 2006
@@ -0,0 +1,27 @@
+/***********************************************************************
+ * Copyright (c) 1999-2006 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 javax.mail.internet.MimeMessage;
+
+public class MimeMessageFromMimeMessageTest extends MimeMessageFromStreamTest {
+    
+    protected MimeMessage getMessageFromSources(String sources) throws Exception {
+        return new MimeMessage(super.getMessageFromSources(sources));
+    }
+
+}

Added: james/server/trunk/src/test/org/apache/james/core/MimeMessageFromSharedStreamTest.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/test/org/apache/james/core/MimeMessageFromSharedStreamTest.java?rev=385090&view=auto
==============================================================================
--- james/server/trunk/src/test/org/apache/james/core/MimeMessageFromSharedStreamTest.java (added)
+++ james/server/trunk/src/test/org/apache/james/core/MimeMessageFromSharedStreamTest.java Sat Mar 11 07:19:33 2006
@@ -0,0 +1,31 @@
+/***********************************************************************
+ * Copyright (c) 1999-2006 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 javax.mail.Session;
+import javax.mail.internet.MimeMessage;
+
+import java.io.ByteArrayInputStream;
+import java.util.Properties;
+
+public class MimeMessageFromSharedStreamTest extends MimeMessageFromStreamTest {
+    
+    protected MimeMessage getMessageFromSources(String sources) throws Exception {
+        return new MimeMessage(Session.getDefaultInstance(new Properties()),new ByteArrayInputStream(sources.getBytes()));
+    }
+
+}

Added: james/server/trunk/src/test/org/apache/james/core/MimeMessageFromStreamTest.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/test/org/apache/james/core/MimeMessageFromStreamTest.java?rev=385090&view=auto
==============================================================================
--- james/server/trunk/src/test/org/apache/james/core/MimeMessageFromStreamTest.java (added)
+++ james/server/trunk/src/test/org/apache/james/core/MimeMessageFromStreamTest.java Sat Mar 11 07:19:33 2006
@@ -0,0 +1,44 @@
+/***********************************************************************
+ * Copyright (c) 1999-2006 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 javax.mail.Session;
+import javax.mail.internet.MimeMessage;
+
+import java.io.ByteArrayInputStream;
+import java.util.Properties;
+
+public class MimeMessageFromStreamTest extends MimeMessageTest {
+    
+    protected MimeMessage getMessageFromSources(String sources) throws Exception {
+        return new MimeMessage(Session.getDefaultInstance(new Properties()),new ByteArrayInputStream(sources.getBytes()));
+    }
+
+    protected MimeMessage getMultipartMessage() throws Exception {
+        return getMessageFromSources(getMultipartMessageSource());
+    }
+
+    protected MimeMessage getSimpleMessage() throws Exception {
+        return getMessageFromSources(getSimpleMessageCleanedSource());
+    }
+
+    protected MimeMessage getMissingEncodingAddHeaderMessage() throws Exception {
+        return getMessageFromSources(getMissingEncodingAddHeaderSource());
+    }
+
+
+}

Added: james/server/trunk/src/test/org/apache/james/core/MimeMessageTest.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/test/org/apache/james/core/MimeMessageTest.java?rev=385090&view=auto
==============================================================================
--- james/server/trunk/src/test/org/apache/james/core/MimeMessageTest.java (added)
+++ james/server/trunk/src/test/org/apache/james/core/MimeMessageTest.java Sat Mar 11 07:19:33 2006
@@ -0,0 +1,262 @@
+/***********************************************************************
+ * Copyright (c) 1999-2006 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.RFC2822Headers;
+
+import javax.mail.BodyPart;
+import javax.mail.Session;
+import javax.mail.internet.InternetHeaders;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+/**
+ * Test the subject folding issue.
+ */
+public class MimeMessageTest extends TestCase {
+
+    protected MimeMessage getSimpleMessage() throws Exception {
+        MimeMessage mmCreated = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        mmCreated.setSubject("test");
+        mmCreated.setText("test body");
+        mmCreated.saveChanges();
+        return mmCreated;
+    }
+    
+    protected String getSimpleMessageCleanedSource() throws Exception {
+        return "Subject: test\r\n"
+            +"MIME-Version: 1.0\r\n"
+            +"Content-Type: text/plain; charset=us-ascii\r\n"
+            +"Content-Transfer-Encoding: 7bit\r\n"
+            +"\r\n"
+            +"test body";
+    }
+    
+    /*
+     * Class under test for String getSubject()
+     */
+    public void testSimpleMessage() throws Exception {
+        assertEquals(getSimpleMessageCleanedSource(), getCleanedMessageSource(getSimpleMessage()));
+    }
+
+    
+    protected MimeMessage getMultipartMessage() throws Exception {
+        MimeMessage mmCreated = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        mmCreated.setSubject("test");
+        MimeMultipart mm = new MimeMultipart("alternative");
+        mm.addBodyPart(new MimeBodyPart(new InternetHeaders(new ByteArrayInputStream("X-header: test1\r\n".getBytes())),"first part òàù".getBytes()));
+        mm.addBodyPart(new MimeBodyPart(new InternetHeaders(new ByteArrayInputStream("X-header: test2\r\n".getBytes())),"second part èè".getBytes()));
+        mmCreated.setContent(mm);
+        mmCreated.saveChanges();
+        return mmCreated;
+    }
+    
+    protected String getMultipartMessageSource() {
+        return "Subject: test\r\n"
+            +"MIME-Version: 1.0\r\n"
+            +"Content-Type: multipart/alternative; \r\n" 
+            +"\tboundary=\"----=_Part_0_XXXXXXXXXXX.XXXXXXXXXXX\"\r\n"
+            +"\r\n"
+            +"------=_Part_0_XXXXXXXXXXX.XXXXXXXXXXX\r\n"
+            +"X-header: test1\r\n"
+            +"Content-Transfer-Encoding: quoted-printable\r\n"
+            +"Content-Type: text/plain; charset=Cp1252\r\n"
+            +"\r\n"
+            +"first part òàù\r\n"
+            +"------=_Part_0_XXXXXXXXXXX.XXXXXXXXXXX\r\n"
+            +"X-header: test2\r\n"
+            +"Content-Transfer-Encoding: quoted-printable\r\n"
+            +"Content-Type: text/plain; charset=Cp1252\r\n"
+            +"\r\n"
+            +"second part =E8=E8\r\n"
+            +"------=_Part_0_XXXXXXXXXXX.XXXXXXXXXXX--\r\n";
+    }
+    
+    protected String getMultipartMessageExpected1() {
+        return "Subject: test\r\n"
+            +"MIME-Version: 1.0\r\n"
+            +"Content-Type: multipart/alternative; \r\n" 
+            +"\tboundary=\"----=_Part_0_XXXXXXXXXXX.XXXXXXXXXXX\"\r\n"
+            +"\r\n"
+            +"------=_Part_0_XXXXXXXXXXX.XXXXXXXXXXX\r\n"
+            +"X-header: test1\r\n"
+            +"Content-Transfer-Encoding: quoted-printable\r\n"
+            +"Content-Type: text/plain; charset=Cp1252\r\n"
+            +"\r\n"
+            +"test=E8\r\n"
+            +"------=_Part_0_XXXXXXXXXXX.XXXXXXXXXXX\r\n"
+            +"X-header: test2\r\n"
+            +"Content-Transfer-Encoding: quoted-printable\r\n"
+            +"Content-Type: text/plain; charset=Cp1252\r\n"
+            +"\r\n"
+            +"second part =E8=E8\r\n"
+            +"------=_Part_0_XXXXXXXXXXX.XXXXXXXXXXX--\r\n";
+    }
+    
+    protected String getMultipartMessageExpected2() {
+        return "Subject: test\r\n"
+            +"MIME-Version: 1.0\r\n"
+            +"Content-Type: multipart/alternative; \r\n" 
+            +"\tboundary=\"----=_Part_0_XXXXXXXXXXX.XXXXXXXXXXX\"\r\n"
+            +"\r\n"
+            +"------=_Part_0_XXXXXXXXXXX.XXXXXXXXXXX\r\n"
+            +"X-header: test1\r\n"
+            +"Content-Transfer-Encoding: quoted-printable\r\n"
+            +"Content-Type: text/plain; charset=Cp1252\r\n"
+            +"\r\n"
+            +"test=E8\r\n"
+            +"------=_Part_0_XXXXXXXXXXX.XXXXXXXXXXX\r\n"
+            +"X-header: test2\r\n"
+            +"Content-Transfer-Encoding: quoted-printable\r\n"
+            +"Content-Type: text/plain; charset=Cp1252\r\n"
+            +"\r\n"
+            +"second part =E8=E8\r\n"
+            +"------=_Part_0_XXXXXXXXXXX.XXXXXXXXXXX\r\n"
+            +"Subject: test3\r\n"
+            +"Content-Transfer-Encoding: 7bit\r\n"
+            +"Content-Type: text/plain; charset=us-ascii\r\n"
+            +"\r\n"
+            +"second part\r\n"
+            +"------=_Part_0_XXXXXXXXXXX.XXXXXXXXXXX--\r\n";
+    }
+    
+    protected String getMultipartMessageExpected3() {
+        return "Subject: test\r\n"
+            +"MIME-Version: 1.0\r\n"
+            +"Content-Type: binary/octet-stream\r\n"
+            +"Content-Transfer-Encoding: 8bit\r\n"
+            +"\r\n"
+            +"mynewcoòàùntent?à!";
+    }
+    
+    /*
+     * Class under test for String getSubject()
+     */
+    public void testMultipartMessageChanges() throws Exception {
+
+        MimeMessage mm = getMultipartMessage();
+        
+//        ByteArrayOutputStream out = new ByteArrayOutputStream();
+//        mmCreated.writeTo(out,new String[] {"Message-ID"});
+//        String messageSource = out.toString();
+//        System.out.println(messageSource);
+        
+        
+        MimeMultipart content1 = (MimeMultipart) mm.getContent();
+        BodyPart b1 = content1.getBodyPart(0);
+        b1.setText("testè");
+        mm.setContent(content1,mm.getContentType());
+        mm.saveChanges();
+
+        assertEquals(getMultipartMessageExpected1(),getCleanedMessageSource(mm));
+
+        MimeMultipart content2 = (MimeMultipart) mm.getContent();
+        content2.addBodyPart(new MimeBodyPart(new InternetHeaders(new ByteArrayInputStream("Subject: test3\r\n".getBytes())),"second part".getBytes()));
+        mm.setContent(content2,mm.getContentType());
+        mm.saveChanges();
+
+        assertEquals(getMultipartMessageExpected2(),getCleanedMessageSource(mm));
+
+        mm.setContent("mynewcoòàùntent€à!","text/plain");
+        mm.setHeader(RFC2822Headers.CONTENT_TYPE,"binary/octet-stream");
+        mm.setHeader("Content-Transfer-Encoding","8bit");
+        mm.saveChanges();
+        
+        assertEquals(getMultipartMessageExpected3(),getCleanedMessageSource(mm));
+        
+    }
+
+    protected MimeMessage getMissingEncodingAddHeaderMessage() throws Exception {
+        MimeMessage m = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        m.setText("Testà\r\n");
+        m.setSubject("test");
+        m.saveChanges();
+        return m;
+    }
+    
+
+    protected String getMissingEncodingAddHeaderSource() {
+        return "Subject: test\r\n"+
+                "\r\n"+
+                "Testà\r\n";
+    }
+    
+    protected String getMissingEncodingAddHeaderExpected() {
+        return "Subject: test\r\n"
+            +"MIME-Version: 1.0\r\n"
+            +"Content-Type: text/plain; charset=Cp1252\r\n"
+            +"Content-Transfer-Encoding: quoted-printable\r\n"
+            +"\r\n"
+            +"Test=E0\r\n";
+    }
+    
+
+    public void testMissingEncodingAddHeader() throws Exception {
+        MimeMessage mm = getMissingEncodingAddHeaderMessage();
+        mm.setHeader("Content-Transfer-Encoding", "quoted-printable");
+        mm.saveChanges();
+
+        assertEquals(getMissingEncodingAddHeaderExpected(),getCleanedMessageSource(mm));
+}
+    
+
+    protected String getCleanedMessageSource(MimeMessage mm) throws Exception {
+        ByteArrayOutputStream out2;
+        out2 = new ByteArrayOutputStream();
+        mm.writeTo(out2,new String[] {"Message-ID"});
+
+        String res = out2.toString();
+
+        // we put a "Return-Path: null" placeholder in MimeMessageWrapper.
+        // if noone write it, we should consider it equals.
+        if (res.startsWith("Return-Path: null")) res = res.substring(19);
+        
+        int p = res.indexOf("\r\n\r\n");
+        if (p > 0) {
+            String head = res.substring(0,p);
+            String[] str = head.split("\r\n");
+            Arrays.sort(str);
+            StringBuffer outputHead = new StringBuffer();
+            for (int i = str.length-1; i >= 0; i--) {
+                outputHead.append(str[i]);
+                outputHead.append("\r\n");
+            }
+            outputHead.append(res.substring(p+2));
+            res = outputHead.toString();
+        }
+        
+        res = res.replaceAll("----=_Part_\\d_\\d+\\.\\d+","----=_Part_\\0_XXXXXXXXXXX.XXXXXXXXXXX");
+        return res;
+    }
+    
+    protected void debugMessage(MimeMessage mm) throws Exception {
+        System.out.println("-------------------");
+        System.out.println(getCleanedMessageSource(mm));
+        System.out.println("-------------------");
+    }
+    
+    
+    
+}

Added: james/server/trunk/src/test/org/apache/james/core/MimeMessageUtilTest.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/test/org/apache/james/core/MimeMessageUtilTest.java?rev=385090&view=auto
==============================================================================
--- james/server/trunk/src/test/org/apache/james/core/MimeMessageUtilTest.java (added)
+++ james/server/trunk/src/test/org/apache/james/core/MimeMessageUtilTest.java Sat Mar 11 07:19:33 2006
@@ -0,0 +1,66 @@
+/***********************************************************************
+ * Copyright (c) 2006 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 javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.internet.MimeMessage;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+public class MimeMessageUtilTest extends TestCase {
+
+    public void testWriteMimeMessageMultipartWithMessageID() throws MessagingException, IOException {
+        String message = "Received: from localhost.localdomain ([127.0.0.1])\r\n"+
+        "          by athlon14 (JAMES SMTP Server 2.3-dev) with SMTP ID 694\r\n"+
+        "          for <te...@athlon14.bf.loc>;\r\n"+
+        "          Sat, 18 Feb 2006 19:30:53 +0100 (CET)\r\n"+
+        "Subject: ext2int\r\n"+
+        "X-James-Postage: This is a test mail sent by James Postage\r\n"+
+        "Mime-Version: 1.0\r\n"+
+        "Content-Type: multipart/alternative; boundary=\"XyoYyxCQIfmZ5Sxofid6XQVZt5Z09XtTnqBF4Z45XSA=\"\r\n"+
+        "Date: Sat, 18 Feb 2006 19:30:53 +0100 (CET)\r\n"+
+        "From: test_ext2@another.bf.loc\r\n"+
+        "\r\n"+
+        "\r\n"+
+        "--XyoYyxCQIfmZ5Sxofid6XQVZt5Z09XtTnqBF4Z45XSA=\r\n"+
+        "Content-Type: text/plain\r\n"+
+        "\r\n"+
+        "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r\n"+
+        "--XyoYyxCQIfmZ5Sxofid6XQVZt5Z09XtTnqBF4Z45XSA=\r\n"+
+        "Content-Type: application/octet-stream\r\n"+
+        "\r\n"+
+        "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r\n"+
+        "--XyoYyxCQIfmZ5Sxofid6XQVZt5Z09XtTnqBF4Z45XSA=--\r\n";
+        
+        ;
+
+        MimeMessage mimeMessage = new MimeMessage(Session.getDefaultInstance(new Properties()),new ByteArrayInputStream(message.getBytes()));
+        mimeMessage.getSize();
+        ByteArrayOutputStream headerOut = new ByteArrayOutputStream();
+        ByteArrayOutputStream bodyOut = new ByteArrayOutputStream();
+        MimeMessageUtil.writeTo(mimeMessage, headerOut, bodyOut);
+    }
+
+}

Modified: james/server/trunk/src/test/org/apache/james/core/MimeMessageWrapperTest.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/test/org/apache/james/core/MimeMessageWrapperTest.java?rev=385090&r1=385089&r2=385090&view=diff
==============================================================================
--- james/server/trunk/src/test/org/apache/james/core/MimeMessageWrapperTest.java (original)
+++ james/server/trunk/src/test/org/apache/james/core/MimeMessageWrapperTest.java Sat Mar 11 07:19:33 2006
@@ -19,33 +19,127 @@
 import com.sun.mail.util.SharedByteArrayInputStream;
 
 import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
 
 import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.InputStreamReader;
 
-import junit.framework.TestCase;
-
 /**
  * Test the subject folding issue.
  */
-public class MimeMessageWrapperTest extends TestCase {
+public class MimeMessageWrapperTest extends MimeMessageFromStreamTest {
+
+    private final class TestableMimeMessageWrapper extends MimeMessageWrapper {
+        
+        boolean messageLoadable = true;
+        boolean headersLoadable = true;
+        
+        private TestableMimeMessageWrapper(MimeMessageSource source) throws MessagingException {
+            super(source);
+        }
+
+        public boolean messageParsed() {
+            return messageParsed;
+        }
+
+        public MailHeaders getInnerHeaders() {
+            return (MailHeaders) headers;
+        }
+
+        public boolean isHeadersLoadable() {
+            return headersLoadable;
+        }
+
+        public void setHeadersLoadable(boolean headersLoadable) {
+            this.headersLoadable = headersLoadable;
+        }
+
+        public boolean isMessageLoadable() {
+            return messageLoadable;
+        }
+
+        public void setMessageLoadable(boolean messageLoadable) {
+            this.messageLoadable = messageLoadable;
+        }
+
+        protected synchronized void loadHeaders() throws MessagingException {
+            if (headersLoadable) {
+                super.loadHeaders();
+            } else {
+                throw new IllegalStateException("headersLoadable disabled");
+            }
+        }
+
+        protected synchronized MailHeaders loadHeaders(InputStream is) throws MessagingException {
+            if (headersLoadable) {
+                return (MailHeaders) super.createInternetHeaders(is);
+            } else {
+                throw new IllegalStateException("headersLoadable disabled");
+            }
+        }
+
+        protected synchronized void loadMessage() throws MessagingException {
+            if (messageLoadable) {
+                super.loadMessage();
+            } else {
+                throw new IllegalStateException("messageLoadable disabled");
+            }
+        }
+        
+        
+        
+    }
 
-    MimeMessageWrapper mw = null;
+    TestableMimeMessageWrapper mw = null;
     String content = "Subject: foo\r\nContent-Transfer-Encoding2: plain";
     String sep = "\r\n\r\n";
-    String body = "bar\r\n.\r\n";
-
-    public MimeMessageWrapperTest(String arg0) {
-        super(arg0);
+    String body = "bar\r\n";
 
+    protected MimeMessage getMessageFromSources(String sources) throws Exception {
         MimeMessageInputStreamSource mmis = null;
         try {
-            mmis = new MimeMessageInputStreamSource("test", new SharedByteArrayInputStream((content+sep+body).getBytes()));
+            mmis = new MimeMessageInputStreamSource("test", new SharedByteArrayInputStream(sources.getBytes()));
         } catch (MessagingException e) {
         }
-        mw = new MimeMessageWrapper(mmis);
+        return new TestableMimeMessageWrapper(mmis);
+    }
+
+    protected void setUp() throws Exception {
+        mw = (TestableMimeMessageWrapper) getMessageFromSources(content+sep+body);
+    }
+
+    
+    public void testDeferredMessageLoading() throws MessagingException, IOException {
+        assertEquals("foo",mw.getSubject());
+        assertFalse(mw.messageParsed());
+        assertEquals("bar\r\n",mw.getContent());
+        assertTrue(mw.messageParsed());
+        assertFalse(mw.isModified());
+    }
+
+    public void testDeferredMessageLoadingWhileWriting() throws MessagingException, IOException {
+        mw.setMessageLoadable(false);
+        assertEquals("foo",mw.getSubject());
+        assertFalse(mw.isModified());
+        mw.setSubject("newSubject");
+        assertEquals("newSubject",mw.getSubject());
+        assertFalse(mw.messageParsed());
+        assertTrue(mw.isModified());
+        mw.setMessageLoadable(true);
+        
+    }
+
+    public void testDeferredHeaderLoading() throws MessagingException, IOException {
+        mw.setHeadersLoadable(false);
+        try {
+            assertEquals("foo",mw.getSubject());
+            fail("subject should not be loadable here, headers loading is disabled");
+        } catch (IllegalStateException e) {
+            
+        }
     }
 
     /*
@@ -77,10 +171,16 @@
     public void testAddHeaderAndSave() {
         try {
             mw.addHeader("X-Test", "X-Value");
+            
+            assertEquals("X-Value", mw.getHeader("X-Test")[0]);
+            
             mw.saveChanges();
 
             ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
             mw.writeTo(rawMessage);
+            
+            assertEquals("X-Value", mw.getHeader("X-Test")[0]);
+
             String res = rawMessage.toString();
             
             boolean found = res.indexOf("X-Test: X-Value") > 0;



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


DISCLAIMER about changes to MimeMessageWrapper (Was: svn commit: r385090)

Posted by Stefano Bagnara <ap...@bago.org>.
Please note that I wrote simple tests for this change but I still have 
not tested this version in real use cases.

This patch and the upcoming "streaming support for db repositories" 
patch should be considered "critical" to James stability.

So, please, don't deploy next nightly builds in production environments 
because this is not as much as tested as 2.3.0a1!

I will run more real use tests at the end of this set of patches, but I 
wanted to commit this in steps to keep a better history of what I did.

Another thing I would like to check out is wether we still need of the 
CopyOnWrite proxy after this patch or better we can get rid of it 
(eventually integrating some of the behaviour in the mimemessagewrapper).

Stefano

> Author: bago
> Date: Sat Mar 11 07:19:33 2006
> New Revision: 385090
> 
> URL: http://svn.apache.org/viewcvs?rev=385090&view=rev
> Log:
> Removed wrapping from MimeMessageWrapper: now it is a simple MimeMessage extension (thanks to latest javamail providing much more protected methods than earlier releases)
> Updated a few file/stream handling objects to use SharedFileInputStream so that javamail will not load the full message in memory when cloning the message. (Related to JAMES-134)
> Added a bunch of tests to check consistency of the various MimeMessage implementation/constructors.
> (Sorry, no "streaming support" for db repositories in this commit: still working on it)
> 
> Added:
>     james/server/trunk/src/test/org/apache/james/core/MimeMessageFromMimeMessageTest.java
>     james/server/trunk/src/test/org/apache/james/core/MimeMessageFromSharedStreamTest.java
>     james/server/trunk/src/test/org/apache/james/core/MimeMessageFromStreamTest.java
>     james/server/trunk/src/test/org/apache/james/core/MimeMessageTest.java
>     james/server/trunk/src/test/org/apache/james/core/MimeMessageUtilTest.java
> Modified:
>     james/server/trunk/src/java/org/apache/james/core/MimeMessageCopyOnWriteProxy.java
>     james/server/trunk/src/java/org/apache/james/core/MimeMessageInputStreamSource.java
>     james/server/trunk/src/java/org/apache/james/core/MimeMessageUtil.java
>     james/server/trunk/src/java/org/apache/james/core/MimeMessageWrapper.java
>     james/server/trunk/src/java/org/apache/james/mailrepository/filepair/AbstractFileRepository.java
>     james/server/trunk/src/java/org/apache/james/mailrepository/filepair/File_Persistent_Stream_Repository.java
>     james/server/trunk/src/java/org/apache/james/transport/mailets/AbstractRedirect.java
>     james/server/trunk/src/java/org/apache/james/transport/mailets/AddHeader.java
>     james/server/trunk/src/test/org/apache/james/core/MimeMessageCopyOnWriteProxyTest.java
>     james/server/trunk/src/test/org/apache/james/core/MimeMessageWrapperTest.java



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


Re: DISCLAIMER about changes to MimeMessageWrapper (Was: svn commit: r385090)

Posted by Stefano Bagnara <ap...@bago.org>.
Norman Maurer wrote:
> Hi,
> 
> any update on this ? Or will you send a email to the mailinglist when
> the work is done ?

I applied the patches to use streams writing to repositories.
Reading streams from db is what is taking me too much time and is not 
ready to be committed.

I'm currently using the current trunk in a test server but it handle 
only a few internal mails (less than 100 mails per day).

Stefano

> Am Samstag, den 11.03.2006, 16:55 +0100 schrieb Stefano Bagnara:
>> Please note that I wrote simple tests for this change but I still have 
>> not tested this version in real use cases.
>>
>> This patch and the upcoming "streaming support for db repositories" 
>> patch should be considered "critical" to James stability.
>>
>> So, please, don't deploy next nightly builds in production environments 
>> because this is not as much as tested as 2.3.0a1!
>>
>> I will run more real use tests at the end of this set of patches, but I 
>> wanted to commit this in steps to keep a better history of what I did.
>>
>> Another thing I would like to check out is wether we still need of the 
>> CopyOnWrite proxy after this patch or better we can get rid of it 
>> (eventually integrating some of the behaviour in the mimemessagewrapper).
>>
>> Stefano



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


Re: DISCLAIMER about changes to MimeMessageWrapper (Was: svn commit: r385090)

Posted by Norman Maurer <nm...@byteaction.de>.
Hi,

any update on this ? Or will you send a email to the mailinglist when
the work is done ?

bye

Am Samstag, den 11.03.2006, 16:55 +0100 schrieb Stefano Bagnara:
> Please note that I wrote simple tests for this change but I still have 
> not tested this version in real use cases.
> 
> This patch and the upcoming "streaming support for db repositories" 
> patch should be considered "critical" to James stability.
> 
> So, please, don't deploy next nightly builds in production environments 
> because this is not as much as tested as 2.3.0a1!
> 
> I will run more real use tests at the end of this set of patches, but I 
> wanted to commit this in steps to keep a better history of what I did.
> 
> Another thing I would like to check out is wether we still need of the 
> CopyOnWrite proxy after this patch or better we can get rid of it 
> (eventually integrating some of the behaviour in the mimemessagewrapper).
> 
> Stefano
> 
> > Author: bago
> > Date: Sat Mar 11 07:19:33 2006
> > New Revision: 385090
> > 
> > URL: http://svn.apache.org/viewcvs?rev=385090&view=rev
> > Log:
> > Removed wrapping from MimeMessageWrapper: now it is a simple MimeMessage extension (thanks to latest javamail providing much more protected methods than earlier releases)
> > Updated a few file/stream handling objects to use SharedFileInputStream so that javamail will not load the full message in memory when cloning the message. (Related to JAMES-134)
> > Added a bunch of tests to check consistency of the various MimeMessage implementation/constructors.
> > (Sorry, no "streaming support" for db repositories in this commit: still working on it)
> > 
> > Added:
> >     james/server/trunk/src/test/org/apache/james/core/MimeMessageFromMimeMessageTest.java
> >     james/server/trunk/src/test/org/apache/james/core/MimeMessageFromSharedStreamTest.java
> >     james/server/trunk/src/test/org/apache/james/core/MimeMessageFromStreamTest.java
> >     james/server/trunk/src/test/org/apache/james/core/MimeMessageTest.java
> >     james/server/trunk/src/test/org/apache/james/core/MimeMessageUtilTest.java
> > Modified:
> >     james/server/trunk/src/java/org/apache/james/core/MimeMessageCopyOnWriteProxy.java
> >     james/server/trunk/src/java/org/apache/james/core/MimeMessageInputStreamSource.java
> >     james/server/trunk/src/java/org/apache/james/core/MimeMessageUtil.java
> >     james/server/trunk/src/java/org/apache/james/core/MimeMessageWrapper.java
> >     james/server/trunk/src/java/org/apache/james/mailrepository/filepair/AbstractFileRepository.java
> >     james/server/trunk/src/java/org/apache/james/mailrepository/filepair/File_Persistent_Stream_Repository.java
> >     james/server/trunk/src/java/org/apache/james/transport/mailets/AbstractRedirect.java
> >     james/server/trunk/src/java/org/apache/james/transport/mailets/AddHeader.java
> >     james/server/trunk/src/test/org/apache/james/core/MimeMessageCopyOnWriteProxyTest.java
> >     james/server/trunk/src/test/org/apache/james/core/MimeMessageWrapperTest.java
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
> For additional commands, e-mail: server-dev-help@james.apache.org
> 
>