Index: torque/src/test/java/org/apache/james/mailboxmanager/torque/PartContentBuilderMultipartAlternativeTest.java
===================================================================
--- torque/src/test/java/org/apache/james/mailboxmanager/torque/PartContentBuilderMultipartAlternativeTest.java	(Revision 950435)
+++ torque/src/test/java/org/apache/james/mailboxmanager/torque/PartContentBuilderMultipartAlternativeTest.java	(Arbeitskopie)
@@ -27,8 +27,8 @@
 import java.util.List;
 
 import org.apache.james.imap.mailbox.MessageResult.Header;
-import org.apache.james.imap.store.PartContentBuilder;
 import org.apache.james.imap.store.StringBuilderChannel;
+import org.apache.james.imap.store.streaming.PartContentBuilder;
 import org.junit.Before;
 import org.junit.Test;
 
Index: torque/src/test/java/org/apache/james/mailboxmanager/torque/PartContentBuilderComplexMultipartTest.java
===================================================================
--- torque/src/test/java/org/apache/james/mailboxmanager/torque/PartContentBuilderComplexMultipartTest.java	(Revision 950435)
+++ torque/src/test/java/org/apache/james/mailboxmanager/torque/PartContentBuilderComplexMultipartTest.java	(Arbeitskopie)
@@ -27,9 +27,9 @@
 import java.util.List;
 
 import org.apache.james.imap.mailbox.MessageResult.Header;
-import org.apache.james.imap.store.PartContentBuilder;
 import org.apache.james.imap.store.StringBuilderChannel;
-import org.apache.james.imap.store.PartContentBuilder.PartNotFoundException;
+import org.apache.james.imap.store.streaming.PartContentBuilder;
+import org.apache.james.imap.store.streaming.PartContentBuilder.PartNotFoundException;
 import org.junit.Before;
 import org.junit.Test;
 
Index: torque/src/main/java/org/apache/james/mailboxmanager/torque/TorqueMailbox.java
===================================================================
--- torque/src/main/java/org/apache/james/mailboxmanager/torque/TorqueMailbox.java	(Revision 950435)
+++ torque/src/main/java/org/apache/james/mailboxmanager/torque/TorqueMailbox.java	(Arbeitskopie)
@@ -59,7 +59,7 @@
 import org.apache.james.imap.mailbox.SearchQuery.NumericRange;
 import org.apache.james.imap.mailbox.util.FetchGroupImpl;
 import org.apache.james.imap.mailbox.util.UidRange;
-import org.apache.james.imap.store.CRLFOutputStream;
+import org.apache.james.imap.store.streaming.CRLFOutputStream;
 import org.apache.james.mailboxmanager.torque.om.MailboxRow;
 import org.apache.james.mailboxmanager.torque.om.MailboxRowPeer;
 import org.apache.james.mailboxmanager.torque.om.MessageBody;
Index: torque/src/main/java/org/apache/james/mailboxmanager/torque/MessageRowUtils.java
===================================================================
--- torque/src/main/java/org/apache/james/mailboxmanager/torque/MessageRowUtils.java	(Revision 950435)
+++ torque/src/main/java/org/apache/james/mailboxmanager/torque/MessageRowUtils.java	(Arbeitskopie)
@@ -39,11 +39,11 @@
 import org.apache.james.imap.mailbox.MessageResult.FetchGroup;
 import org.apache.james.imap.mailbox.MessageResult.MimePath;
 import org.apache.james.imap.mailbox.util.MessageResultImpl;
-import org.apache.james.imap.store.ByteContent;
-import org.apache.james.imap.store.FullByteContent;
 import org.apache.james.imap.store.MimeDescriptorImpl;
-import org.apache.james.imap.store.PartContentBuilder;
 import org.apache.james.imap.store.ResultHeader;
+import org.apache.james.imap.store.streaming.ByteContent;
+import org.apache.james.imap.store.streaming.FullByteContent;
+import org.apache.james.imap.store.streaming.PartContentBuilder;
 import org.apache.james.mailboxmanager.torque.om.MessageBody;
 import org.apache.james.mailboxmanager.torque.om.MessageHeader;
 import org.apache.james.mailboxmanager.torque.om.MessageRow;
Index: store/src/test/java/org/apache/james/imap/store/SimpleMessage.java
===================================================================
--- store/src/test/java/org/apache/james/imap/store/SimpleMessage.java	(Revision 950435)
+++ store/src/test/java/org/apache/james/imap/store/SimpleMessage.java	(Arbeitskopie)
@@ -29,6 +29,8 @@
 import org.apache.james.imap.store.mail.model.Document;
 import org.apache.james.imap.store.mail.model.Header;
 import org.apache.james.imap.store.mail.model.Property;
+import org.apache.james.imap.store.streaming.InMemoryRewindableInputStream;
+import org.apache.james.imap.store.streaming.RewindableInputStream;
 
 public class SimpleMessage implements Document {
     
Index: store/src/test/java/org/apache/james/imap/store/RewindableInputStreamTest.java
===================================================================
--- store/src/test/java/org/apache/james/imap/store/RewindableInputStreamTest.java	(Revision 950435)
+++ store/src/test/java/org/apache/james/imap/store/RewindableInputStreamTest.java	(Arbeitskopie)
@@ -25,6 +25,7 @@
 
 import static org.junit.Assert.*;
 
+import org.apache.james.imap.store.streaming.RewindableInputStream;
 import org.junit.Before;
 import org.junit.Test;
 
Index: store/src/test/java/org/apache/james/imap/store/PartContentBuilderMultipartAlternativeTest.java
===================================================================
--- store/src/test/java/org/apache/james/imap/store/PartContentBuilderMultipartAlternativeTest.java	(Revision 950435)
+++ store/src/test/java/org/apache/james/imap/store/PartContentBuilderMultipartAlternativeTest.java	(Arbeitskopie)
@@ -27,6 +27,7 @@
 import java.util.List;
 
 import org.apache.james.imap.mailbox.MessageResult.Header;
+import org.apache.james.imap.store.streaming.PartContentBuilder;
 import org.junit.Before;
 import org.junit.Test;
 
Index: store/src/test/java/org/apache/james/imap/store/PartContentBuilderComplexMultipartTest.java
===================================================================
--- store/src/test/java/org/apache/james/imap/store/PartContentBuilderComplexMultipartTest.java	(Revision 950435)
+++ store/src/test/java/org/apache/james/imap/store/PartContentBuilderComplexMultipartTest.java	(Arbeitskopie)
@@ -28,7 +28,8 @@
 import java.util.List;
 
 import org.apache.james.imap.mailbox.MessageResult.Header;
-import org.apache.james.imap.store.PartContentBuilder.PartNotFoundException;
+import org.apache.james.imap.store.streaming.PartContentBuilder;
+import org.apache.james.imap.store.streaming.PartContentBuilder.PartNotFoundException;
 import org.junit.Before;
 import org.junit.Test;
 
Index: store/src/test/java/org/apache/james/imap/store/InMemoryRewindableInputStreamTest.java
===================================================================
--- store/src/test/java/org/apache/james/imap/store/InMemoryRewindableInputStreamTest.java	(Revision 950435)
+++ store/src/test/java/org/apache/james/imap/store/InMemoryRewindableInputStreamTest.java	(Arbeitskopie)
@@ -21,6 +21,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.apache.james.imap.store.streaming.InMemoryRewindableInputStream;
+import org.apache.james.imap.store.streaming.RewindableInputStream;
+
 public class InMemoryRewindableInputStreamTest extends RewindableInputStreamTest{
 
     @Override
Index: store/src/test/java/org/apache/james/imap/store/FileRewindableInputStreamTest.java
===================================================================
--- store/src/test/java/org/apache/james/imap/store/FileRewindableInputStreamTest.java	(Revision 950435)
+++ store/src/test/java/org/apache/james/imap/store/FileRewindableInputStreamTest.java	(Arbeitskopie)
@@ -21,6 +21,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.apache.james.imap.store.streaming.FileRewindableInputStream;
+import org.apache.james.imap.store.streaming.RewindableInputStream;
+
 public class FileRewindableInputStreamTest extends RewindableInputStreamTest{
 
     @Override
Index: store/src/main/java/org/apache/james/imap/store/transaction/AbstractTransactionalMapper.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/transaction/AbstractTransactionalMapper.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/transaction/AbstractTransactionalMapper.java	(Arbeitskopie)
@@ -26,7 +26,7 @@
  * Run Transaction and handle begin, commit and rollback in the right order
  *
  */
-public abstract class AbstractTransactionalMapper implements TransactionalMapper{
+public abstract class AbstractTransactionalMapper implements TransactionalMapper {
 
     /*
      * (non-Javadoc)
@@ -41,7 +41,6 @@
             rollback();
             throw e;
         }
-        
     }
     
     /**
@@ -58,13 +57,11 @@
      */
     protected abstract void commit() throws MailboxException;
     
-    
     /**
      * Rollback transaction
      * 
      * @throws StorageException
      */
     protected abstract void rollback() throws MailboxException;
-    
 
 }
Index: store/src/main/java/org/apache/james/imap/store/streaming/StreamUtils.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/StreamUtils.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/StreamUtils.java	(Revision 0)
@@ -0,0 +1,57 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.imap.store.streaming;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Utility methods for messages.
+ * 
+ */
+public class StreamUtils {
+
+    private static final int BYTE_STREAM_CAPACITY = 8182;
+
+    private static final int BYTE_BUFFER_SIZE = 4096;
+
+    public static byte[] toByteArray(InputStream is) throws IOException {
+        ByteArrayOutputStream baos = out(is);
+
+        final byte[] bytes = baos.toByteArray();
+        return bytes;
+    }
+
+    public static ByteArrayOutputStream out(InputStream is) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(
+                BYTE_STREAM_CAPACITY);
+        out(is, baos);
+        return baos;
+    }
+
+    public static void out(InputStream is, ByteArrayOutputStream baos) throws IOException {
+        byte[] buf = new byte[BYTE_BUFFER_SIZE];
+        int read;
+        while ((read = is.read(buf)) > 0) {
+            baos.write(buf, 0, read);
+        }
+    }
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/RewindableInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/RewindableInputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/RewindableInputStream.java	(Revision 0)
@@ -0,0 +1,73 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * {@link FilterInputStream} which support the get rewinded.
+ * 
+ * The rewinding will get delayed as long as possible. So if you call
+ * rewind, it will only get performed when needed
+ * 
+ * Be sure to call {@link #close()} to cleanup temporary data when you 
+ * are done with reading from the stream
+ * 
+ *
+ */
+public abstract class RewindableInputStream extends FilterInputStream{
+
+    private boolean rewind;
+
+    protected RewindableInputStream(InputStream in) {
+        super(in);
+    }
+
+    /**
+     * Return if the stream needs to get rewinded
+     * 
+     * @return needsRewind
+     */
+    public final boolean needsRewind() {
+        return rewind;
+    }
+    
+    /**
+     * Rewind was done
+     */
+    protected final void rewindDone() {
+        this.rewind = false;
+    }
+    
+    /**
+     * Mark the stream for rewind. The rewind itself should get delayed as long as possible
+     */
+    public final void rewind() {
+        this.rewind = true;
+    }
+
+    /**
+     * Perform the actual rewind 
+     * @throws IOException
+     */
+    protected abstract void rewindIfNeeded() throws IOException;
+
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/PartContentBuilder.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/PartContentBuilder.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/PartContentBuilder.java	(Revision 0)
@@ -0,0 +1,291 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.james.imap.mailbox.Content;
+import org.apache.james.imap.mailbox.MessageResult;
+import org.apache.james.imap.mailbox.MessageResult.Header;
+import org.apache.james.imap.store.ResultHeader;
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.parser.MimeTokenStream;
+
+public class PartContentBuilder {
+
+    private static final byte[] EMPTY = {};
+
+    private MimeTokenStream parser;
+
+    private boolean empty = false;
+
+    private boolean topLevel = true;
+
+    public PartContentBuilder() {
+        parser = new MimeTokenStream();
+    }
+
+    public void markEmpty() {
+        empty = true;
+    }
+
+    public void parse(final InputStream in) {
+        parser.setRecursionMode(MimeTokenStream.M_RECURSE);
+        parser.parse(in);
+        topLevel = true;
+    }
+
+    private void skipToStartOfInner(int position) throws IOException, MimeException {
+        final int state = parser.next();
+        switch (state) {
+            case MimeTokenStream.T_START_MULTIPART:
+                break;
+            case MimeTokenStream.T_START_MESSAGE:
+                break;
+            case MimeTokenStream.T_END_OF_STREAM:
+                throw new PartNotFoundException(position);
+            case MimeTokenStream.T_END_BODYPART:
+                throw new PartNotFoundException(position);
+            default:
+                skipToStartOfInner(position);
+        }
+    }
+
+    public void to(int position) throws IOException, MimeException {
+        try {
+            if (topLevel) {
+                topLevel = false;
+            } else {
+                skipToStartOfInner(position);
+            }
+            for (int count = 0; count < position;) {
+                final int state = parser.next();
+                switch (state) {
+                    case MimeTokenStream.T_BODY:
+                        if (position == 1) {
+                            count++;
+                        }
+                        break;
+                    case MimeTokenStream.T_START_BODYPART:
+                        count++;
+                        break;
+                    case MimeTokenStream.T_START_MULTIPART:
+                        if (count > 0 && count < position) {
+                            ignoreInnerMessage();
+                        }
+                        break;
+                    case MimeTokenStream.T_END_OF_STREAM:
+                        throw new PartNotFoundException(position);
+                }
+            }
+        } catch (IllegalStateException e) {
+            throw new PartNotFoundException(position, e);
+        }
+    }
+
+    private void ignoreInnerMessage() throws IOException, UnexpectedEOFException, MimeException {
+        for (int state = parser.next(); state != MimeTokenStream.T_END_MULTIPART; state = parser
+                .next()) {
+            switch (state) {
+                case MimeTokenStream.T_END_OF_STREAM:
+                    throw new UnexpectedEOFException();
+
+                case MimeTokenStream.T_START_MULTIPART:
+                    ignoreInnerMessage();
+                    break;
+            }
+        }
+    }
+
+    public Content getFullContent() throws IOException, UnexpectedEOFException, MimeException {
+        final List<Header> headers = getMimeHeaders();
+        final byte[] content = mimeBodyContent();
+        return new FullByteContent(ByteBuffer.wrap(content), headers);
+    }
+
+    public Content getMessageBodyContent() throws IOException, MimeException {
+        final byte[] content = messageBodyContent();
+        return new ByteContent(ByteBuffer.wrap(content));
+    }
+
+    private byte[] messageBodyContent() throws IOException, MimeException {
+        final byte[] content;
+        if (empty) {
+            content = EMPTY;
+        } else {
+            boolean valid;
+            try {
+                advancedToMessage();
+                valid = true;
+            } catch (UnexpectedEOFException e) {
+                // No TEXT part
+                valid = false;
+            }
+            if (valid) {
+                parser.setRecursionMode(MimeTokenStream.M_FLAT);
+                for (int state = parser.getState(); state != MimeTokenStream.T_BODY
+                        && state != MimeTokenStream.T_START_MULTIPART; state = parser
+                        .next()) {
+                    if (state == MimeTokenStream.T_END_OF_STREAM) {
+                        valid = false;
+                        break;
+                    }
+                }
+                if (valid) {
+                    content = StreamUtils.toByteArray(parser.getInputStream());
+                } else {
+                    content = EMPTY;
+                }
+            } else {
+                content = EMPTY;
+            }
+        }
+        return content;
+    }
+
+    public Content getMimeBodyContent() throws IOException, MimeException {
+        final byte[] content = mimeBodyContent();
+        return new ByteContent(ByteBuffer.wrap(content));
+    }
+
+    private byte[] mimeBodyContent() throws IOException, MimeException {
+        final byte[] content;
+        if (empty) {
+            content = EMPTY;
+        } else {
+            parser.setRecursionMode(MimeTokenStream.M_FLAT);
+            boolean valid = true;
+            for (int state = parser.getState(); state != MimeTokenStream.T_BODY
+                    && state != MimeTokenStream.T_START_MULTIPART; state = parser
+                    .next()) {
+                if (state == MimeTokenStream.T_END_OF_STREAM) {
+                    valid = false;
+                    break;
+                }
+            }
+            if (valid) {
+                content = StreamUtils.toByteArray(parser.getInputStream());
+            } else {
+                content = EMPTY;
+            }
+        }
+        return content;
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<MessageResult.Header> getMimeHeaders() throws IOException, UnexpectedEOFException, MimeException {
+        final List<MessageResult.Header> results;
+        if (empty) {
+            results = Collections.EMPTY_LIST;
+        } else {
+            results = new ArrayList<MessageResult.Header>();
+            for (int state = parser.getState(); state != MimeTokenStream.T_END_HEADER; state = parser
+                    .next()) {
+                switch (state) {
+                    case MimeTokenStream.T_END_OF_STREAM:
+                        throw new UnexpectedEOFException();
+
+                    case MimeTokenStream.T_FIELD:
+                        final String fieldValue = parser.getField().getBody().trim();
+                        final String fieldName = parser.getField().getName();
+                        ResultHeader header = new ResultHeader(fieldName, fieldValue);
+                        results.add(header);
+                        break;
+                }
+            }
+        }
+        return results;
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<MessageResult.Header> getMessageHeaders() throws IOException, MimeException {
+        final List<MessageResult.Header> results;
+        if (empty) {
+            results = Collections.EMPTY_LIST;
+        } else {
+            results = new ArrayList<MessageResult.Header>();
+            try {
+                advancedToMessage();
+
+                for (int state = parser.getState(); state != MimeTokenStream.T_END_HEADER; state = parser
+                        .next()) {
+                    switch (state) {
+                        case MimeTokenStream.T_END_OF_STREAM:
+                            throw new IOException("Unexpected EOF");
+
+                        case MimeTokenStream.T_FIELD:
+                            final String fieldValue = parser.getField().getBody().trim();
+                            final String fieldName = parser.getField().getName();
+                            ResultHeader header = new ResultHeader(fieldName, fieldValue);
+                            results.add(header);
+                            break;
+                    }
+                }
+            } catch (UnexpectedEOFException e) {
+                // No headers found
+            }
+        }
+        return results;
+    }
+
+    private void advancedToMessage() throws IOException, UnexpectedEOFException, MimeException {
+        for (int state = parser.getState(); state != MimeTokenStream.T_START_MESSAGE; state = parser
+                .next()) {
+            if (state == MimeTokenStream.T_END_OF_STREAM) {
+                throw new UnexpectedEOFException();
+            }
+        }
+    }
+
+    public static final class UnexpectedEOFException extends MimeException {
+
+        private static final long serialVersionUID = -3755637466593055796L;
+
+        public UnexpectedEOFException() {
+            super("Unexpected EOF");
+        }
+    }
+
+    public static final class PartNotFoundException extends MimeException {
+
+        private static final long serialVersionUID = 7519976990944851574L;
+
+        private final int position;
+
+        public PartNotFoundException(int position) {
+            this(position, null);
+        }
+
+        public PartNotFoundException(int position, Exception e) {
+            super("Part " + position + " not found.", e);
+            this.position = position;
+        }
+
+        public final int getPosition() {
+            return position;
+        }
+
+    }
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/LazySkippingInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/LazySkippingInputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/LazySkippingInputStream.java	(Revision 0)
@@ -0,0 +1,101 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.imap.store.streaming;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * {@link FilterInputStream} implementation which skip the given bytes as late as possible.
+ * 
+ *
+ */
+public class LazySkippingInputStream extends FilterInputStream{
+
+    private long skipBytes;
+    private boolean skipped = false;
+
+    /**
+     * Construct the {@link LazySkippingInputStream}
+     * 
+     * @param in {@link InputStream} to wrap
+     * @param skipBytes bytes to skip
+     */
+    public LazySkippingInputStream(InputStream in, long skipBytes) {
+        super(in);
+        this.skipBytes = skipBytes;
+    }
+
+    @Override
+    public int read() throws IOException {
+        skipIfNeeded();
+
+        return super.read();
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        skipIfNeeded();
+        return super.read(b, off, len);
+    }
+
+    @Override
+    public int read(byte[] b) throws IOException {
+        skipIfNeeded();
+        return super.read(b);
+    }
+    
+    @Override
+    public int available() throws IOException {
+        skipIfNeeded();
+
+        return super.available();
+    }
+
+    @Override
+    public synchronized void mark(int readlimit) {
+        // not supported
+    }
+
+    @Override
+    public boolean markSupported() {
+        return false;
+    }
+
+    @Override
+    public long skip(long n) throws IOException {
+        skipIfNeeded();
+        return super.skip(n);
+    }
+
+    /**
+     * Check if the bytes are skipped already. If not do now
+     * 
+     * @throws IOException
+     */
+    private void skipIfNeeded() throws IOException {
+        if (skipped == false) {
+            super.skip(skipBytes);
+            skipped = true;
+        }
+    }
+
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/InputStreamFullContent.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/InputStreamFullContent.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/InputStreamFullContent.java	(Revision 0)
@@ -0,0 +1,81 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+import java.util.List;
+
+import org.apache.james.imap.mailbox.MessageResult;
+
+
+/**
+ * {@link AbstractFullContent} implementations which uses an {@link InputStream} as source for the 
+ * body content
+ *
+ */
+public class InputStreamFullContent extends AbstractFullContent{
+
+    private final RewindableInputStream in;
+    private long size;
+
+
+    public InputStreamFullContent(final RewindableInputStream contents, final List<MessageResult.Header> headers) throws IOException{
+        super(headers);
+        this.in = contents;
+        this.size = caculateSize();
+    }
+
+    
+
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.mailbox.Content#size()
+     */
+    public final long size() {
+        return size;
+    }
+
+    @Override
+    protected void bodyWriteTo(WritableByteChannel channel) throws IOException {
+        // rewind the stream before write it to the channel
+        in.rewind();
+        
+        // read all the content of the underlying InputStream in 16384 byte chunks, wrap them
+        // in a ByteBuffer and finally write the Buffer to the channel
+        byte[] buf = new byte[16384];
+        int i = 0;
+        while ((i = in.read(buf)) != -1) {
+            ByteBuffer buffer = ByteBuffer.wrap(buf);
+            // set the limit of the buffer to the returned bytes
+            buffer.limit(i);
+            channel.write(buffer);
+        }  
+    }
+
+
+    @Override
+    protected long getBodySize() throws IOException{
+        return in.available();
+    }
+
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/InputStreamContent.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/InputStreamContent.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/InputStreamContent.java	(Revision 0)
@@ -0,0 +1,79 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+
+import org.apache.james.imap.mailbox.Content;
+
+/**
+ * {@link Content} which is stored in a {@link InputStream}
+ *
+ */
+public final class InputStreamContent implements Content{
+
+    private RewindableInputStream in;
+    private long size;
+
+    public InputStreamContent(RewindableInputStream in) throws IOException{
+        this.in = in;
+        this.size = in.available();
+    }
+    
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.mailbox.Content#size()
+     */
+    public long size() {
+        return size;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.mailbox.Content#writeTo(java.nio.channels.WritableByteChannel)
+     */
+    public void writeTo(WritableByteChannel channel) throws IOException {
+        
+        try {
+            // rewind the stream before write it to the channel
+            in.rewind();
+        
+            // read all the content of the underlying InputStream in 16384 byte chunks, wrap them
+            // in a ByteBuffer and finally write the Buffer to the channel
+            byte[] buf = new byte[16384];
+            int i = 0;
+            while ((i = in.read(buf)) != -1) {
+                ByteBuffer buffer = ByteBuffer.wrap(buf);
+                // set the limit of the buffer to the returned bytes
+                    buffer.limit(i);
+                    channel.write(buffer);
+            }
+        } finally {
+            // close the stream so temporary files could get delete
+            in.close();
+        }
+        
+    }
+    
+   
+
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/InMemoryRewindableInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/InMemoryRewindableInputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/InMemoryRewindableInputStream.java	(Revision 0)
@@ -0,0 +1,62 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * {@link RewindableInputStream} implementations which stores the data into a {@link ByteArrayOutputStream}. This is
+ * only useful for small data, because it is complete handled in memory
+ * 
+ */
+public class InMemoryRewindableInputStream extends AbstractRewindableInputStream{
+
+    private ByteArrayOutputStream out;
+    private ByteArrayInputStream in;
+    public InMemoryRewindableInputStream(InputStream wrappedIn) throws IOException {
+        super(wrappedIn);
+        this.out = new ByteArrayOutputStream();
+        this.in = new ByteArrayInputStream(out.toByteArray());
+    }
+
+    @Override
+    protected void afterRewindComplete() throws IOException {
+        in = new ByteArrayInputStream(out.toByteArray());
+    }
+
+    @Override
+    protected void dispose() throws IOException {
+        // nothing todo
+    }
+
+    @Override
+    protected InputStream getRewindInputStream() {
+        return in;
+    }
+
+    @Override
+    protected OutputStream getRewindOutputStream() {
+        return out;
+    }
+
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/FullByteContent.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/FullByteContent.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/FullByteContent.java	(Revision 0)
@@ -0,0 +1,65 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+/**
+ * 
+ */
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+import java.util.List;
+
+import org.apache.james.imap.mailbox.MessageResult;
+
+/**
+ * Content which holds the full content, including {@link Header} objets
+ *
+ */
+public final class FullByteContent extends  AbstractFullContent {
+    private final ByteBuffer contents;
+    private final long size;
+
+    public FullByteContent(final ByteBuffer contents, final List<MessageResult.Header> headers) throws IOException {
+        super(headers);
+        this.contents = contents;
+        this.size = caculateSize();
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.mailbox.Content#size()
+     */
+    public long size() {
+        return size;
+    }
+
+    @Override
+    protected void bodyWriteTo(WritableByteChannel channel) throws IOException {
+        contents.rewind();
+        writeAll(channel, contents);        
+    }
+
+    @Override
+    protected long getBodySize() throws IOException {
+        return contents.limit();
+    }
+
+}
\ No newline at end of file
Index: store/src/main/java/org/apache/james/imap/store/streaming/FileRewindableInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/FileRewindableInputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/FileRewindableInputStream.java	(Revision 0)
@@ -0,0 +1,78 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * {@link RewindableInputStream} implementations which stores the data into a {@link File}. This is
+ * useful for big data
+ * 
+ */
+public class FileRewindableInputStream extends AbstractRewindableInputStream{
+
+    private File f;
+    private FileOutputStream fOut;
+    private FileInputStream fIn;
+
+    public FileRewindableInputStream(InputStream in) throws IOException {
+        super(in);
+    }
+
+    @Override
+    protected OutputStream getRewindOutputStream() throws IOException {
+        if (f == null) {
+            f = File.createTempFile("rewindable", ".tmp");
+        }
+        if (fOut == null) {
+            fOut = new FileOutputStream(f);
+        
+        }
+        return fOut;
+    }
+    
+    @Override
+    protected void afterRewindComplete() throws IOException {
+        fIn = new FileInputStream(f);        
+    }
+
+    @Override
+    protected void dispose() throws IOException {
+        if (f != null) {
+            f.delete();
+        }
+    }
+
+    @Override
+    protected InputStream getRewindInputStream() throws IOException {
+        if (f == null) {
+            f = File.createTempFile("rewindable", ".tmp");
+        }
+        if (fIn == null) {
+
+            fIn = new FileInputStream(f);
+        }
+        return fIn;
+    }
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/DelegatingRewindableInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/DelegatingRewindableInputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/DelegatingRewindableInputStream.java	(Revision 0)
@@ -0,0 +1,98 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * {@link RewindableInputStream} implementation which just delegate the calls to {@link FileRewindableInputStream} 
+ * or {@link InMemoryRewindableInputStream} depending on the size 
+ * 
+ *
+ */
+public class DelegatingRewindableInputStream extends RewindableInputStream{
+
+    public final static long  MAX_INMEMORY_SIZE= 524288;
+    
+    public DelegatingRewindableInputStream(InputStream in, long size, long maxInmemorySize) throws IOException {
+        super(null);
+        if (size > maxInmemorySize) {
+            this.in = new FileRewindableInputStream(in);
+        } else {
+            this.in = new InMemoryRewindableInputStream(in);
+
+        }
+    }
+
+    public DelegatingRewindableInputStream(InputStream in, long size) throws IOException {
+        this(in, size, MAX_INMEMORY_SIZE);
+    }
+
+    @Override
+    public int available() throws IOException {
+        return in.available();
+    }
+
+    @Override
+    public void close() throws IOException {
+        in.close();
+    }
+
+    @Override
+    public synchronized void mark(int readlimit) {
+        in.mark(readlimit);
+    }
+
+    @Override
+    public boolean markSupported() {
+        return in.markSupported();
+    }
+
+    @Override
+    public int read() throws IOException {
+        return in.read();
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        return in.read(b, off, len);
+    }
+
+    @Override
+    public int read(byte[] b) throws IOException {
+        return in.read(b);
+    }
+
+    @Override
+    public synchronized void reset() throws IOException {
+        in.reset();
+    }
+
+    @Override
+    public long skip(long n) throws IOException {
+        return in.skip(n);
+    }
+
+    @Override
+    protected void rewindIfNeeded() throws IOException {
+        ((RewindableInputStream)in).rewindIfNeeded();
+    }
+
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/CountingInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/CountingInputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/CountingInputStream.java	(Revision 0)
@@ -0,0 +1,86 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+/**
+ * 
+ */
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * {@link InputStream} implementation which just consume the the wrapped {@link InputStream} and count
+ * the lines which are contained within the wrapped stream
+ * 
+ *
+ */
+final public class CountingInputStream extends InputStream {
+
+    private final InputStream in;
+
+    private int lineCount;
+
+    private int octetCount;
+
+    public CountingInputStream(InputStream in) {
+        super();
+        this.in = in;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see java.io.InputStream#read()
+     */
+    public int read() throws IOException {
+        int next = in.read();
+        if (next > 0) {
+            octetCount++;
+            if (next == '\r') {
+                lineCount++;
+            }
+        }
+        return next;
+    }
+
+    /**
+     * Return the line count 
+     * 
+     * @return lineCount
+     */
+    public final int getLineCount() {
+        return lineCount;
+    }
+
+    /**
+     * Return the octet count
+     * 
+     * @return octetCount
+     */
+    public final int getOctetCount() {
+        return octetCount;
+    }
+    
+    /**
+     * Reads - and discards - the rest of the stream
+     * @throws IOException
+     */
+    public void readAll() throws IOException {
+        while (read()>0);
+    }
+}
\ No newline at end of file
Index: store/src/main/java/org/apache/james/imap/store/streaming/ConfigurableMimeTokenStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/ConfigurableMimeTokenStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/ConfigurableMimeTokenStream.java	(Revision 0)
@@ -0,0 +1,29 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import org.apache.james.mime4j.parser.MimeEntityConfig;
+import org.apache.james.mime4j.parser.MimeTokenStream;
+
+public class ConfigurableMimeTokenStream extends MimeTokenStream {
+    
+    public ConfigurableMimeTokenStream(MimeEntityConfig config) {
+        super(config);
+    }
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/CRLFOutputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/CRLFOutputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/CRLFOutputStream.java	(Revision 0)
@@ -0,0 +1,161 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.imap.store.streaming;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A Filter for use with SMTP or other protocols in which lines must end with
+ * CRLF. Converts every "isolated" occourency of \r or \n with \r\n
+ * 
+ * RFC 2821 #2.3.7 mandates that line termination is CRLF, and that CR and LF
+ * must not be transmitted except in that pairing. If we get a naked LF, convert
+ * to CRLF.
+ * 
+ */
+public class CRLFOutputStream extends FilterOutputStream {
+
+    /**
+     * Counter for number of last (0A or 0D).
+     */
+    protected int statusLast;
+
+    protected final static int LAST_WAS_OTHER = 0;
+
+    protected final static int LAST_WAS_CR = 1;
+
+    protected final static int LAST_WAS_LF = 2;
+
+    protected boolean startOfLine = true;
+
+    /**
+     * Constructor that wraps an OutputStream.
+     * 
+     * @param out
+     *            the OutputStream to be wrapped
+     */
+    public CRLFOutputStream(OutputStream out) {
+        super(out);
+        statusLast = LAST_WAS_LF; // we already assume a CRLF at beginning
+        // (otherwise TOP would not work correctly
+        // !)
+    }
+
+    /**
+     * Writes a byte to the stream Fixes any naked CR or LF to the RFC 2821
+     * mandated CFLF pairing.
+     * 
+     * @param b
+     *            the byte to write
+     * 
+     * @throws IOException
+     *             if an error occurs writing the byte
+     */
+    public void write(int b) throws IOException {
+        switch (b) {
+            case '\r':
+                out.write('\r');
+                out.write('\n');
+                startOfLine = true;
+                statusLast = LAST_WAS_CR;
+                break;
+            case '\n':
+                if (statusLast != LAST_WAS_CR) {
+                    out.write('\r');
+                    out.write('\n');
+                    startOfLine = true;
+                }
+                statusLast = LAST_WAS_LF;
+                break;
+            default:
+                // we're no longer at the start of a line
+                out.write(b);
+                startOfLine = false;
+                statusLast = LAST_WAS_OTHER;
+                break;
+        }
+    }
+
+    /**
+     * Provides an extension point for ExtraDotOutputStream to be able to add
+     * dots at the beginning of new lines.
+     * 
+     * @see java.io.FilterOutputStream#write(byte[], int, int)
+     */
+    protected void writeChunk(byte buffer[], int offset, int length)
+            throws IOException {
+        out.write(buffer, offset, length);
+    }
+
+    /**
+     * @see java.io.FilterOutputStream#write(byte[], int, int)
+     */
+    public synchronized void write(byte buffer[], int offset, int length)
+            throws IOException {
+        /* optimized */
+        int lineStart = offset;
+        for (int i = offset; i < length + offset; i++) {
+            switch (buffer[i]) {
+                case '\r':
+                    // CR case. Write down the last line
+                    // and position the new lineStart at the next char
+                    writeChunk(buffer, lineStart, i - lineStart);
+                    out.write('\r');
+                    out.write('\n');
+                    startOfLine = true;
+                    lineStart = i + 1;
+                    statusLast = LAST_WAS_CR;
+                    break;
+                case '\n':
+                    if (statusLast != LAST_WAS_CR) {
+                        writeChunk(buffer, lineStart, i - lineStart);
+                        out.write('\r');
+                        out.write('\n');
+                        startOfLine = true;
+                    }
+                    lineStart = i + 1;
+                    statusLast = LAST_WAS_LF;
+                    break;
+                default:
+                    statusLast = LAST_WAS_OTHER;
+            }
+        }
+        if (length + offset > lineStart) {
+            writeChunk(buffer, lineStart, length + offset - lineStart);
+            startOfLine = false;
+        }
+    }
+
+    /**
+     * Ensure that the stream is CRLF terminated.
+     * 
+     * @throws IOException
+     *             if an error occurs writing the byte
+     */
+    public void checkCRLFTerminator() throws IOException {
+        if (statusLast == LAST_WAS_OTHER) {
+            out.write('\r');
+            out.write('\n');
+            statusLast = LAST_WAS_CR;
+        }
+    }
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/ByteContent.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/ByteContent.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/ByteContent.java	(Revision 0)
@@ -0,0 +1,60 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+/**
+ * 
+ */
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+
+import org.apache.james.imap.mailbox.Content;
+
+public final class ByteContent implements Content {
+
+    private final ByteBuffer contents;
+
+    private final long size;
+
+    public ByteContent(final ByteBuffer contents) {
+        this.contents = contents;
+        size = contents.limit();
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.mailbox.Content#size()
+     */
+    public long size() {
+        return size;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.mailbox.Content#writeTo(java.nio.channels.WritableByteChannel)
+     */
+    public void writeTo(WritableByteChannel channel) throws IOException {
+        contents.rewind();
+        while (channel.write(contents) > 0) {
+            // write more
+        }
+    }
+}
\ No newline at end of file
Index: store/src/main/java/org/apache/james/imap/store/streaming/AbstractRewindableInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/AbstractRewindableInputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/AbstractRewindableInputStream.java	(Revision 0)
@@ -0,0 +1,182 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * {@link RewindableInputStream} which support the get rewinded. This is done by copy over every byte
+ * over to another {@link OutputStream}. What {@link OutputStream} to use is up to the implementations.
+ * 
+ * The rewinding will get delayed as long as possible. So if you call
+ * rewind, it will only get performed when needed
+ * 
+ * Be sure to call {@link #close()} once you done reading from the object. This will
+ * remove all temporary data
+ * 
+ *
+ */
+public abstract class AbstractRewindableInputStream extends RewindableInputStream{
+
+    protected boolean end = false;
+
+    public AbstractRewindableInputStream(InputStream in) throws IOException {
+        super(in);
+    }
+
+    /**
+     * Return the OutputStream to which the data should get written when they are read the 
+     * first time
+     * 
+     * @return output
+     * @throws IOException
+     */
+    protected abstract OutputStream getRewindOutputStream() throws IOException;
+    
+    /**
+     * Return the InputStream which should get used after the stream was rewinded
+     * 
+     * @return rewindInput
+     * @throws IOException
+     */
+    protected abstract InputStream getRewindInputStream() throws IOException;
+
+    /**
+     * Dispose all temporary data
+     * 
+     * @throws IOException
+     */
+    protected abstract void dispose() throws IOException;
+    
+    /**
+     * Get called after the rewind was complete
+     * 
+     * @throws IOException
+     */
+    protected abstract void afterRewindComplete() throws IOException;
+    
+    /**
+     * Close the stream and dispose all temporary data
+     * 
+     */
+    public void close() throws IOException {
+        try {
+            in.close();
+            OutputStream out = getRewindOutputStream();
+            if (out != null) {
+                out.close();
+            }
+            InputStream in = getRewindInputStream();
+            if (in != null) {
+                in.close();
+            }
+        } finally {
+            dispose();
+        }
+    }
+
+    
+    /**
+     * Read data and write and store it for later usage once the rewind was done
+     */
+    @Override
+    public int read() throws IOException {   
+        int i;
+        if (needsRewind()) {
+
+            rewindIfNeeded();
+        }
+        
+        if (end == false) {
+            i = in.read();
+            if (i == -1) {
+                end = true;
+            } else {
+                getRewindOutputStream().write(i);
+            }
+        } else {
+            i = getRewindInputStream().read();
+        }
+        return i;
+    }
+
+    /**
+     * Read data and write and store it for later usage once the rewind was done
+     */
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        if (len == 0) {
+            return 0;
+        }
+        if (needsRewind()) {
+            rewindIfNeeded();
+        }    
+        
+        int i;
+        if (end == false) {
+            i = in.read(b, off, len);
+            if (i == -1) {
+                end = true;
+            }
+            getRewindOutputStream().write(b, off, len);
+        } else {
+            i = getRewindInputStream().read(b,off,len);
+        }
+        return i;
+    }
+
+    /**
+     * Read data and write and store it for later usage once the rewind was done
+     */
+    @Override
+    public void rewindIfNeeded() throws IOException {
+        if (needsRewind()) {
+            rewindDone();
+            
+            if (end == false) {
+                while ( read() != -1);
+            }
+            // we don't need the original InputStream anymore so close it
+            in.close();
+            afterRewindComplete();
+        }        
+    }
+
+    @Override
+    public int available() throws IOException {
+        if (end == false) {
+            return in.available();
+        } else {
+            return getRewindInputStream().available();
+        }
+    }
+
+    @Override
+    public long skip(long n) throws IOException {
+        for (int i = 0; i < n; i++) {
+            if (read() == -1) {
+                return n -i;
+            }
+            if (end) break;
+        }
+        return 0;
+    }
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/AbstractFullContent.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/AbstractFullContent.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/AbstractFullContent.java	(Revision 0)
@@ -0,0 +1,111 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.james.imap.mailbox.Content;
+import org.apache.james.imap.mailbox.MessageResult;
+import org.apache.james.imap.mailbox.MessageResult.Header;
+import org.apache.james.imap.store.ResultUtils;
+
+/**
+ * Abstract base class for {@link Content} implementations which hold the headers and 
+ * the body a email
+ *
+ */
+public abstract class AbstractFullContent implements Content{
+
+
+    private List<Header> headers;
+    
+    public AbstractFullContent(final List<MessageResult.Header> headers) throws IOException {
+        this.headers = headers;
+    }
+    
+    protected long caculateSize() throws IOException{
+        long result = getBodySize();
+        result += 2;
+        for (final Iterator<MessageResult.Header> it = headers.iterator(); it.hasNext();) {
+            final MessageResult.Header header = it.next();
+            if (header != null) {
+                result += header.size();
+                result += 2;
+            }
+        }
+        return result;
+    }
+    
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.mailbox.Content#writeTo(java.nio.channels.WritableByteChannel)
+     */
+    public final void writeTo(WritableByteChannel channel) throws IOException {
+        ByteBuffer newLine = ByteBuffer.wrap(ResultUtils.BYTES_NEW_LINE);
+        for (final Iterator<MessageResult.Header> it = headers.iterator(); it.hasNext();) {
+            final MessageResult.Header header = it.next();
+            if (header != null) {
+                header.writeTo(channel);
+            }
+            newLine.rewind();
+            writeAll(channel, newLine);
+        }
+        newLine.rewind();
+        writeAll(channel, newLine);
+        bodyWriteTo(channel);
+    }
+
+    
+    /**
+     * Write all 
+     * 
+     * @param channel
+     * @param buffer
+     * @throws IOException
+     */
+    protected void writeAll(WritableByteChannel channel, ByteBuffer buffer)
+            throws IOException {
+        while (channel.write(buffer) > 0) {
+            // write more
+        }
+    }
+    
+    /**
+     * Return the size of the body
+     * 
+     * @return size
+     * @throws IOException
+     */
+    protected abstract long getBodySize() throws IOException;
+    
+    /**
+     * Write the body to the channel
+     * 
+     * @param channel
+     * @throws IOException
+     */
+    protected abstract void bodyWriteTo(WritableByteChannel channel) throws IOException;
+
+    
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/InputStreamContent.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/InputStreamContent.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/InputStreamContent.java	(Revision 0)
@@ -0,0 +1,79 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+
+import org.apache.james.imap.mailbox.Content;
+
+/**
+ * {@link Content} which is stored in a {@link InputStream}
+ *
+ */
+public final class InputStreamContent implements Content{
+
+    private RewindableInputStream in;
+    private long size;
+
+    public InputStreamContent(RewindableInputStream in) throws IOException{
+        this.in = in;
+        this.size = in.available();
+    }
+    
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.mailbox.Content#size()
+     */
+    public long size() {
+        return size;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.mailbox.Content#writeTo(java.nio.channels.WritableByteChannel)
+     */
+    public void writeTo(WritableByteChannel channel) throws IOException {
+        
+        try {
+            // rewind the stream before write it to the channel
+            in.rewind();
+        
+            // read all the content of the underlying InputStream in 16384 byte chunks, wrap them
+            // in a ByteBuffer and finally write the Buffer to the channel
+            byte[] buf = new byte[16384];
+            int i = 0;
+            while ((i = in.read(buf)) != -1) {
+                ByteBuffer buffer = ByteBuffer.wrap(buf);
+                // set the limit of the buffer to the returned bytes
+                    buffer.limit(i);
+                    channel.write(buffer);
+            }
+        } finally {
+            // close the stream so temporary files could get delete
+            in.close();
+        }
+        
+    }
+    
+   
+
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/RewindableInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/RewindableInputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/RewindableInputStream.java	(Revision 0)
@@ -0,0 +1,73 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * {@link FilterInputStream} which support the get rewinded.
+ * 
+ * The rewinding will get delayed as long as possible. So if you call
+ * rewind, it will only get performed when needed
+ * 
+ * Be sure to call {@link #close()} to cleanup temporary data when you 
+ * are done with reading from the stream
+ * 
+ *
+ */
+public abstract class RewindableInputStream extends FilterInputStream{
+
+    private boolean rewind;
+
+    protected RewindableInputStream(InputStream in) {
+        super(in);
+    }
+
+    /**
+     * Return if the stream needs to get rewinded
+     * 
+     * @return needsRewind
+     */
+    public final boolean needsRewind() {
+        return rewind;
+    }
+    
+    /**
+     * Rewind was done
+     */
+    protected final void rewindDone() {
+        this.rewind = false;
+    }
+    
+    /**
+     * Mark the stream for rewind. The rewind itself should get delayed as long as possible
+     */
+    public final void rewind() {
+        this.rewind = true;
+    }
+
+    /**
+     * Perform the actual rewind 
+     * @throws IOException
+     */
+    protected abstract void rewindIfNeeded() throws IOException;
+
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/FileRewindableInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/FileRewindableInputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/FileRewindableInputStream.java	(Revision 0)
@@ -0,0 +1,78 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * {@link RewindableInputStream} implementations which stores the data into a {@link File}. This is
+ * useful for big data
+ * 
+ */
+public class FileRewindableInputStream extends AbstractRewindableInputStream{
+
+    private File f;
+    private FileOutputStream fOut;
+    private FileInputStream fIn;
+
+    public FileRewindableInputStream(InputStream in) throws IOException {
+        super(in);
+    }
+
+    @Override
+    protected OutputStream getRewindOutputStream() throws IOException {
+        if (f == null) {
+            f = File.createTempFile("rewindable", ".tmp");
+        }
+        if (fOut == null) {
+            fOut = new FileOutputStream(f);
+        
+        }
+        return fOut;
+    }
+    
+    @Override
+    protected void afterRewindComplete() throws IOException {
+        fIn = new FileInputStream(f);        
+    }
+
+    @Override
+    protected void dispose() throws IOException {
+        if (f != null) {
+            f.delete();
+        }
+    }
+
+    @Override
+    protected InputStream getRewindInputStream() throws IOException {
+        if (f == null) {
+            f = File.createTempFile("rewindable", ".tmp");
+        }
+        if (fIn == null) {
+
+            fIn = new FileInputStream(f);
+        }
+        return fIn;
+    }
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/PartContentBuilder.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/PartContentBuilder.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/PartContentBuilder.java	(Revision 0)
@@ -0,0 +1,291 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.james.imap.mailbox.Content;
+import org.apache.james.imap.mailbox.MessageResult;
+import org.apache.james.imap.mailbox.MessageResult.Header;
+import org.apache.james.imap.store.ResultHeader;
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.parser.MimeTokenStream;
+
+public class PartContentBuilder {
+
+    private static final byte[] EMPTY = {};
+
+    private MimeTokenStream parser;
+
+    private boolean empty = false;
+
+    private boolean topLevel = true;
+
+    public PartContentBuilder() {
+        parser = new MimeTokenStream();
+    }
+
+    public void markEmpty() {
+        empty = true;
+    }
+
+    public void parse(final InputStream in) {
+        parser.setRecursionMode(MimeTokenStream.M_RECURSE);
+        parser.parse(in);
+        topLevel = true;
+    }
+
+    private void skipToStartOfInner(int position) throws IOException, MimeException {
+        final int state = parser.next();
+        switch (state) {
+            case MimeTokenStream.T_START_MULTIPART:
+                break;
+            case MimeTokenStream.T_START_MESSAGE:
+                break;
+            case MimeTokenStream.T_END_OF_STREAM:
+                throw new PartNotFoundException(position);
+            case MimeTokenStream.T_END_BODYPART:
+                throw new PartNotFoundException(position);
+            default:
+                skipToStartOfInner(position);
+        }
+    }
+
+    public void to(int position) throws IOException, MimeException {
+        try {
+            if (topLevel) {
+                topLevel = false;
+            } else {
+                skipToStartOfInner(position);
+            }
+            for (int count = 0; count < position;) {
+                final int state = parser.next();
+                switch (state) {
+                    case MimeTokenStream.T_BODY:
+                        if (position == 1) {
+                            count++;
+                        }
+                        break;
+                    case MimeTokenStream.T_START_BODYPART:
+                        count++;
+                        break;
+                    case MimeTokenStream.T_START_MULTIPART:
+                        if (count > 0 && count < position) {
+                            ignoreInnerMessage();
+                        }
+                        break;
+                    case MimeTokenStream.T_END_OF_STREAM:
+                        throw new PartNotFoundException(position);
+                }
+            }
+        } catch (IllegalStateException e) {
+            throw new PartNotFoundException(position, e);
+        }
+    }
+
+    private void ignoreInnerMessage() throws IOException, UnexpectedEOFException, MimeException {
+        for (int state = parser.next(); state != MimeTokenStream.T_END_MULTIPART; state = parser
+                .next()) {
+            switch (state) {
+                case MimeTokenStream.T_END_OF_STREAM:
+                    throw new UnexpectedEOFException();
+
+                case MimeTokenStream.T_START_MULTIPART:
+                    ignoreInnerMessage();
+                    break;
+            }
+        }
+    }
+
+    public Content getFullContent() throws IOException, UnexpectedEOFException, MimeException {
+        final List<Header> headers = getMimeHeaders();
+        final byte[] content = mimeBodyContent();
+        return new FullByteContent(ByteBuffer.wrap(content), headers);
+    }
+
+    public Content getMessageBodyContent() throws IOException, MimeException {
+        final byte[] content = messageBodyContent();
+        return new ByteContent(ByteBuffer.wrap(content));
+    }
+
+    private byte[] messageBodyContent() throws IOException, MimeException {
+        final byte[] content;
+        if (empty) {
+            content = EMPTY;
+        } else {
+            boolean valid;
+            try {
+                advancedToMessage();
+                valid = true;
+            } catch (UnexpectedEOFException e) {
+                // No TEXT part
+                valid = false;
+            }
+            if (valid) {
+                parser.setRecursionMode(MimeTokenStream.M_FLAT);
+                for (int state = parser.getState(); state != MimeTokenStream.T_BODY
+                        && state != MimeTokenStream.T_START_MULTIPART; state = parser
+                        .next()) {
+                    if (state == MimeTokenStream.T_END_OF_STREAM) {
+                        valid = false;
+                        break;
+                    }
+                }
+                if (valid) {
+                    content = StreamUtils.toByteArray(parser.getInputStream());
+                } else {
+                    content = EMPTY;
+                }
+            } else {
+                content = EMPTY;
+            }
+        }
+        return content;
+    }
+
+    public Content getMimeBodyContent() throws IOException, MimeException {
+        final byte[] content = mimeBodyContent();
+        return new ByteContent(ByteBuffer.wrap(content));
+    }
+
+    private byte[] mimeBodyContent() throws IOException, MimeException {
+        final byte[] content;
+        if (empty) {
+            content = EMPTY;
+        } else {
+            parser.setRecursionMode(MimeTokenStream.M_FLAT);
+            boolean valid = true;
+            for (int state = parser.getState(); state != MimeTokenStream.T_BODY
+                    && state != MimeTokenStream.T_START_MULTIPART; state = parser
+                    .next()) {
+                if (state == MimeTokenStream.T_END_OF_STREAM) {
+                    valid = false;
+                    break;
+                }
+            }
+            if (valid) {
+                content = StreamUtils.toByteArray(parser.getInputStream());
+            } else {
+                content = EMPTY;
+            }
+        }
+        return content;
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<MessageResult.Header> getMimeHeaders() throws IOException, UnexpectedEOFException, MimeException {
+        final List<MessageResult.Header> results;
+        if (empty) {
+            results = Collections.EMPTY_LIST;
+        } else {
+            results = new ArrayList<MessageResult.Header>();
+            for (int state = parser.getState(); state != MimeTokenStream.T_END_HEADER; state = parser
+                    .next()) {
+                switch (state) {
+                    case MimeTokenStream.T_END_OF_STREAM:
+                        throw new UnexpectedEOFException();
+
+                    case MimeTokenStream.T_FIELD:
+                        final String fieldValue = parser.getField().getBody().trim();
+                        final String fieldName = parser.getField().getName();
+                        ResultHeader header = new ResultHeader(fieldName, fieldValue);
+                        results.add(header);
+                        break;
+                }
+            }
+        }
+        return results;
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<MessageResult.Header> getMessageHeaders() throws IOException, MimeException {
+        final List<MessageResult.Header> results;
+        if (empty) {
+            results = Collections.EMPTY_LIST;
+        } else {
+            results = new ArrayList<MessageResult.Header>();
+            try {
+                advancedToMessage();
+
+                for (int state = parser.getState(); state != MimeTokenStream.T_END_HEADER; state = parser
+                        .next()) {
+                    switch (state) {
+                        case MimeTokenStream.T_END_OF_STREAM:
+                            throw new IOException("Unexpected EOF");
+
+                        case MimeTokenStream.T_FIELD:
+                            final String fieldValue = parser.getField().getBody().trim();
+                            final String fieldName = parser.getField().getName();
+                            ResultHeader header = new ResultHeader(fieldName, fieldValue);
+                            results.add(header);
+                            break;
+                    }
+                }
+            } catch (UnexpectedEOFException e) {
+                // No headers found
+            }
+        }
+        return results;
+    }
+
+    private void advancedToMessage() throws IOException, UnexpectedEOFException, MimeException {
+        for (int state = parser.getState(); state != MimeTokenStream.T_START_MESSAGE; state = parser
+                .next()) {
+            if (state == MimeTokenStream.T_END_OF_STREAM) {
+                throw new UnexpectedEOFException();
+            }
+        }
+    }
+
+    public static final class UnexpectedEOFException extends MimeException {
+
+        private static final long serialVersionUID = -3755637466593055796L;
+
+        public UnexpectedEOFException() {
+            super("Unexpected EOF");
+        }
+    }
+
+    public static final class PartNotFoundException extends MimeException {
+
+        private static final long serialVersionUID = 7519976990944851574L;
+
+        private final int position;
+
+        public PartNotFoundException(int position) {
+            this(position, null);
+        }
+
+        public PartNotFoundException(int position, Exception e) {
+            super("Part " + position + " not found.", e);
+            this.position = position;
+        }
+
+        public final int getPosition() {
+            return position;
+        }
+
+    }
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/StreamUtils.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/StreamUtils.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/StreamUtils.java	(Revision 0)
@@ -0,0 +1,57 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.imap.store.streaming;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Utility methods for messages.
+ * 
+ */
+public class StreamUtils {
+
+    private static final int BYTE_STREAM_CAPACITY = 8182;
+
+    private static final int BYTE_BUFFER_SIZE = 4096;
+
+    public static byte[] toByteArray(InputStream is) throws IOException {
+        ByteArrayOutputStream baos = out(is);
+
+        final byte[] bytes = baos.toByteArray();
+        return bytes;
+    }
+
+    public static ByteArrayOutputStream out(InputStream is) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(
+                BYTE_STREAM_CAPACITY);
+        out(is, baos);
+        return baos;
+    }
+
+    public static void out(InputStream is, ByteArrayOutputStream baos) throws IOException {
+        byte[] buf = new byte[BYTE_BUFFER_SIZE];
+        int read;
+        while ((read = is.read(buf)) > 0) {
+            baos.write(buf, 0, read);
+        }
+    }
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/LazySkippingInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/LazySkippingInputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/LazySkippingInputStream.java	(Revision 0)
@@ -0,0 +1,101 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.imap.store.streaming;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * {@link FilterInputStream} implementation which skip the given bytes as late as possible.
+ * 
+ *
+ */
+public class LazySkippingInputStream extends FilterInputStream{
+
+    private long skipBytes;
+    private boolean skipped = false;
+
+    /**
+     * Construct the {@link LazySkippingInputStream}
+     * 
+     * @param in {@link InputStream} to wrap
+     * @param skipBytes bytes to skip
+     */
+    public LazySkippingInputStream(InputStream in, long skipBytes) {
+        super(in);
+        this.skipBytes = skipBytes;
+    }
+
+    @Override
+    public int read() throws IOException {
+        skipIfNeeded();
+
+        return super.read();
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        skipIfNeeded();
+        return super.read(b, off, len);
+    }
+
+    @Override
+    public int read(byte[] b) throws IOException {
+        skipIfNeeded();
+        return super.read(b);
+    }
+    
+    @Override
+    public int available() throws IOException {
+        skipIfNeeded();
+
+        return super.available();
+    }
+
+    @Override
+    public synchronized void mark(int readlimit) {
+        // not supported
+    }
+
+    @Override
+    public boolean markSupported() {
+        return false;
+    }
+
+    @Override
+    public long skip(long n) throws IOException {
+        skipIfNeeded();
+        return super.skip(n);
+    }
+
+    /**
+     * Check if the bytes are skipped already. If not do now
+     * 
+     * @throws IOException
+     */
+    private void skipIfNeeded() throws IOException {
+        if (skipped == false) {
+            super.skip(skipBytes);
+            skipped = true;
+        }
+    }
+
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/FullByteContent.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/FullByteContent.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/FullByteContent.java	(Revision 0)
@@ -0,0 +1,65 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+/**
+ * 
+ */
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+import java.util.List;
+
+import org.apache.james.imap.mailbox.MessageResult;
+
+/**
+ * Content which holds the full content, including {@link Header} objets
+ *
+ */
+public final class FullByteContent extends  AbstractFullContent {
+    private final ByteBuffer contents;
+    private final long size;
+
+    public FullByteContent(final ByteBuffer contents, final List<MessageResult.Header> headers) throws IOException {
+        super(headers);
+        this.contents = contents;
+        this.size = caculateSize();
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.mailbox.Content#size()
+     */
+    public long size() {
+        return size;
+    }
+
+    @Override
+    protected void bodyWriteTo(WritableByteChannel channel) throws IOException {
+        contents.rewind();
+        writeAll(channel, contents);        
+    }
+
+    @Override
+    protected long getBodySize() throws IOException {
+        return contents.limit();
+    }
+
+}
\ No newline at end of file
Index: store/src/main/java/org/apache/james/imap/store/streaming/AbstractFullContent.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/AbstractFullContent.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/AbstractFullContent.java	(Revision 0)
@@ -0,0 +1,111 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.james.imap.mailbox.Content;
+import org.apache.james.imap.mailbox.MessageResult;
+import org.apache.james.imap.mailbox.MessageResult.Header;
+import org.apache.james.imap.store.ResultUtils;
+
+/**
+ * Abstract base class for {@link Content} implementations which hold the headers and 
+ * the body a email
+ *
+ */
+public abstract class AbstractFullContent implements Content{
+
+
+    private List<Header> headers;
+    
+    public AbstractFullContent(final List<MessageResult.Header> headers) throws IOException {
+        this.headers = headers;
+    }
+    
+    protected long caculateSize() throws IOException{
+        long result = getBodySize();
+        result += 2;
+        for (final Iterator<MessageResult.Header> it = headers.iterator(); it.hasNext();) {
+            final MessageResult.Header header = it.next();
+            if (header != null) {
+                result += header.size();
+                result += 2;
+            }
+        }
+        return result;
+    }
+    
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.mailbox.Content#writeTo(java.nio.channels.WritableByteChannel)
+     */
+    public final void writeTo(WritableByteChannel channel) throws IOException {
+        ByteBuffer newLine = ByteBuffer.wrap(ResultUtils.BYTES_NEW_LINE);
+        for (final Iterator<MessageResult.Header> it = headers.iterator(); it.hasNext();) {
+            final MessageResult.Header header = it.next();
+            if (header != null) {
+                header.writeTo(channel);
+            }
+            newLine.rewind();
+            writeAll(channel, newLine);
+        }
+        newLine.rewind();
+        writeAll(channel, newLine);
+        bodyWriteTo(channel);
+    }
+
+    
+    /**
+     * Write all 
+     * 
+     * @param channel
+     * @param buffer
+     * @throws IOException
+     */
+    protected void writeAll(WritableByteChannel channel, ByteBuffer buffer)
+            throws IOException {
+        while (channel.write(buffer) > 0) {
+            // write more
+        }
+    }
+    
+    /**
+     * Return the size of the body
+     * 
+     * @return size
+     * @throws IOException
+     */
+    protected abstract long getBodySize() throws IOException;
+    
+    /**
+     * Write the body to the channel
+     * 
+     * @param channel
+     * @throws IOException
+     */
+    protected abstract void bodyWriteTo(WritableByteChannel channel) throws IOException;
+
+    
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/CountingInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/CountingInputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/CountingInputStream.java	(Revision 0)
@@ -0,0 +1,86 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+/**
+ * 
+ */
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * {@link InputStream} implementation which just consume the the wrapped {@link InputStream} and count
+ * the lines which are contained within the wrapped stream
+ * 
+ *
+ */
+final public class CountingInputStream extends InputStream {
+
+    private final InputStream in;
+
+    private int lineCount;
+
+    private int octetCount;
+
+    public CountingInputStream(InputStream in) {
+        super();
+        this.in = in;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see java.io.InputStream#read()
+     */
+    public int read() throws IOException {
+        int next = in.read();
+        if (next > 0) {
+            octetCount++;
+            if (next == '\r') {
+                lineCount++;
+            }
+        }
+        return next;
+    }
+
+    /**
+     * Return the line count 
+     * 
+     * @return lineCount
+     */
+    public final int getLineCount() {
+        return lineCount;
+    }
+
+    /**
+     * Return the octet count
+     * 
+     * @return octetCount
+     */
+    public final int getOctetCount() {
+        return octetCount;
+    }
+    
+    /**
+     * Reads - and discards - the rest of the stream
+     * @throws IOException
+     */
+    public void readAll() throws IOException {
+        while (read()>0);
+    }
+}
\ No newline at end of file
Index: store/src/main/java/org/apache/james/imap/store/streaming/CRLFOutputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/CRLFOutputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/CRLFOutputStream.java	(Revision 0)
@@ -0,0 +1,161 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.imap.store.streaming;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A Filter for use with SMTP or other protocols in which lines must end with
+ * CRLF. Converts every "isolated" occourency of \r or \n with \r\n
+ * 
+ * RFC 2821 #2.3.7 mandates that line termination is CRLF, and that CR and LF
+ * must not be transmitted except in that pairing. If we get a naked LF, convert
+ * to CRLF.
+ * 
+ */
+public class CRLFOutputStream extends FilterOutputStream {
+
+    /**
+     * Counter for number of last (0A or 0D).
+     */
+    protected int statusLast;
+
+    protected final static int LAST_WAS_OTHER = 0;
+
+    protected final static int LAST_WAS_CR = 1;
+
+    protected final static int LAST_WAS_LF = 2;
+
+    protected boolean startOfLine = true;
+
+    /**
+     * Constructor that wraps an OutputStream.
+     * 
+     * @param out
+     *            the OutputStream to be wrapped
+     */
+    public CRLFOutputStream(OutputStream out) {
+        super(out);
+        statusLast = LAST_WAS_LF; // we already assume a CRLF at beginning
+        // (otherwise TOP would not work correctly
+        // !)
+    }
+
+    /**
+     * Writes a byte to the stream Fixes any naked CR or LF to the RFC 2821
+     * mandated CFLF pairing.
+     * 
+     * @param b
+     *            the byte to write
+     * 
+     * @throws IOException
+     *             if an error occurs writing the byte
+     */
+    public void write(int b) throws IOException {
+        switch (b) {
+            case '\r':
+                out.write('\r');
+                out.write('\n');
+                startOfLine = true;
+                statusLast = LAST_WAS_CR;
+                break;
+            case '\n':
+                if (statusLast != LAST_WAS_CR) {
+                    out.write('\r');
+                    out.write('\n');
+                    startOfLine = true;
+                }
+                statusLast = LAST_WAS_LF;
+                break;
+            default:
+                // we're no longer at the start of a line
+                out.write(b);
+                startOfLine = false;
+                statusLast = LAST_WAS_OTHER;
+                break;
+        }
+    }
+
+    /**
+     * Provides an extension point for ExtraDotOutputStream to be able to add
+     * dots at the beginning of new lines.
+     * 
+     * @see java.io.FilterOutputStream#write(byte[], int, int)
+     */
+    protected void writeChunk(byte buffer[], int offset, int length)
+            throws IOException {
+        out.write(buffer, offset, length);
+    }
+
+    /**
+     * @see java.io.FilterOutputStream#write(byte[], int, int)
+     */
+    public synchronized void write(byte buffer[], int offset, int length)
+            throws IOException {
+        /* optimized */
+        int lineStart = offset;
+        for (int i = offset; i < length + offset; i++) {
+            switch (buffer[i]) {
+                case '\r':
+                    // CR case. Write down the last line
+                    // and position the new lineStart at the next char
+                    writeChunk(buffer, lineStart, i - lineStart);
+                    out.write('\r');
+                    out.write('\n');
+                    startOfLine = true;
+                    lineStart = i + 1;
+                    statusLast = LAST_WAS_CR;
+                    break;
+                case '\n':
+                    if (statusLast != LAST_WAS_CR) {
+                        writeChunk(buffer, lineStart, i - lineStart);
+                        out.write('\r');
+                        out.write('\n');
+                        startOfLine = true;
+                    }
+                    lineStart = i + 1;
+                    statusLast = LAST_WAS_LF;
+                    break;
+                default:
+                    statusLast = LAST_WAS_OTHER;
+            }
+        }
+        if (length + offset > lineStart) {
+            writeChunk(buffer, lineStart, length + offset - lineStart);
+            startOfLine = false;
+        }
+    }
+
+    /**
+     * Ensure that the stream is CRLF terminated.
+     * 
+     * @throws IOException
+     *             if an error occurs writing the byte
+     */
+    public void checkCRLFTerminator() throws IOException {
+        if (statusLast == LAST_WAS_OTHER) {
+            out.write('\r');
+            out.write('\n');
+            statusLast = LAST_WAS_CR;
+        }
+    }
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/ConfigurableMimeTokenStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/ConfigurableMimeTokenStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/ConfigurableMimeTokenStream.java	(Revision 0)
@@ -0,0 +1,29 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import org.apache.james.mime4j.parser.MimeEntityConfig;
+import org.apache.james.mime4j.parser.MimeTokenStream;
+
+public class ConfigurableMimeTokenStream extends MimeTokenStream {
+    
+    public ConfigurableMimeTokenStream(MimeEntityConfig config) {
+        super(config);
+    }
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/InMemoryRewindableInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/InMemoryRewindableInputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/InMemoryRewindableInputStream.java	(Revision 0)
@@ -0,0 +1,62 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * {@link RewindableInputStream} implementations which stores the data into a {@link ByteArrayOutputStream}. This is
+ * only useful for small data, because it is complete handled in memory
+ * 
+ */
+public class InMemoryRewindableInputStream extends AbstractRewindableInputStream{
+
+    private ByteArrayOutputStream out;
+    private ByteArrayInputStream in;
+    public InMemoryRewindableInputStream(InputStream wrappedIn) throws IOException {
+        super(wrappedIn);
+        this.out = new ByteArrayOutputStream();
+        this.in = new ByteArrayInputStream(out.toByteArray());
+    }
+
+    @Override
+    protected void afterRewindComplete() throws IOException {
+        in = new ByteArrayInputStream(out.toByteArray());
+    }
+
+    @Override
+    protected void dispose() throws IOException {
+        // nothing todo
+    }
+
+    @Override
+    protected InputStream getRewindInputStream() {
+        return in;
+    }
+
+    @Override
+    protected OutputStream getRewindOutputStream() {
+        return out;
+    }
+
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/InputStreamFullContent.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/InputStreamFullContent.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/InputStreamFullContent.java	(Revision 0)
@@ -0,0 +1,81 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+import java.util.List;
+
+import org.apache.james.imap.mailbox.MessageResult;
+
+
+/**
+ * {@link AbstractFullContent} implementations which uses an {@link InputStream} as source for the 
+ * body content
+ *
+ */
+public class InputStreamFullContent extends AbstractFullContent{
+
+    private final RewindableInputStream in;
+    private long size;
+
+
+    public InputStreamFullContent(final RewindableInputStream contents, final List<MessageResult.Header> headers) throws IOException{
+        super(headers);
+        this.in = contents;
+        this.size = caculateSize();
+    }
+
+    
+
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.mailbox.Content#size()
+     */
+    public final long size() {
+        return size;
+    }
+
+    @Override
+    protected void bodyWriteTo(WritableByteChannel channel) throws IOException {
+        // rewind the stream before write it to the channel
+        in.rewind();
+        
+        // read all the content of the underlying InputStream in 16384 byte chunks, wrap them
+        // in a ByteBuffer and finally write the Buffer to the channel
+        byte[] buf = new byte[16384];
+        int i = 0;
+        while ((i = in.read(buf)) != -1) {
+            ByteBuffer buffer = ByteBuffer.wrap(buf);
+            // set the limit of the buffer to the returned bytes
+            buffer.limit(i);
+            channel.write(buffer);
+        }  
+    }
+
+
+    @Override
+    protected long getBodySize() throws IOException{
+        return in.available();
+    }
+
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/AbstractRewindableInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/AbstractRewindableInputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/AbstractRewindableInputStream.java	(Revision 0)
@@ -0,0 +1,182 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * {@link RewindableInputStream} which support the get rewinded. This is done by copy over every byte
+ * over to another {@link OutputStream}. What {@link OutputStream} to use is up to the implementations.
+ * 
+ * The rewinding will get delayed as long as possible. So if you call
+ * rewind, it will only get performed when needed
+ * 
+ * Be sure to call {@link #close()} once you done reading from the object. This will
+ * remove all temporary data
+ * 
+ *
+ */
+public abstract class AbstractRewindableInputStream extends RewindableInputStream{
+
+    protected boolean end = false;
+
+    public AbstractRewindableInputStream(InputStream in) throws IOException {
+        super(in);
+    }
+
+    /**
+     * Return the OutputStream to which the data should get written when they are read the 
+     * first time
+     * 
+     * @return output
+     * @throws IOException
+     */
+    protected abstract OutputStream getRewindOutputStream() throws IOException;
+    
+    /**
+     * Return the InputStream which should get used after the stream was rewinded
+     * 
+     * @return rewindInput
+     * @throws IOException
+     */
+    protected abstract InputStream getRewindInputStream() throws IOException;
+
+    /**
+     * Dispose all temporary data
+     * 
+     * @throws IOException
+     */
+    protected abstract void dispose() throws IOException;
+    
+    /**
+     * Get called after the rewind was complete
+     * 
+     * @throws IOException
+     */
+    protected abstract void afterRewindComplete() throws IOException;
+    
+    /**
+     * Close the stream and dispose all temporary data
+     * 
+     */
+    public void close() throws IOException {
+        try {
+            in.close();
+            OutputStream out = getRewindOutputStream();
+            if (out != null) {
+                out.close();
+            }
+            InputStream in = getRewindInputStream();
+            if (in != null) {
+                in.close();
+            }
+        } finally {
+            dispose();
+        }
+    }
+
+    
+    /**
+     * Read data and write and store it for later usage once the rewind was done
+     */
+    @Override
+    public int read() throws IOException {   
+        int i;
+        if (needsRewind()) {
+
+            rewindIfNeeded();
+        }
+        
+        if (end == false) {
+            i = in.read();
+            if (i == -1) {
+                end = true;
+            } else {
+                getRewindOutputStream().write(i);
+            }
+        } else {
+            i = getRewindInputStream().read();
+        }
+        return i;
+    }
+
+    /**
+     * Read data and write and store it for later usage once the rewind was done
+     */
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        if (len == 0) {
+            return 0;
+        }
+        if (needsRewind()) {
+            rewindIfNeeded();
+        }    
+        
+        int i;
+        if (end == false) {
+            i = in.read(b, off, len);
+            if (i == -1) {
+                end = true;
+            }
+            getRewindOutputStream().write(b, off, len);
+        } else {
+            i = getRewindInputStream().read(b,off,len);
+        }
+        return i;
+    }
+
+    /**
+     * Read data and write and store it for later usage once the rewind was done
+     */
+    @Override
+    public void rewindIfNeeded() throws IOException {
+        if (needsRewind()) {
+            rewindDone();
+            
+            if (end == false) {
+                while ( read() != -1);
+            }
+            // we don't need the original InputStream anymore so close it
+            in.close();
+            afterRewindComplete();
+        }        
+    }
+
+    @Override
+    public int available() throws IOException {
+        if (end == false) {
+            return in.available();
+        } else {
+            return getRewindInputStream().available();
+        }
+    }
+
+    @Override
+    public long skip(long n) throws IOException {
+        for (int i = 0; i < n; i++) {
+            if (read() == -1) {
+                return n -i;
+            }
+            if (end) break;
+        }
+        return 0;
+    }
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/DelegatingRewindableInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/DelegatingRewindableInputStream.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/DelegatingRewindableInputStream.java	(Revision 0)
@@ -0,0 +1,98 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * {@link RewindableInputStream} implementation which just delegate the calls to {@link FileRewindableInputStream} 
+ * or {@link InMemoryRewindableInputStream} depending on the size 
+ * 
+ *
+ */
+public class DelegatingRewindableInputStream extends RewindableInputStream{
+
+    public final static long  MAX_INMEMORY_SIZE= 524288;
+    
+    public DelegatingRewindableInputStream(InputStream in, long size, long maxInmemorySize) throws IOException {
+        super(null);
+        if (size > maxInmemorySize) {
+            this.in = new FileRewindableInputStream(in);
+        } else {
+            this.in = new InMemoryRewindableInputStream(in);
+
+        }
+    }
+
+    public DelegatingRewindableInputStream(InputStream in, long size) throws IOException {
+        this(in, size, MAX_INMEMORY_SIZE);
+    }
+
+    @Override
+    public int available() throws IOException {
+        return in.available();
+    }
+
+    @Override
+    public void close() throws IOException {
+        in.close();
+    }
+
+    @Override
+    public synchronized void mark(int readlimit) {
+        in.mark(readlimit);
+    }
+
+    @Override
+    public boolean markSupported() {
+        return in.markSupported();
+    }
+
+    @Override
+    public int read() throws IOException {
+        return in.read();
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        return in.read(b, off, len);
+    }
+
+    @Override
+    public int read(byte[] b) throws IOException {
+        return in.read(b);
+    }
+
+    @Override
+    public synchronized void reset() throws IOException {
+        in.reset();
+    }
+
+    @Override
+    public long skip(long n) throws IOException {
+        return in.skip(n);
+    }
+
+    @Override
+    protected void rewindIfNeeded() throws IOException {
+        ((RewindableInputStream)in).rewindIfNeeded();
+    }
+
+}
Index: store/src/main/java/org/apache/james/imap/store/streaming/ByteContent.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/streaming/ByteContent.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/streaming/ByteContent.java	(Revision 0)
@@ -0,0 +1,60 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+/**
+ * 
+ */
+package org.apache.james.imap.store.streaming;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+
+import org.apache.james.imap.mailbox.Content;
+
+public final class ByteContent implements Content {
+
+    private final ByteBuffer contents;
+
+    private final long size;
+
+    public ByteContent(final ByteBuffer contents) {
+        this.contents = contents;
+        size = contents.limit();
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.mailbox.Content#size()
+     */
+    public long size() {
+        return size;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.imap.mailbox.Content#writeTo(java.nio.channels.WritableByteChannel)
+     */
+    public void writeTo(WritableByteChannel channel) throws IOException {
+        contents.rewind();
+        while (channel.write(contents) > 0) {
+            // write more
+        }
+    }
+}
\ No newline at end of file
Index: store/src/main/java/org/apache/james/imap/store/mail/model/Document.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/mail/model/Document.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/mail/model/Document.java	(Arbeitskopie)
@@ -21,7 +21,7 @@
 import java.io.IOException;
 import java.util.List;
 
-import org.apache.james.imap.store.RewindableInputStream;
+import org.apache.james.imap.store.streaming.RewindableInputStream;
 
 /**
  * A MIME documents, consisting of meta-data (including MIME headers)
Index: store/src/main/java/org/apache/james/imap/store/mail/model/AbstractDocument.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/mail/model/AbstractDocument.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/mail/model/AbstractDocument.java	(Arbeitskopie)
@@ -21,9 +21,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 
-import org.apache.james.imap.store.DelegatingRewindableInputStream;
-import org.apache.james.imap.store.LazySkippingInputStream;
-import org.apache.james.imap.store.RewindableInputStream;
+import org.apache.james.imap.store.streaming.DelegatingRewindableInputStream;
+import org.apache.james.imap.store.streaming.LazySkippingInputStream;
+import org.apache.james.imap.store.streaming.RewindableInputStream;
 
 
 /**
Index: store/src/main/java/org/apache/james/imap/store/mail/MessageMapper.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/mail/MessageMapper.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/mail/MessageMapper.java	(Arbeitskopie)
@@ -42,7 +42,7 @@
      * @return list
      * @throws StorageException
      */
-    public abstract List<MailboxMembership<Id>> findInMailbox(MessageRange set)
+    public abstract List<MailboxMembership<Id>> findInMailbox(Id mailboxId, MessageRange set)
             throws StorageException;
 
     /**
@@ -53,7 +53,7 @@
      * @throws StorageException
      */
     public abstract List<MailboxMembership<Id>> findMarkedForDeletionInMailbox(
-            final MessageRange set)
+            Id mailboxId, final MessageRange set)
             throws StorageException;
 
     /**
@@ -62,7 +62,7 @@
      * @return count
      * @throws StorageException
      */
-    public abstract long countMessagesInMailbox()
+    public abstract long countMessagesInMailbox(Id mailboxId)
             throws StorageException;
 
     /**
@@ -71,7 +71,7 @@
      * @return unseenCount
      * @throws StorageException
      */
-    public abstract long countUnseenMessagesInMailbox()
+    public abstract long countUnseenMessagesInMailbox(Id mailboxId)
             throws StorageException;
 
     /**
@@ -81,7 +81,7 @@
      * @return
      * @throws StorageException
      */
-    public abstract List<MailboxMembership<Id>> searchMailbox(SearchQuery query) throws StorageException;
+    public abstract List<MailboxMembership<Id>> searchMailbox(Id mailboxId, SearchQuery query) throws StorageException;
 
     /**
      * Delete the given {@link MailboxMembership}
@@ -98,7 +98,7 @@
      * @return list
      * @throws StorageException
      */
-    public abstract List<MailboxMembership<Id>> findUnseenMessagesInMailbox() throws StorageException;
+    public abstract List<MailboxMembership<Id>> findUnseenMessagesInMailbox(Id mailboxId) throws StorageException;
 
     /**
      * Return a List of {@link MailboxMembership} which are recent.
@@ -107,7 +107,7 @@
      * @return recentList
      * @throws StorageException
      */
-    public abstract List<MailboxMembership<Id>> findRecentMessagesInMailbox() throws StorageException;
+    public abstract List<MailboxMembership<Id>> findRecentMessagesInMailbox(Id mailboxId) throws StorageException;
 
 
     /**
@@ -116,6 +116,6 @@
      * @param message
      * @throws StorageException
      */
-    public abstract void save(MailboxMembership<Id> message) throws StorageException;
+    public abstract void save(Id mailboxId, MailboxMembership<Id> message) throws StorageException;
 
 }
\ No newline at end of file
Index: store/src/main/java/org/apache/james/imap/store/mail/MailboxMapper.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/mail/MailboxMapper.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/mail/MailboxMapper.java	(Arbeitskopie)
@@ -30,7 +30,7 @@
  * to the end of the request.
  *
  */
-public interface MailboxMapper<Id> extends TransactionalMapper{
+public interface MailboxMapper<Id> extends TransactionalMapper {
     
     /**
      * Save the give {@link Mailbox} to the underlying storage
Index: store/src/main/java/org/apache/james/imap/store/StreamUtils.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/StreamUtils.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/StreamUtils.java	(Arbeitskopie)
@@ -1,57 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.imap.store;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Utility methods for messages.
- * 
- */
-public class StreamUtils {
-
-    private static final int BYTE_STREAM_CAPACITY = 8182;
-
-    private static final int BYTE_BUFFER_SIZE = 4096;
-
-    public static byte[] toByteArray(InputStream is) throws IOException {
-        ByteArrayOutputStream baos = out(is);
-
-        final byte[] bytes = baos.toByteArray();
-        return bytes;
-    }
-
-    public static ByteArrayOutputStream out(InputStream is) throws IOException {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream(
-                BYTE_STREAM_CAPACITY);
-        out(is, baos);
-        return baos;
-    }
-
-    public static void out(InputStream is, ByteArrayOutputStream baos) throws IOException {
-        byte[] buf = new byte[BYTE_BUFFER_SIZE];
-        int read;
-        while ((read = is.read(buf)) > 0) {
-            baos.write(buf, 0, read);
-        }
-    }
-}
Index: store/src/main/java/org/apache/james/imap/store/StoreSubscriptionManager.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/StoreSubscriptionManager.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/StoreSubscriptionManager.java	(Arbeitskopie)
@@ -32,28 +32,22 @@
 /**
  * Manages subscriptions.
  */
-public abstract class StoreSubscriptionManager implements Subscriber {
+public abstract class StoreSubscriptionManager<Id> implements Subscriber {
 
     private static final int INITIAL_SIZE = 32;
     
-    public StoreSubscriptionManager() {
-        super();
+    protected MailboxSessionMapperFactory<Id> mapperFactory;
+    
+    public StoreSubscriptionManager(final MailboxSessionMapperFactory<Id> mapperFactory) {
+        this.mapperFactory = mapperFactory;
     }
 
-    /**
-     * Create the SubscriptionMapper to use
-     * 
-     * @return mapper
-     */
-    protected abstract SubscriptionMapper createMapper(MailboxSession session) throws SubscriptionException;
-    
-
     /*
      * (non-Javadoc)
      * @see org.apache.james.imap.store.Subscriber#subscribe(org.apache.james.imap.mailbox.MailboxSession, java.lang.String)
      */
     public void subscribe(final MailboxSession session, final String mailbox) throws SubscriptionException {
-        final SubscriptionMapper mapper = createMapper(session);
+        final SubscriptionMapper mapper = mapperFactory.getSubscriptionMapper(session);
         try {
             mapper.execute(new TransactionalMapper.Transaction() {
 
@@ -69,8 +63,6 @@
         } catch (MailboxException e) {
             throw new SubscriptionException(e.getKey(), e);
         }
-
-
     }
 
     /**
@@ -80,14 +72,14 @@
      * @param mailbox
      * @return subscription 
      */
-    protected abstract Subscription createSubscription(final MailboxSession sonessi, final String mailbox);
+    protected abstract Subscription createSubscription(final MailboxSession session, final String mailbox);
 
     /*
      * (non-Javadoc)
      * @see org.apache.james.imap.store.Subscriber#subscriptions(org.apache.james.imap.mailbox.MailboxSession)
      */
     public Collection<String> subscriptions(final MailboxSession session) throws SubscriptionException {
-        final SubscriptionMapper mapper = createMapper(session);
+        final SubscriptionMapper mapper = mapperFactory.getSubscriptionMapper(session);
         final List<Subscription> subscriptions = mapper.findSubscriptionsForUser(session.getUser().getUserName());
         final Collection<String> results = new HashSet<String>(INITIAL_SIZE);
         for (Subscription subscription:subscriptions) {
@@ -101,7 +93,7 @@
      * @see org.apache.james.imap.store.Subscriber#unsubscribe(java.lang.String, java.lang.String)
      */
     public void unsubscribe(final MailboxSession session, final String mailbox) throws SubscriptionException {
-        final SubscriptionMapper mapper = createMapper(session);
+        final SubscriptionMapper mapper = mapperFactory.getSubscriptionMapper(session);
         try {
             mapper.execute(new TransactionalMapper.Transaction() {
 
Index: store/src/main/java/org/apache/james/imap/store/StoreMessageManager.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/StoreMessageManager.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/StoreMessageManager.java	(Arbeitskopie)
@@ -52,12 +52,13 @@
 import org.apache.james.imap.mailbox.MessageResult.FetchGroup;
 import org.apache.james.imap.mailbox.util.MailboxEventDispatcher;
 import org.apache.james.imap.mailbox.util.UidRange;
-import org.apache.james.imap.store.mail.MailboxMapper;
 import org.apache.james.imap.store.mail.MessageMapper;
 import org.apache.james.imap.store.mail.model.Header;
 import org.apache.james.imap.store.mail.model.Mailbox;
 import org.apache.james.imap.store.mail.model.MailboxMembership;
 import org.apache.james.imap.store.mail.model.PropertyBuilder;
+import org.apache.james.imap.store.streaming.ConfigurableMimeTokenStream;
+import org.apache.james.imap.store.streaming.CountingInputStream;
 import org.apache.james.imap.store.transaction.TransactionalMapper;
 import org.apache.james.mime4j.MimeException;
 import org.apache.james.mime4j.descriptor.MaximalBodyDescriptor;
@@ -73,23 +74,26 @@
  * 
  *
  */
-public abstract class StoreMailbox<Id> implements org.apache.james.imap.mailbox.Mailbox, StoreConstants {
+public abstract class StoreMessageManager<Id> implements org.apache.james.imap.mailbox.Mailbox, StoreConstants {
 
     private static final int INITIAL_SIZE_FLAGS = 32;
 
     private static final int INITIAL_SIZE_HEADERS = 32;
+    
+    private MessageMapper<Id> messageMapper;
 
-    private final Id mailboxId;
+    private final Mailbox<Id> mailbox;
     
     private MailboxEventDispatcher dispatcher;
 
     private UidConsumer<Id> consumer;
     
     
-    public StoreMailbox(final MailboxEventDispatcher dispatcher, UidConsumer<Id> consumer, final Mailbox<Id> mailbox) {
-        this.mailboxId = mailbox.getMailboxId();
+    public StoreMessageManager(MailboxSessionMapperFactory<Id> mapperFactory, final MailboxEventDispatcher dispatcher, UidConsumer<Id> consumer, final Mailbox<Id> mailbox, MailboxSession session) throws MailboxException {
+        this.mailbox = mailbox;
         this.dispatcher = dispatcher;
         this.consumer = consumer;
+        this.messageMapper = mapperFactory.getMessageMapper(session);
     }
 
     /**
@@ -111,14 +115,6 @@
     protected abstract MailboxMembership<Id> copyMessage(MailboxMembership<Id> originalMessage, long uid, MailboxSession session) throws MailboxException;
     
     /**
-     * Create a new {@link MessageMapper} to use for the current Request. 
-     * 
-     * @return mapper
-     */
-    protected abstract MessageMapper<Id> createMessageMapper(MailboxSession session) throws MailboxException;
-    
-    
-    /**
      * Return the underlying {@link Mailbox}
      * 
      * @param session
@@ -126,9 +122,8 @@
      * @throws MailboxException
      */
     
-    protected Mailbox<Id> getMailboxRow(MailboxSession session) throws MailboxException {
-        final MailboxMapper<Id> mapper = createMailboxMapper(session);
-        return mapper.findMailboxById(getMailboxId());
+    public Mailbox<Id> getMailboxEntity() throws MailboxException {
+        return mailbox;
     }
 
     /**
@@ -137,7 +132,7 @@
      * @return id
      */
     protected Id getMailboxId() {
-        return mailboxId;
+        return mailbox.getMailboxId();
     }
 
     /*
@@ -145,8 +140,7 @@
      * @see org.apache.james.imap.mailbox.Mailbox#getMessageCount(org.apache.james.imap.mailbox.MailboxSession)
      */
     public int getMessageCount(MailboxSession mailboxSession) throws MailboxException {
-        final MessageMapper<Id> messageMapper = createMessageMapper(mailboxSession);
-        return (int) messageMapper.countMessagesInMailbox();
+        return (int) messageMapper.countMessagesInMailbox(getMailboxId());
     }
 
     /*
@@ -157,11 +151,8 @@
             final MailboxSession mailboxSession,final boolean isRecent, final Flags flagsToBeSet)
     throws MailboxException {
         // this will hold the uid after the transaction was complete
-        final MessageMapper<Id> mapper = createMessageMapper(mailboxSession);
+        final long uid = consumer.reserveNextUid(getMailboxEntity(), mailboxSession);
         
-        final long uid = consumer.reserveNextUid(getMailboxRow(mailboxSession), mailboxSession);
-        
-        
         File file = null;
         try {
             // Create a temporary file and copy the message to it. We will work with the file as
@@ -282,14 +273,14 @@
             }
             final MailboxMembership<Id> message = createMessage(internalDate, uid, size, bodyStartOctet, new FileInputStream(file), flags, headers, propertyBuilder);
 
-            mapper.execute(new TransactionalMapper.Transaction() {
+            messageMapper.execute(new TransactionalMapper.Transaction() {
                 
                 public void run() throws MailboxException {
-                    mapper.save(message);
+                	messageMapper.save(getMailboxId(), message);
                 }
             });
            
-            dispatcher.added(uid, mailboxSession.getSessionId(), getMailboxRow(mailboxSession).getName());
+            dispatcher.added(uid, mailboxSession.getSessionId(), getMailboxEntity().getName());
             return uid;
         } catch (IOException e) {
             e.printStackTrace();
@@ -387,8 +378,7 @@
     public Iterator<MessageResult> getMessages(final MessageRange set, FetchGroup fetchGroup,
             MailboxSession mailboxSession) throws MailboxException {
         UidRange range = uidRangeForMessageSet(set);
-        final MessageMapper<Id> messageMapper = createMessageMapper(mailboxSession);
-        final List<MailboxMembership<Id>> rows = new ArrayList<MailboxMembership<Id>>(messageMapper.findInMailbox(set));
+        final List<MailboxMembership<Id>> rows = new ArrayList<MailboxMembership<Id>>(messageMapper.findInMailbox(getMailboxId(), set));
         return getMessages(fetchGroup, range, rows);
     }
 
@@ -421,20 +411,19 @@
     }
 
     private long[] recent(final boolean reset, MailboxSession mailboxSession) throws MailboxException {
-        final MessageMapper<Id> mapper = createMessageMapper(mailboxSession);
         final List<Long> results = new ArrayList<Long>();
 
-        mapper.execute(new TransactionalMapper.Transaction() {
+        messageMapper.execute(new TransactionalMapper.Transaction() {
 
             public void run() throws MailboxException {
-                final List<MailboxMembership<Id>> members = mapper.findRecentMessagesInMailbox();
+                final List<MailboxMembership<Id>> members = messageMapper.findRecentMessagesInMailbox(getMailboxId());
 
                 for (MailboxMembership<Id> member:members) {
                     results.add(member.getUid());
                     if (reset) {
                         member.unsetRecent();
                     }
-                    mapper.save(member);
+                    messageMapper.save(getMailboxId(), member);
                 }
             }
             
@@ -445,9 +434,7 @@
 
     private Long getFirstUnseen(MailboxSession mailboxSession) throws MailboxException {
         try {
-            final MessageMapper<Id> messageMapper = createMessageMapper(mailboxSession);
-            
-            final List<MailboxMembership<Id>> members = messageMapper.findUnseenMessagesInMailbox();
+            final List<MailboxMembership<Id>> members = messageMapper.findUnseenMessagesInMailbox(getMailboxId());
             final Iterator<MailboxMembership<Id>> it = members.iterator();
             final Long result;
             if (it.hasNext()) {
@@ -463,8 +450,7 @@
     }
 
     private int getUnseenCount(MailboxSession mailboxSession) throws MailboxException {
-        final MessageMapper<Id> messageMapper = createMessageMapper(mailboxSession);
-        final int count = (int) messageMapper.countUnseenMessagesInMailbox();
+        final int count = (int) messageMapper.countUnseenMessagesInMailbox(getMailboxId());
         return count;
     }
 
@@ -478,16 +464,15 @@
 
     private Iterator<Long> doExpunge(final MessageRange set, MailboxSession mailboxSession)
     throws MailboxException {
-        final MessageMapper<Id> mapper = createMessageMapper(mailboxSession);
         final Collection<Long> uids = new TreeSet<Long>();
         
-        mapper.execute(new TransactionalMapper.Transaction() {
+        messageMapper.execute(new TransactionalMapper.Transaction() {
 
             public void run() throws MailboxException {
-                final List<MailboxMembership<Id>> members = mapper.findMarkedForDeletionInMailbox(set);
+                final List<MailboxMembership<Id>> members = messageMapper.findMarkedForDeletionInMailbox(getMailboxId(), set);
                 for (MailboxMembership<Id> message:members) {
                     uids.add(message.getUid());
-                    mapper.delete(message);
+                    messageMapper.delete(message);
                 }  
             }
             
@@ -495,7 +480,7 @@
         
         Iterator<Long> uidIt = uids.iterator();
         while(uidIt.hasNext()) {
-            dispatcher.expunged(uidIt.next(), mailboxSession.getSessionId(), getMailboxRow(mailboxSession).getName());
+            dispatcher.expunged(uidIt.next(), mailboxSession.getSessionId(), getMailboxEntity().getName());
         }
         return uids.iterator();
     }
@@ -511,13 +496,12 @@
 
     private Map<Long, Flags> doSetFlags(final Flags flags, final boolean value, final boolean replace,
             final MessageRange set, final MailboxSession mailboxSession) throws MailboxException {
-        final MessageMapper<Id> mapper = createMessageMapper(mailboxSession);
         final SortedMap<Long, Flags> newFlagsByUid = new TreeMap<Long, Flags>();
         final Map<Long, Flags> originalFlagsByUid = new HashMap<Long, Flags>(INITIAL_SIZE_FLAGS);
-        mapper.execute(new TransactionalMapper.Transaction(){
+        messageMapper.execute(new TransactionalMapper.Transaction(){
 
             public void run() throws MailboxException {
-                final List<MailboxMembership<Id>> members = mapper.findInMailbox(set);
+                final List<MailboxMembership<Id>> members = messageMapper.findInMailbox(getMailboxId(), set);
                 for (final MailboxMembership<Id> member:members) {
                     originalFlagsByUid.put(member.getUid(), member.createFlags());
                     if (replace) {
@@ -532,7 +516,7 @@
                         member.setFlags(current);
                     }
                     newFlagsByUid.put(member.getUid(), member.createFlags());
-                    mapper.save(member);
+                    messageMapper.save(getMailboxId(), member);
                 }
             }
             
@@ -541,7 +525,7 @@
         Iterator<Long> it = newFlagsByUid.keySet().iterator();
         while (it.hasNext()) {
             Long uid = it.next();
-            dispatcher.flagsUpdated(uid, mailboxSession.getSessionId(), getMailboxRow(mailboxSession).getName(), originalFlagsByUid.get(uid), newFlagsByUid.get(uid));
+            dispatcher.flagsUpdated(uid, mailboxSession.getSessionId(), getMailboxEntity().getName(), originalFlagsByUid.get(uid), newFlagsByUid.get(uid));
 
         }
         return newFlagsByUid;
@@ -552,12 +536,12 @@
     }
 
     private long getUidValidity(MailboxSession mailboxSession) throws MailboxException {
-        final long result = getMailboxRow(mailboxSession).getUidValidity();
+        final long result = getMailboxEntity().getUidValidity();
         return result;
     }
 
     private long getUidNext(MailboxSession mailboxSession) throws MailboxException {
-        Mailbox<Id> mailbox = getMailboxRow(mailboxSession);
+        Mailbox<Id> mailbox = getMailboxEntity();
         if (mailbox == null) {
             throw new MailboxNotFoundException("Mailbox has been deleted");
         } else {
@@ -571,8 +555,7 @@
      * @see org.apache.james.imap.mailbox.Mailbox#search(org.apache.james.imap.mailbox.SearchQuery, org.apache.james.imap.mailbox.MailboxSession)
      */
     public Iterator<Long> search(SearchQuery query, MailboxSession mailboxSession) throws MailboxException {
-        final MessageMapper<Id> messageMapper = createMessageMapper(mailboxSession);
-        final List<MailboxMembership<Id>> members = messageMapper.searchMailbox(query);
+        final List<MailboxMembership<Id>> members = messageMapper.searchMailbox(getMailboxId(), query);
         final Set<Long> uids = new TreeSet<Long>();
         for (MailboxMembership<Id> member:members) {
             try {
@@ -594,64 +577,49 @@
         return uids.iterator();
     }
 
-
     /**
      * This mailbox is writable
      */
     public boolean isWriteable() {
         return true;
     }
-    
 
     private void copy(final List<MailboxMembership<Id>> originalRows, final MailboxSession session) throws MailboxException {
         try {
             final List<MailboxMembership<Id>> copiedRows = new ArrayList<MailboxMembership<Id>>();
-            final MessageMapper<Id> mapper = createMessageMapper(session);
-            
 
             for (final MailboxMembership<Id> originalMessage:originalRows) {
-                final long uid = consumer.reserveNextUid(getMailboxRow(session),session);
-                
-                mapper.execute(new TransactionalMapper.Transaction() {
+                final long uid = consumer.reserveNextUid(getMailboxEntity(),session);
+                messageMapper.execute(new TransactionalMapper.Transaction() {
 
                     public void run() throws MailboxException {
                         final MailboxMembership<Id> newRow = copyMessage(originalMessage, uid, session);
-                        mapper.save(newRow);
+                        messageMapper.save(getMailboxId(), newRow);
                         copiedRows.add(newRow);
-                          
                     }
                     
                 });
-
-                
-            }  
-            
-           
-            
-            
+            }
             // Wait until commit before issuing events
             for (MailboxMembership<Id> newMember:copiedRows) {
-                dispatcher.added(newMember.getUid(), session.getSessionId(), getMailboxRow(session).getName());
+                dispatcher.added(newMember.getUid(), session.getSessionId(), getMailboxEntity().getName());
             }
-            
         } catch (MessagingException e) {
             throw new MailboxException(HumanReadableText.FAILURE_MAIL_PARSE, e);
         }
     }
 
     /**
-     * Copy the {@link MessageSet} to the {@link StoreMailbox}
+     * Copy the {@link MessageSet} to the {@link StoreMessageManager}
      * 
      * @param set
      * @param toMailbox
      * @param session
      * @throws MailboxException
      */
-    public void copyTo(MessageRange set, StoreMailbox<Id> toMailbox, MailboxSession session) throws MailboxException {
+    public void copyTo(MessageRange set, StoreMessageManager<Id> toMailbox, MailboxSession session) throws MailboxException {
         try {
-            final MessageMapper<Id> mapper = createMessageMapper(session);
-            
-            final List<MailboxMembership<Id>> originalRows = mapper.findInMailbox(set);
+            final List<MailboxMembership<Id>> originalRows = messageMapper.findInMailbox(getMailboxId(), set);
             toMailbox.copy(originalRows, session);
 
         } catch (MessagingException e) {
@@ -686,17 +654,7 @@
                 unseenCount = 0;
                 break;
         }
-            
         return new MailboxMetaData(recent, permanentFlags, uidValidity, uidNext, messageCount, unseenCount, firstUnseen, isWriteable());
     }
-    
-    
-    /**
-     * Create MailboxMapper 
-     * 
-     * @return mapper
-     */
-    protected abstract MailboxMapper<Id> createMailboxMapper(MailboxSession session) throws MailboxException;
-    
 
 }
Index: store/src/main/java/org/apache/james/imap/store/StoreMailboxManager.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/StoreMailboxManager.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/StoreMailboxManager.java	(Arbeitskopie)
@@ -68,22 +68,23 @@
 
     private final MailboxEventDispatcher dispatcher = new MailboxEventDispatcher();
     private final DelegatingMailboxListener delegatingListener = new DelegatingMailboxListener();
-    private final Authenticator authenticator;    
-    private final Subscriber subscriber;    
+    private final Authenticator authenticator;
+    private final Subscriber subscriber;
+    protected final MailboxSessionMapperFactory<Id> mailboxSessionMapperFactory;
     private final char delimiter;
 
     private UidConsumer<Id> consumer;
     
-    public StoreMailboxManager(final Authenticator authenticator, final Subscriber subscriber, final UidConsumer<Id> consumer) {
-        this(authenticator, subscriber, consumer, '.');
+    public StoreMailboxManager(MailboxSessionMapperFactory<Id> mailboxSessionMapperFactory, final Authenticator authenticator, final Subscriber subscriber, final UidConsumer<Id> consumer) {
+        this(mailboxSessionMapperFactory, authenticator, subscriber, consumer, '.');
     }
-
     
-    public StoreMailboxManager(final Authenticator authenticator, final Subscriber subscriber, final UidConsumer<Id> consumer, final char delimiter) {
+    public StoreMailboxManager(MailboxSessionMapperFactory<Id> mailboxSessionMapperFactory, final Authenticator authenticator, final Subscriber subscriber, final UidConsumer<Id> consumer, final char delimiter) {
         this.authenticator = authenticator;
         this.subscriber = subscriber;
         this.delimiter = delimiter;
         this.consumer = consumer;
+        this.mailboxSessionMapperFactory = mailboxSessionMapperFactory;
     }
 
     /**
@@ -92,22 +93,15 @@
      * @param mailboxRow
      * @return storeMailbox
      */
-    protected abstract StoreMailbox<Id> createMailbox(MailboxEventDispatcher dispatcher, UidConsumer<Id> consumer, Mailbox<Id> mailboxRow, MailboxSession session) throws MailboxException;
+    protected abstract StoreMessageManager<Id> createMessageManager(MailboxEventDispatcher dispatcher, UidConsumer<Id> consumer, Mailbox<Id> mailboxRow, MailboxSession session) throws MailboxException;
     
     /**
-     * Create the MailboxMapper
-     * 
-     * @return mailboxMapper
-     */
-    protected abstract MailboxMapper<Id> createMailboxMapper(MailboxSession session) throws MailboxException;
-    
-    /**
      * Create a Mailbox for the given namespace and store it to the underlying storage
      * 
      * @param namespaceName
      * @throws MailboxException
      */
-    protected abstract void doCreate(String namespaceName, MailboxSession session) throws MailboxException;
+    protected abstract void doCreateMailbox(String namespaceName, MailboxSession session) throws MailboxException;
     
     
     /*
@@ -126,9 +120,9 @@
      * @return mailbox the mailbox for the given name
      * @throws MailboxException get thrown if no Mailbox could be found for the given name
      */
-    private StoreMailbox<Id> doGetMailbox(String mailboxName, MailboxSession session) throws MailboxException {
+    private StoreMessageManager<Id> doGetMailbox(String mailboxName, MailboxSession session) throws MailboxException {
         synchronized (mutex) {
-            final MailboxMapper<Id> mapper = createMailboxMapper(session);
+            final MailboxMapper<Id> mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
             Mailbox<Id> mailboxRow = mapper.findMailboxByName(mailboxName);
             
             if (mailboxRow == null) {
@@ -138,7 +132,7 @@
             } else {
                 getLog().debug("Loaded mailbox " + mailboxName);
 
-                StoreMailbox<Id> result = createMailbox(dispatcher, consumer, mailboxRow, session);
+                StoreMessageManager<Id> result = createMessageManager(dispatcher, consumer, mailboxRow, session);
                 result.addListener(delegatingListener);
                 return result;
             }
@@ -173,7 +167,7 @@
                         final String mailbox = namespaceName
                         .substring(0, index);
                         if (!mailboxExists(mailbox, mailboxSession)) {
-                            doCreate(mailbox, mailboxSession);
+                            doCreateMailbox(mailbox, mailboxSession);
                         }
                     }
                     index = namespaceName.indexOf(delimiter, ++index);
@@ -181,7 +175,7 @@
                 if (mailboxExists(namespaceName, mailboxSession)) {
                     throw new MailboxExistsException(namespaceName); 
                 } else {
-                    doCreate(namespaceName, mailboxSession);
+                    doCreateMailbox(namespaceName, mailboxSession);
                 }
             }
         }
@@ -197,7 +191,7 @@
         synchronized (mutex) {
             // TODO put this into a serilizable transaction
             
-            final MailboxMapper<Id> mapper = createMailboxMapper(session);
+            final MailboxMapper<Id> mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
             
             mapper.execute(new TransactionalMapper.Transaction() {
 
@@ -228,7 +222,7 @@
                 throw new MailboxExistsException(to);
             }
 
-            final MailboxMapper<Id> mapper = createMailboxMapper(session);                
+            final MailboxMapper<Id> mapper = mailboxSessionMapperFactory.getMailboxMapper(session);                
             mapper.execute(new TransactionalMapper.Transaction() {
 
                 public void run() throws MailboxException {
@@ -288,8 +282,8 @@
             MailboxSession session) throws MailboxException {
         synchronized (mutex) {
 
-        StoreMailbox<Id> toMailbox = doGetMailbox(to, session);
-        StoreMailbox<Id> fromMailbox = doGetMailbox(from, session);
+        StoreMessageManager<Id> toMailbox = doGetMailbox(to, session);
+        StoreMessageManager<Id> fromMailbox = doGetMailbox(from, session);
             fromMailbox.copyTo(set, toMailbox, session);
         }
     }
@@ -314,7 +308,7 @@
                 delimiter).replace(freeWildcard, SQL_WILDCARD_CHAR)
                 .replace(localWildcard, SQL_WILDCARD_CHAR);
 
-        final MailboxMapper<Id> mapper = createMailboxMapper(session);
+        final MailboxMapper<Id> mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
         final List<Mailbox<Id>> mailboxes = mapper.findMailboxWithNameLike(search);
         final List<MailboxMetaData> results = new ArrayList<MailboxMetaData>(mailboxes.size());
         for (Mailbox<Id> mailbox: mailboxes) {
@@ -354,7 +348,7 @@
      */
     public boolean mailboxExists(String mailboxName, MailboxSession session) throws MailboxException {
         synchronized (mutex) {
-            final MailboxMapper<Id> mapper = createMailboxMapper(session);
+            final MailboxMapper<Id> mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
             final long count = mapper.countMailboxesWithName(mailboxName);
             if (count == 0) {
                 return false;
Index: store/src/main/java/org/apache/james/imap/store/StoreMailbox.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/StoreMailbox.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/StoreMailbox.java	(Arbeitskopie)
@@ -1,702 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.imap.store;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PushbackInputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.TreeSet;
-
-import javax.mail.Flags;
-import javax.mail.MessagingException;
-
-import org.apache.commons.lang.ArrayUtils;
-import org.apache.james.imap.api.display.HumanReadableText;
-import org.apache.james.imap.mailbox.MailboxException;
-import org.apache.james.imap.mailbox.MailboxListener;
-import org.apache.james.imap.mailbox.MailboxNotFoundException;
-import org.apache.james.imap.mailbox.MailboxSession;
-import org.apache.james.imap.mailbox.MessageRange;
-import org.apache.james.imap.mailbox.MessageResult;
-import org.apache.james.imap.mailbox.SearchQuery;
-import org.apache.james.imap.mailbox.MessageResult.FetchGroup;
-import org.apache.james.imap.mailbox.util.MailboxEventDispatcher;
-import org.apache.james.imap.mailbox.util.UidRange;
-import org.apache.james.imap.store.mail.MailboxMapper;
-import org.apache.james.imap.store.mail.MessageMapper;
-import org.apache.james.imap.store.mail.model.Header;
-import org.apache.james.imap.store.mail.model.Mailbox;
-import org.apache.james.imap.store.mail.model.MailboxMembership;
-import org.apache.james.imap.store.mail.model.PropertyBuilder;
-import org.apache.james.imap.store.transaction.TransactionalMapper;
-import org.apache.james.mime4j.MimeException;
-import org.apache.james.mime4j.descriptor.MaximalBodyDescriptor;
-import org.apache.james.mime4j.parser.MimeEntityConfig;
-import org.apache.james.mime4j.parser.MimeTokenStream;
-
-import com.sun.mail.imap.protocol.MessageSet;
-
-/**
- * Abstract base class for {@link org.apache.james.imap.mailbox.Mailbox} implementations.
- * 
- * This class provides a high-level api, and is most times the best to just extend
- * 
- *
- */
-public abstract class StoreMailbox<Id> implements org.apache.james.imap.mailbox.Mailbox, StoreConstants {
-
-    private static final int INITIAL_SIZE_FLAGS = 32;
-
-    private static final int INITIAL_SIZE_HEADERS = 32;
-
-    private final Id mailboxId;
-    
-    private MailboxEventDispatcher dispatcher;
-
-    private UidConsumer<Id> consumer;
-    
-    
-    public StoreMailbox(final MailboxEventDispatcher dispatcher, UidConsumer<Id> consumer, final Mailbox<Id> mailbox) {
-        this.mailboxId = mailbox.getMailboxId();
-        this.dispatcher = dispatcher;
-        this.consumer = consumer;
-    }
-
-    /**
-     * Return the {@link MailboxEventDispatcher} for this Mailbox
-     * 
-     * @return dispatcher
-     */
-    protected MailboxEventDispatcher getDispatcher() {
-        return dispatcher;
-    }
-    
-    /**
-     * Copy the given {@link MailboxMembership} to a new instance with the given uid
-     * 
-     * @param originalMessage
-     * @param uid
-     * @return membershipCopy
-     */
-    protected abstract MailboxMembership<Id> copyMessage(MailboxMembership<Id> originalMessage, long uid, MailboxSession session) throws MailboxException;
-    
-    /**
-     * Create a new {@link MessageMapper} to use for the current Request. 
-     * 
-     * @return mapper
-     */
-    protected abstract MessageMapper<Id> createMessageMapper(MailboxSession session) throws MailboxException;
-    
-    
-    /**
-     * Return the underlying {@link Mailbox}
-     * 
-     * @param session
-     * @return mailbox
-     * @throws MailboxException
-     */
-    
-    protected Mailbox<Id> getMailboxRow(MailboxSession session) throws MailboxException {
-        final MailboxMapper<Id> mapper = createMailboxMapper(session);
-        return mapper.findMailboxById(getMailboxId());
-    }
-
-    /**
-     * Return the Id of the wrapped {@link Mailbox}
-     * 
-     * @return id
-     */
-    protected Id getMailboxId() {
-        return mailboxId;
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.mailbox.Mailbox#getMessageCount(org.apache.james.imap.mailbox.MailboxSession)
-     */
-    public int getMessageCount(MailboxSession mailboxSession) throws MailboxException {
-        final MessageMapper<Id> messageMapper = createMessageMapper(mailboxSession);
-        return (int) messageMapper.countMessagesInMailbox();
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.mailbox.Mailbox#appendMessage(byte[], java.util.Date, org.apache.james.imap.mailbox.MailboxSession, boolean, javax.mail.Flags)
-     */
-    public long appendMessage(final InputStream msgIn, final Date internalDate,
-            final MailboxSession mailboxSession,final boolean isRecent, final Flags flagsToBeSet)
-    throws MailboxException {
-        // this will hold the uid after the transaction was complete
-        final MessageMapper<Id> mapper = createMessageMapper(mailboxSession);
-        
-        final long uid = consumer.reserveNextUid(getMailboxRow(mailboxSession), mailboxSession);
-        
-        
-        File file = null;
-        try {
-            // Create a temporary file and copy the message to it. We will work with the file as
-            // source for the InputStream
-            file = File.createTempFile("imap", ".msg");
-            FileOutputStream out = new FileOutputStream(file);
-            
-            byte[] buf = new byte[1024];
-            int i = 0;
-            while ((i = msgIn.read(buf)) != -1) {
-                out.write(buf, 0, i);
-            }
-            out.flush();
-            out.close();
-            
-            FileInputStream tmpMsgIn = new FileInputStream(file);
-            // To be thread safe, we first get our own copy and the
-            // exclusive
-            // Uid
-            // TODO create own message_id and assign uid later
-            // at the moment it could lead to the situation that uid 5
-            // is
-            // inserted long before 4, when
-            // mail 4 is big and comes over a slow connection.
-            final int size = tmpMsgIn.available();
-            final int bodyStartOctet = bodyStartOctet(new FileInputStream(file));
-
-            // Disable line length... This should be handled by the smtp server component and not the parser itself
-            // https://issues.apache.org/jira/browse/IMAP-122
-            MimeEntityConfig config = new MimeEntityConfig();
-            config.setMaximalBodyDescriptor(true);
-            config.setMaxLineLen(-1);
-            final ConfigurableMimeTokenStream parser = new ConfigurableMimeTokenStream(config);
-           
-            parser.setRecursionMode(MimeTokenStream.M_NO_RECURSE);
-            parser.parse(new FileInputStream(file));
-            final List<Header> headers = new ArrayList<Header>(INITIAL_SIZE_HEADERS);
-            
-            int lineNumber = 0;
-            int next = parser.next();
-            while (next != MimeTokenStream.T_BODY
-                    && next != MimeTokenStream.T_END_OF_STREAM
-                    && next != MimeTokenStream.T_START_MULTIPART) {
-                if (next == MimeTokenStream.T_FIELD) {
-                    String fieldValue = parser.getField().getBody();
-                    if (fieldValue.endsWith("\r\f")) {
-                        fieldValue = fieldValue.substring(0,fieldValue.length() - 2);
-                    }
-                    if (fieldValue.startsWith(" ")) {
-                        fieldValue = fieldValue.substring(1);
-                    }
-                    final Header header 
-                        = createHeader(++lineNumber, parser.getField().getName(), 
-                            fieldValue);
-                    headers.add(header);
-                }
-                next = parser.next();
-            }
-            final MaximalBodyDescriptor descriptor = (MaximalBodyDescriptor) parser.getBodyDescriptor();
-            final PropertyBuilder propertyBuilder = new PropertyBuilder();
-            final String mediaType;
-            final String mediaTypeFromHeader = descriptor.getMediaType();
-            final String subType;
-            if (mediaTypeFromHeader == null) {
-                mediaType = "text";
-                subType = "plain";
-            } else {
-                mediaType = mediaTypeFromHeader;
-                subType = descriptor.getSubType();
-            }
-            propertyBuilder.setMediaType(mediaType);
-            propertyBuilder.setSubType(subType);
-            propertyBuilder.setContentID(descriptor.getContentId());
-            propertyBuilder.setContentDescription(descriptor.getContentDescription());
-            propertyBuilder.setContentLocation(descriptor.getContentLocation());
-            propertyBuilder.setContentMD5(descriptor.getContentMD5Raw());
-            propertyBuilder.setContentTransferEncoding(descriptor.getTransferEncoding());
-            propertyBuilder.setContentLanguage(descriptor.getContentLanguage());
-            propertyBuilder.setContentDispositionType(descriptor.getContentDispositionType());
-            propertyBuilder.setContentDispositionParameters(descriptor.getContentDispositionParameters());
-            propertyBuilder.setContentTypeParameters(descriptor.getContentTypeParameters());
-            // Add missing types
-            final String codeset = descriptor.getCharset();
-            if (codeset == null) {
-                if ("TEXT".equalsIgnoreCase(mediaType)) {
-                    propertyBuilder.setCharset("us-ascii");
-                }
-            } else {
-                propertyBuilder.setCharset(codeset);
-            }
-            
-            final String boundary = descriptor.getBoundary();
-            if (boundary != null) {
-                propertyBuilder.setBoundary(boundary);
-            }   
-            if ("text".equalsIgnoreCase(mediaType)) {
-                final CountingInputStream bodyStream = new CountingInputStream(parser.getInputStream());
-                bodyStream.readAll();
-                long lines = bodyStream.getLineCount();
-                
-                next = parser.next();
-                if (next == MimeTokenStream.T_EPILOGUE)  {
-                    final CountingInputStream epilogueStream = new CountingInputStream(parser.getInputStream());
-                    epilogueStream.readAll();
-                    lines+=epilogueStream.getLineCount();
-                }
-                propertyBuilder.setTextualLineCount(lines);
-            }
-            
-            final Flags flags;
-            if (flagsToBeSet == null) {
-                flags = new Flags();
-            } else {
-                flags = flagsToBeSet;
-            }
-            if (isRecent) {
-                flags.add(Flags.Flag.RECENT);
-            }
-            final MailboxMembership<Id> message = createMessage(internalDate, uid, size, bodyStartOctet, new FileInputStream(file), flags, headers, propertyBuilder);
-
-            mapper.execute(new TransactionalMapper.Transaction() {
-                
-                public void run() throws MailboxException {
-                    mapper.save(message);
-                }
-            });
-           
-            dispatcher.added(uid, mailboxSession.getSessionId(), getMailboxRow(mailboxSession).getName());
-            return uid;
-        } catch (IOException e) {
-            e.printStackTrace();
-            throw new MailboxException(HumanReadableText.FAILURE_MAIL_PARSE, e);
-        } catch (MessagingException e) {
-            e.printStackTrace();
-            throw new MailboxException(HumanReadableText.FAILURE_MAIL_PARSE, e);
-        } catch (MimeException e) {
-            e.printStackTrace();
-            throw new MailboxException(HumanReadableText.FAILURE_MAIL_PARSE, e);
-        } finally {
-            // delete the temporary file if one was specified
-            if (file != null) {
-                file.delete();
-            }
-        }
-
-    }
-
-    /**
-     * Return the position in the given {@link InputStream} at which the Body of the 
-     * Message starts
-     * 
-     * @param msgIn
-     * @return bodyStartOctet
-     * @throws IOException
-     */
-    private int bodyStartOctet(InputStream msgIn) throws IOException{
-        // we need to pushback maximal 3 bytes
-        PushbackInputStream in = new PushbackInputStream(msgIn,3);
-        
-        int bodyStartOctet = in.available();
-        int i = -1;
-        int count = 0;
-        while ((i = in.read()) != -1 && in.available() > 4) {
-            if (i == 0x0D) {
-                int a = in.read();
-                if (a == 0x0A) {
-                    int b = in.read();
-
-                    if (b == 0x0D) {
-                        int c = in.read();
-
-                        if (c == 0x0A) {
-                            bodyStartOctet = count+4;
-                            break;
-                        }
-                        in.unread(c);
-                    }
-                    in.unread(b);
-                }
-                in.unread(a);
-            }
-            count++;
-        }
-        
-        // close the stream
-        in.close();
-        
-        return bodyStartOctet;
-    }
-
-    /**
-     * Create a new {@link MailboxMembership} for the given data
-     * 
-     * @param internalDate
-     * @param uid
-     * @param size
-     * @param bodyStartOctet
-     * @param documentIn
-     * @param flags
-     * @param headers
-     * @param propertyBuilder
-     * @return membership
-     * @throws MailboxException 
-     */
-    protected abstract MailboxMembership<Id> createMessage(Date internalDate, final long uid, final int size, int bodyStartOctet, 
-            final InputStream documentIn, final Flags flags, final List<Header> headers, PropertyBuilder propertyBuilder) throws MailboxException;
-    
-    /**
-     * Create a new {@link Header} for the given data
-     * 
-     * @param lineNumber
-     * @param name
-     * @param value
-     * @return header
-     */
-    protected abstract Header createHeader(int lineNumber, String name, String value);
-
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.mailbox.Mailbox#getMessages(org.apache.james.imap.mailbox.MessageRange, org.apache.james.imap.mailbox.MessageResult.FetchGroup, org.apache.james.imap.mailbox.MailboxSession)
-     */
-    public Iterator<MessageResult> getMessages(final MessageRange set, FetchGroup fetchGroup,
-            MailboxSession mailboxSession) throws MailboxException {
-        UidRange range = uidRangeForMessageSet(set);
-        final MessageMapper<Id> messageMapper = createMessageMapper(mailboxSession);
-        final List<MailboxMembership<Id>> rows = new ArrayList<MailboxMembership<Id>>(messageMapper.findInMailbox(set));
-        return getMessages(fetchGroup, range, rows);
-    }
-
-    private ResultIterator<Id> getMessages(FetchGroup result, UidRange range, List<MailboxMembership<Id>> messages) {
-        final ResultIterator<Id> results = getResults(result, messages);
-        return results;
-    }
-
-    private ResultIterator<Id> getResults(FetchGroup result, List<MailboxMembership<Id>> messages) {
-        final ResultIterator<Id> results = new ResultIterator<Id>(messages,result);
-        return results;
-    }
-
-    private static UidRange uidRangeForMessageSet(MessageRange set) throws MailboxException {
-        if (set.getType().equals(MessageRange.Type.ALL)) {
-            return new UidRange(1, -1);
-        } else {
-            return new UidRange(set.getUidFrom(), set.getUidTo());
-        }
-    }
-
-    private Flags getPermanentFlags() {
-        Flags permanentFlags = new Flags();
-        permanentFlags.add(Flags.Flag.ANSWERED);
-        permanentFlags.add(Flags.Flag.DELETED);
-        permanentFlags.add(Flags.Flag.DRAFT);
-        permanentFlags.add(Flags.Flag.FLAGGED);
-        permanentFlags.add(Flags.Flag.SEEN);
-        return permanentFlags;
-    }
-
-    private long[] recent(final boolean reset, MailboxSession mailboxSession) throws MailboxException {
-        final MessageMapper<Id> mapper = createMessageMapper(mailboxSession);
-        final List<Long> results = new ArrayList<Long>();
-
-        mapper.execute(new TransactionalMapper.Transaction() {
-
-            public void run() throws MailboxException {
-                final List<MailboxMembership<Id>> members = mapper.findRecentMessagesInMailbox();
-
-                for (MailboxMembership<Id> member:members) {
-                    results.add(member.getUid());
-                    if (reset) {
-                        member.unsetRecent();
-                    }
-                    mapper.save(member);
-                }
-            }
-            
-        });;
-        
-        return ArrayUtils.toPrimitive(results.toArray(new Long[results.size()]));
-    }
-
-    private Long getFirstUnseen(MailboxSession mailboxSession) throws MailboxException {
-        try {
-            final MessageMapper<Id> messageMapper = createMessageMapper(mailboxSession);
-            
-            final List<MailboxMembership<Id>> members = messageMapper.findUnseenMessagesInMailbox();
-            final Iterator<MailboxMembership<Id>> it = members.iterator();
-            final Long result;
-            if (it.hasNext()) {
-                final MailboxMembership<Id> member = it.next();
-                result = member.getUid();
-            } else {
-                result = null;
-            }
-            return result;
-        } catch (MessagingException e) {
-            throw new MailboxException(HumanReadableText.FAILURE_MAIL_PARSE, e);
-        }
-    }
-
-    private int getUnseenCount(MailboxSession mailboxSession) throws MailboxException {
-        final MessageMapper<Id> messageMapper = createMessageMapper(mailboxSession);
-        final int count = (int) messageMapper.countUnseenMessagesInMailbox();
-        return count;
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.mailbox.Mailbox#expunge(org.apache.james.imap.mailbox.MessageRange, org.apache.james.imap.mailbox.MailboxSession)
-     */
-    public Iterator<Long> expunge(MessageRange set, MailboxSession mailboxSession) throws MailboxException {
-        return doExpunge(set, mailboxSession);
-    }
-
-    private Iterator<Long> doExpunge(final MessageRange set, MailboxSession mailboxSession)
-    throws MailboxException {
-        final MessageMapper<Id> mapper = createMessageMapper(mailboxSession);
-        final Collection<Long> uids = new TreeSet<Long>();
-        
-        mapper.execute(new TransactionalMapper.Transaction() {
-
-            public void run() throws MailboxException {
-                final List<MailboxMembership<Id>> members = mapper.findMarkedForDeletionInMailbox(set);
-                for (MailboxMembership<Id> message:members) {
-                    uids.add(message.getUid());
-                    mapper.delete(message);
-                }  
-            }
-            
-        });
-        
-        Iterator<Long> uidIt = uids.iterator();
-        while(uidIt.hasNext()) {
-            dispatcher.expunged(uidIt.next(), mailboxSession.getSessionId(), getMailboxRow(mailboxSession).getName());
-        }
-        return uids.iterator();
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.mailbox.Mailbox#setFlags(javax.mail.Flags, boolean, boolean, org.apache.james.imap.mailbox.MessageRange, org.apache.james.imap.mailbox.MailboxSession)
-     */
-    public Map<Long, Flags> setFlags(Flags flags, boolean value, boolean replace,
-            MessageRange set, MailboxSession mailboxSession) throws MailboxException {
-        return doSetFlags(flags, value, replace, set, mailboxSession);
-    }
-
-    private Map<Long, Flags> doSetFlags(final Flags flags, final boolean value, final boolean replace,
-            final MessageRange set, final MailboxSession mailboxSession) throws MailboxException {
-        final MessageMapper<Id> mapper = createMessageMapper(mailboxSession);
-        final SortedMap<Long, Flags> newFlagsByUid = new TreeMap<Long, Flags>();
-        final Map<Long, Flags> originalFlagsByUid = new HashMap<Long, Flags>(INITIAL_SIZE_FLAGS);
-        mapper.execute(new TransactionalMapper.Transaction(){
-
-            public void run() throws MailboxException {
-                final List<MailboxMembership<Id>> members = mapper.findInMailbox(set);
-                for (final MailboxMembership<Id> member:members) {
-                    originalFlagsByUid.put(member.getUid(), member.createFlags());
-                    if (replace) {
-                        member.setFlags(flags);
-                    } else {
-                        Flags current = member.createFlags();
-                        if (value) {
-                            current.add(flags);
-                        } else {
-                            current.remove(flags);
-                        }
-                        member.setFlags(current);
-                    }
-                    newFlagsByUid.put(member.getUid(), member.createFlags());
-                    mapper.save(member);
-                }
-            }
-            
-        });
-       
-        Iterator<Long> it = newFlagsByUid.keySet().iterator();
-        while (it.hasNext()) {
-            Long uid = it.next();
-            dispatcher.flagsUpdated(uid, mailboxSession.getSessionId(), getMailboxRow(mailboxSession).getName(), originalFlagsByUid.get(uid), newFlagsByUid.get(uid));
-
-        }
-        return newFlagsByUid;
-    }
-
-    public void addListener(MailboxListener listener) throws MailboxException {
-        dispatcher.addMailboxListener(listener);
-    }
-
-    private long getUidValidity(MailboxSession mailboxSession) throws MailboxException {
-        final long result = getMailboxRow(mailboxSession).getUidValidity();
-        return result;
-    }
-
-    private long getUidNext(MailboxSession mailboxSession) throws MailboxException {
-        Mailbox<Id> mailbox = getMailboxRow(mailboxSession);
-        if (mailbox == null) {
-            throw new MailboxNotFoundException("Mailbox has been deleted");
-        } else {
-            final long lastUid = mailbox.getLastUid();
-            return lastUid + 1;
-        }
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.mailbox.Mailbox#search(org.apache.james.imap.mailbox.SearchQuery, org.apache.james.imap.mailbox.MailboxSession)
-     */
-    public Iterator<Long> search(SearchQuery query, MailboxSession mailboxSession) throws MailboxException {
-        final MessageMapper<Id> messageMapper = createMessageMapper(mailboxSession);
-        final List<MailboxMembership<Id>> members = messageMapper.searchMailbox(query);
-        final Set<Long> uids = new TreeSet<Long>();
-        for (MailboxMembership<Id> member:members) {
-            try {
-                final MessageSearches searches = new MessageSearches();
-                searches.setLog(mailboxSession.getLog());
-                if (searches.isMatch(query, member)) {
-                    uids.add(member.getUid());
-                }
-            } catch (MailboxException e) {
-                mailboxSession.getLog()
-                .info(
-                        "Cannot test message against search criteria. Will continue to test other messages.",
-                        e);
-                if (mailboxSession.getLog().isDebugEnabled())
-                    mailboxSession.getLog().debug("UID: " + member.getUid());
-            }
-        }
-
-        return uids.iterator();
-    }
-
-
-    /**
-     * This mailbox is writable
-     */
-    public boolean isWriteable() {
-        return true;
-    }
-    
-
-    private void copy(final List<MailboxMembership<Id>> originalRows, final MailboxSession session) throws MailboxException {
-        try {
-            final List<MailboxMembership<Id>> copiedRows = new ArrayList<MailboxMembership<Id>>();
-            final MessageMapper<Id> mapper = createMessageMapper(session);
-            
-
-            for (final MailboxMembership<Id> originalMessage:originalRows) {
-                final long uid = consumer.reserveNextUid(getMailboxRow(session),session);
-                
-                mapper.execute(new TransactionalMapper.Transaction() {
-
-                    public void run() throws MailboxException {
-                        final MailboxMembership<Id> newRow = copyMessage(originalMessage, uid, session);
-                        mapper.save(newRow);
-                        copiedRows.add(newRow);
-                          
-                    }
-                    
-                });
-
-                
-            }  
-            
-           
-            
-            
-            // Wait until commit before issuing events
-            for (MailboxMembership<Id> newMember:copiedRows) {
-                dispatcher.added(newMember.getUid(), session.getSessionId(), getMailboxRow(session).getName());
-            }
-            
-        } catch (MessagingException e) {
-            throw new MailboxException(HumanReadableText.FAILURE_MAIL_PARSE, e);
-        }
-    }
-
-    /**
-     * Copy the {@link MessageSet} to the {@link StoreMailbox}
-     * 
-     * @param set
-     * @param toMailbox
-     * @param session
-     * @throws MailboxException
-     */
-    public void copyTo(MessageRange set, StoreMailbox<Id> toMailbox, MailboxSession session) throws MailboxException {
-        try {
-            final MessageMapper<Id> mapper = createMessageMapper(session);
-            
-            final List<MailboxMembership<Id>> originalRows = mapper.findInMailbox(set);
-            toMailbox.copy(originalRows, session);
-
-        } catch (MessagingException e) {
-            e.printStackTrace();
-            throw new MailboxException(HumanReadableText.FAILURE_MAIL_PARSE, e);
-        }
-    }
-    
-    /**
-     * @see {@link Mailbox#getMetaData(boolean, MailboxSession, FetchGroup)}
-     */
-    public MetaData getMetaData(boolean resetRecent, MailboxSession mailboxSession, 
-            org.apache.james.imap.mailbox.Mailbox.MetaData.FetchGroup fetchGroup) throws MailboxException {
-        final long[] recent = recent(resetRecent, mailboxSession);
-        final Flags permanentFlags = getPermanentFlags();
-        final long uidValidity = getUidValidity(mailboxSession);
-        final long uidNext = getUidNext(mailboxSession);
-        final int messageCount = getMessageCount(mailboxSession);
-        final int unseenCount;
-        final Long firstUnseen;
-        switch (fetchGroup) {
-            case UNSEEN_COUNT:
-                unseenCount = getUnseenCount(mailboxSession);
-                firstUnseen = null;
-                break;
-            case FIRST_UNSEEN:
-                firstUnseen = getFirstUnseen(mailboxSession);
-                unseenCount = 0;
-                break;
-            default:
-                firstUnseen = null;
-                unseenCount = 0;
-                break;
-        }
-            
-        return new MailboxMetaData(recent, permanentFlags, uidValidity, uidNext, messageCount, unseenCount, firstUnseen, isWriteable());
-    }
-    
-    
-    /**
-     * Create MailboxMapper 
-     * 
-     * @return mapper
-     */
-    protected abstract MailboxMapper<Id> createMailboxMapper(MailboxSession session) throws MailboxException;
-    
-
-}
Index: store/src/main/java/org/apache/james/imap/store/RewindableInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/RewindableInputStream.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/RewindableInputStream.java	(Arbeitskopie)
@@ -1,73 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-package org.apache.james.imap.store;
-
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * {@link FilterInputStream} which support the get rewinded.
- * 
- * The rewinding will get delayed as long as possible. So if you call
- * rewind, it will only get performed when needed
- * 
- * Be sure to call {@link #close()} to cleanup temporary data when you 
- * are done with reading from the stream
- * 
- *
- */
-public abstract class RewindableInputStream extends FilterInputStream{
-
-    private boolean rewind;
-
-    protected RewindableInputStream(InputStream in) {
-        super(in);
-    }
-
-    /**
-     * Return if the stream needs to get rewinded
-     * 
-     * @return needsRewind
-     */
-    public final boolean needsRewind() {
-        return rewind;
-    }
-    
-    /**
-     * Rewind was done
-     */
-    protected final void rewindDone() {
-        this.rewind = false;
-    }
-    
-    /**
-     * Mark the stream for rewind. The rewind itself should get delayed as long as possible
-     */
-    public final void rewind() {
-        this.rewind = true;
-    }
-
-    /**
-     * Perform the actual rewind 
-     * @throws IOException
-     */
-    protected abstract void rewindIfNeeded() throws IOException;
-
-}
Index: store/src/main/java/org/apache/james/imap/store/ResultUtils.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/ResultUtils.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/ResultUtils.java	(Arbeitskopie)
@@ -40,6 +40,10 @@
 import org.apache.james.imap.mailbox.util.MessageResultImpl;
 import org.apache.james.imap.store.mail.model.Header;
 import org.apache.james.imap.store.mail.model.MailboxMembership;
+import org.apache.james.imap.store.streaming.DelegatingRewindableInputStream;
+import org.apache.james.imap.store.streaming.InputStreamContent;
+import org.apache.james.imap.store.streaming.PartContentBuilder;
+import org.apache.james.imap.store.streaming.RewindableInputStream;
 import org.apache.james.mime4j.MimeException;
 
 /**
Index: store/src/main/java/org/apache/james/imap/store/PasswordAwareMailboxSession.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/PasswordAwareMailboxSession.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/PasswordAwareMailboxSession.java	(Arbeitskopie)
@@ -28,6 +28,7 @@
  * 
  *
  */
+// TODO: Why does a session implement a user? This is not needed, I think.
 public class PasswordAwareMailboxSession extends SimpleMailboxSession implements PasswordAwareUser{
 
 	private final String password;
Index: store/src/main/java/org/apache/james/imap/store/PartContentBuilder.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/PartContentBuilder.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/PartContentBuilder.java	(Arbeitskopie)
@@ -1,290 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.imap.store;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.james.imap.mailbox.Content;
-import org.apache.james.imap.mailbox.MessageResult;
-import org.apache.james.imap.mailbox.MessageResult.Header;
-import org.apache.james.mime4j.MimeException;
-import org.apache.james.mime4j.parser.MimeTokenStream;
-
-public class PartContentBuilder {
-
-    private static final byte[] EMPTY = {};
-
-    private MimeTokenStream parser;
-
-    private boolean empty = false;
-
-    private boolean topLevel = true;
-
-    public PartContentBuilder() {
-        parser = new MimeTokenStream();
-    }
-
-    public void markEmpty() {
-        empty = true;
-    }
-
-    public void parse(final InputStream in) {
-        parser.setRecursionMode(MimeTokenStream.M_RECURSE);
-        parser.parse(in);
-        topLevel = true;
-    }
-
-    private void skipToStartOfInner(int position) throws IOException, MimeException {
-        final int state = parser.next();
-        switch (state) {
-            case MimeTokenStream.T_START_MULTIPART:
-                break;
-            case MimeTokenStream.T_START_MESSAGE:
-                break;
-            case MimeTokenStream.T_END_OF_STREAM:
-                throw new PartNotFoundException(position);
-            case MimeTokenStream.T_END_BODYPART:
-                throw new PartNotFoundException(position);
-            default:
-                skipToStartOfInner(position);
-        }
-    }
-
-    public void to(int position) throws IOException, MimeException {
-        try {
-            if (topLevel) {
-                topLevel = false;
-            } else {
-                skipToStartOfInner(position);
-            }
-            for (int count = 0; count < position;) {
-                final int state = parser.next();
-                switch (state) {
-                    case MimeTokenStream.T_BODY:
-                        if (position == 1) {
-                            count++;
-                        }
-                        break;
-                    case MimeTokenStream.T_START_BODYPART:
-                        count++;
-                        break;
-                    case MimeTokenStream.T_START_MULTIPART:
-                        if (count > 0 && count < position) {
-                            ignoreInnerMessage();
-                        }
-                        break;
-                    case MimeTokenStream.T_END_OF_STREAM:
-                        throw new PartNotFoundException(position);
-                }
-            }
-        } catch (IllegalStateException e) {
-            throw new PartNotFoundException(position, e);
-        }
-    }
-
-    private void ignoreInnerMessage() throws IOException, UnexpectedEOFException, MimeException {
-        for (int state = parser.next(); state != MimeTokenStream.T_END_MULTIPART; state = parser
-                .next()) {
-            switch (state) {
-                case MimeTokenStream.T_END_OF_STREAM:
-                    throw new UnexpectedEOFException();
-
-                case MimeTokenStream.T_START_MULTIPART:
-                    ignoreInnerMessage();
-                    break;
-            }
-        }
-    }
-
-    public Content getFullContent() throws IOException, UnexpectedEOFException, MimeException {
-        final List<Header> headers = getMimeHeaders();
-        final byte[] content = mimeBodyContent();
-        return new FullByteContent(ByteBuffer.wrap(content), headers);
-    }
-
-    public Content getMessageBodyContent() throws IOException, MimeException {
-        final byte[] content = messageBodyContent();
-        return new ByteContent(ByteBuffer.wrap(content));
-    }
-
-    private byte[] messageBodyContent() throws IOException, MimeException {
-        final byte[] content;
-        if (empty) {
-            content = EMPTY;
-        } else {
-            boolean valid;
-            try {
-                advancedToMessage();
-                valid = true;
-            } catch (UnexpectedEOFException e) {
-                // No TEXT part
-                valid = false;
-            }
-            if (valid) {
-                parser.setRecursionMode(MimeTokenStream.M_FLAT);
-                for (int state = parser.getState(); state != MimeTokenStream.T_BODY
-                        && state != MimeTokenStream.T_START_MULTIPART; state = parser
-                        .next()) {
-                    if (state == MimeTokenStream.T_END_OF_STREAM) {
-                        valid = false;
-                        break;
-                    }
-                }
-                if (valid) {
-                    content = StreamUtils.toByteArray(parser.getInputStream());
-                } else {
-                    content = EMPTY;
-                }
-            } else {
-                content = EMPTY;
-            }
-        }
-        return content;
-    }
-
-    public Content getMimeBodyContent() throws IOException, MimeException {
-        final byte[] content = mimeBodyContent();
-        return new ByteContent(ByteBuffer.wrap(content));
-    }
-
-    private byte[] mimeBodyContent() throws IOException, MimeException {
-        final byte[] content;
-        if (empty) {
-            content = EMPTY;
-        } else {
-            parser.setRecursionMode(MimeTokenStream.M_FLAT);
-            boolean valid = true;
-            for (int state = parser.getState(); state != MimeTokenStream.T_BODY
-                    && state != MimeTokenStream.T_START_MULTIPART; state = parser
-                    .next()) {
-                if (state == MimeTokenStream.T_END_OF_STREAM) {
-                    valid = false;
-                    break;
-                }
-            }
-            if (valid) {
-                content = StreamUtils.toByteArray(parser.getInputStream());
-            } else {
-                content = EMPTY;
-            }
-        }
-        return content;
-    }
-
-    @SuppressWarnings("unchecked")
-    public List<MessageResult.Header> getMimeHeaders() throws IOException, UnexpectedEOFException, MimeException {
-        final List<MessageResult.Header> results;
-        if (empty) {
-            results = Collections.EMPTY_LIST;
-        } else {
-            results = new ArrayList<MessageResult.Header>();
-            for (int state = parser.getState(); state != MimeTokenStream.T_END_HEADER; state = parser
-                    .next()) {
-                switch (state) {
-                    case MimeTokenStream.T_END_OF_STREAM:
-                        throw new UnexpectedEOFException();
-
-                    case MimeTokenStream.T_FIELD:
-                        final String fieldValue = parser.getField().getBody().trim();
-                        final String fieldName = parser.getField().getName();
-                        ResultHeader header = new ResultHeader(fieldName, fieldValue);
-                        results.add(header);
-                        break;
-                }
-            }
-        }
-        return results;
-    }
-
-    @SuppressWarnings("unchecked")
-    public List<MessageResult.Header> getMessageHeaders() throws IOException, MimeException {
-        final List<MessageResult.Header> results;
-        if (empty) {
-            results = Collections.EMPTY_LIST;
-        } else {
-            results = new ArrayList<MessageResult.Header>();
-            try {
-                advancedToMessage();
-
-                for (int state = parser.getState(); state != MimeTokenStream.T_END_HEADER; state = parser
-                        .next()) {
-                    switch (state) {
-                        case MimeTokenStream.T_END_OF_STREAM:
-                            throw new IOException("Unexpected EOF");
-
-                        case MimeTokenStream.T_FIELD:
-                            final String fieldValue = parser.getField().getBody().trim();
-                            final String fieldName = parser.getField().getName();
-                            ResultHeader header = new ResultHeader(fieldName, fieldValue);
-                            results.add(header);
-                            break;
-                    }
-                }
-            } catch (UnexpectedEOFException e) {
-                // No headers found
-            }
-        }
-        return results;
-    }
-
-    private void advancedToMessage() throws IOException, UnexpectedEOFException, MimeException {
-        for (int state = parser.getState(); state != MimeTokenStream.T_START_MESSAGE; state = parser
-                .next()) {
-            if (state == MimeTokenStream.T_END_OF_STREAM) {
-                throw new UnexpectedEOFException();
-            }
-        }
-    }
-
-    public static final class UnexpectedEOFException extends MimeException {
-
-        private static final long serialVersionUID = -3755637466593055796L;
-
-        public UnexpectedEOFException() {
-            super("Unexpected EOF");
-        }
-    }
-
-    public static final class PartNotFoundException extends MimeException {
-
-        private static final long serialVersionUID = 7519976990944851574L;
-
-        private final int position;
-
-        public PartNotFoundException(int position) {
-            this(position, null);
-        }
-
-        public PartNotFoundException(int position, Exception e) {
-            super("Part " + position + " not found.", e);
-            this.position = position;
-        }
-
-        public final int getPosition() {
-            return position;
-        }
-
-    }
-}
Index: store/src/main/java/org/apache/james/imap/store/MimeDescriptorImpl.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/MimeDescriptorImpl.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/MimeDescriptorImpl.java	(Arbeitskopie)
@@ -33,6 +33,8 @@
 import org.apache.james.imap.store.mail.model.Document;
 import org.apache.james.imap.store.mail.model.Property;
 import org.apache.james.imap.store.mail.model.PropertyBuilder;
+import org.apache.james.imap.store.streaming.ConfigurableMimeTokenStream;
+import org.apache.james.imap.store.streaming.CountingInputStream;
 import org.apache.james.mime4j.MimeException;
 import org.apache.james.mime4j.descriptor.MaximalBodyDescriptor;
 import org.apache.james.mime4j.parser.MimeEntityConfig;
Index: store/src/main/java/org/apache/james/imap/store/MailboxSessionMapperFactory.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/MailboxSessionMapperFactory.java	(Revision 0)
+++ store/src/main/java/org/apache/james/imap/store/MailboxSessionMapperFactory.java	(Revision 0)
@@ -0,0 +1,89 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.store;
+
+import org.apache.james.imap.mailbox.MailboxException;
+import org.apache.james.imap.mailbox.MailboxSession;
+import org.apache.james.imap.mailbox.SubscriptionException;
+import org.apache.james.imap.store.mail.MailboxMapper;
+import org.apache.james.imap.store.mail.MessageMapper;
+import org.apache.james.imap.store.user.SubscriptionMapper;
+
+/**
+ * Maintain mapper instances by {@link MailboxSession}. So only one mapper instance is used
+ * in a {@link MailboxSession}
+ */
+public abstract class MailboxSessionMapperFactory <Id> {
+
+    protected final static String MESSAGEMAPPER ="MESSAGEMAPPER";
+    protected final static String MAILBOXMAPPER ="MAILBOXMAPPER";
+    protected final static String SUBSCRIPTIONMAPPER ="SUBSCRIPTIONMAPPER";
+
+    /**
+     * Create a {@link MessageMapper} instance of return the one which exists for the {@link MailboxSession} already
+     * 
+     * @param session
+     * @param mailboxId
+     * @return mapper
+     */
+    public MessageMapper<Id> getMessageMapper(MailboxSession session) throws MailboxException {
+        MessageMapper<Id> mapper = (MessageMapper<Id>) session.getAttributes().get(MESSAGEMAPPER);
+        if (mapper == null) {
+            mapper = createMessageMapper(session);
+            session.getAttributes().put(MESSAGEMAPPER, mapper);
+        }
+        return mapper;
+    }
+
+    protected abstract MessageMapper<Id> createMessageMapper(MailboxSession session) throws MailboxException;
+
+    /**
+     * Create a {@link MailboxMapper} instance of return the one which exists for the {@link MailboxSession} already
+     * 
+     * @param session
+     * @return mapper
+     */
+    public MailboxMapper<Id> getMailboxMapper(MailboxSession session) throws MailboxException {
+        MailboxMapper<Id> mapper = (MailboxMapper<Id>) session.getAttributes().get(MAILBOXMAPPER);
+        if (mapper == null) {
+            mapper = createMailboxMapper(session);
+            session.getAttributes().put(MAILBOXMAPPER, mapper);
+        }
+        return mapper;
+    }
+
+    protected abstract MailboxMapper<Id> createMailboxMapper(MailboxSession session) throws MailboxException;
+
+    /**
+     * Create a {@link SubscriptionMapper} instance of return the one which exists for the {@link MailboxSession} already
+     * 
+     * @param session
+     * @return mapper
+     */
+    public SubscriptionMapper getSubscriptionMapper(MailboxSession session) throws SubscriptionException {
+        SubscriptionMapper mapper = (SubscriptionMapper) session.getAttributes().get(SUBSCRIPTIONMAPPER);
+        if (mapper == null) {
+            mapper = createSubscriptionMapper(session);
+            session.getAttributes().put(SUBSCRIPTIONMAPPER, mapper);
+        }
+        return mapper;
+    }
+
+    protected abstract SubscriptionMapper createSubscriptionMapper(MailboxSession session) throws SubscriptionException;
+}
Index: store/src/main/java/org/apache/james/imap/store/LazySkippingInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/LazySkippingInputStream.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/LazySkippingInputStream.java	(Arbeitskopie)
@@ -1,101 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.imap.store;
-
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * {@link FilterInputStream} implementation which skip the given bytes as late as possible.
- * 
- *
- */
-public class LazySkippingInputStream extends FilterInputStream{
-
-    private long skipBytes;
-    private boolean skipped = false;
-
-    /**
-     * Construct the {@link LazySkippingInputStream}
-     * 
-     * @param in {@link InputStream} to wrap
-     * @param skipBytes bytes to skip
-     */
-    public LazySkippingInputStream(InputStream in, long skipBytes) {
-        super(in);
-        this.skipBytes = skipBytes;
-    }
-
-    @Override
-    public int read() throws IOException {
-        skipIfNeeded();
-
-        return super.read();
-    }
-
-    @Override
-    public int read(byte[] b, int off, int len) throws IOException {
-        skipIfNeeded();
-        return super.read(b, off, len);
-    }
-
-    @Override
-    public int read(byte[] b) throws IOException {
-        skipIfNeeded();
-        return super.read(b);
-    }
-    
-    @Override
-    public int available() throws IOException {
-        skipIfNeeded();
-
-        return super.available();
-    }
-
-    @Override
-    public synchronized void mark(int readlimit) {
-        // not supported
-    }
-
-    @Override
-    public boolean markSupported() {
-        return false;
-    }
-
-    @Override
-    public long skip(long n) throws IOException {
-        skipIfNeeded();
-        return super.skip(n);
-    }
-
-    /**
-     * Check if the bytes are skipped already. If not do now
-     * 
-     * @throws IOException
-     */
-    private void skipIfNeeded() throws IOException {
-        if (skipped == false) {
-            super.skip(skipBytes);
-            skipped = true;
-        }
-    }
-
-}
Index: store/src/main/java/org/apache/james/imap/store/InputStreamFullContent.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/InputStreamFullContent.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/InputStreamFullContent.java	(Arbeitskopie)
@@ -1,81 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-package org.apache.james.imap.store;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.WritableByteChannel;
-import java.util.List;
-
-import org.apache.james.imap.mailbox.MessageResult;
-
-
-/**
- * {@link AbstractFullContent} implementations which uses an {@link InputStream} as source for the 
- * body content
- *
- */
-public class InputStreamFullContent extends AbstractFullContent{
-
-    private final RewindableInputStream in;
-    private long size;
-
-
-    public InputStreamFullContent(final RewindableInputStream contents, final List<MessageResult.Header> headers) throws IOException{
-        super(headers);
-        this.in = contents;
-        this.size = caculateSize();
-    }
-
-    
-
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.mailbox.Content#size()
-     */
-    public final long size() {
-        return size;
-    }
-
-    @Override
-    protected void bodyWriteTo(WritableByteChannel channel) throws IOException {
-        // rewind the stream before write it to the channel
-        in.rewind();
-        
-        // read all the content of the underlying InputStream in 16384 byte chunks, wrap them
-        // in a ByteBuffer and finally write the Buffer to the channel
-        byte[] buf = new byte[16384];
-        int i = 0;
-        while ((i = in.read(buf)) != -1) {
-            ByteBuffer buffer = ByteBuffer.wrap(buf);
-            // set the limit of the buffer to the returned bytes
-            buffer.limit(i);
-            channel.write(buffer);
-        }  
-    }
-
-
-    @Override
-    protected long getBodySize() throws IOException{
-        return in.available();
-    }
-
-}
Index: store/src/main/java/org/apache/james/imap/store/InputStreamContent.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/InputStreamContent.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/InputStreamContent.java	(Arbeitskopie)
@@ -1,79 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-package org.apache.james.imap.store;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.WritableByteChannel;
-
-import org.apache.james.imap.mailbox.Content;
-
-/**
- * {@link Content} which is stored in a {@link InputStream}
- *
- */
-public final class InputStreamContent implements Content{
-
-    private RewindableInputStream in;
-    private long size;
-
-    public InputStreamContent(RewindableInputStream in) throws IOException{
-        this.in = in;
-        this.size = in.available();
-    }
-    
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.mailbox.Content#size()
-     */
-    public long size() {
-        return size;
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.mailbox.Content#writeTo(java.nio.channels.WritableByteChannel)
-     */
-    public void writeTo(WritableByteChannel channel) throws IOException {
-        
-        try {
-            // rewind the stream before write it to the channel
-            in.rewind();
-        
-            // read all the content of the underlying InputStream in 16384 byte chunks, wrap them
-            // in a ByteBuffer and finally write the Buffer to the channel
-            byte[] buf = new byte[16384];
-            int i = 0;
-            while ((i = in.read(buf)) != -1) {
-                ByteBuffer buffer = ByteBuffer.wrap(buf);
-                // set the limit of the buffer to the returned bytes
-                    buffer.limit(i);
-                    channel.write(buffer);
-            }
-        } finally {
-            // close the stream so temporary files could get delete
-            in.close();
-        }
-        
-    }
-    
-   
-
-}
Index: store/src/main/java/org/apache/james/imap/store/InMemoryRewindableInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/InMemoryRewindableInputStream.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/InMemoryRewindableInputStream.java	(Arbeitskopie)
@@ -1,62 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-package org.apache.james.imap.store;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * {@link RewindableInputStream} implementations which stores the data into a {@link ByteArrayOutputStream}. This is
- * only useful for small data, because it is complete handled in memory
- * 
- */
-public class InMemoryRewindableInputStream extends AbstractRewindableInputStream{
-
-    private ByteArrayOutputStream out;
-    private ByteArrayInputStream in;
-    public InMemoryRewindableInputStream(InputStream wrappedIn) throws IOException {
-        super(wrappedIn);
-        this.out = new ByteArrayOutputStream();
-        this.in = new ByteArrayInputStream(out.toByteArray());
-    }
-
-    @Override
-    protected void afterRewindComplete() throws IOException {
-        in = new ByteArrayInputStream(out.toByteArray());
-    }
-
-    @Override
-    protected void dispose() throws IOException {
-        // nothing todo
-    }
-
-    @Override
-    protected InputStream getRewindInputStream() {
-        return in;
-    }
-
-    @Override
-    protected OutputStream getRewindOutputStream() {
-        return out;
-    }
-
-}
Index: store/src/main/java/org/apache/james/imap/store/FullByteContent.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/FullByteContent.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/FullByteContent.java	(Arbeitskopie)
@@ -1,65 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-/**
- * 
- */
-package org.apache.james.imap.store;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.WritableByteChannel;
-import java.util.List;
-
-import org.apache.james.imap.mailbox.MessageResult;
-
-/**
- * Content which holds the full content, including {@link Header} objets
- *
- */
-public final class FullByteContent extends  AbstractFullContent {
-    private final ByteBuffer contents;
-    private final long size;
-
-    public FullByteContent(final ByteBuffer contents, final List<MessageResult.Header> headers) throws IOException {
-        super(headers);
-        this.contents = contents;
-        this.size = caculateSize();
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.mailbox.Content#size()
-     */
-    public long size() {
-        return size;
-    }
-
-    @Override
-    protected void bodyWriteTo(WritableByteChannel channel) throws IOException {
-        contents.rewind();
-        writeAll(channel, contents);        
-    }
-
-    @Override
-    protected long getBodySize() throws IOException {
-        return contents.limit();
-    }
-
-}
\ No newline at end of file
Index: store/src/main/java/org/apache/james/imap/store/FileRewindableInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/FileRewindableInputStream.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/FileRewindableInputStream.java	(Arbeitskopie)
@@ -1,78 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-package org.apache.james.imap.store;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * {@link RewindableInputStream} implementations which stores the data into a {@link File}. This is
- * useful for big data
- * 
- */
-public class FileRewindableInputStream extends AbstractRewindableInputStream{
-
-    private File f;
-    private FileOutputStream fOut;
-    private FileInputStream fIn;
-
-    public FileRewindableInputStream(InputStream in) throws IOException {
-        super(in);
-    }
-
-    @Override
-    protected OutputStream getRewindOutputStream() throws IOException {
-        if (f == null) {
-            f = File.createTempFile("rewindable", ".tmp");
-        }
-        if (fOut == null) {
-            fOut = new FileOutputStream(f);
-        
-        }
-        return fOut;
-    }
-    
-    @Override
-    protected void afterRewindComplete() throws IOException {
-        fIn = new FileInputStream(f);        
-    }
-
-    @Override
-    protected void dispose() throws IOException {
-        if (f != null) {
-            f.delete();
-        }
-    }
-
-    @Override
-    protected InputStream getRewindInputStream() throws IOException {
-        if (f == null) {
-            f = File.createTempFile("rewindable", ".tmp");
-        }
-        if (fIn == null) {
-
-            fIn = new FileInputStream(f);
-        }
-        return fIn;
-    }
-}
Index: store/src/main/java/org/apache/james/imap/store/DelegatingRewindableInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/DelegatingRewindableInputStream.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/DelegatingRewindableInputStream.java	(Arbeitskopie)
@@ -1,98 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-package org.apache.james.imap.store;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * {@link RewindableInputStream} implementation which just delegate the calls to {@link FileRewindableInputStream} 
- * or {@link InMemoryRewindableInputStream} depending on the size 
- * 
- *
- */
-public class DelegatingRewindableInputStream extends RewindableInputStream{
-
-    public final static long  MAX_INMEMORY_SIZE= 524288;
-    
-    public DelegatingRewindableInputStream(InputStream in, long size, long maxInmemorySize) throws IOException {
-        super(null);
-        if (size > maxInmemorySize) {
-            this.in = new FileRewindableInputStream(in);
-        } else {
-            this.in = new InMemoryRewindableInputStream(in);
-
-        }
-    }
-
-    public DelegatingRewindableInputStream(InputStream in, long size) throws IOException {
-        this(in, size, MAX_INMEMORY_SIZE);
-    }
-
-    @Override
-    public int available() throws IOException {
-        return in.available();
-    }
-
-    @Override
-    public void close() throws IOException {
-        in.close();
-    }
-
-    @Override
-    public synchronized void mark(int readlimit) {
-        in.mark(readlimit);
-    }
-
-    @Override
-    public boolean markSupported() {
-        return in.markSupported();
-    }
-
-    @Override
-    public int read() throws IOException {
-        return in.read();
-    }
-
-    @Override
-    public int read(byte[] b, int off, int len) throws IOException {
-        return in.read(b, off, len);
-    }
-
-    @Override
-    public int read(byte[] b) throws IOException {
-        return in.read(b);
-    }
-
-    @Override
-    public synchronized void reset() throws IOException {
-        in.reset();
-    }
-
-    @Override
-    public long skip(long n) throws IOException {
-        return in.skip(n);
-    }
-
-    @Override
-    protected void rewindIfNeeded() throws IOException {
-        ((RewindableInputStream)in).rewindIfNeeded();
-    }
-
-}
Index: store/src/main/java/org/apache/james/imap/store/CountingInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/CountingInputStream.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/CountingInputStream.java	(Arbeitskopie)
@@ -1,86 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-/**
- * 
- */
-package org.apache.james.imap.store;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * {@link InputStream} implementation which just consume the the wrapped {@link InputStream} and count
- * the lines which are contained within the wrapped stream
- * 
- *
- */
-final class CountingInputStream extends InputStream {
-
-    private final InputStream in;
-
-    private int lineCount;
-
-    private int octetCount;
-
-    CountingInputStream(InputStream in) {
-        super();
-        this.in = in;
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see java.io.InputStream#read()
-     */
-    public int read() throws IOException {
-        int next = in.read();
-        if (next > 0) {
-            octetCount++;
-            if (next == '\r') {
-                lineCount++;
-            }
-        }
-        return next;
-    }
-
-    /**
-     * Return the line count 
-     * 
-     * @return lineCount
-     */
-    public final int getLineCount() {
-        return lineCount;
-    }
-
-    /**
-     * Return the octet count
-     * 
-     * @return octetCount
-     */
-    public final int getOctetCount() {
-        return octetCount;
-    }
-    
-    /**
-     * Reads - and discards - the rest of the stream
-     * @throws IOException
-     */
-    public void readAll() throws IOException {
-        while (read()>0);
-    }
-}
\ No newline at end of file
Index: store/src/main/java/org/apache/james/imap/store/ConfigurableMimeTokenStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/ConfigurableMimeTokenStream.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/ConfigurableMimeTokenStream.java	(Arbeitskopie)
@@ -1,29 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-package org.apache.james.imap.store;
-
-import org.apache.james.mime4j.parser.MimeEntityConfig;
-import org.apache.james.mime4j.parser.MimeTokenStream;
-
-public class ConfigurableMimeTokenStream extends MimeTokenStream {
-    
-    public ConfigurableMimeTokenStream(MimeEntityConfig config) {
-        super(config);
-    }
-}
Index: store/src/main/java/org/apache/james/imap/store/CRLFOutputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/CRLFOutputStream.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/CRLFOutputStream.java	(Arbeitskopie)
@@ -1,161 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.imap.store;
-
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * A Filter for use with SMTP or other protocols in which lines must end with
- * CRLF. Converts every "isolated" occourency of \r or \n with \r\n
- * 
- * RFC 2821 #2.3.7 mandates that line termination is CRLF, and that CR and LF
- * must not be transmitted except in that pairing. If we get a naked LF, convert
- * to CRLF.
- * 
- */
-public class CRLFOutputStream extends FilterOutputStream {
-
-    /**
-     * Counter for number of last (0A or 0D).
-     */
-    protected int statusLast;
-
-    protected final static int LAST_WAS_OTHER = 0;
-
-    protected final static int LAST_WAS_CR = 1;
-
-    protected final static int LAST_WAS_LF = 2;
-
-    protected boolean startOfLine = true;
-
-    /**
-     * Constructor that wraps an OutputStream.
-     * 
-     * @param out
-     *            the OutputStream to be wrapped
-     */
-    public CRLFOutputStream(OutputStream out) {
-        super(out);
-        statusLast = LAST_WAS_LF; // we already assume a CRLF at beginning
-        // (otherwise TOP would not work correctly
-        // !)
-    }
-
-    /**
-     * Writes a byte to the stream Fixes any naked CR or LF to the RFC 2821
-     * mandated CFLF pairing.
-     * 
-     * @param b
-     *            the byte to write
-     * 
-     * @throws IOException
-     *             if an error occurs writing the byte
-     */
-    public void write(int b) throws IOException {
-        switch (b) {
-            case '\r':
-                out.write('\r');
-                out.write('\n');
-                startOfLine = true;
-                statusLast = LAST_WAS_CR;
-                break;
-            case '\n':
-                if (statusLast != LAST_WAS_CR) {
-                    out.write('\r');
-                    out.write('\n');
-                    startOfLine = true;
-                }
-                statusLast = LAST_WAS_LF;
-                break;
-            default:
-                // we're no longer at the start of a line
-                out.write(b);
-                startOfLine = false;
-                statusLast = LAST_WAS_OTHER;
-                break;
-        }
-    }
-
-    /**
-     * Provides an extension point for ExtraDotOutputStream to be able to add
-     * dots at the beginning of new lines.
-     * 
-     * @see java.io.FilterOutputStream#write(byte[], int, int)
-     */
-    protected void writeChunk(byte buffer[], int offset, int length)
-            throws IOException {
-        out.write(buffer, offset, length);
-    }
-
-    /**
-     * @see java.io.FilterOutputStream#write(byte[], int, int)
-     */
-    public synchronized void write(byte buffer[], int offset, int length)
-            throws IOException {
-        /* optimized */
-        int lineStart = offset;
-        for (int i = offset; i < length + offset; i++) {
-            switch (buffer[i]) {
-                case '\r':
-                    // CR case. Write down the last line
-                    // and position the new lineStart at the next char
-                    writeChunk(buffer, lineStart, i - lineStart);
-                    out.write('\r');
-                    out.write('\n');
-                    startOfLine = true;
-                    lineStart = i + 1;
-                    statusLast = LAST_WAS_CR;
-                    break;
-                case '\n':
-                    if (statusLast != LAST_WAS_CR) {
-                        writeChunk(buffer, lineStart, i - lineStart);
-                        out.write('\r');
-                        out.write('\n');
-                        startOfLine = true;
-                    }
-                    lineStart = i + 1;
-                    statusLast = LAST_WAS_LF;
-                    break;
-                default:
-                    statusLast = LAST_WAS_OTHER;
-            }
-        }
-        if (length + offset > lineStart) {
-            writeChunk(buffer, lineStart, length + offset - lineStart);
-            startOfLine = false;
-        }
-    }
-
-    /**
-     * Ensure that the stream is CRLF terminated.
-     * 
-     * @throws IOException
-     *             if an error occurs writing the byte
-     */
-    public void checkCRLFTerminator() throws IOException {
-        if (statusLast == LAST_WAS_OTHER) {
-            out.write('\r');
-            out.write('\n');
-            statusLast = LAST_WAS_CR;
-        }
-    }
-}
Index: store/src/main/java/org/apache/james/imap/store/ByteContent.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/ByteContent.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/ByteContent.java	(Arbeitskopie)
@@ -1,60 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-/**
- * 
- */
-package org.apache.james.imap.store;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.WritableByteChannel;
-
-import org.apache.james.imap.mailbox.Content;
-
-public final class ByteContent implements Content {
-
-    private final ByteBuffer contents;
-
-    private final long size;
-
-    public ByteContent(final ByteBuffer contents) {
-        this.contents = contents;
-        size = contents.limit();
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.mailbox.Content#size()
-     */
-    public long size() {
-        return size;
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.mailbox.Content#writeTo(java.nio.channels.WritableByteChannel)
-     */
-    public void writeTo(WritableByteChannel channel) throws IOException {
-        contents.rewind();
-        while (channel.write(contents) > 0) {
-            // write more
-        }
-    }
-}
\ No newline at end of file
Index: store/src/main/java/org/apache/james/imap/store/AbstractRewindableInputStream.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/AbstractRewindableInputStream.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/AbstractRewindableInputStream.java	(Arbeitskopie)
@@ -1,182 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-package org.apache.james.imap.store;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * {@link RewindableInputStream} which support the get rewinded. This is done by copy over every byte
- * over to another {@link OutputStream}. What {@link OutputStream} to use is up to the implementations.
- * 
- * The rewinding will get delayed as long as possible. So if you call
- * rewind, it will only get performed when needed
- * 
- * Be sure to call {@link #close()} once you done reading from the object. This will
- * remove all temporary data
- * 
- *
- */
-public abstract class AbstractRewindableInputStream extends RewindableInputStream{
-
-    protected boolean end = false;
-
-    public AbstractRewindableInputStream(InputStream in) throws IOException {
-        super(in);
-    }
-
-    /**
-     * Return the OutputStream to which the data should get written when they are read the 
-     * first time
-     * 
-     * @return output
-     * @throws IOException
-     */
-    protected abstract OutputStream getRewindOutputStream() throws IOException;
-    
-    /**
-     * Return the InputStream which should get used after the stream was rewinded
-     * 
-     * @return rewindInput
-     * @throws IOException
-     */
-    protected abstract InputStream getRewindInputStream() throws IOException;
-
-    /**
-     * Dispose all temporary data
-     * 
-     * @throws IOException
-     */
-    protected abstract void dispose() throws IOException;
-    
-    /**
-     * Get called after the rewind was complete
-     * 
-     * @throws IOException
-     */
-    protected abstract void afterRewindComplete() throws IOException;
-    
-    /**
-     * Close the stream and dispose all temporary data
-     * 
-     */
-    public void close() throws IOException {
-        try {
-            in.close();
-            OutputStream out = getRewindOutputStream();
-            if (out != null) {
-                out.close();
-            }
-            InputStream in = getRewindInputStream();
-            if (in != null) {
-                in.close();
-            }
-        } finally {
-            dispose();
-        }
-    }
-
-    
-    /**
-     * Read data and write and store it for later usage once the rewind was done
-     */
-    @Override
-    public int read() throws IOException {   
-        int i;
-        if (needsRewind()) {
-
-            rewindIfNeeded();
-        }
-        
-        if (end == false) {
-            i = in.read();
-            if (i == -1) {
-                end = true;
-            } else {
-                getRewindOutputStream().write(i);
-            }
-        } else {
-            i = getRewindInputStream().read();
-        }
-        return i;
-    }
-
-    /**
-     * Read data and write and store it for later usage once the rewind was done
-     */
-    @Override
-    public int read(byte[] b, int off, int len) throws IOException {
-        if (len == 0) {
-            return 0;
-        }
-        if (needsRewind()) {
-            rewindIfNeeded();
-        }    
-        
-        int i;
-        if (end == false) {
-            i = in.read(b, off, len);
-            if (i == -1) {
-                end = true;
-            }
-            getRewindOutputStream().write(b, off, len);
-        } else {
-            i = getRewindInputStream().read(b,off,len);
-        }
-        return i;
-    }
-
-    /**
-     * Read data and write and store it for later usage once the rewind was done
-     */
-    @Override
-    public void rewindIfNeeded() throws IOException {
-        if (needsRewind()) {
-            rewindDone();
-            
-            if (end == false) {
-                while ( read() != -1);
-            }
-            // we don't need the original InputStream anymore so close it
-            in.close();
-            afterRewindComplete();
-        }        
-    }
-
-    @Override
-    public int available() throws IOException {
-        if (end == false) {
-            return in.available();
-        } else {
-            return getRewindInputStream().available();
-        }
-    }
-
-    @Override
-    public long skip(long n) throws IOException {
-        for (int i = 0; i < n; i++) {
-            if (read() == -1) {
-                return n -i;
-            }
-            if (end) break;
-        }
-        return 0;
-    }
-}
Index: store/src/main/java/org/apache/james/imap/store/AbstractFullContent.java
===================================================================
--- store/src/main/java/org/apache/james/imap/store/AbstractFullContent.java	(Revision 950435)
+++ store/src/main/java/org/apache/james/imap/store/AbstractFullContent.java	(Arbeitskopie)
@@ -1,110 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-package org.apache.james.imap.store;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.WritableByteChannel;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.james.imap.mailbox.Content;
-import org.apache.james.imap.mailbox.MessageResult;
-import org.apache.james.imap.mailbox.MessageResult.Header;
-
-/**
- * Abstract base class for {@link Content} implementations which hold the headers and 
- * the body a email
- *
- */
-public abstract class AbstractFullContent implements Content{
-
-
-    private List<Header> headers;
-    
-    public AbstractFullContent(final List<MessageResult.Header> headers) throws IOException {
-        this.headers = headers;
-    }
-    
-    protected long caculateSize() throws IOException{
-        long result = getBodySize();
-        result += 2;
-        for (final Iterator<MessageResult.Header> it = headers.iterator(); it.hasNext();) {
-            final MessageResult.Header header = it.next();
-            if (header != null) {
-                result += header.size();
-                result += 2;
-            }
-        }
-        return result;
-    }
-    
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.mailbox.Content#writeTo(java.nio.channels.WritableByteChannel)
-     */
-    public final void writeTo(WritableByteChannel channel) throws IOException {
-        ByteBuffer newLine = ByteBuffer.wrap(ResultUtils.BYTES_NEW_LINE);
-        for (final Iterator<MessageResult.Header> it = headers.iterator(); it.hasNext();) {
-            final MessageResult.Header header = it.next();
-            if (header != null) {
-                header.writeTo(channel);
-            }
-            newLine.rewind();
-            writeAll(channel, newLine);
-        }
-        newLine.rewind();
-        writeAll(channel, newLine);
-        bodyWriteTo(channel);
-    }
-
-    
-    /**
-     * Write all 
-     * 
-     * @param channel
-     * @param buffer
-     * @throws IOException
-     */
-    protected void writeAll(WritableByteChannel channel, ByteBuffer buffer)
-            throws IOException {
-        while (channel.write(buffer) > 0) {
-            // write more
-        }
-    }
-    
-    /**
-     * Return the size of the body
-     * 
-     * @return size
-     * @throws IOException
-     */
-    protected abstract long getBodySize() throws IOException;
-    
-    /**
-     * Write the body to the channel
-     * 
-     * @param channel
-     * @throws IOException
-     */
-    protected abstract void bodyWriteTo(WritableByteChannel channel) throws IOException;
-
-    
-}
Index: memory/src/main/java/org/apache/james/imap/inmemory/model/SimpleMailboxMembership.java
===================================================================
--- memory/src/main/java/org/apache/james/imap/inmemory/model/SimpleMailboxMembership.java	(Revision 0)
+++ memory/src/main/java/org/apache/james/imap/inmemory/model/SimpleMailboxMembership.java	(Revision 0)
@@ -0,0 +1,243 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.imap.inmemory.model;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+
+import javax.mail.Flags;
+
+import org.apache.james.imap.store.mail.model.AbstractMailboxMembership;
+import org.apache.james.imap.store.mail.model.Document;
+import org.apache.james.imap.store.mail.model.Header;
+import org.apache.james.imap.store.mail.model.MailboxMembership;
+import org.apache.james.imap.store.mail.model.Property;
+import org.apache.james.imap.store.mail.model.PropertyBuilder;
+import org.apache.james.imap.store.streaming.DelegatingRewindableInputStream;
+import org.apache.james.imap.store.streaming.LazySkippingInputStream;
+import org.apache.james.imap.store.streaming.RewindableInputStream;
+
+public class SimpleMailboxMembership extends AbstractMailboxMembership<Long> implements Document, Comparable<MailboxMembership<Long>> {
+
+    private final long uid;
+    private final long mailboxId;
+    private int size;
+    private boolean answered;
+    private boolean deleted;
+    private boolean draft;
+    private boolean flagged;
+    private boolean recent;
+    private boolean seen;
+    private Date internalDate;
+    private final String subType;
+    private List<Property> properties;
+    private final String mediaType;
+    private List<Header> headers;
+    private Long lineCount;
+    private byte[] document;
+    private int bodyStartOctet;
+    
+    public SimpleMailboxMembership(long mailboxId, long uid, final SimpleMailboxMembership original) {
+        this.uid = uid;
+        this.mailboxId = mailboxId;
+        this.size = original.size;
+        this.answered = original.answered;
+        this.deleted = original.deleted;
+        this.draft = original.draft;
+        this.flagged = original.flagged;
+        this.recent = original.recent;
+        this.seen = original.seen;
+        this.internalDate = original.internalDate;
+        this.subType  = original.subType;
+        this.mediaType = original.mediaType;
+        this.properties = original.properties;
+        this.headers = original.headers;
+        this.lineCount = original.lineCount;
+        this.document = original.document;
+        this.bodyStartOctet = original.bodyStartOctet;
+    }
+    
+    public SimpleMailboxMembership(Date internalDate, long uid, int size, int bodyStartOctet, byte[] document, 
+            Flags flags, List<Header> headers, PropertyBuilder propertyBuilder, final long mailboxId) {
+        this.uid = uid;
+        this.document = document;
+        
+        this.size = size;
+        this.bodyStartOctet = bodyStartOctet;
+        setFlags(flags);
+        lineCount = propertyBuilder.getTextualLineCount();
+        this.headers = headers;
+        this.internalDate = internalDate;
+        this.mailboxId = mailboxId;
+        this.properties = propertyBuilder.toProperties();
+        this.mediaType = propertyBuilder.getMediaType();
+        this.subType = propertyBuilder.getSubType();
+    }
+
+
+    public Document getDocument() {
+        return this;
+    }
+
+    public Date getInternalDate() {
+        return internalDate;
+    }
+
+    public Long getMailboxId() {
+        return mailboxId;
+    }
+
+    public int getSize() {
+        return size;
+    }
+
+    public long getUid() {
+        return uid;
+    }
+
+    public boolean isAnswered() {
+        return answered;
+    }
+
+    public boolean isDeleted() {
+        return deleted;
+    }
+
+    public boolean isDraft() {
+        return draft;
+    }
+
+    public boolean isFlagged() {
+        return flagged;
+    }
+
+    public boolean isRecent() {
+        return recent;
+    }
+
+    public boolean isSeen() {
+        return seen;
+    }
+
+    public synchronized void setFlags(Flags flags) {
+        answered = flags.contains(Flags.Flag.ANSWERED);
+        deleted = flags.contains(Flags.Flag.DELETED);
+        draft = flags.contains(Flags.Flag.DRAFT);
+        flagged = flags.contains(Flags.Flag.FLAGGED);
+        recent = flags.contains(Flags.Flag.RECENT);
+        seen = flags.contains(Flags.Flag.SEEN);
+    }
+
+    public void unsetRecent() {
+        recent = false;
+    }
+
+    public RewindableInputStream getBodyContent() throws IOException {
+        return new DelegatingRewindableInputStream(new LazySkippingInputStream(new ByteArrayInputStream(document),bodyStartOctet), getFullContentOctets());
+       
+    }
+
+    public long getBodyOctets() {
+        return getFullContentOctets() - bodyStartOctet;
+    }
+
+    public RewindableInputStream getFullContent() throws IOException {
+        return new DelegatingRewindableInputStream(new ByteArrayInputStream(document), getFullContentOctets());
+    }
+
+    public long getFullContentOctets() {
+        return document.length;
+    }
+
+    public List<Header> getHeaders() {
+        return headers;
+    }
+
+    public String getMediaType() {
+        return mediaType;
+    }
+
+    public List<Property> getProperties() {
+        return properties;
+    }
+
+    public String getSubType() {
+        return subType;
+    }
+
+    public Long getTextualLineCount() {
+        return lineCount;
+    }
+
+    @Override
+    public int hashCode() {
+        final int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + (int) (uid ^ (uid >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final SimpleMailboxMembership other = (SimpleMailboxMembership) obj;
+        if (uid != other.uid)
+            return false;
+        return true;
+    }
+
+    public int compareTo(MailboxMembership<Long> o) {
+        final long otherUid = getUid();
+        return uid < otherUid ? -1 : uid == otherUid ? 0 : 1;
+    }
+
+    /**
+     * Representation suitable for logging and debugging.
+     *
+     * @return a <code>String</code> representation 
+     * of this object.
+     */
+    public String toString()
+    {
+        return super.toString() + "["
+            + "uid = " + this.uid + " "
+            + "mailboxId = " + this.mailboxId + " "
+            + "size = " + this.size + " "
+            + "answered = " + this.answered + " "
+            + "deleted = " + this.deleted + " "
+            + "draft = " + this.draft + " "
+            + "flagged = " + this.flagged + " "
+            + "recent = " + this.recent + " "
+            + "seen = " + this.seen + " "
+            + "internalDate = " + this.internalDate + " "
+            + "subType = " + this.subType + " "
+            + "mediaType = " + this.mediaType + " "
+            + " ]";
+    }
+    
+    
+}
Index: memory/src/main/java/org/apache/james/imap/inmemory/model/SimpleHeader.java
===================================================================
--- memory/src/main/java/org/apache/james/imap/inmemory/model/SimpleHeader.java	(Revision 0)
+++ memory/src/main/java/org/apache/james/imap/inmemory/model/SimpleHeader.java	(Revision 0)
@@ -0,0 +1,56 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.imap.inmemory.model;
+
+import org.apache.james.imap.store.mail.model.AbstractComparableHeader;
+
+public class SimpleHeader extends AbstractComparableHeader {
+
+    public String field;
+    public int lineNumber;
+    public String value;
+    
+    public SimpleHeader() {}
+    
+    public SimpleHeader(SimpleHeader header) {
+        this.field = header.field;
+        this.lineNumber = header.lineNumber;
+        this.value = header.value;
+    }
+    
+    public SimpleHeader(String field, int lineNumber, String value) {
+        super();
+        this.field = field;
+        this.lineNumber = lineNumber;
+        this.value = value;
+    }
+
+    public String getFieldName() {
+        return field;
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public String getValue() {
+        return value;
+    }
+}
\ No newline at end of file
Index: memory/src/main/java/org/apache/james/imap/inmemory/model/InMemoryMailbox.java
===================================================================
--- memory/src/main/java/org/apache/james/imap/inmemory/model/InMemoryMailbox.java	(Revision 0)
+++ memory/src/main/java/org/apache/james/imap/inmemory/model/InMemoryMailbox.java	(Revision 0)
@@ -0,0 +1,68 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.imap.inmemory.model;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.james.imap.store.mail.model.Mailbox;
+
+/**
+ * Mailbox data which is stored only in memory.
+ */
+public class InMemoryMailbox implements Mailbox<Long> {
+
+    private final long id;    
+    private final long uidValidity;
+    private final AtomicLong nextUid;
+    private String name;
+    
+    public InMemoryMailbox(final long id, final String name, final long uidValidity) {
+        super();
+        this.nextUid = new AtomicLong(0);
+        this.id = id;
+        this.name = name;
+        this.uidValidity = uidValidity;
+    }
+
+    public void consumeUid() {
+        nextUid.incrementAndGet();
+    }
+
+    public long getLastUid() {
+        return nextUid.get();
+    }
+
+    public Long getMailboxId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+
+    public long getUidValidity() {
+        return uidValidity;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}
Index: memory/src/main/java/org/apache/james/imap/inmemory/model/SimpleMailboxMembership.java
===================================================================
--- memory/src/main/java/org/apache/james/imap/inmemory/model/SimpleMailboxMembership.java	(Revision 0)
+++ memory/src/main/java/org/apache/james/imap/inmemory/model/SimpleMailboxMembership.java	(Revision 0)
@@ -0,0 +1,243 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.imap.inmemory.model;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+
+import javax.mail.Flags;
+
+import org.apache.james.imap.store.mail.model.AbstractMailboxMembership;
+import org.apache.james.imap.store.mail.model.Document;
+import org.apache.james.imap.store.mail.model.Header;
+import org.apache.james.imap.store.mail.model.MailboxMembership;
+import org.apache.james.imap.store.mail.model.Property;
+import org.apache.james.imap.store.mail.model.PropertyBuilder;
+import org.apache.james.imap.store.streaming.DelegatingRewindableInputStream;
+import org.apache.james.imap.store.streaming.LazySkippingInputStream;
+import org.apache.james.imap.store.streaming.RewindableInputStream;
+
+public class SimpleMailboxMembership extends AbstractMailboxMembership<Long> implements Document, Comparable<MailboxMembership<Long>> {
+
+    private final long uid;
+    private final long mailboxId;
+    private int size;
+    private boolean answered;
+    private boolean deleted;
+    private boolean draft;
+    private boolean flagged;
+    private boolean recent;
+    private boolean seen;
+    private Date internalDate;
+    private final String subType;
+    private List<Property> properties;
+    private final String mediaType;
+    private List<Header> headers;
+    private Long lineCount;
+    private byte[] document;
+    private int bodyStartOctet;
+    
+    public SimpleMailboxMembership(long mailboxId, long uid, final SimpleMailboxMembership original) {
+        this.uid = uid;
+        this.mailboxId = mailboxId;
+        this.size = original.size;
+        this.answered = original.answered;
+        this.deleted = original.deleted;
+        this.draft = original.draft;
+        this.flagged = original.flagged;
+        this.recent = original.recent;
+        this.seen = original.seen;
+        this.internalDate = original.internalDate;
+        this.subType  = original.subType;
+        this.mediaType = original.mediaType;
+        this.properties = original.properties;
+        this.headers = original.headers;
+        this.lineCount = original.lineCount;
+        this.document = original.document;
+        this.bodyStartOctet = original.bodyStartOctet;
+    }
+    
+    public SimpleMailboxMembership(Date internalDate, long uid, int size, int bodyStartOctet, byte[] document, 
+            Flags flags, List<Header> headers, PropertyBuilder propertyBuilder, final long mailboxId) {
+        this.uid = uid;
+        this.document = document;
+        
+        this.size = size;
+        this.bodyStartOctet = bodyStartOctet;
+        setFlags(flags);
+        lineCount = propertyBuilder.getTextualLineCount();
+        this.headers = headers;
+        this.internalDate = internalDate;
+        this.mailboxId = mailboxId;
+        this.properties = propertyBuilder.toProperties();
+        this.mediaType = propertyBuilder.getMediaType();
+        this.subType = propertyBuilder.getSubType();
+    }
+
+
+    public Document getDocument() {
+        return this;
+    }
+
+    public Date getInternalDate() {
+        return internalDate;
+    }
+
+    public Long getMailboxId() {
+        return mailboxId;
+    }
+
+    public int getSize() {
+        return size;
+    }
+
+    public long getUid() {
+        return uid;
+    }
+
+    public boolean isAnswered() {
+        return answered;
+    }
+
+    public boolean isDeleted() {
+        return deleted;
+    }
+
+    public boolean isDraft() {
+        return draft;
+    }
+
+    public boolean isFlagged() {
+        return flagged;
+    }
+
+    public boolean isRecent() {
+        return recent;
+    }
+
+    public boolean isSeen() {
+        return seen;
+    }
+
+    public synchronized void setFlags(Flags flags) {
+        answered = flags.contains(Flags.Flag.ANSWERED);
+        deleted = flags.contains(Flags.Flag.DELETED);
+        draft = flags.contains(Flags.Flag.DRAFT);
+        flagged = flags.contains(Flags.Flag.FLAGGED);
+        recent = flags.contains(Flags.Flag.RECENT);
+        seen = flags.contains(Flags.Flag.SEEN);
+    }
+
+    public void unsetRecent() {
+        recent = false;
+    }
+
+    public RewindableInputStream getBodyContent() throws IOException {
+        return new DelegatingRewindableInputStream(new LazySkippingInputStream(new ByteArrayInputStream(document),bodyStartOctet), getFullContentOctets());
+       
+    }
+
+    public long getBodyOctets() {
+        return getFullContentOctets() - bodyStartOctet;
+    }
+
+    public RewindableInputStream getFullContent() throws IOException {
+        return new DelegatingRewindableInputStream(new ByteArrayInputStream(document), getFullContentOctets());
+    }
+
+    public long getFullContentOctets() {
+        return document.length;
+    }
+
+    public List<Header> getHeaders() {
+        return headers;
+    }
+
+    public String getMediaType() {
+        return mediaType;
+    }
+
+    public List<Property> getProperties() {
+        return properties;
+    }
+
+    public String getSubType() {
+        return subType;
+    }
+
+    public Long getTextualLineCount() {
+        return lineCount;
+    }
+
+    @Override
+    public int hashCode() {
+        final int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + (int) (uid ^ (uid >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final SimpleMailboxMembership other = (SimpleMailboxMembership) obj;
+        if (uid != other.uid)
+            return false;
+        return true;
+    }
+
+    public int compareTo(MailboxMembership<Long> o) {
+        final long otherUid = getUid();
+        return uid < otherUid ? -1 : uid == otherUid ? 0 : 1;
+    }
+
+    /**
+     * Representation suitable for logging and debugging.
+     *
+     * @return a <code>String</code> representation 
+     * of this object.
+     */
+    public String toString()
+    {
+        return super.toString() + "["
+            + "uid = " + this.uid + " "
+            + "mailboxId = " + this.mailboxId + " "
+            + "size = " + this.size + " "
+            + "answered = " + this.answered + " "
+            + "deleted = " + this.deleted + " "
+            + "draft = " + this.draft + " "
+            + "flagged = " + this.flagged + " "
+            + "recent = " + this.recent + " "
+            + "seen = " + this.seen + " "
+            + "internalDate = " + this.internalDate + " "
+            + "subType = " + this.subType + " "
+            + "mediaType = " + this.mediaType + " "
+            + " ]";
+    }
+    
+    
+}
Index: memory/src/main/java/org/apache/james/imap/inmemory/model/SimpleHeader.java
===================================================================
--- memory/src/main/java/org/apache/james/imap/inmemory/model/SimpleHeader.java	(Revision 0)
+++ memory/src/main/java/org/apache/james/imap/inmemory/model/SimpleHeader.java	(Revision 0)
@@ -0,0 +1,56 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.imap.inmemory.model;
+
+import org.apache.james.imap.store.mail.model.AbstractComparableHeader;
+
+public class SimpleHeader extends AbstractComparableHeader {
+
+    public String field;
+    public int lineNumber;
+    public String value;
+    
+    public SimpleHeader() {}
+    
+    public SimpleHeader(SimpleHeader header) {
+        this.field = header.field;
+        this.lineNumber = header.lineNumber;
+        this.value = header.value;
+    }
+    
+    public SimpleHeader(String field, int lineNumber, String value) {
+        super();
+        this.field = field;
+        this.lineNumber = lineNumber;
+        this.value = value;
+    }
+
+    public String getFieldName() {
+        return field;
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public String getValue() {
+        return value;
+    }
+}
\ No newline at end of file
Index: memory/src/main/java/org/apache/james/imap/inmemory/model/InMemoryMailbox.java
===================================================================
--- memory/src/main/java/org/apache/james/imap/inmemory/model/InMemoryMailbox.java	(Revision 0)
+++ memory/src/main/java/org/apache/james/imap/inmemory/model/InMemoryMailbox.java	(Revision 0)
@@ -0,0 +1,68 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.imap.inmemory.model;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.james.imap.store.mail.model.Mailbox;
+
+/**
+ * Mailbox data which is stored only in memory.
+ */
+public class InMemoryMailbox implements Mailbox<Long> {
+
+    private final long id;    
+    private final long uidValidity;
+    private final AtomicLong nextUid;
+    private String name;
+    
+    public InMemoryMailbox(final long id, final String name, final long uidValidity) {
+        super();
+        this.nextUid = new AtomicLong(0);
+        this.id = id;
+        this.name = name;
+        this.uidValidity = uidValidity;
+    }
+
+    public void consumeUid() {
+        nextUid.incrementAndGet();
+    }
+
+    public long getLastUid() {
+        return nextUid.get();
+    }
+
+    public Long getMailboxId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+
+    public long getUidValidity() {
+        return uidValidity;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}
Index: memory/src/main/java/org/apache/james/imap/inmemory/SimpleMailboxMembership.java
===================================================================
--- memory/src/main/java/org/apache/james/imap/inmemory/SimpleMailboxMembership.java	(Revision 950435)
+++ memory/src/main/java/org/apache/james/imap/inmemory/SimpleMailboxMembership.java	(Arbeitskopie)
@@ -1,243 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.imap.inmemory;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.util.Date;
-import java.util.List;
-
-import javax.mail.Flags;
-
-import org.apache.james.imap.store.DelegatingRewindableInputStream;
-import org.apache.james.imap.store.LazySkippingInputStream;
-import org.apache.james.imap.store.RewindableInputStream;
-import org.apache.james.imap.store.mail.model.AbstractMailboxMembership;
-import org.apache.james.imap.store.mail.model.Document;
-import org.apache.james.imap.store.mail.model.Header;
-import org.apache.james.imap.store.mail.model.MailboxMembership;
-import org.apache.james.imap.store.mail.model.Property;
-import org.apache.james.imap.store.mail.model.PropertyBuilder;
-
-public class SimpleMailboxMembership extends AbstractMailboxMembership<Long> implements Document, Comparable<MailboxMembership<Long>> {
-
-    private final long uid;
-    private final long mailboxId;
-    private int size;
-    private boolean answered;
-    private boolean deleted;
-    private boolean draft;
-    private boolean flagged;
-    private boolean recent;
-    private boolean seen;
-    private Date internalDate;
-    private final String subType;
-    private List<Property> properties;
-    private final String mediaType;
-    private List<Header> headers;
-    private Long lineCount;
-    private byte[] document;
-    private int bodyStartOctet;
-    
-    public SimpleMailboxMembership(long mailboxId, long uid, final SimpleMailboxMembership original) {
-        this.uid = uid;
-        this.mailboxId = mailboxId;
-        this.size = original.size;
-        this.answered = original.answered;
-        this.deleted = original.deleted;
-        this.draft = original.draft;
-        this.flagged = original.flagged;
-        this.recent = original.recent;
-        this.seen = original.seen;
-        this.internalDate = original.internalDate;
-        this.subType  = original.subType;
-        this.mediaType = original.mediaType;
-        this.properties = original.properties;
-        this.headers = original.headers;
-        this.lineCount = original.lineCount;
-        this.document = original.document;
-        this.bodyStartOctet = original.bodyStartOctet;
-    }
-    
-    public SimpleMailboxMembership(Date internalDate, long uid, int size, int bodyStartOctet, byte[] document, 
-            Flags flags, List<Header> headers, PropertyBuilder propertyBuilder, final long mailboxId) {
-        this.uid = uid;
-        this.document = document;
-        
-        this.size = size;
-        this.bodyStartOctet = bodyStartOctet;
-        setFlags(flags);
-        lineCount = propertyBuilder.getTextualLineCount();
-        this.headers = headers;
-        this.internalDate = internalDate;
-        this.mailboxId = mailboxId;
-        this.properties = propertyBuilder.toProperties();
-        this.mediaType = propertyBuilder.getMediaType();
-        this.subType = propertyBuilder.getSubType();
-    }
-
-
-    public Document getDocument() {
-        return this;
-    }
-
-    public Date getInternalDate() {
-        return internalDate;
-    }
-
-    public Long getMailboxId() {
-        return mailboxId;
-    }
-
-    public int getSize() {
-        return size;
-    }
-
-    public long getUid() {
-        return uid;
-    }
-
-    public boolean isAnswered() {
-        return answered;
-    }
-
-    public boolean isDeleted() {
-        return deleted;
-    }
-
-    public boolean isDraft() {
-        return draft;
-    }
-
-    public boolean isFlagged() {
-        return flagged;
-    }
-
-    public boolean isRecent() {
-        return recent;
-    }
-
-    public boolean isSeen() {
-        return seen;
-    }
-
-    public synchronized void setFlags(Flags flags) {
-        answered = flags.contains(Flags.Flag.ANSWERED);
-        deleted = flags.contains(Flags.Flag.DELETED);
-        draft = flags.contains(Flags.Flag.DRAFT);
-        flagged = flags.contains(Flags.Flag.FLAGGED);
-        recent = flags.contains(Flags.Flag.RECENT);
-        seen = flags.contains(Flags.Flag.SEEN);
-    }
-
-    public void unsetRecent() {
-        recent = false;
-    }
-
-    public RewindableInputStream getBodyContent() throws IOException {
-        return new DelegatingRewindableInputStream(new LazySkippingInputStream(new ByteArrayInputStream(document),bodyStartOctet), getFullContentOctets());
-       
-    }
-
-    public long getBodyOctets() {
-        return getFullContentOctets() - bodyStartOctet;
-    }
-
-    public RewindableInputStream getFullContent() throws IOException {
-        return new DelegatingRewindableInputStream(new ByteArrayInputStream(document), getFullContentOctets());
-    }
-
-    public long getFullContentOctets() {
-        return document.length;
-    }
-
-    public List<Header> getHeaders() {
-        return headers;
-    }
-
-    public String getMediaType() {
-        return mediaType;
-    }
-
-    public List<Property> getProperties() {
-        return properties;
-    }
-
-    public String getSubType() {
-        return subType;
-    }
-
-    public Long getTextualLineCount() {
-        return lineCount;
-    }
-
-    @Override
-    public int hashCode() {
-        final int PRIME = 31;
-        int result = 1;
-        result = PRIME * result + (int) (uid ^ (uid >>> 32));
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        final SimpleMailboxMembership other = (SimpleMailboxMembership) obj;
-        if (uid != other.uid)
-            return false;
-        return true;
-    }
-
-    public int compareTo(MailboxMembership<Long> o) {
-        final long otherUid = getUid();
-        return uid < otherUid ? -1 : uid == otherUid ? 0 : 1;
-    }
-
-    /**
-     * Representation suitable for logging and debugging.
-     *
-     * @return a <code>String</code> representation 
-     * of this object.
-     */
-    public String toString()
-    {
-        return super.toString() + "["
-            + "uid = " + this.uid + " "
-            + "mailboxId = " + this.mailboxId + " "
-            + "size = " + this.size + " "
-            + "answered = " + this.answered + " "
-            + "deleted = " + this.deleted + " "
-            + "draft = " + this.draft + " "
-            + "flagged = " + this.flagged + " "
-            + "recent = " + this.recent + " "
-            + "seen = " + this.seen + " "
-            + "internalDate = " + this.internalDate + " "
-            + "subType = " + this.subType + " "
-            + "mediaType = " + this.mediaType + " "
-            + " ]";
-    }
-    
-    
-}
Index: memory/src/main/java/org/apache/james/imap/inmemory/SimpleHeader.java
===================================================================
--- memory/src/main/java/org/apache/james/imap/inmemory/SimpleHeader.java	(Revision 950435)
+++ memory/src/main/java/org/apache/james/imap/inmemory/SimpleHeader.java	(Arbeitskopie)
@@ -1,56 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.imap.inmemory;
-
-import org.apache.james.imap.store.mail.model.AbstractComparableHeader;
-
-public class SimpleHeader extends AbstractComparableHeader {
-
-    public String field;
-    public int lineNumber;
-    public String value;
-    
-    public SimpleHeader() {}
-    
-    public SimpleHeader(SimpleHeader header) {
-        this.field = header.field;
-        this.lineNumber = header.lineNumber;
-        this.value = header.value;
-    }
-    
-    public SimpleHeader(String field, int lineNumber, String value) {
-        super();
-        this.field = field;
-        this.lineNumber = lineNumber;
-        this.value = value;
-    }
-
-    public String getFieldName() {
-        return field;
-    }
-
-    public int getLineNumber() {
-        return lineNumber;
-    }
-
-    public String getValue() {
-        return value;
-    }
-}
\ No newline at end of file
Index: memory/src/main/java/org/apache/james/imap/inmemory/InMemorySubscriptionManager.java
===================================================================
--- memory/src/main/java/org/apache/james/imap/inmemory/InMemorySubscriptionManager.java	(Revision 950435)
+++ memory/src/main/java/org/apache/james/imap/inmemory/InMemorySubscriptionManager.java	(Arbeitskopie)
@@ -28,6 +28,7 @@
 import org.apache.james.imap.mailbox.MailboxException;
 import org.apache.james.imap.mailbox.MailboxSession;
 import org.apache.james.imap.mailbox.MailboxSession.User;
+import org.apache.james.imap.store.MailboxSessionMapperFactory;
 import org.apache.james.imap.store.StoreSubscriptionManager;
 import org.apache.james.imap.store.user.SubscriptionMapper;
 import org.apache.james.imap.store.user.model.Subscription;
@@ -35,22 +36,17 @@
 /**
  * Stores subscriptions in memory.
  */
-public class InMemorySubscriptionManager extends StoreSubscriptionManager implements SubscriptionMapper {
+public class InMemorySubscriptionManager extends StoreSubscriptionManager<Long> implements SubscriptionMapper {
     
     private static final int INITIAL_SIZE = 64;
     private final Map<String, List<Subscription>> subscriptionsByUser;
     
-    public InMemorySubscriptionManager() {
-        super();
+    public InMemorySubscriptionManager(MailboxSessionMapperFactory<Long> mapperFactory) {
+        super(mapperFactory);
         subscriptionsByUser = new ConcurrentHashMap<String, List<Subscription>>(INITIAL_SIZE);
     }
 
     @Override
-    protected SubscriptionMapper createMapper(MailboxSession session) {
-        return this;
-    }
-
-    @Override
     protected Subscription createSubscription(MailboxSession session, String mailbox) {
         return new InMemorySubscription(mailbox, session.getUser());
     }
Index: memory/src/main/java/org/apache/james/imap/inmemory/InMemoryStoreMessageManager.java
===================================================================
--- memory/src/main/java/org/apache/james/imap/inmemory/InMemoryStoreMessageManager.java	(Revision 950435)
+++ memory/src/main/java/org/apache/james/imap/inmemory/InMemoryStoreMessageManager.java	(Arbeitskopie)
@@ -31,6 +31,9 @@
 
 import javax.mail.Flags;
 
+import org.apache.james.imap.inmemory.model.InMemoryMailbox;
+import org.apache.james.imap.inmemory.model.SimpleHeader;
+import org.apache.james.imap.inmemory.model.SimpleMailboxMembership;
 import org.apache.james.imap.mailbox.MailboxException;
 import org.apache.james.imap.mailbox.MailboxSession;
 import org.apache.james.imap.mailbox.MessageRange;
@@ -38,27 +41,25 @@
 import org.apache.james.imap.mailbox.StorageException;
 import org.apache.james.imap.mailbox.util.MailboxEventDispatcher;
 import org.apache.james.imap.store.MailboxMembershipComparator;
-import org.apache.james.imap.store.StoreMailbox;
+import org.apache.james.imap.store.MailboxSessionMapperFactory;
+import org.apache.james.imap.store.StoreMessageManager;
 import org.apache.james.imap.store.UidConsumer;
-import org.apache.james.imap.store.mail.MailboxMapper;
 import org.apache.james.imap.store.mail.MessageMapper;
 import org.apache.james.imap.store.mail.model.Header;
-import org.apache.james.imap.store.mail.model.Mailbox;
 import org.apache.james.imap.store.mail.model.MailboxMembership;
 import org.apache.james.imap.store.mail.model.PropertyBuilder;
 
-public class InMemoryStoreMailbox extends StoreMailbox<Long> implements MessageMapper<Long> {
+public class InMemoryStoreMessageManager extends StoreMessageManager<Long> implements MessageMapper<Long> {
     
     private static final int INITIAL_SIZE = 256;
     private Map<Long, MailboxMembership<Long>> membershipByUid;
-    private InMemoryMailbox mailbox;
 
-    public InMemoryStoreMailbox(MailboxEventDispatcher dispatcher, UidConsumer<Long> consumer, InMemoryMailbox mailbox) {
-        super(dispatcher, consumer, mailbox);
-        this.mailbox = mailbox;
+    public InMemoryStoreMessageManager(MailboxSessionMapperFactory<Long> mapperFactory,
+            MailboxEventDispatcher dispatcher, UidConsumer<Long> consumer, InMemoryMailbox mailbox,
+            MailboxSession session) throws MailboxException {
+        super(mapperFactory, dispatcher, consumer, mailbox, session);
         this.membershipByUid = new ConcurrentHashMap<Long, MailboxMembership<Long>>(INITIAL_SIZE);
     }
-    
 
     @Override
     protected MailboxMembership<Long> copyMessage(MailboxMembership<Long> originalMessage, long uid, MailboxSession session) {
@@ -90,14 +91,8 @@
             byteContent = new byte[0];
         }
         return new SimpleMailboxMembership(internalDate, uid, size, bodyStartOctet, byteContent, flags, headers, propertyBuilder, getMailboxId());
-
-
     }
 
-    @Override
-    protected MessageMapper<Long> createMessageMapper(MailboxSession session) {
-        return this;
-    }
     /*
      * (non-Javadoc)
      * @see org.apache.james.imap.store.mail.MessageMapper#countMessagesInMailbox()
@@ -229,7 +224,6 @@
         return new ArrayList<MailboxMembership<Long>>(membershipByUid.values());
     }
 
-
     /**
      * There is no really Transaction handling here.. Just run it 
      */
@@ -237,28 +231,12 @@
         transaction.run();
     }
 
-
     public void dispose() {
         // do nothing
-        
     }
     
-    
     public MessageMapper<Long> getMessageMapperForRequest(MailboxSession session) throws MailboxException {
-        return createMessageMapper(session);
+        return this;
     }
-
-
-    @Override
-    protected MailboxMapper<Long> createMailboxMapper(MailboxSession session) throws MailboxException {
-        return null;
-    }
-
-
-    @Override
-    protected Mailbox<Long> getMailboxRow(MailboxSession session) throws MailboxException {
-        return mailbox;
-    }
-
     
 }
Index: memory/src/main/java/org/apache/james/imap/inmemory/InMemoryStoreMailbox.java
===================================================================
--- memory/src/main/java/org/apache/james/imap/inmemory/InMemoryStoreMailbox.java	(Revision 950435)
+++ memory/src/main/java/org/apache/james/imap/inmemory/InMemoryStoreMailbox.java	(Arbeitskopie)
@@ -1,264 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.imap.inmemory;
-
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.mail.Flags;
-
-import org.apache.james.imap.mailbox.MailboxException;
-import org.apache.james.imap.mailbox.MailboxSession;
-import org.apache.james.imap.mailbox.MessageRange;
-import org.apache.james.imap.mailbox.SearchQuery;
-import org.apache.james.imap.mailbox.StorageException;
-import org.apache.james.imap.mailbox.util.MailboxEventDispatcher;
-import org.apache.james.imap.store.MailboxMembershipComparator;
-import org.apache.james.imap.store.StoreMailbox;
-import org.apache.james.imap.store.UidConsumer;
-import org.apache.james.imap.store.mail.MailboxMapper;
-import org.apache.james.imap.store.mail.MessageMapper;
-import org.apache.james.imap.store.mail.model.Header;
-import org.apache.james.imap.store.mail.model.Mailbox;
-import org.apache.james.imap.store.mail.model.MailboxMembership;
-import org.apache.james.imap.store.mail.model.PropertyBuilder;
-
-public class InMemoryStoreMailbox extends StoreMailbox<Long> implements MessageMapper<Long> {
-    
-    private static final int INITIAL_SIZE = 256;
-    private Map<Long, MailboxMembership<Long>> membershipByUid;
-    private InMemoryMailbox mailbox;
-
-    public InMemoryStoreMailbox(MailboxEventDispatcher dispatcher, UidConsumer<Long> consumer, InMemoryMailbox mailbox) {
-        super(dispatcher, consumer, mailbox);
-        this.mailbox = mailbox;
-        this.membershipByUid = new ConcurrentHashMap<Long, MailboxMembership<Long>>(INITIAL_SIZE);
-    }
-    
-
-    @Override
-    protected MailboxMembership<Long> copyMessage(MailboxMembership<Long> originalMessage, long uid, MailboxSession session) {
-        return new SimpleMailboxMembership(getMailboxId(), uid, (SimpleMailboxMembership) originalMessage);
-    }
-
-    @Override
-    protected Header createHeader(int lineNumber, String name, String value) {
-        return new SimpleHeader(name, lineNumber, value);
-    }
-
-    @Override
-    protected MailboxMembership<Long> createMessage(Date internalDate, long uid, int size, int bodyStartOctet, 
-            InputStream  document, Flags flags, List<Header> headers, PropertyBuilder propertyBuilder) {
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        byte[] byteContent;
-        try {
-            byte[] buf = new byte[1024];
-            int i = 0;
-            while ((i = document.read(buf)) != -1) {
-                out.write(buf, 0, i);
-            }
-            byteContent = out.toByteArray();
-            if (out != null)
-                out.close();
-
-        } catch (Exception e) {
-            e.printStackTrace();
-            byteContent = new byte[0];
-        }
-        return new SimpleMailboxMembership(internalDate, uid, size, bodyStartOctet, byteContent, flags, headers, propertyBuilder, getMailboxId());
-
-
-    }
-
-    @Override
-    protected MessageMapper<Long> createMessageMapper(MailboxSession session) {
-        return this;
-    }
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#countMessagesInMailbox()
-     */
-    public long countMessagesInMailbox() throws StorageException {
-        return membershipByUid.size();
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#countUnseenMessagesInMailbox()
-     */
-    public long countUnseenMessagesInMailbox() throws StorageException {
-        long count = 0;
-        for(MailboxMembership<Long> member:membershipByUid.values()) {
-            if (!member.isSeen()) {
-                count++;
-            }
-        }
-        return count;
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#delete(org.apache.james.imap.store.mail.model.MailboxMembership)
-     */
-    public void delete(MailboxMembership<Long> message) throws StorageException {
-        membershipByUid.remove(message.getUid());
-    }
-
-    @SuppressWarnings("unchecked")
-    public List<MailboxMembership<Long>> findInMailbox(MessageRange set) throws StorageException {
-        final List<MailboxMembership<Long>> results;
-        final MessageRange.Type type = set.getType();
-        switch (type) {
-            case ALL:
-                results = new ArrayList<MailboxMembership<Long>>(membershipByUid.values());
-                break;
-            case FROM:
-                results = new ArrayList<MailboxMembership<Long>>(membershipByUid.values());
-                for (final Iterator<MailboxMembership<Long>> it=results.iterator();it.hasNext();) {
-                   if (it.next().getUid()< set.getUidFrom()) {
-                       it.remove(); 
-                   }
-                }
-                break;
-            case RANGE:
-                results = new ArrayList<MailboxMembership<Long>>(membershipByUid.values());
-                for (final Iterator<MailboxMembership<Long>> it=results.iterator();it.hasNext();) {
-                   final long uid = it.next().getUid();
-                if (uid<set.getUidFrom() || uid>set.getUidTo()) {
-                       it.remove(); 
-                   }
-                }
-                break;
-            case ONE:
-                results  = new ArrayList<MailboxMembership<Long>>(1);
-                final MailboxMembership member = membershipByUid.get(set.getUidFrom());
-                if (member != null) {
-                    results.add(member);
-                }
-                break;
-            default:
-                results = new ArrayList<MailboxMembership<Long>>();
-                break;
-        }
-        Collections.sort(results, MailboxMembershipComparator.INSTANCE);
-        return results;
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#findMarkedForDeletionInMailbox(org.apache.james.imap.mailbox.MessageRange)
-     */
-    public List<MailboxMembership<Long>> findMarkedForDeletionInMailbox(MessageRange set) throws StorageException {
-        final List<MailboxMembership<Long>> results = findInMailbox(set);
-        for(final Iterator<MailboxMembership<Long>> it=results.iterator();it.hasNext();) {
-            if (!it.next().isDeleted()) {
-                it.remove();
-            }
-        }
-        return results;
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#findRecentMessagesInMailbox()
-     */
-    public List<MailboxMembership<Long>> findRecentMessagesInMailbox() throws StorageException {
-        final List<MailboxMembership<Long>> results = new ArrayList<MailboxMembership<Long>>();
-        for(MailboxMembership<Long> member:membershipByUid.values()) {
-            if (member.isRecent()) {
-                results.add(member);
-            }
-        }
-        Collections.sort(results, MailboxMembershipComparator.INSTANCE);
-
-        return results;
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#findUnseenMessagesInMailbox()
-     */
-    public List<MailboxMembership<Long>> findUnseenMessagesInMailbox() throws StorageException {
-        final List<MailboxMembership<Long>> results = new ArrayList<MailboxMembership<Long>>();
-        for(MailboxMembership<Long> member:membershipByUid.values()) {
-            if (!member.isSeen()) {
-                results.add(member);
-            }
-        }
-        Collections.sort(results, MailboxMembershipComparator.INSTANCE);
-        return results;
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#save(org.apache.james.imap.store.mail.model.MailboxMembership)
-     */
-    public void save(MailboxMembership<Long> message) throws StorageException {
-        membershipByUid.put(message.getUid(), message);
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.store.mail.MessageMapper#searchMailbox(org.apache.james.imap.mailbox.SearchQuery)
-     */
-    public List<MailboxMembership<Long>> searchMailbox(SearchQuery query) throws StorageException {
-        return new ArrayList<MailboxMembership<Long>>(membershipByUid.values());
-    }
-
-
-    /**
-     * There is no really Transaction handling here.. Just run it 
-     */
-    public void execute(Transaction transaction) throws MailboxException {
-        transaction.run();
-    }
-
-
-    public void dispose() {
-        // do nothing
-        
-    }
-    
-    
-    public MessageMapper<Long> getMessageMapperForRequest(MailboxSession session) throws MailboxException {
-        return createMessageMapper(session);
-    }
-
-
-    @Override
-    protected MailboxMapper<Long> createMailboxMapper(MailboxSession session) throws MailboxException {
-        return null;
-    }
-
-
-    @Override
-    protected Mailbox<Long> getMailboxRow(MailboxSession session) throws MailboxException {
-        return mailbox;
-    }
-
-    
-}
Index: memory/src/main/java/org/apache/james/imap/inmemory/InMemoryMailboxSessionMapperFactory.java
===================================================================
--- memory/src/main/java/org/apache/james/imap/inmemory/InMemoryMailboxSessionMapperFactory.java	(Revision 0)
+++ memory/src/main/java/org/apache/james/imap/inmemory/InMemoryMailboxSessionMapperFactory.java	(Revision 0)
@@ -0,0 +1,46 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.inmemory;
+
+import org.apache.james.imap.mailbox.MailboxException;
+import org.apache.james.imap.mailbox.MailboxSession;
+import org.apache.james.imap.mailbox.SubscriptionException;
+import org.apache.james.imap.store.MailboxSessionMapperFactory;
+import org.apache.james.imap.store.mail.MailboxMapper;
+import org.apache.james.imap.store.mail.MessageMapper;
+import org.apache.james.imap.store.user.SubscriptionMapper;
+
+public class InMemoryMailboxSessionMapperFactory extends MailboxSessionMapperFactory<Long> {
+
+    @Override
+    public MailboxMapper<Long> createMailboxMapper(MailboxSession session) throws MailboxException {
+        return null;
+    }
+
+    @Override
+    public MessageMapper<Long> createMessageMapper(MailboxSession session, Long mailboxId) throws MailboxException {
+        return null;
+    }
+
+    @Override
+    public SubscriptionMapper createSubscriptionMapper(MailboxSession session) throws SubscriptionException {
+        return null;
+    }
+
+}
Index: memory/src/main/java/org/apache/james/imap/inmemory/InMemoryMailboxManager.java
===================================================================
--- memory/src/main/java/org/apache/james/imap/inmemory/InMemoryMailboxManager.java	(Revision 950435)
+++ memory/src/main/java/org/apache/james/imap/inmemory/InMemoryMailboxManager.java	(Arbeitskopie)
@@ -24,13 +24,15 @@
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.apache.james.imap.inmemory.model.InMemoryMailbox;
 import org.apache.james.imap.mailbox.MailboxException;
 import org.apache.james.imap.mailbox.MailboxNotFoundException;
 import org.apache.james.imap.mailbox.MailboxSession;
 import org.apache.james.imap.mailbox.StorageException;
 import org.apache.james.imap.mailbox.util.MailboxEventDispatcher;
 import org.apache.james.imap.store.Authenticator;
-import org.apache.james.imap.store.StoreMailbox;
+import org.apache.james.imap.store.MailboxSessionMapperFactory;
+import org.apache.james.imap.store.StoreMessageManager;
 import org.apache.james.imap.store.StoreMailboxManager;
 import org.apache.james.imap.store.Subscriber;
 import org.apache.james.imap.store.UidConsumer;
@@ -42,12 +44,11 @@
 
     private static final int INITIAL_SIZE = 128;
     private Map<Long, InMemoryMailbox> mailboxesById;
-    private Map<String, InMemoryStoreMailbox> storeMailboxByName;
+    private Map<String, InMemoryStoreMessageManager> storeMailboxByName;
     private Map<Long, String> idNameMap;
-    private MailboxSession session;
 
-    public InMemoryMailboxManager(Authenticator authenticator, Subscriber subscriber) {
-        super(authenticator, subscriber, new UidConsumer<Long>() {
+    public InMemoryMailboxManager(MailboxSessionMapperFactory<Long> mapperFactory, Authenticator authenticator, Subscriber subscriber) {
+        super(mapperFactory, authenticator, subscriber, new UidConsumer<Long>() {
 
             public long reserveNextUid(Mailbox<Long> mailbox, MailboxSession session) throws MailboxException {
                 mailbox.consumeUid();
@@ -55,15 +56,15 @@
             }
         });
         mailboxesById = new ConcurrentHashMap<Long, InMemoryMailbox>(INITIAL_SIZE);
-        storeMailboxByName = new ConcurrentHashMap<String, InMemoryStoreMailbox>(INITIAL_SIZE);
+        storeMailboxByName = new ConcurrentHashMap<String, InMemoryStoreMessageManager>(INITIAL_SIZE);
         idNameMap = new ConcurrentHashMap<Long, String>(INITIAL_SIZE);
     }
 
     @Override
-    protected StoreMailbox<Long> createMailbox(MailboxEventDispatcher dispatcher, UidConsumer<Long> consumer, Mailbox<Long> mailboxRow, MailboxSession session) {
-        InMemoryStoreMailbox storeMailbox = storeMailboxByName.get(mailboxRow.getName());
+    protected StoreMessageManager<Long> createMessageManager(MailboxEventDispatcher dispatcher, UidConsumer<Long> consumer, Mailbox<Long> mailboxRow, MailboxSession session) throws MailboxException {
+        InMemoryStoreMessageManager storeMailbox = storeMailboxByName.get(mailboxRow.getName());
         if (storeMailbox == null) {
-            storeMailbox = new InMemoryStoreMailbox(dispatcher, consumer, (InMemoryMailbox)mailboxRow);
+            storeMailbox = new InMemoryStoreMessageManager(mailboxSessionMapperFactory, dispatcher, consumer, (InMemoryMailbox)mailboxRow, session);
             storeMailboxByName.put(mailboxRow.getName(), storeMailbox);
         }
         
@@ -71,13 +72,7 @@
     }
 
     @Override
-    protected MailboxMapper<Long> createMailboxMapper(MailboxSession session) {
-        this.session = session;
-        return this;
-    }
-
-    @Override
-    protected void doCreate(String namespaceName, MailboxSession session) throws StorageException {
+    protected void doCreateMailbox(String namespaceName, MailboxSession session) throws StorageException {
         InMemoryMailbox mailbox = new InMemoryMailbox(randomId(), namespaceName, randomUidValidity());
         idNameMap.put(mailbox.getMailboxId(), mailbox.getName());
         save(mailbox);
@@ -176,10 +171,10 @@
         mailboxesById.put(mailbox.getMailboxId(), (InMemoryMailbox) mailbox);
         String name = idNameMap.remove(mailbox.getMailboxId());
         if (name != null) {
-            InMemoryStoreMailbox m = storeMailboxByName.remove(name);
+            InMemoryStoreMessageManager m = storeMailboxByName.remove(name);
             if (m!= null) {
                 try {
-                    m.getMailboxRow(session).setName(mailbox.getName());
+                    m.getMailboxEntity().setName(mailbox.getName());
                     storeMailboxByName.put(mailbox.getName(), m);
                 } catch (MailboxException e) {
                     throw new StorageException(e.getKey(), e);
@@ -204,7 +199,7 @@
      */
 
     public synchronized void deleteEverything() throws MailboxException {
-        final MailboxMapper<Long> mapper = createMailboxMapper(null);
+        final MailboxMapper<Long> mapper = this;
         mapper.execute(new TransactionalMapper.Transaction() {
 
             public void run() throws MailboxException {
Index: memory/src/main/java/org/apache/james/imap/inmemory/InMemoryMailbox.java
===================================================================
--- memory/src/main/java/org/apache/james/imap/inmemory/InMemoryMailbox.java	(Revision 950435)
+++ memory/src/main/java/org/apache/james/imap/inmemory/InMemoryMailbox.java	(Arbeitskopie)
@@ -1,68 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.imap.inmemory;
-
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.apache.james.imap.store.mail.model.Mailbox;
-
-/**
- * Mailbox data which is stored only in memory.
- */
-public class InMemoryMailbox implements Mailbox<Long> {
-
-    private final long id;    
-    private final long uidValidity;
-    private final AtomicLong nextUid;
-    private String name;
-    
-    public InMemoryMailbox(final long id, final String name, final long uidValidity) {
-        super();
-        this.nextUid = new AtomicLong(0);
-        this.id = id;
-        this.name = name;
-        this.uidValidity = uidValidity;
-    }
-
-    public void consumeUid() {
-        nextUid.incrementAndGet();
-    }
-
-    public long getLastUid() {
-        return nextUid.get();
-    }
-
-    public Long getMailboxId() {
-        return id;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-
-    public long getUidValidity() {
-        return uidValidity;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-}
Index: jpa/src/main/java/org/apache/james/imap/jpa/user/JPASubscriptionMapper.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/user/JPASubscriptionMapper.java	(Revision 950435)
+++ jpa/src/main/java/org/apache/james/imap/jpa/user/JPASubscriptionMapper.java	(Arbeitskopie)
@@ -20,7 +20,7 @@
 
 import java.util.List;
 
-import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
 import javax.persistence.NoResultException;
 import javax.persistence.PersistenceException;
 
@@ -35,18 +35,17 @@
  */
 public class JPASubscriptionMapper extends JPATransactionalMapper implements SubscriptionMapper {
 
-    public JPASubscriptionMapper(final EntityManager factory) {
-        super(factory);
+    public JPASubscriptionMapper(final EntityManagerFactory entityManagerFactory) {
+        super(entityManagerFactory);
     }
 
-
     /**
      * @throws SubscriptionException 
      * @see org.apache.james.imap.store.user.SubscriptionMapper#findFindMailboxSubscriptionForUser(java.lang.String, java.lang.String)
      */
     public Subscription findFindMailboxSubscriptionForUser(final String user, final String mailbox) throws SubscriptionException {
         try {
-            return (Subscription) getManager().createNamedQuery("findFindMailboxSubscriptionForUser")
+            return (Subscription) getEntityManager().createNamedQuery("findFindMailboxSubscriptionForUser")
             .setParameter("userParam", user).setParameter("mailboxParam", mailbox).getSingleResult();
         } catch (NoResultException e) {
             return null;
@@ -61,7 +60,7 @@
      */
     public void save(Subscription subscription) throws SubscriptionException {
         try {
-            getManager().persist(subscription);
+            getEntityManager().persist(subscription);
         } catch (PersistenceException e) {
             throw new SubscriptionException(HumanReadableText.SAVE_FAILED, e);
         }
@@ -74,7 +73,7 @@
     @SuppressWarnings("unchecked")
     public List<Subscription> findSubscriptionsForUser(String user) throws SubscriptionException {
         try {
-            return (List<Subscription>) getManager().createNamedQuery("findSubscriptionsForUser").setParameter("userParam", user).getResultList();
+            return (List<Subscription>) getEntityManager().createNamedQuery("findSubscriptionsForUser").setParameter("userParam", user).getResultList();
         } catch (PersistenceException e) {
             throw new SubscriptionException(HumanReadableText.SEARCH_FAILED, e);
         }
@@ -86,7 +85,7 @@
      */
     public void delete(Subscription subscription) throws SubscriptionException {
         try {
-            getManager().remove(subscription);
+            getEntityManager().remove(subscription);
         } catch (PersistenceException e) {
             throw new SubscriptionException(HumanReadableText.DELETED_FAILED, e);
         }
Index: jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMessageManager.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMessageManager.java	(Revision 950435)
+++ jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMessageManager.java	(Arbeitskopie)
@@ -26,8 +26,8 @@
 
 import javax.mail.Flags;
 
-import org.apache.james.imap.jpa.JPAMailbox;
-import org.apache.james.imap.jpa.MailboxSessionEntityManagerFactory;
+import org.apache.james.imap.jpa.JPAMailboxSessionMapperFactory;
+import org.apache.james.imap.jpa.JPAMessageManager;
 import org.apache.james.imap.jpa.mail.model.AbstractJPAMailboxMembership;
 import org.apache.james.imap.jpa.mail.model.JPAHeader;
 import org.apache.james.imap.jpa.mail.model.openjpa.JPAStreamingMailboxMembership;
@@ -44,16 +44,20 @@
  * OpenJPA implementation of Mailbox
  *
  */
-public class OpenJPAMailbox extends JPAMailbox{
+public class OpenJPAMessageManager extends JPAMessageManager {
 
     private final boolean useStreaming;
 
-    public OpenJPAMailbox(MailboxEventDispatcher dispatcher, UidConsumer<Long> consumer, Mailbox<Long> mailbox, MailboxSessionEntityManagerFactory entityManagerFactory) {
-        this(dispatcher, consumer, mailbox, entityManagerFactory, false);
+    public OpenJPAMessageManager(JPAMailboxSessionMapperFactory mapperFactory,
+            MailboxEventDispatcher dispatcher, UidConsumer<Long> consumer,
+            Mailbox<Long> mailbox, MailboxSession session) throws MailboxException {
+        this(mapperFactory, dispatcher, consumer, mailbox, session, false);
     }
 
-    public OpenJPAMailbox(MailboxEventDispatcher dispatcher, UidConsumer<Long> consumer, Mailbox<Long> mailbox, MailboxSessionEntityManagerFactory entityManagerFactory, final boolean useStreaming) {
-        super(dispatcher, consumer, mailbox, entityManagerFactory);
+    public OpenJPAMessageManager(JPAMailboxSessionMapperFactory mapperFactory,
+            MailboxEventDispatcher dispatcher, UidConsumer<Long> consumer,
+            Mailbox<Long> mailbox, MailboxSession session, final boolean useStreaming) throws MailboxException {
+        super(mapperFactory, dispatcher, consumer, mailbox, session);
         this.useStreaming = useStreaming;
     }
 
@@ -78,6 +82,5 @@
             return super.createMessage(internalDate, uid, size, bodyStartOctet, document, flags, headers, propertyBuilder);
         }
     }
-    
 
 }
Index: jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailboxManager.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailboxManager.java	(Revision 950435)
+++ jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailboxManager.java	(Arbeitskopie)
@@ -19,13 +19,13 @@
 
 package org.apache.james.imap.jpa.openjpa;
 
-
 import org.apache.james.imap.jpa.JPAMailboxManager;
-import org.apache.james.imap.jpa.MailboxSessionEntityManagerFactory;
+import org.apache.james.imap.jpa.JPAMailboxSessionMapperFactory;
+import org.apache.james.imap.mailbox.MailboxException;
 import org.apache.james.imap.mailbox.MailboxSession;
 import org.apache.james.imap.mailbox.util.MailboxEventDispatcher;
 import org.apache.james.imap.store.Authenticator;
-import org.apache.james.imap.store.StoreMailbox;
+import org.apache.james.imap.store.StoreMessageManager;
 import org.apache.james.imap.store.Subscriber;
 import org.apache.james.imap.store.UidConsumer;
 import org.apache.james.imap.store.mail.model.Mailbox;
@@ -38,17 +38,21 @@
 
     private boolean useStreaming;
 
-    public OpenJPAMailboxManager(Authenticator authenticator, Subscriber subscriber, MailboxSessionEntityManagerFactory entityManagerFactory, boolean useStreaming) {
-        super(authenticator, subscriber, entityManagerFactory);
+    public OpenJPAMailboxManager(JPAMailboxSessionMapperFactory mapperFactory,
+            Authenticator authenticator, Subscriber subscriber, boolean useStreaming) {
+        super(mapperFactory, authenticator, subscriber);
         this.useStreaming = useStreaming;
     }
 
-    public OpenJPAMailboxManager(Authenticator authenticator, Subscriber subscriber, MailboxSessionEntityManagerFactory entityManagerFactory) {
-        this(authenticator, subscriber, entityManagerFactory, false);
+    public OpenJPAMailboxManager(JPAMailboxSessionMapperFactory mapperFactory,
+            Authenticator authenticator, Subscriber subscriber) {
+        this(mapperFactory, authenticator, subscriber, false);
     }
 
-    protected StoreMailbox<Long> createMailbox(MailboxEventDispatcher dispatcher, UidConsumer<Long> consumer, Mailbox<Long> mailboxRow, MailboxSession session) {
-        StoreMailbox<Long> result =  new OpenJPAMailbox(dispatcher, consumer, mailboxRow,entityManagerFactory, useStreaming);
+    @Override
+    protected StoreMessageManager<Long> createMessageManager(MailboxEventDispatcher dispatcher, UidConsumer<Long> consumer, Mailbox<Long> mailboxRow, MailboxSession session) throws MailboxException {
+        StoreMessageManager<Long> result =  new OpenJPAMessageManager((JPAMailboxSessionMapperFactory) mailboxSessionMapperFactory,
+                dispatcher, consumer, mailboxRow, session, useStreaming);
         return result;
     }
 }
Index: jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailbox.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailbox.java	(Revision 950435)
+++ jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailbox.java	(Arbeitskopie)
@@ -1,83 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.imap.jpa.openjpa;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-import javax.mail.Flags;
-
-import org.apache.james.imap.jpa.JPAMailbox;
-import org.apache.james.imap.jpa.MailboxSessionEntityManagerFactory;
-import org.apache.james.imap.jpa.mail.model.AbstractJPAMailboxMembership;
-import org.apache.james.imap.jpa.mail.model.JPAHeader;
-import org.apache.james.imap.jpa.mail.model.openjpa.JPAStreamingMailboxMembership;
-import org.apache.james.imap.mailbox.MailboxException;
-import org.apache.james.imap.mailbox.MailboxSession;
-import org.apache.james.imap.mailbox.util.MailboxEventDispatcher;
-import org.apache.james.imap.store.UidConsumer;
-import org.apache.james.imap.store.mail.model.Header;
-import org.apache.james.imap.store.mail.model.Mailbox;
-import org.apache.james.imap.store.mail.model.MailboxMembership;
-import org.apache.james.imap.store.mail.model.PropertyBuilder;
-
-/**
- * OpenJPA implementation of Mailbox
- *
- */
-public class OpenJPAMailbox extends JPAMailbox{
-
-    private final boolean useStreaming;
-
-    public OpenJPAMailbox(MailboxEventDispatcher dispatcher, UidConsumer<Long> consumer, Mailbox<Long> mailbox, MailboxSessionEntityManagerFactory entityManagerFactory) {
-        this(dispatcher, consumer, mailbox, entityManagerFactory, false);
-    }
-
-    public OpenJPAMailbox(MailboxEventDispatcher dispatcher, UidConsumer<Long> consumer, Mailbox<Long> mailbox, MailboxSessionEntityManagerFactory entityManagerFactory, final boolean useStreaming) {
-        super(dispatcher, consumer, mailbox, entityManagerFactory);
-        this.useStreaming = useStreaming;
-    }
-
-    @Override
-    protected MailboxMembership<Long> copyMessage(MailboxMembership<Long> originalMessage, long uid, MailboxSession session) throws MailboxException {
-        if (useStreaming) {
-            return  new JPAStreamingMailboxMembership(getMailboxId(), uid, (AbstractJPAMailboxMembership) originalMessage);
-        } else {
-            return super.copyMessage(originalMessage, uid, session);
-        }
-    }
-
-    @Override
-    protected MailboxMembership<Long> createMessage(Date internalDate, long uid, int size, int bodyStartOctet, InputStream document, Flags flags, List<Header> headers, PropertyBuilder propertyBuilder) throws MailboxException {
-        if (useStreaming) {
-            final List<JPAHeader> jpaHeaders = new ArrayList<JPAHeader>(headers.size());
-            for (Header header: headers) {
-                jpaHeaders.add((JPAHeader) header);
-            }
-            return new JPAStreamingMailboxMembership(getMailboxId(), uid, internalDate, size, flags, document, bodyStartOctet, jpaHeaders, propertyBuilder);
-        } else {
-            return super.createMessage(internalDate, uid, size, bodyStartOctet, document, flags, headers, propertyBuilder);
-        }
-    }
-    
-
-}
Index: jpa/src/main/java/org/apache/james/imap/jpa/mail/model/openjpa/JPAStreamingMessage.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/mail/model/openjpa/JPAStreamingMessage.java	(Revision 950435)
+++ jpa/src/main/java/org/apache/james/imap/jpa/mail/model/openjpa/JPAStreamingMessage.java	(Arbeitskopie)
@@ -31,9 +31,9 @@
 import org.apache.james.imap.jpa.mail.model.AbstractJPAMessage;
 import org.apache.james.imap.jpa.mail.model.JPAHeader;
 import org.apache.james.imap.jpa.mail.model.JPAMessage;
-import org.apache.james.imap.store.StreamUtils;
 import org.apache.james.imap.store.mail.model.Document;
 import org.apache.james.imap.store.mail.model.PropertyBuilder;
+import org.apache.james.imap.store.streaming.StreamUtils;
 import org.apache.openjpa.persistence.Persistent;
 
 /**
Index: jpa/src/main/java/org/apache/james/imap/jpa/mail/model/JPAMessage.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/mail/model/JPAMessage.java	(Revision 950435)
+++ jpa/src/main/java/org/apache/james/imap/jpa/mail/model/JPAMessage.java	(Arbeitskopie)
@@ -29,9 +29,9 @@
 import javax.persistence.FetchType;
 import javax.persistence.Lob;
 
-import org.apache.james.imap.store.StreamUtils;
 import org.apache.james.imap.store.mail.model.Document;
 import org.apache.james.imap.store.mail.model.PropertyBuilder;
+import org.apache.james.imap.store.streaming.StreamUtils;
 
 @Entity(name="Message")
 public class JPAMessage extends AbstractJPAMessage{
Index: jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMessageMapper.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMessageMapper.java	(Revision 950435)
+++ jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMessageMapper.java	(Arbeitskopie)
@@ -20,7 +20,7 @@
 
 import java.util.List;
 
-import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
 import javax.persistence.PersistenceException;
 
 import org.apache.james.imap.api.display.HumanReadableText;
@@ -40,18 +40,15 @@
  *
  */
 public class JPAMessageMapper extends JPATransactionalMapper implements MessageMapper<Long> {
-
-    private final long mailboxId;
     
-    public JPAMessageMapper(final EntityManager factory, final long mailboxId) {
-        super(factory);
-        this.mailboxId = mailboxId;
+    public JPAMessageMapper(final EntityManagerFactory entityManagerFactory) {
+        super(entityManagerFactory);
     }
 
     /**
      * @see org.apache.james.imap.store.mail.MessageMapper#findInMailbox(org.apache.james.imap.mailbox.MessageRange)
      */
-    public List<MailboxMembership<Long>> findInMailbox(MessageRange set) throws StorageException {
+    public List<MailboxMembership<Long>> findInMailbox(Long mailboxId, MessageRange set) throws StorageException {
         try {
             final List<MailboxMembership<Long>> results;
             final long from = set.getUidFrom();
@@ -79,36 +76,36 @@
     }
 
     @SuppressWarnings("unchecked")
-    private List<MailboxMembership<Long>> findMessagesInMailboxAfterUID(long mailboxId, long uid) {
-        return getManager().createNamedQuery("findMessagesInMailboxAfterUID")
+    private List<MailboxMembership<Long>> findMessagesInMailboxAfterUID(Long mailboxId, long uid) {
+        return getEntityManager().createNamedQuery("findMessagesInMailboxAfterUID")
         .setParameter("idParam", mailboxId)
         .setParameter("uidParam", uid).getResultList();
     }
 
     @SuppressWarnings("unchecked")
-    private List<MailboxMembership<Long>> findMessagesInMailboxWithUID(long mailboxId, long uid) {
-        return getManager().createNamedQuery("findMessagesInMailboxWithUID")
+    private List<MailboxMembership<Long>> findMessagesInMailboxWithUID(Long mailboxId, long uid) {
+        return getEntityManager().createNamedQuery("findMessagesInMailboxWithUID")
         .setParameter("idParam", mailboxId)
         .setParameter("uidParam", uid).getResultList();
     }
 
     @SuppressWarnings("unchecked")
-    private List<MailboxMembership<Long>> findMessagesInMailboxBetweenUIDs(long mailboxId, long from, long to) {
-        return getManager().createNamedQuery("findMessagesInMailboxBetweenUIDs")
+    private List<MailboxMembership<Long>> findMessagesInMailboxBetweenUIDs(Long mailboxId, long from, long to) {
+        return getEntityManager().createNamedQuery("findMessagesInMailboxBetweenUIDs")
         .setParameter("idParam", mailboxId)
         .setParameter("fromParam", from)
         .setParameter("toParam", to).getResultList();
     }
 
     @SuppressWarnings("unchecked")
-    private List<MailboxMembership<Long>> findMessagesInMailbox(long mailboxId) {
-        return getManager().createNamedQuery("findMessagesInMailbox").setParameter("idParam", mailboxId).getResultList();
+    private List<MailboxMembership<Long>> findMessagesInMailbox(Long mailboxId) {
+        return getEntityManager().createNamedQuery("findMessagesInMailbox").setParameter("idParam", mailboxId).getResultList();
     }
 
     /**
      * @see org.apache.james.imap.store.mail.MessageMapper#findMarkedForDeletionInMailbox(org.apache.james.imap.mailbox.MessageRange)
      */
-    public List<MailboxMembership<Long>> findMarkedForDeletionInMailbox(final MessageRange set) throws StorageException {
+    public List<MailboxMembership<Long>> findMarkedForDeletionInMailbox(Long mailboxId, final MessageRange set) throws StorageException {
         try {
             final List<MailboxMembership<Long>> results;
             final long from = set.getUidFrom();
@@ -135,27 +132,27 @@
     }
 
     @SuppressWarnings("unchecked")
-    private List<MailboxMembership<Long>> findDeletedMessagesInMailbox(long mailboxId) {
-        return getManager().createNamedQuery("findDeletedMessagesInMailbox").setParameter("idParam", mailboxId).getResultList();
+    private List<MailboxMembership<Long>> findDeletedMessagesInMailbox(Long mailboxId) {
+        return getEntityManager().createNamedQuery("findDeletedMessagesInMailbox").setParameter("idParam", mailboxId).getResultList();
     }
 
     @SuppressWarnings("unchecked")
-    private List<MailboxMembership<Long>> findDeletedMessagesInMailboxAfterUID(long mailboxId, long uid) {
-        return getManager().createNamedQuery("findDeletedMessagesInMailboxAfterUID")
+    private List<MailboxMembership<Long>> findDeletedMessagesInMailboxAfterUID(Long mailboxId, long uid) {
+        return getEntityManager().createNamedQuery("findDeletedMessagesInMailboxAfterUID")
         .setParameter("idParam", mailboxId)
         .setParameter("uidParam", uid).getResultList();
     }
 
     @SuppressWarnings("unchecked")
-    private List<MailboxMembership<Long>> findDeletedMessagesInMailboxWithUID(long mailboxId, long uid) {
-        return getManager().createNamedQuery("findDeletedMessagesInMailboxWithUID")
+    private List<MailboxMembership<Long>> findDeletedMessagesInMailboxWithUID(Long mailboxId, long uid) {
+        return getEntityManager().createNamedQuery("findDeletedMessagesInMailboxWithUID")
         .setParameter("idParam", mailboxId)
         .setParameter("uidParam", uid).getResultList();
     }
 
     @SuppressWarnings("unchecked")
-    private List<MailboxMembership<Long>> findDeletedMessagesInMailboxBetweenUIDs(long mailboxId, long from, long to) {
-        return getManager().createNamedQuery("findDeletedMessagesInMailboxBetweenUIDs")
+    private List<MailboxMembership<Long>> findDeletedMessagesInMailboxBetweenUIDs(Long mailboxId, long from, long to) {
+        return getEntityManager().createNamedQuery("findDeletedMessagesInMailboxBetweenUIDs")
         .setParameter("idParam", mailboxId)
         .setParameter("fromParam", from)
         .setParameter("toParam", to).getResultList();
@@ -164,9 +161,9 @@
     /**
      * @see org.apache.james.imap.store.mail.MessageMapper#countMessagesInMailbox()
      */
-    public long countMessagesInMailbox() throws StorageException {
+    public long countMessagesInMailbox(Long mailboxId) throws StorageException {
         try {
-            return (Long) getManager().createNamedQuery("countMessagesInMailbox").setParameter("idParam", mailboxId).getSingleResult();
+            return (Long) getEntityManager().createNamedQuery("countMessagesInMailbox").setParameter("idParam", mailboxId).getSingleResult();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.COUNT_FAILED, e);
         }
@@ -175,9 +172,9 @@
     /**
      * @see org.apache.james.imap.store.mail.MessageMapper#countUnseenMessagesInMailbox()
      */
-    public long countUnseenMessagesInMailbox() throws StorageException {
+    public long countUnseenMessagesInMailbox(Long mailboxId) throws StorageException {
         try {
-            return (Long) getManager().createNamedQuery("countUnseenMessagesInMailbox").setParameter("idParam", mailboxId).getSingleResult();
+            return (Long) getEntityManager().createNamedQuery("countUnseenMessagesInMailbox").setParameter("idParam", mailboxId).getSingleResult();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.COUNT_FAILED, e);
         }
@@ -187,16 +184,16 @@
      * @see org.apache.james.imap.store.mail.MessageMapper#searchMailbox(org.apache.james.imap.mailbox.SearchQuery)
      */
     @SuppressWarnings("unchecked")
-    public List<MailboxMembership<Long>> searchMailbox(SearchQuery query) throws StorageException {
+    public List<MailboxMembership<Long>> searchMailbox(Long mailboxId, SearchQuery query) throws StorageException {
         try {
             final String jql = formulateJQL(mailboxId, query);
-            return getManager().createQuery(jql).getResultList();
+            return getEntityManager().createQuery(jql).getResultList();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.SEARCH_FAILED, e);
         }
     }
 
-    private String formulateJQL(long mailboxId, SearchQuery query) {
+    private String formulateJQL(Long mailboxId, SearchQuery query) {
         final StringBuilder queryBuilder = new StringBuilder(50);
         queryBuilder.append("SELECT membership FROM Membership membership WHERE membership.mailboxId = ").append(mailboxId);
         final List<Criterion> criteria = query.getCriterias();
@@ -228,7 +225,7 @@
      */
     public void delete(MailboxMembership<Long> message) throws StorageException {
         try {
-            getManager().remove(message);
+            getEntityManager().remove(message);
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.DELETED_FAILED, e);
         }
@@ -239,9 +236,9 @@
      * @see org.apache.james.imap.store.mail.MessageMapper#findUnseenMessagesInMailbox()
      */
     @SuppressWarnings("unchecked")
-    public List<MailboxMembership<Long>> findUnseenMessagesInMailbox()  throws StorageException {
+    public List<MailboxMembership<Long>> findUnseenMessagesInMailbox(Long mailboxId)  throws StorageException {
         try {
-            return getManager().createNamedQuery("findUnseenMessagesInMailboxOrderByUid").setParameter("idParam", mailboxId).getResultList();
+            return getEntityManager().createNamedQuery("findUnseenMessagesInMailboxOrderByUid").setParameter("idParam", mailboxId).getResultList();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.SEARCH_FAILED, e);
         }
@@ -251,9 +248,9 @@
      * @see org.apache.james.imap.store.mail.MessageMapper#findRecentMessagesInMailbox()
      */
     @SuppressWarnings("unchecked")
-    public List<MailboxMembership<Long>> findRecentMessagesInMailbox() throws StorageException {
+    public List<MailboxMembership<Long>> findRecentMessagesInMailbox(Long mailboxId) throws StorageException {
         try {
-            return getManager().createNamedQuery("findRecentMessagesInMailbox").setParameter("idParam", mailboxId).getResultList();
+            return getEntityManager().createNamedQuery("findRecentMessagesInMailbox").setParameter("idParam", mailboxId).getResultList();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.SEARCH_FAILED, e);
         }
@@ -262,9 +259,9 @@
     /**
      * @see org.apache.james.imap.store.mail.MessageMapper#save(MailboxMembership)
      */
-    public void save(MailboxMembership<Long> message) throws StorageException {
+    public void save(Long mailboxId, MailboxMembership<Long> message) throws StorageException {
         try {
-            getManager().persist(message);
+            getEntityManager().persist(message);
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.SAVE_FAILED, e);
         }
Index: jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMailboxMapper.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMailboxMapper.java	(Revision 950435)
+++ jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMailboxMapper.java	(Arbeitskopie)
@@ -21,7 +21,7 @@
 
 import java.util.List;
 
-import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
 import javax.persistence.NoResultException;
 import javax.persistence.PersistenceException;
 
@@ -40,8 +40,8 @@
 
     private static final char SQL_WILDCARD_CHAR = '%';
     
-    public JPAMailboxMapper(EntityManager factory) {
-        super(factory);
+    public JPAMailboxMapper(EntityManagerFactory entityManagerFactory) {
+        super(entityManagerFactory);
     }
 
     /**
@@ -50,18 +50,16 @@
     public boolean existsMailboxStartingWith(String mailboxName) throws StorageException {
         
         final String name = mailboxName + SQL_WILDCARD_CHAR; 
-        final Long numberOfChildMailboxes = (Long) getManager().createNamedQuery("countMailboxesWithNameLike").setParameter("nameParam", name).getSingleResult();
+        final Long numberOfChildMailboxes = (Long) getEntityManager().createNamedQuery("countMailboxesWithNameLike").setParameter("nameParam", name).getSingleResult();
         return numberOfChildMailboxes != null && numberOfChildMailboxes > 0;
     }
 
-
-
     /**
      * @see org.apache.james.imap.store.mail.MailboxMapper#save(Mailbox)
      */
     public void save(Mailbox<Long> mailbox) throws StorageException {
         try {
-            getManager().persist(mailbox);
+            getEntityManager().persist(mailbox);
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.SAVE_FAILED, e);
         } 
@@ -72,7 +70,7 @@
      */
     public Mailbox<Long> findMailboxByName(String name) throws StorageException, MailboxNotFoundException {
         try {
-            return (JPAMailbox) getManager().createNamedQuery("findMailboxByName").setParameter("nameParam", name).getSingleResult();
+            return (JPAMailbox) getEntityManager().createNamedQuery("findMailboxByName").setParameter("nameParam", name).getSingleResult();
         } catch (NoResultException e) {
             throw new MailboxNotFoundException(name);
             
@@ -86,7 +84,7 @@
      */
     public void delete(Mailbox<Long> mailbox) throws StorageException {
         try {  
-            getManager().remove(mailbox);
+            getEntityManager().remove(mailbox);
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.DELETED_FAILED, e);
         } 
@@ -98,7 +96,7 @@
     @SuppressWarnings("unchecked")
     public List<Mailbox<Long>> findMailboxWithNameLike(String name) throws StorageException {
         try {
-            return getManager().createNamedQuery("findMailboxWithNameLike").setParameter("nameParam", SQL_WILDCARD_CHAR + name + SQL_WILDCARD_CHAR).getResultList();
+            return getEntityManager().createNamedQuery("findMailboxWithNameLike").setParameter("nameParam", SQL_WILDCARD_CHAR + name + SQL_WILDCARD_CHAR).getResultList();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.SEARCH_FAILED, e);
         } 
@@ -109,7 +107,7 @@
      */
     public void deleteAll() throws StorageException {
         try {
-            getManager().createNamedQuery("deleteAll").executeUpdate();
+            getEntityManager().createNamedQuery("deleteAll").executeUpdate();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.DELETED_FAILED, e);
         } 
@@ -120,7 +118,7 @@
      */
     public long countMailboxesWithName(String name) throws StorageException {
         try {
-            return (Long) getManager().createNamedQuery("countMailboxesWithName").setParameter("nameParam", name).getSingleResult();
+            return (Long) getEntityManager().createNamedQuery("countMailboxesWithName").setParameter("nameParam", name).getSingleResult();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.COUNT_FAILED, e);
         } 
@@ -131,7 +129,7 @@
      */
     public Mailbox<Long> findMailboxById(Long mailboxId) throws StorageException, MailboxNotFoundException  {
         try {
-            return (JPAMailbox) getManager().createNamedQuery("findMailboxById").setParameter("idParam", mailboxId).getSingleResult();
+            return (JPAMailbox) getEntityManager().createNamedQuery("findMailboxById").setParameter("idParam", mailboxId).getSingleResult();
         } catch (NoResultException e) {
             throw new MailboxNotFoundException(mailboxId);   
         } catch (PersistenceException e) {
Index: jpa/src/main/java/org/apache/james/imap/jpa/MailboxSessionEntityManagerFactory.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/MailboxSessionEntityManagerFactory.java	(Revision 950435)
+++ jpa/src/main/java/org/apache/james/imap/jpa/MailboxSessionEntityManagerFactory.java	(Arbeitskopie)
@@ -1,71 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-package org.apache.james.imap.jpa;
-
-import javax.persistence.EntityManager;
-import javax.persistence.EntityManagerFactory;
-
-import org.apache.james.imap.mailbox.MailboxSession;
-
-/**
- * Maintain {@link EntityManager} instances by {@link MailboxSession}. So only one {@link EntityManager} instance is used
- * in a {@link MailboxSession}. 
- *
- */
-public class MailboxSessionEntityManagerFactory {
-
-    protected final static String ENTITYMANAGER ="ENTITYMANAGER";
-    private final EntityManagerFactory factory;
-    
-    public MailboxSessionEntityManagerFactory(final EntityManagerFactory factory) {
-        this.factory = factory;
-    }
-    
-    
-    /**
-     * Create a {@link EntityManager} instance of return the one which exists for the {@link MailboxSession} already
-     * 
-     * @param session
-     * @return manager
-     */
-    public EntityManager createEntityManager(MailboxSession session) {
-        EntityManager manager = (EntityManager) session.getAttributes().get(ENTITYMANAGER);
-        
-        if (manager == null) {
-            manager = factory.createEntityManager();
-            session.getAttributes().put(ENTITYMANAGER, manager);
-        }
-        
-        return manager;
-    }
-    
-    /**
-     * Close the {@link EntityManager} which exists for the {@link MailboxSession}
-     * 
-     * @param session
-     */
-    public void closeEntityManager(MailboxSession session) {
-        if (session != null) {
-            EntityManager manager = (EntityManager) session.getAttributes().remove(ENTITYMANAGER);
-            if (manager != null && manager.isOpen()) {
-                manager.close();
-            }
-        }
-    }
-}
Index: jpa/src/main/java/org/apache/james/imap/jpa/JPAUidConsumer.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/JPAUidConsumer.java	(Revision 950435)
+++ jpa/src/main/java/org/apache/james/imap/jpa/JPAUidConsumer.java	(Arbeitskopie)
@@ -22,42 +22,41 @@
 import javax.persistence.EntityTransaction;
 import javax.persistence.LockModeType;
 
+import org.apache.james.imap.jpa.mail.model.JPAMailbox;
 import org.apache.james.imap.mailbox.MailboxSession;
 import org.apache.james.imap.store.UidConsumer;
 import org.apache.james.imap.store.mail.model.Mailbox;
 
 /**
  * Take care of consume/reserve the next uid for a {@link Mailbox}. This is done by using database locks
- * 
  *
  */
 public class JPAUidConsumer implements UidConsumer<Long>{
 
-    private final MailboxSessionEntityManagerFactory factory;
+    private final JPAMailboxSessionMapperFactory factory;
 
-    public JPAUidConsumer(final MailboxSessionEntityManagerFactory factory) {
+    public JPAUidConsumer(final JPAMailboxSessionMapperFactory factory) {
         this.factory = factory;
     }
     
     /**
-     * 
      * Reserve next Uid in mailbox and return the mailbox. We use a PESSIMISTIC_WRITE lock here to be sure we don't see any duplicates here when
      * accessing the database with many different threads / connections
      * 
      * @see org.apache.james.imap.store.UidConsumer#reserveNextUid(org.apache.james.imap.store.mail.model.Mailbox, org.apache.james.imap.mailbox.MailboxSession)
      */
     public long reserveNextUid(Mailbox<Long> mailbox, MailboxSession session) {
-        EntityManager manager = factory.createEntityManager(session);
+        EntityManager manager = factory.createEntityManager();
         EntityTransaction transaction = manager.getTransaction();
         transaction.begin();
-
-        // we need to set a persimistic write lock to be sure we don't get any problems with dirty reads etc
-        org.apache.james.imap.jpa.mail.model.JPAMailbox m = manager.find(org.apache.james.imap.jpa.mail.model.JPAMailbox.class, mailbox.getMailboxId(), LockModeType.PESSIMISTIC_WRITE);
+        // we need to set a pessimistic write lock to be sure we don't get any problems with dirty reads etc.
+        JPAMailbox m = manager.find(JPAMailbox.class, mailbox.getMailboxId(), LockModeType.PESSIMISTIC_WRITE);
         manager.refresh(m);
         m.consumeUid();
         manager.persist(m);
         manager.flush();
         transaction.commit();
+        manager.close();
         return m.getLastUid();
     }
 
Index: jpa/src/main/java/org/apache/james/imap/jpa/JPATransactionalMapper.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/JPATransactionalMapper.java	(Revision 950435)
+++ jpa/src/main/java/org/apache/james/imap/jpa/JPATransactionalMapper.java	(Arbeitskopie)
@@ -18,7 +18,6 @@
  ****************************************************************/
 package org.apache.james.imap.jpa;
 
-
 import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
 import javax.persistence.EntityTransaction;
@@ -35,19 +34,32 @@
  */
 public abstract class JPATransactionalMapper extends AbstractTransactionalMapper {
 
-    private EntityManager entityManager;
-    public JPATransactionalMapper(final EntityManager entityManager) {
-        this.entityManager = entityManager;
+    protected EntityManagerFactory entityManagerFactory;
+    protected EntityManager entityManager;
+    
+    public JPATransactionalMapper(final EntityManagerFactory entityManagerFactory) {
+        this.entityManagerFactory = entityManagerFactory;
     }
 
     /**
-     * Return the currently used {@link EntityManager}. If the currently used {@link EntityManager} is null or is closed a new will get obtained from the {@link EntityManagerFactory}
+     * Return the currently used {@link EntityManager} or a new one if none exists.
      * 
      * @return entitymanger
      */
-    protected EntityManager getManager() {
+    public EntityManager getEntityManager() {
+        if (entityManager != null)
+            return entityManager;
+        entityManager = entityManagerFactory.createEntityManager();
         return entityManager;
     }
+    
+    public void removeEntityManager() {
+        if (entityManager != null) {
+            if (entityManager.isOpen())
+                entityManager.close();
+            entityManager = null;
+        }
+    }
 
     /*
      * (non-Javadoc)
@@ -55,19 +67,18 @@
      */
     protected void begin() throws MailboxException {
         try {
-            getManager().getTransaction().begin();
+            getEntityManager().getTransaction().begin();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.START_TRANSACTION_FAILED, e);
         }
     }
-    
 
     /**
      * Commit the Transaction and close the EntityManager
      */
     protected void commit() throws MailboxException {
         try {
-            getManager().getTransaction().commit();
+            getEntityManager().getTransaction().commit();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.COMMIT_TRANSACTION_FAILED, e);
         }
@@ -81,9 +92,8 @@
         EntityTransaction transaction = entityManager.getTransaction();
         // check if we have a transaction to rollback
         if (transaction.isActive()) {
-            getManager().getTransaction().rollback();
+            getEntityManager().getTransaction().rollback();
         }
     }
-    
 
 }
Index: jpa/src/main/java/org/apache/james/imap/jpa/JPASubscriptionManager.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/JPASubscriptionManager.java	(Revision 950435)
+++ jpa/src/main/java/org/apache/james/imap/jpa/JPASubscriptionManager.java	(Arbeitskopie)
@@ -18,35 +18,20 @@
  ****************************************************************/
 package org.apache.james.imap.jpa;
 
-import org.apache.james.imap.jpa.user.JPASubscriptionMapper;
 import org.apache.james.imap.jpa.user.model.JPASubscription;
 import org.apache.james.imap.mailbox.MailboxSession;
 import org.apache.james.imap.store.StoreSubscriptionManager;
-import org.apache.james.imap.store.user.SubscriptionMapper;
 import org.apache.james.imap.store.user.model.Subscription;
 
 /**
  * JPA implementation of {@link StoreSubscriptionManager}
- * 
  *
  */
-public class JPASubscriptionManager extends StoreSubscriptionManager {
-    private final MailboxSessionEntityManagerFactory factory;
+public class JPASubscriptionManager extends StoreSubscriptionManager<Long> {
     
-    public JPASubscriptionManager(final MailboxSessionEntityManagerFactory factory) {
-        super();
-        this.factory = factory;
+    public JPASubscriptionManager(final JPAMailboxSessionMapperFactory mapperFactory) {
+        super(mapperFactory);
     }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.imap.store.StoreSubscriptionManager#createMapper(org.apache.james.imap.mailbox.MailboxSession)
-     */
-    protected SubscriptionMapper createMapper(MailboxSession session) {                
-        JPASubscriptionMapper  mapper = new JPASubscriptionMapper(factory.createEntityManager(session));
-        
-        return mapper;
-    }
     
     /*
      * (non-Javadoc)
Index: jpa/src/main/java/org/apache/james/imap/jpa/JPAMessageManager.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/JPAMessageManager.java	(Revision 950435)
+++ jpa/src/main/java/org/apache/james/imap/jpa/JPAMessageManager.java	(Arbeitskopie)
@@ -25,18 +25,14 @@
 
 import javax.mail.Flags;
 
-import org.apache.james.imap.jpa.mail.JPAMailboxMapper;
-import org.apache.james.imap.jpa.mail.JPAMessageMapper;
 import org.apache.james.imap.jpa.mail.model.AbstractJPAMailboxMembership;
 import org.apache.james.imap.jpa.mail.model.JPAHeader;
 import org.apache.james.imap.jpa.mail.model.JPAMailboxMembership;
 import org.apache.james.imap.mailbox.MailboxException;
 import org.apache.james.imap.mailbox.MailboxSession;
 import org.apache.james.imap.mailbox.util.MailboxEventDispatcher;
-import org.apache.james.imap.store.StoreMailbox;
+import org.apache.james.imap.store.StoreMessageManager;
 import org.apache.james.imap.store.UidConsumer;
-import org.apache.james.imap.store.mail.MailboxMapper;
-import org.apache.james.imap.store.mail.MessageMapper;
 import org.apache.james.imap.store.mail.model.Header;
 import org.apache.james.imap.store.mail.model.Mailbox;
 import org.apache.james.imap.store.mail.model.MailboxMembership;
@@ -44,27 +40,13 @@
 
 /**
  * Abstract base class which should be used from JPA 2.0 implementations
- * 
- * 
- *
  */
-public class JPAMailbox extends StoreMailbox<Long> {
-
-    protected final MailboxSessionEntityManagerFactory entityManagerFactory;
+public class JPAMessageManager extends StoreMessageManager<Long> {
     
-    public JPAMailbox(final MailboxEventDispatcher dispatcher, final UidConsumer<Long> consumer,final Mailbox<Long> mailbox, final MailboxSessionEntityManagerFactory entityManagerFactory) {
-        super(dispatcher, consumer, mailbox);
-        this.entityManagerFactory = entityManagerFactory;        
-    }  
-
-
-
-    
-    @Override
-    protected MessageMapper<Long> createMessageMapper(MailboxSession session) {                
-        JPAMessageMapper mapper = new JPAMessageMapper(entityManagerFactory.createEntityManager(session), getMailboxId());
-       
-        return mapper;
+    public JPAMessageManager(JPAMailboxSessionMapperFactory mapperFactory,
+            final MailboxEventDispatcher dispatcher, final UidConsumer<Long> consumer,
+            final Mailbox<Long> mailbox, MailboxSession session) throws MailboxException {
+        super(mapperFactory, dispatcher, consumer, mailbox, session);     
     }
     
     @Override
@@ -76,8 +58,6 @@
         }
         final MailboxMembership<Long> message = new JPAMailboxMembership(getMailboxId(), uid, internalDate, size, flags, document, bodyStartOctet, jpaHeaders, propertyBuilder);
         return message;
-
-       
     }
     
     @Override
@@ -86,20 +66,10 @@
         return newRow;
     }
     
-    
     @Override
     protected Header createHeader(int lineNumber, String name, String value) {
         final Header header = new JPAHeader(lineNumber, name, value);
         return header;
     }
-
-
-
-
-    @Override
-    protected MailboxMapper<Long> createMailboxMapper(MailboxSession session) {
-        return new JPAMailboxMapper(entityManagerFactory.createEntityManager(session));
-    }
     
-    
 }
Index: jpa/src/main/java/org/apache/james/imap/jpa/JPAMailboxSessionMapperFactory.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/JPAMailboxSessionMapperFactory.java	(Revision 0)
+++ jpa/src/main/java/org/apache/james/imap/jpa/JPAMailboxSessionMapperFactory.java	(Revision 0)
@@ -0,0 +1,78 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.jpa;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+
+import org.apache.james.imap.jpa.mail.JPAMailboxMapper;
+import org.apache.james.imap.jpa.mail.JPAMessageMapper;
+import org.apache.james.imap.jpa.user.JPASubscriptionMapper;
+import org.apache.james.imap.mailbox.MailboxSession;
+import org.apache.james.imap.store.MailboxSessionMapperFactory;
+import org.apache.james.imap.store.mail.MailboxMapper;
+import org.apache.james.imap.store.mail.MessageMapper;
+import org.apache.james.imap.store.user.SubscriptionMapper;
+
+public class JPAMailboxSessionMapperFactory extends	MailboxSessionMapperFactory<Long> {
+
+    private final EntityManagerFactory entityManagerFactory;
+
+    public JPAMailboxSessionMapperFactory(EntityManagerFactory entityManagerFactory) {
+        this.entityManagerFactory = entityManagerFactory;
+    }
+
+    @Override
+    public MailboxMapper<Long> createMailboxMapper(MailboxSession session) {
+        return new JPAMailboxMapper(entityManagerFactory);
+    }
+
+    @Override
+    public MessageMapper<Long> createMessageMapper(MailboxSession session) {
+        return new JPAMessageMapper(entityManagerFactory);
+    }
+
+    @Override
+    public SubscriptionMapper createSubscriptionMapper(MailboxSession session) {
+        return new JPASubscriptionMapper(entityManagerFactory);
+    }
+
+    public EntityManager createEntityManager() {
+        return entityManagerFactory.createEntityManager();
+    }
+
+    /**
+     * Close the {@link EntityManager}s
+     * 
+     * @param session
+     */
+    public void closeEntityManagers(MailboxSession session) {
+        if (session == null) return;
+        JPAMessageMapper messageMapper = (JPAMessageMapper) session.getAttributes().get(MESSAGEMAPPER);
+        JPAMailboxMapper mailboxMapper = (JPAMailboxMapper) session.getAttributes().get(MAILBOXMAPPER);
+        JPASubscriptionMapper subscriptionMapper = (JPASubscriptionMapper) session.getAttributes().get(SUBSCRIPTIONMAPPER);
+        if (messageMapper != null)
+            messageMapper.removeEntityManager();
+        if (mailboxMapper != null)
+            mailboxMapper.removeEntityManager();
+        if (subscriptionMapper != null)
+            subscriptionMapper.removeEntityManager();
+    }
+
+}
Index: jpa/src/main/java/org/apache/james/imap/jpa/JPAMailboxManager.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/JPAMailboxManager.java	(Revision 950435)
+++ jpa/src/main/java/org/apache/james/imap/jpa/JPAMailboxManager.java	(Arbeitskopie)
@@ -18,8 +18,7 @@
  ****************************************************************/
 package org.apache.james.imap.jpa;
 
-
-import org.apache.james.imap.jpa.mail.JPAMailboxMapper;
+import org.apache.james.imap.jpa.mail.model.JPAMailbox;
 import org.apache.james.imap.mailbox.MailboxException;
 import org.apache.james.imap.mailbox.MailboxSession;
 import org.apache.james.imap.store.Authenticator;
@@ -29,26 +28,20 @@
 import org.apache.james.imap.store.mail.model.Mailbox;
 import org.apache.james.imap.store.transaction.TransactionalMapper;
 
-
 /**
  * JPA implementation of {@link StoreMailboxManager}
- * 
- *
  */
 public abstract class JPAMailboxManager extends StoreMailboxManager<Long> {
-
-    protected final MailboxSessionEntityManagerFactory entityManagerFactory;
-    public JPAMailboxManager(final Authenticator authenticator, final Subscriber subscriber, 
-            final MailboxSessionEntityManagerFactory entityManagerFactory) {
-        super(authenticator, subscriber,new JPAUidConsumer(entityManagerFactory));
-        this.entityManagerFactory = entityManagerFactory;
+    
+    public JPAMailboxManager(JPAMailboxSessionMapperFactory mailboxSessionMapperFactory,
+            final Authenticator authenticator, final Subscriber subscriber) {
+        super(mailboxSessionMapperFactory, authenticator, subscriber, new JPAUidConsumer(mailboxSessionMapperFactory));
     }
     
-    
     @Override
-    protected void doCreate(String namespaceName, MailboxSession session) throws MailboxException {
-        final Mailbox<Long> mailbox = new org.apache.james.imap.jpa.mail.model.JPAMailbox(namespaceName, randomUidValidity());
-        final MailboxMapper<Long> mapper = createMailboxMapper(session);
+    protected void doCreateMailbox(String namespaceName, MailboxSession session) throws MailboxException {
+        final Mailbox<Long> mailbox = new JPAMailbox(namespaceName, randomUidValidity());
+        final MailboxMapper<Long> mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
         mapper.execute(new TransactionalMapper.Transaction(){
 
             public void run() throws MailboxException {
@@ -65,7 +58,7 @@
      * @throws MailboxException
      */
     public void deleteEverything(MailboxSession mailboxSession) throws MailboxException {
-        final MailboxMapper<Long> mapper = createMailboxMapper(mailboxSession);
+        final MailboxMapper<Long> mapper = mailboxSessionMapperFactory.getMailboxMapper(mailboxSession);
         mapper.execute(new TransactionalMapper.Transaction() {
 
             public void run() throws MailboxException {
@@ -74,18 +67,10 @@
             
         });
     }
-
     
     @Override
     public void endProcessingRequest(MailboxSession session) {
-        entityManagerFactory.closeEntityManager(session);
+        ((JPAMailboxSessionMapperFactory) mailboxSessionMapperFactory).closeEntityManagers(session);
     }
-
-
-    @Override
-    protected MailboxMapper<Long> createMailboxMapper(MailboxSession session) {
-        return new JPAMailboxMapper(entityManagerFactory.createEntityManager(session));
-    }
-
     
 }
Index: jpa/src/main/java/org/apache/james/imap/jpa/JPAMailbox.java
===================================================================
--- jpa/src/main/java/org/apache/james/imap/jpa/JPAMailbox.java	(Revision 950435)
+++ jpa/src/main/java/org/apache/james/imap/jpa/JPAMailbox.java	(Arbeitskopie)
@@ -1,105 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-package org.apache.james.imap.jpa;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-import javax.mail.Flags;
-
-import org.apache.james.imap.jpa.mail.JPAMailboxMapper;
-import org.apache.james.imap.jpa.mail.JPAMessageMapper;
-import org.apache.james.imap.jpa.mail.model.AbstractJPAMailboxMembership;
-import org.apache.james.imap.jpa.mail.model.JPAHeader;
-import org.apache.james.imap.jpa.mail.model.JPAMailboxMembership;
-import org.apache.james.imap.mailbox.MailboxException;
-import org.apache.james.imap.mailbox.MailboxSession;
-import org.apache.james.imap.mailbox.util.MailboxEventDispatcher;
-import org.apache.james.imap.store.StoreMailbox;
-import org.apache.james.imap.store.UidConsumer;
-import org.apache.james.imap.store.mail.MailboxMapper;
-import org.apache.james.imap.store.mail.MessageMapper;
-import org.apache.james.imap.store.mail.model.Header;
-import org.apache.james.imap.store.mail.model.Mailbox;
-import org.apache.james.imap.store.mail.model.MailboxMembership;
-import org.apache.james.imap.store.mail.model.PropertyBuilder;
-
-/**
- * Abstract base class which should be used from JPA 2.0 implementations
- * 
- * 
- *
- */
-public class JPAMailbox extends StoreMailbox<Long> {
-
-    protected final MailboxSessionEntityManagerFactory entityManagerFactory;
-    
-    public JPAMailbox(final MailboxEventDispatcher dispatcher, final UidConsumer<Long> consumer,final Mailbox<Long> mailbox, final MailboxSessionEntityManagerFactory entityManagerFactory) {
-        super(dispatcher, consumer, mailbox);
-        this.entityManagerFactory = entityManagerFactory;        
-    }  
-
-
-
-    
-    @Override
-    protected MessageMapper<Long> createMessageMapper(MailboxSession session) {                
-        JPAMessageMapper mapper = new JPAMessageMapper(entityManagerFactory.createEntityManager(session), getMailboxId());
-       
-        return mapper;
-    }
-    
-    @Override
-    protected MailboxMembership<Long> createMessage(Date internalDate, final long uid, final int size, int bodyStartOctet, final InputStream document, 
-            final Flags flags, final List<Header> headers, PropertyBuilder propertyBuilder) throws MailboxException{
-        final List<JPAHeader> jpaHeaders = new ArrayList<JPAHeader>(headers.size());
-        for (Header header: headers) {
-            jpaHeaders.add((JPAHeader) header);
-        }
-        final MailboxMembership<Long> message = new JPAMailboxMembership(getMailboxId(), uid, internalDate, size, flags, document, bodyStartOctet, jpaHeaders, propertyBuilder);
-        return message;
-
-       
-    }
-    
-    @Override
-    protected MailboxMembership<Long> copyMessage(MailboxMembership<Long> originalMessage, long uid, MailboxSession session) throws MailboxException{
-        final MailboxMembership<Long> newRow = new JPAMailboxMembership(getMailboxId(), uid, (AbstractJPAMailboxMembership) originalMessage);
-        return newRow;
-    }
-    
-    
-    @Override
-    protected Header createHeader(int lineNumber, String name, String value) {
-        final Header header = new JPAHeader(lineNumber, name, value);
-        return header;
-    }
-
-
-
-
-    @Override
-    protected MailboxMapper<Long> createMailboxMapper(MailboxSession session) {
-        return new JPAMailboxMapper(entityManagerFactory.createEntityManager(session));
-    }
-    
-    
-}
Index: jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMessage.java
===================================================================
--- jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMessage.java	(Revision 950435)
+++ jcr/src/main/java/org/apache/james/imap/jcr/mail/model/JCRMessage.java	(Arbeitskopie)
@@ -38,13 +38,13 @@
 import org.apache.james.imap.jcr.JCRImapConstants;
 import org.apache.james.imap.jcr.Persistent;
 import org.apache.james.imap.mailbox.MailboxException;
-import org.apache.james.imap.store.StreamUtils;
 import org.apache.james.imap.store.mail.model.AbstractDocument;
 import org.apache.james.imap.store.mail.model.Document;
 import org.apache.james.imap.store.mail.model.Header;
 import org.apache.james.imap.store.mail.model.MailboxMembership;
 import org.apache.james.imap.store.mail.model.Property;
 import org.apache.james.imap.store.mail.model.PropertyBuilder;
+import org.apache.james.imap.store.streaming.StreamUtils;
 
 /**
  * JCR implementation of {@link Document}
@@ -485,6 +485,7 @@
      */
     public Document getDocument() {
         if (isPersistent()) {
+        	//TODO: Why not "this"?
             return new JCRMessage(node, logger);
            
         }
Index: jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMessageMapper.java
===================================================================
--- jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMessageMapper.java	(Revision 950435)
+++ jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMessageMapper.java	(Arbeitskopie)
@@ -54,11 +54,8 @@
  */
 public class JCRMessageMapper extends AbstractJCRMapper implements MessageMapper<String> {
 
-    private final String uuid;
-
-    public JCRMessageMapper(final Session session, final String uuid, final Log logger) {
+    public JCRMessageMapper(final Session session, final Log logger) {
         super(session, logger);
-        this.uuid = uuid;
     }
 
     /*
@@ -67,7 +64,7 @@
      * @see
      * org.apache.james.imap.store.mail.MessageMapper#countMessagesInMailbox()
      */
-    public long countMessagesInMailbox() throws StorageException {
+    public long countMessagesInMailbox(String uuid) throws StorageException {
         try {
             // we use order by because without it count will always be 0 in jackrabbit
             String queryString = "//" + MAILBOXES_PATH + "//element(*,jamesMailbox:message)[@" + JCRMessage.MAILBOX_UUID_PROPERTY +"='" + uuid +"'] order by @" + JCRMessage.UID_PROPERTY;
@@ -97,7 +94,7 @@
      * org.apache.james.imap.store.mail.MessageMapper#countUnseenMessagesInMailbox
      * ()
      */
-    public long countUnseenMessagesInMailbox() throws StorageException {
+    public long countUnseenMessagesInMailbox(String uuid) throws StorageException {
         
         try {
             // we use order by because without it count will always be 0 in jackrabbit
@@ -149,7 +146,7 @@
      * org.apache.james.imap.store.mail.MessageMapper#findInMailbox(org.apache
      * .james.imap.mailbox.MessageRange)
      */
-    public List<MailboxMembership<String>> findInMailbox(MessageRange set) throws StorageException {
+    public List<MailboxMembership<String>> findInMailbox(String uuid, MessageRange set) throws StorageException {
         try {
             final List<MailboxMembership<String>> results;
             final long from = set.getUidFrom();
@@ -300,7 +297,7 @@
      * org.apache.james.imap.store.mail.MessageMapper#findMarkedForDeletionInMailbox
      * (org.apache.james.imap.mailbox.MessageRange)
      */
-    public List<MailboxMembership<String>> findMarkedForDeletionInMailbox(MessageRange set) throws StorageException {
+    public List<MailboxMembership<String>> findMarkedForDeletionInMailbox(String uuid, MessageRange set) throws StorageException {
         try {
             final List<MailboxMembership<String>> results;
             final long from = set.getUidFrom();
@@ -335,7 +332,7 @@
      * org.apache.james.imap.store.mail.MessageMapper#findRecentMessagesInMailbox
      * ()
      */
-    public List<MailboxMembership<String>> findRecentMessagesInMailbox() throws StorageException {
+    public List<MailboxMembership<String>> findRecentMessagesInMailbox(String uuid) throws StorageException {
         
         try {
             List<MailboxMembership<String>> list = new ArrayList<MailboxMembership<String>>();
@@ -360,7 +357,7 @@
      * (non-Javadoc)
      * @see org.apache.james.imap.store.mail.MessageMapper#findUnseenMessagesInMailbox()
      */
-    public List<MailboxMembership<String>> findUnseenMessagesInMailbox() throws StorageException {
+    public List<MailboxMembership<String>> findUnseenMessagesInMailbox(String uuid) throws StorageException {
         try {
             List<MailboxMembership<String>> list = new ArrayList<MailboxMembership<String>>();
             String queryString = "//" + MAILBOXES_PATH + "//element(*,jamesMailbox:message)[@" + JCRMessage.MAILBOX_UUID_PROPERTY +"='" + uuid +"'] AND [@" + JCRMessage.SEEN_PROPERTY +"='false'] order by @" + JCRMessage.UID_PROPERTY;
@@ -386,7 +383,7 @@
      * org.apache.james.imap.store.mail.MessageMapper#save(org.apache.james.
      * imap.store.mail.model.MailboxMembership)
      */
-    public void save(MailboxMembership<String> message) throws StorageException {
+    public void save(String uuid, MailboxMembership<String> message) throws StorageException {
         final JCRMessage membership = (JCRMessage) message;
         try {
             //JCRUtils.createNodeRecursive(getSession().getRootNode(), mailboxN);
@@ -483,7 +480,7 @@
      * org.apache.james.imap.store.mail.MessageMapper#searchMailbox(org.apache
      * .james.imap.mailbox.SearchQuery)
      */
-    public List<MailboxMembership<String>> searchMailbox(SearchQuery query) throws StorageException {
+    public List<MailboxMembership<String>> searchMailbox(String uuid, SearchQuery query) throws StorageException {
         try {
             List<MailboxMembership<String>> list = new ArrayList<MailboxMembership<String>>();
             final String xpathQuery = formulateXPath(uuid, query);
Index: jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMailboxMapper.java
===================================================================
--- jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMailboxMapper.java	(Revision 950435)
+++ jcr/src/main/java/org/apache/james/imap/jcr/mail/JCRMailboxMapper.java	(Arbeitskopie)
@@ -144,7 +144,6 @@
         }
     }
 
-
     /*
      * (non-Javadoc)
      * @see org.apache.james.imap.store.mail.MailboxMapper#findMailboxById(java.lang.Object)
@@ -241,7 +240,7 @@
                         final String name = jcrMailbox.getName();
                         
                         //split the name so we can construct a nice node tree
-                        final String nameParts[] = name.split("\\" +String.valueOf(delimiter),3);
+                        final String nameParts[] = name.split("\\" + String.valueOf(delimiter), 3);
                         
                         // this loop will create a structure like:
                         // /mailboxes/u/user/INBOX
Index: jcr/src/main/java/org/apache/james/imap/jcr/MailboxSessionJCRRepository.java
===================================================================
--- jcr/src/main/java/org/apache/james/imap/jcr/MailboxSessionJCRRepository.java	(Revision 950435)
+++ jcr/src/main/java/org/apache/james/imap/jcr/MailboxSessionJCRRepository.java	(Arbeitskopie)
@@ -42,7 +42,6 @@
         this.workspace = workspace;
     }
 
-
     /**
      * If no {@link Session} exists for the {@link MailboxSession} one will get created.
      * If one exists it just return the existing.
@@ -90,7 +89,6 @@
         return repository;
     }
     
-    
     /**
      * Return the workspace
      * 
Index: jcr/src/main/java/org/apache/james/imap/jcr/JCRSubscriptionManager.java
===================================================================
--- jcr/src/main/java/org/apache/james/imap/jcr/JCRSubscriptionManager.java	(Revision 950435)
+++ jcr/src/main/java/org/apache/james/imap/jcr/JCRSubscriptionManager.java	(Arbeitskopie)
@@ -18,51 +18,25 @@
  ****************************************************************/
 package org.apache.james.imap.jcr;
 
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.james.imap.api.display.HumanReadableText;
-import org.apache.james.imap.jcr.user.JCRSubscriptionMapper;
 import org.apache.james.imap.jcr.user.model.JCRSubscription;
 import org.apache.james.imap.mailbox.MailboxSession;
-import org.apache.james.imap.mailbox.SubscriptionException;
 import org.apache.james.imap.store.StoreSubscriptionManager;
-import org.apache.james.imap.store.user.SubscriptionMapper;
 import org.apache.james.imap.store.user.model.Subscription;
 
 /**
  * JCR implementation of a SubscriptionManager
- * 
- * 
  */
-public class JCRSubscriptionManager extends StoreSubscriptionManager implements JCRImapConstants{
+public class JCRSubscriptionManager extends StoreSubscriptionManager<String> implements JCRImapConstants {
+    
     private final Log logger = LogFactory.getLog(JCRSubscriptionManager.class);
-    private final MailboxSessionJCRRepository repository;
 
-    public JCRSubscriptionManager(final MailboxSessionJCRRepository repository ) {
-        super();
-        this.repository = repository;
+    public JCRSubscriptionManager(JCRMailboxSessionMapperFactory mapperFactory) {
+        super(mapperFactory);
     }
 
-
-    
     @Override
-    protected SubscriptionMapper createMapper(MailboxSession session) throws SubscriptionException {
-        try {
-            Session jcrSession = repository.login(session);
-            JCRSubscriptionMapper mapper = new JCRSubscriptionMapper(jcrSession, logger);
-
-            return mapper;
-        } catch (RepositoryException e) {
-            throw new SubscriptionException(HumanReadableText.GENERIC_SUBSCRIPTION_FAILURE, e);
-        }        
-        
-      
-    }
-
-    @Override
     protected Subscription createSubscription(MailboxSession session, String mailbox) {
         return new JCRSubscription(session.getUser().getUserName(), mailbox, logger);
     }
Index: jcr/src/main/java/org/apache/james/imap/jcr/JCRMessageManager.java
===================================================================
--- jcr/src/main/java/org/apache/james/imap/jcr/JCRMessageManager.java	(Revision 950435)
+++ jcr/src/main/java/org/apache/james/imap/jcr/JCRMessageManager.java	(Arbeitskopie)
@@ -23,44 +23,36 @@
 import java.util.Date;
 import java.util.List;
 
-import javax.jcr.RepositoryException;
 import javax.mail.Flags;
 
 import org.apache.commons.logging.Log;
-import org.apache.james.imap.api.display.HumanReadableText;
-import org.apache.james.imap.jcr.mail.JCRMailboxMapper;
-import org.apache.james.imap.jcr.mail.JCRMessageMapper;
 import org.apache.james.imap.jcr.mail.model.JCRHeader;
+import org.apache.james.imap.jcr.mail.model.JCRMailbox;
 import org.apache.james.imap.jcr.mail.model.JCRMessage;
 import org.apache.james.imap.mailbox.MailboxException;
 import org.apache.james.imap.mailbox.MailboxSession;
 import org.apache.james.imap.mailbox.util.MailboxEventDispatcher;
-import org.apache.james.imap.store.StoreMailbox;
+import org.apache.james.imap.store.StoreMessageManager;
 import org.apache.james.imap.store.UidConsumer;
-import org.apache.james.imap.store.mail.MessageMapper;
 import org.apache.james.imap.store.mail.model.Header;
 import org.apache.james.imap.store.mail.model.MailboxMembership;
 import org.apache.james.imap.store.mail.model.PropertyBuilder;
 
 /**
- * JCR implementation of a {@link StoreMailbox}
+ * JCR implementation of a {@link StoreMessageManager}
  *
  */
-public class JCRMailbox extends StoreMailbox<String>{
+public class JCRMessageManager extends StoreMessageManager<String> {
 
-    private final MailboxSessionJCRRepository repos;
     private final Log log;
-    private char delimiter;
 
-    public JCRMailbox(final MailboxEventDispatcher dispatcher, UidConsumer<String> consumer, final org.apache.james.imap.jcr.mail.model.JCRMailbox mailbox, final MailboxSessionJCRRepository repos, final Log log, final char delimiter) {
-        super(dispatcher, consumer, mailbox);
+    public JCRMessageManager(JCRMailboxSessionMapperFactory mapperFactory,
+            final MailboxEventDispatcher dispatcher, UidConsumer<String> consumer,
+            final JCRMailbox mailbox, final Log log, final char delimiter, MailboxSession session) throws MailboxException {
+        super(mapperFactory, dispatcher, consumer, mailbox, session);
         this.log = log;
-        this.repos = repos;
-        this.delimiter = delimiter;
-        
     }
 
-
     @Override
     protected MailboxMembership<String> copyMessage(MailboxMembership<String> originalMessage, long uid, MailboxSession session) throws MailboxException {
         MailboxMembership<String> newRow = new JCRMessage(getMailboxId(), uid, (JCRMessage) originalMessage, log);
@@ -80,38 +72,6 @@
         }
         final MailboxMembership<String> message = new JCRMessage(getMailboxId(), uid, internalDate, 
                 size, flags, document, bodyStartOctet, jcrHeaders, propertyBuilder, log);
-        return message;       
-        
+        return message;
     }
-
-    @Override
-    protected MessageMapper<String> createMessageMapper(MailboxSession session) throws MailboxException {
-        try {
-            JCRMessageMapper messageMapper = new JCRMessageMapper(repos.login(session), getMailboxId(), log);
-            return messageMapper;
-        } catch (RepositoryException e) {
-            throw new MailboxException(HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING, e);
-        }
-        
-    }
-
-    /**
-     * Ceate a MailboxMapper for the given {@link MailboxSession} 
-     * 
-     * @param session
-     * @return mailboxMapper
-     * @throws MailboxException 
-     * @throws MailboxException
-     */
-    protected JCRMailboxMapper createMailboxMapper(MailboxSession session) throws MailboxException {
-        try {
-            JCRMailboxMapper mapper = new JCRMailboxMapper(repos.login(session), log, delimiter);
-            return mapper;
-
-        } catch (RepositoryException e) {
-            throw new MailboxException(HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING, e);
-        }
-        
-
-    }
 }
Index: jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxSessionMapperFactory.java
===================================================================
--- jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxSessionMapperFactory.java	(Revision 0)
+++ jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxSessionMapperFactory.java	(Revision 0)
@@ -0,0 +1,86 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.jcr;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.james.imap.api.display.HumanReadableText;
+import org.apache.james.imap.jcr.mail.JCRMailboxMapper;
+import org.apache.james.imap.jcr.mail.JCRMessageMapper;
+import org.apache.james.imap.jcr.user.JCRSubscriptionMapper;
+import org.apache.james.imap.mailbox.MailboxException;
+import org.apache.james.imap.mailbox.MailboxSession;
+import org.apache.james.imap.mailbox.SubscriptionException;
+import org.apache.james.imap.store.MailboxSessionMapperFactory;
+import org.apache.james.imap.store.mail.MailboxMapper;
+import org.apache.james.imap.store.mail.MessageMapper;
+import org.apache.james.imap.store.user.SubscriptionMapper;
+
+public class JCRMailboxSessionMapperFactory extends	MailboxSessionMapperFactory<String> {
+
+    private MailboxSessionJCRRepository repository;
+    private Log logger;
+    private char delimiter;
+
+    public JCRMailboxSessionMapperFactory(final MailboxSessionJCRRepository repository) {
+        this.repository = repository;
+        this.logger = LogFactory.getLog(JCRSubscriptionManager.class);
+        this.delimiter = '.';
+    }
+
+    @Override
+    public MailboxMapper<String> createMailboxMapper(MailboxSession session) throws MailboxException {
+        try {
+            Session jcrSession = repository.login(session);
+            JCRMailboxMapper mapper = new JCRMailboxMapper(jcrSession, logger, delimiter);
+            return mapper;
+        } catch (RepositoryException e) {
+            throw new MailboxException(HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING, e);
+        }
+    }
+
+    @Override
+    public MessageMapper<String> createMessageMapper(MailboxSession session) throws MailboxException {
+        try {
+            JCRMessageMapper messageMapper = new JCRMessageMapper(repository.login(session), logger);
+            return messageMapper;
+        } catch (RepositoryException e) {
+            throw new MailboxException(HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING, e);
+        }
+    }
+
+    @Override
+    public SubscriptionMapper createSubscriptionMapper(MailboxSession session) throws SubscriptionException {
+        try {
+            Session jcrSession = repository.login(session);
+            JCRSubscriptionMapper mapper = new JCRSubscriptionMapper(jcrSession, logger);
+            return mapper;
+        } catch (RepositoryException e) {
+            throw new SubscriptionException(HumanReadableText.GENERIC_SUBSCRIPTION_FAILURE, e);
+        }      
+    }
+    
+    public MailboxSessionJCRRepository getRepository() {
+        return repository;
+    }
+
+}
Index: jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxManager.java
===================================================================
--- jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxManager.java	(Revision 950435)
+++ jcr/src/main/java/org/apache/james/imap/jcr/JCRMailboxManager.java	(Arbeitskopie)
@@ -21,65 +21,50 @@
 import java.util.ArrayList;
 import java.util.Locale;
 
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.james.imap.api.display.HumanReadableText;
 import org.apache.james.imap.jcr.mail.JCRMailboxMapper;
+import org.apache.james.imap.jcr.mail.model.JCRMailbox;
 import org.apache.james.imap.mailbox.BadCredentialsException;
 import org.apache.james.imap.mailbox.MailboxException;
 import org.apache.james.imap.mailbox.MailboxSession;
 import org.apache.james.imap.mailbox.util.MailboxEventDispatcher;
 import org.apache.james.imap.store.Authenticator;
 import org.apache.james.imap.store.PasswordAwareMailboxSession;
-import org.apache.james.imap.store.StoreMailbox;
+import org.apache.james.imap.store.StoreMessageManager;
 import org.apache.james.imap.store.StoreMailboxManager;
 import org.apache.james.imap.store.Subscriber;
 import org.apache.james.imap.store.UidConsumer;
-import org.apache.james.imap.store.mail.MailboxMapper;
 import org.apache.james.imap.store.mail.model.Mailbox;
 import org.apache.james.imap.store.transaction.TransactionalMapper;
 
 /**
  * JCR implementation of a MailboxManager
- * 
- * 
  */
-public class JCRMailboxManager extends StoreMailboxManager<String> implements JCRImapConstants{
+public class JCRMailboxManager extends StoreMailboxManager<String> implements JCRImapConstants {
 
+    private final JCRMailboxSessionMapperFactory mapperFactory;
     private final MailboxSessionJCRRepository repository;
     private final Log logger = LogFactory.getLog(JCRMailboxManager.class);
     
-    public JCRMailboxManager(final Authenticator authenticator, final Subscriber subscriber, final MailboxSessionJCRRepository repository) {
-        super(authenticator, subscriber, new JCRUidConsumer(repository));
-        this.repository = repository;
+    public JCRMailboxManager(JCRMailboxSessionMapperFactory mapperFactory, final Authenticator authenticator, final Subscriber subscriber) {
+        super(mapperFactory, authenticator, subscriber, new JCRUidConsumer(mapperFactory.getRepository()));
+        this.repository = mapperFactory.getRepository();
+        this.mapperFactory = mapperFactory;
     }
 
-
     @Override
-    protected StoreMailbox<String> createMailbox(MailboxEventDispatcher dispatcher, UidConsumer<String> consumer,Mailbox<String> mailboxRow, MailboxSession session) throws MailboxException{
-        return new JCRMailbox(dispatcher, consumer, (org.apache.james.imap.jcr.mail.model.JCRMailbox) mailboxRow, repository, getLog(), getDelimiter());    
+    protected StoreMessageManager<String> createMessageManager(MailboxEventDispatcher dispatcher,
+            UidConsumer<String> consumer, Mailbox<String> mailboxEntity, MailboxSession session)
+            throws MailboxException{
+        return new JCRMessageManager(mapperFactory, dispatcher, consumer,
+                (JCRMailbox) mailboxEntity, logger, getDelimiter(), session);
     }
 
     @Override
-    protected MailboxMapper<String> createMailboxMapper(MailboxSession session) throws MailboxException {
-
-        try {
-            Session jcrSession = repository.login(session);
-            JCRMailboxMapper mapper = new JCRMailboxMapper(jcrSession, getLog(), getDelimiter());
-            return mapper;
-        } catch (RepositoryException e) {
-            throw new MailboxException(HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING, e);
-        }
-        
-    }
-
-    @Override
-    protected void doCreate(String namespaceName, MailboxSession session) throws MailboxException {
+    protected void doCreateMailbox(String namespaceName, MailboxSession session) throws MailboxException {
         final Mailbox<String> mailbox = new org.apache.james.imap.jcr.mail.model.JCRMailbox(namespaceName, randomUidValidity(), logger);
-        final JCRMailboxMapper mapper = (JCRMailboxMapper)createMailboxMapper(session);
+        final JCRMailboxMapper mapper = (JCRMailboxMapper) mapperFactory.getMailboxMapper(session);
         mapper.execute(new TransactionalMapper.Transaction() {
 
             public void run() throws MailboxException {
@@ -89,7 +74,6 @@
         });
     }
 
-
     /**
      * Return a {@link PasswordAwareMailboxSession} if the login was successful
      * 
@@ -104,7 +88,6 @@
         }
     }
 
-
     /**
      * Logout every open JCR Session
      */
@@ -114,5 +97,4 @@
         super.endProcessingRequest(session);
     }
     
-    
 }
Index: jcr/src/main/java/org/apache/james/imap/jcr/JCRMailbox.java
===================================================================
--- jcr/src/main/java/org/apache/james/imap/jcr/JCRMailbox.java	(Revision 950435)
+++ jcr/src/main/java/org/apache/james/imap/jcr/JCRMailbox.java	(Arbeitskopie)
@@ -1,117 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-package org.apache.james.imap.jcr;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-import javax.jcr.RepositoryException;
-import javax.mail.Flags;
-
-import org.apache.commons.logging.Log;
-import org.apache.james.imap.api.display.HumanReadableText;
-import org.apache.james.imap.jcr.mail.JCRMailboxMapper;
-import org.apache.james.imap.jcr.mail.JCRMessageMapper;
-import org.apache.james.imap.jcr.mail.model.JCRHeader;
-import org.apache.james.imap.jcr.mail.model.JCRMessage;
-import org.apache.james.imap.mailbox.MailboxException;
-import org.apache.james.imap.mailbox.MailboxSession;
-import org.apache.james.imap.mailbox.util.MailboxEventDispatcher;
-import org.apache.james.imap.store.StoreMailbox;
-import org.apache.james.imap.store.UidConsumer;
-import org.apache.james.imap.store.mail.MessageMapper;
-import org.apache.james.imap.store.mail.model.Header;
-import org.apache.james.imap.store.mail.model.MailboxMembership;
-import org.apache.james.imap.store.mail.model.PropertyBuilder;
-
-/**
- * JCR implementation of a {@link StoreMailbox}
- *
- */
-public class JCRMailbox extends StoreMailbox<String>{
-
-    private final MailboxSessionJCRRepository repos;
-    private final Log log;
-    private char delimiter;
-
-    public JCRMailbox(final MailboxEventDispatcher dispatcher, UidConsumer<String> consumer, final org.apache.james.imap.jcr.mail.model.JCRMailbox mailbox, final MailboxSessionJCRRepository repos, final Log log, final char delimiter) {
-        super(dispatcher, consumer, mailbox);
-        this.log = log;
-        this.repos = repos;
-        this.delimiter = delimiter;
-        
-    }
-
-
-    @Override
-    protected MailboxMembership<String> copyMessage(MailboxMembership<String> originalMessage, long uid, MailboxSession session) throws MailboxException {
-        MailboxMembership<String> newRow = new JCRMessage(getMailboxId(), uid, (JCRMessage) originalMessage, log);
-        return newRow;
-    }
-
-    @Override
-    protected Header createHeader(int lineNumber, String name, String value) {
-        return new JCRHeader(lineNumber, name, value, log);
-    }
-
-    @Override
-    protected MailboxMembership<String> createMessage(Date internalDate, long uid, int size, int bodyStartOctet, InputStream document, Flags flags, List<Header> headers, PropertyBuilder propertyBuilder) {
-        final List<JCRHeader> jcrHeaders = new ArrayList<JCRHeader>(headers.size());
-        for (Header header: headers) {
-            jcrHeaders.add((JCRHeader) header);
-        }
-        final MailboxMembership<String> message = new JCRMessage(getMailboxId(), uid, internalDate, 
-                size, flags, document, bodyStartOctet, jcrHeaders, propertyBuilder, log);
-        return message;       
-        
-    }
-
-    @Override
-    protected MessageMapper<String> createMessageMapper(MailboxSession session) throws MailboxException {
-        try {
-            JCRMessageMapper messageMapper = new JCRMessageMapper(repos.login(session), getMailboxId(), log);
-            return messageMapper;
-        } catch (RepositoryException e) {
-            throw new MailboxException(HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING, e);
-        }
-        
-    }
-
-    /**
-     * Ceate a MailboxMapper for the given {@link MailboxSession} 
-     * 
-     * @param session
-     * @return mailboxMapper
-     * @throws MailboxException 
-     * @throws MailboxException
-     */
-    protected JCRMailboxMapper createMailboxMapper(MailboxSession session) throws MailboxException {
-        try {
-            JCRMailboxMapper mapper = new JCRMailboxMapper(repos.login(session), log, delimiter);
-            return mapper;
-
-        } catch (RepositoryException e) {
-            throw new MailboxException(HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING, e);
-        }
-        
-
-    }
-}
Index: jcr/src/main/java/org/apache/james/imap/jcr/AbstractJCRMapper.java
===================================================================
--- jcr/src/main/java/org/apache/james/imap/jcr/AbstractJCRMapper.java	(Revision 950435)
+++ jcr/src/main/java/org/apache/james/imap/jcr/AbstractJCRMapper.java	(Arbeitskopie)
@@ -26,15 +26,13 @@
 import org.apache.james.imap.mailbox.MailboxException;
 import org.apache.james.imap.store.transaction.AbstractTransactionalMapper;
 
-
-
 /**
  * Abstract Mapper base class for Level 1 Implementations of JCR. So no real transaction management is used. 
  * 
  * The Session.save() will get called on commit() method,  session.refresh(false) on rollback, and session.refresh(true) on begin()
  *
  */
-public abstract class AbstractJCRMapper extends AbstractTransactionalMapper implements JCRImapConstants{
+public abstract class AbstractJCRMapper extends AbstractTransactionalMapper implements JCRImapConstants {
     public final static String MAILBOXES_PATH =  "mailboxes";
     public final static String SUBSCRIPTIONS_PATH =  "subscriptions";
 
@@ -45,7 +43,6 @@
         this.session = session;
         this.logger = logger;
     }
-    
 
     /**
      * Return the logger
@@ -65,7 +62,6 @@
         return session;
     }
 
-
     /**
      * Begin is not supported by level 1 JCR implementations, however we refresh the session
      */
@@ -76,7 +72,6 @@
             // do nothin on refresh
         }
         // Do nothing
-        
     }
 
     /**
@@ -90,7 +85,6 @@
         } catch (RepositoryException e) {
             throw new MailboxException(HumanReadableText.COMMIT_TRANSACTION_FAILED, e);
         }
-
     }
 
     /**
Index: deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAStressTest.java
===================================================================
--- deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAStressTest.java	(Revision 950435)
+++ deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAStressTest.java	(Arbeitskopie)
@@ -25,8 +25,8 @@
 
 import org.apache.commons.logging.impl.SimpleLog;
 import org.apache.james.imap.functional.AbstractStressTest;
+import org.apache.james.imap.jpa.JPAMailboxSessionMapperFactory;
 import org.apache.james.imap.jpa.JPASubscriptionManager;
-import org.apache.james.imap.jpa.MailboxSessionEntityManagerFactory;
 import org.apache.james.imap.jpa.openjpa.OpenJPAMailboxManager;
 import org.apache.james.imap.mailbox.MailboxException;
 import org.apache.james.imap.mailbox.MailboxSession;
@@ -64,8 +64,8 @@
         properties.put("openjpa.LockTimeout", locktimeout + "");
        
         entityManagerFactory = OpenJPAPersistence.getEntityManagerFactory(properties);
-        MailboxSessionEntityManagerFactory emf = new MailboxSessionEntityManagerFactory(entityManagerFactory);
-        mailboxManager = new OpenJPAMailboxManager(null, new JPASubscriptionManager(emf), emf);
+        JPAMailboxSessionMapperFactory mf = new JPAMailboxSessionMapperFactory(entityManagerFactory);
+        mailboxManager = new OpenJPAMailboxManager(mf, null, new JPASubscriptionManager(mf));
         
         // Set the lock timeout via SQL because of a bug in openJPA
         // https://issues.apache.org/jira/browse/OPENJPA-1656
Index: deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAHostSystem.java
===================================================================
--- deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAHostSystem.java	(Revision 950435)
+++ deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAHostSystem.java	(Arbeitskopie)
@@ -29,8 +29,8 @@
 import org.apache.james.imap.encode.main.DefaultImapEncoderFactory;
 import org.apache.james.imap.functional.ImapHostSystem;
 import org.apache.james.imap.functional.InMemoryUserManager;
+import org.apache.james.imap.jpa.JPAMailboxSessionMapperFactory;
 import org.apache.james.imap.jpa.JPASubscriptionManager;
-import org.apache.james.imap.jpa.MailboxSessionEntityManagerFactory;
 import org.apache.james.imap.jpa.openjpa.OpenJPAMailboxManager;
 import org.apache.james.imap.mailbox.MailboxSession;
 import org.apache.james.imap.main.DefaultImapDecoderFactory;
@@ -68,8 +68,8 @@
                 "org.apache.james.imap.jpa.user.model.JPASubscription)");
         userManager = new InMemoryUserManager();
         entityManagerFactory = OpenJPAPersistence.getEntityManagerFactory(properties);
-        MailboxSessionEntityManagerFactory factory = new MailboxSessionEntityManagerFactory(entityManagerFactory);
-        mailboxManager = new OpenJPAMailboxManager(userManager, new JPASubscriptionManager(factory), factory);
+        JPAMailboxSessionMapperFactory mf = new JPAMailboxSessionMapperFactory(entityManagerFactory);
+        mailboxManager = new OpenJPAMailboxManager(mf, userManager, new JPASubscriptionManager(mf));
         
         final DefaultImapProcessorFactory defaultImapProcessorFactory = new DefaultImapProcessorFactory();
         resetUserMetaData();
Index: deployment/src/test/java/org/apache/james/imap/functional/jcr/JCRStressTest.java
===================================================================
--- deployment/src/test/java/org/apache/james/imap/functional/jcr/JCRStressTest.java	(Revision 950435)
+++ deployment/src/test/java/org/apache/james/imap/functional/jcr/JCRStressTest.java	(Arbeitskopie)
@@ -28,10 +28,12 @@
 import org.apache.james.imap.functional.AbstractStressTest;
 import org.apache.james.imap.jcr.GlobalMailboxSessionJCRRepository;
 import org.apache.james.imap.jcr.JCRMailboxManager;
+import org.apache.james.imap.jcr.JCRMailboxSessionMapperFactory;
 import org.apache.james.imap.jcr.JCRSubscriptionManager;
 import org.apache.james.imap.jcr.JCRUtils;
 import org.apache.james.imap.jcr.MailboxSessionJCRRepository;
 import org.apache.james.imap.mailbox.MailboxSession;
+import org.apache.james.imap.store.MailboxSessionMapperFactory;
 import org.apache.james.imap.store.StoreMailboxManager;
 import org.junit.After;
 import org.junit.Before;
@@ -66,9 +68,10 @@
         JCRUtils.registerCnd(repository, workspace, user, pass);
 
         MailboxSessionJCRRepository sessionRepos = new GlobalMailboxSessionJCRRepository(repository, workspace, user, pass);
+        JCRMailboxSessionMapperFactory mf = new JCRMailboxSessionMapperFactory(sessionRepos);
         // TODO: Fix the scaling stuff so the tests will pass with max scaling
         // too
-        mailboxManager = new JCRMailboxManager(null, new JCRSubscriptionManager(sessionRepos), sessionRepos);
+        mailboxManager = new JCRMailboxManager(mf, null, new JCRSubscriptionManager(mf));
 
     }
     
Index: deployment/src/test/java/org/apache/james/imap/functional/jcr/JCRHostSystem.java
===================================================================
--- deployment/src/test/java/org/apache/james/imap/functional/jcr/JCRHostSystem.java	(Revision 950435)
+++ deployment/src/test/java/org/apache/james/imap/functional/jcr/JCRHostSystem.java	(Arbeitskopie)
@@ -29,11 +29,14 @@
 import org.apache.james.imap.functional.InMemoryUserManager;
 import org.apache.james.imap.jcr.GlobalMailboxSessionJCRRepository;
 import org.apache.james.imap.jcr.JCRMailboxManager;
+import org.apache.james.imap.jcr.JCRMailboxSessionMapperFactory;
 import org.apache.james.imap.jcr.JCRSubscriptionManager;
 import org.apache.james.imap.jcr.JCRUtils;
 import org.apache.james.imap.mailbox.MailboxSession;
 import org.apache.james.imap.main.DefaultImapDecoderFactory;
 import org.apache.james.imap.processor.main.DefaultImapProcessorFactory;
+import org.apache.james.imap.store.Authenticator;
+import org.apache.james.imap.store.Subscriber;
 import org.apache.james.test.functional.HostSystem;
 import org.xml.sax.InputSource;
 
@@ -67,10 +70,10 @@
             JCRUtils.registerCnd(repository, workspace, user, pass);
             
             userManager = new InMemoryUserManager();
+            JCRMailboxSessionMapperFactory mf = new JCRMailboxSessionMapperFactory(sessionRepos);
 
             //TODO: Fix the scaling stuff so the tests will pass with max scaling too
-            mailboxManager = new JCRMailboxManager(userManager, new JCRSubscriptionManager(sessionRepos), sessionRepos);
-
+            mailboxManager = new JCRMailboxManager(mf, userManager, new JCRSubscriptionManager(mf));
             final DefaultImapProcessorFactory defaultImapProcessorFactory = new DefaultImapProcessorFactory();
             resetUserMetaData();
             MailboxSession session = mailboxManager.createSystemSession("test", new SimpleLog("TestLog"));
Index: deployment/src/test/java/org/apache/james/imap/functional/inmemory/InMemoryHostSystem.java
===================================================================
--- deployment/src/test/java/org/apache/james/imap/functional/inmemory/InMemoryHostSystem.java	(Revision 950435)
+++ deployment/src/test/java/org/apache/james/imap/functional/inmemory/InMemoryHostSystem.java	(Arbeitskopie)
@@ -23,10 +23,10 @@
 import org.apache.james.imap.functional.ImapHostSystem;
 import org.apache.james.imap.functional.InMemoryUserManager;
 import org.apache.james.imap.inmemory.InMemoryMailboxManager;
+import org.apache.james.imap.inmemory.InMemoryMailboxSessionMapperFactory;
 import org.apache.james.imap.inmemory.InMemorySubscriptionManager;
 import org.apache.james.imap.main.DefaultImapDecoderFactory;
 import org.apache.james.imap.processor.main.DefaultImapProcessorFactory;
-import org.apache.james.imap.store.StoreMailboxManager;
 import org.apache.james.test.functional.HostSystem;
 
 public class InMemoryHostSystem extends ImapHostSystem {
@@ -41,7 +41,8 @@
     
     private InMemoryHostSystem() {
         userManager = new InMemoryUserManager();
-        mailboxManager = new InMemoryMailboxManager(userManager, new InMemorySubscriptionManager());
+        InMemoryMailboxSessionMapperFactory mf = new InMemoryMailboxSessionMapperFactory();
+        mailboxManager = new InMemoryMailboxManager(mf, userManager, new InMemorySubscriptionManager(mf));
         final DefaultImapProcessorFactory defaultImapProcessorFactory = new DefaultImapProcessorFactory();
         defaultImapProcessorFactory.configure(mailboxManager);
         configure(new DefaultImapDecoderFactory().buildImapDecoder(),
