You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by no...@apache.org on 2010/06/04 15:07:08 UTC

svn commit: r951398 [3/4] - in /james/imap/trunk: deployment/src/test/java/org/apache/james/imap/functional/inmemory/ deployment/src/test/java/org/apache/james/imap/functional/jcr/ deployment/src/test/java/org/apache/james/imap/functional/jpa/ jcr/src/...

Added: james/imap/trunk/memory/src/main/java/org/apache/james/imap/inmemory/user/model/InMemorySubscription.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/memory/src/main/java/org/apache/james/imap/inmemory/user/model/InMemorySubscription.java?rev=951398&view=auto
==============================================================================
--- james/imap/trunk/memory/src/main/java/org/apache/james/imap/inmemory/user/model/InMemorySubscription.java (added)
+++ james/imap/trunk/memory/src/main/java/org/apache/james/imap/inmemory/user/model/InMemorySubscription.java Fri Jun  4 13:07:05 2010
@@ -0,0 +1,87 @@
+/****************************************************************
+ * 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.user.model;
+
+import org.apache.james.imap.mailbox.MailboxSession.User;
+import org.apache.james.imap.store.user.model.Subscription;
+
+public class InMemorySubscription implements Subscription {
+
+    private final String mailbox;
+    private final String user;
+    
+    public InMemorySubscription(final String mailbox, final User user) {
+        super();
+        this.mailbox = mailbox;
+        this.user = user.getUserName();
+    }
+
+    public String getMailbox() {
+        return mailbox;
+    }
+
+    public String getUser() {
+        return user;
+    }
+
+    @Override
+    public int hashCode() {
+        final int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + ((mailbox == null) ? 0 : mailbox.hashCode());
+        result = PRIME * result + ((user == null) ? 0 : user.hashCode());
+        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 InMemorySubscription other = (InMemorySubscription) obj;
+        if (mailbox == null) {
+            if (other.mailbox != null)
+                return false;
+        } else if (!mailbox.equals(other.mailbox))
+            return false;
+        if (user == null) {
+            if (other.user != null)
+                return false;
+        } else if (!user.equals(other.user))
+            return false;
+        return true;
+    }
+
+    /**
+     * Representation suitable for logging and debugging.
+     * @return a <code>String</code> representation 
+     * of this object.
+     */
+    public String toString()
+    {
+        return "InMemorySubscription[ "
+            + "mailbox = " + this.mailbox + " "
+            + "user = " + this.user + " "
+            + " ]";
+    }
+    
+}

Added: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/MailboxSessionMapperFactory.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/MailboxSessionMapperFactory.java?rev=951398&view=auto
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/MailboxSessionMapperFactory.java (added)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/MailboxSessionMapperFactory.java Fri Jun  4 13:07:05 2010
@@ -0,0 +1,132 @@
+/****************************************************************
+ * 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
+     */
+    @SuppressWarnings("unchecked")
+    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;
+    }
+
+    /**
+     * Create a {@link MessageMapper} instance which will get reused during the whole {@link MailboxSession}
+     * 
+     * @param session
+     * @return messageMapper
+     * @throws MailboxException
+     */
+    protected abstract MessageMapper<Id> createMessageMapper(MailboxSession session) throws MailboxException;
+
+    /**
+     * Create a {@link MailboxMapper} instance or return the one which exists for the {@link MailboxSession} already
+     * 
+     * @param session
+     * @return mapper
+     */
+    @SuppressWarnings("unchecked")
+    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;
+    }
+
+    /**
+     * Create a {@link MailboxMapper} instance which will get reused during the whole {@link MailboxSession}
+     * 
+     * @param session
+     * @return mailboxMapper
+     * @throws MailboxException
+     */
+    protected abstract MailboxMapper<Id> createMailboxMapper(MailboxSession session) throws MailboxException;
+
+    /**
+     * Create a {@link SubscriptionMapper} instance or 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;
+    }
+    
+    /**
+     * Create a {@link SubscriptionMapper} instance which will get reused during the whole {@link MailboxSession}
+     * @param session
+     * @return subscriptionMapper
+     * @throws SubscriptionException
+     */
+    protected abstract SubscriptionMapper createSubscriptionMapper(MailboxSession session) throws SubscriptionException;
+
+    /**
+     * Callback which needs to get called once an IMAP Request was complete. It will take care of getting rid of all Session-scoped stuff
+     * 
+     * @param session
+     */
+    @SuppressWarnings("unchecked")
+    public void endRequest(MailboxSession session) {
+        if (session == null) return;
+        MessageMapper<Id> messageMapper = (MessageMapper) session.getAttributes().get(MESSAGEMAPPER);
+        MailboxMapper<Id> mailboxMapper = (MailboxMapper) session.getAttributes().get(MAILBOXMAPPER);
+        SubscriptionMapper subscriptionMapper = (SubscriptionMapper) session.getAttributes().get(SUBSCRIPTIONMAPPER);
+        if (messageMapper != null)
+            messageMapper.endRequest();
+        if (mailboxMapper != null)
+            mailboxMapper.endRequest();
+        if (subscriptionMapper != null)
+            subscriptionMapper.endRequest();
+    }
+    
+
+}

Modified: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/MimeDescriptorImpl.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/MimeDescriptorImpl.java?rev=951398&r1=951397&r2=951398&view=diff
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/MimeDescriptorImpl.java (original)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/MimeDescriptorImpl.java Fri Jun  4 13:07:05 2010
@@ -33,6 +33,8 @@ import org.apache.james.imap.mailbox.Mim
 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;

Modified: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/PasswordAwareMailboxSession.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/PasswordAwareMailboxSession.java?rev=951398&r1=951397&r2=951398&view=diff
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/PasswordAwareMailboxSession.java (original)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/PasswordAwareMailboxSession.java Fri Jun  4 13:07:05 2010
@@ -28,33 +28,35 @@ import org.apache.commons.logging.Log;
  * 
  *
  */
-public class PasswordAwareMailboxSession extends SimpleMailboxSession implements PasswordAwareUser{
+// 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;
+    private final String password;
 
-	public PasswordAwareMailboxSession(long sessionId, String userName,String password,
-			Log log, char deliminator, List<Locale> localePreferences) {
-		super(sessionId, userName, log, deliminator, localePreferences);
-		this.password = password;
-	}
-	
+    public PasswordAwareMailboxSession(long sessionId, String userName,
+            String password, Log log, char deliminator,
+            List<Locale> localePreferences) {
+        super(sessionId, userName, log, deliminator, localePreferences);
+        this.password = password;
+    }
 
-	/**
-	 * Return the User which is bound the the MailboxSession. This User is in fact an
-	 * instance of PasswordAwareUser. 
-	 * 
-	 * return user
-	 */
-	public User getUser() {
-		return this;
-	}
-	
-	/**
-	 * Return the Password for the logged in user
-	 * 
-	 * @return password
-	 */
-	public String getPassword() {
-		return password;
-	}
+    /**
+     * Return the User which is bound the the MailboxSession. This User is in
+     * fact an instance of PasswordAwareUser.
+     * 
+     * return user
+     */
+    public User getUser() {
+        return this;
+    }
+
+    /**
+     * Return the Password for the logged in user
+     * 
+     * @return password
+     */
+    public String getPassword() {
+        return password;
+    }
 }

Modified: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/PasswordAwareUser.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/PasswordAwareUser.java?rev=951398&r1=951397&r2=951398&view=diff
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/PasswordAwareUser.java (original)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/PasswordAwareUser.java Fri Jun  4 13:07:05 2010
@@ -27,12 +27,12 @@ import org.apache.james.imap.mailbox.Mai
  */
 public interface PasswordAwareUser extends MailboxSession.User {
 	
-	/**
-	 * Return the Password for the logged in user
-	 * 
-	 * @return password
-	 */
-	public String getPassword();
+    /**
+     * Return the Password for the logged in user
+     * 
+     * @return password
+     */
+    public String getPassword();
 	
 	
 }

Modified: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/ResultUtils.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/ResultUtils.java?rev=951398&r1=951397&r2=951398&view=diff
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/ResultUtils.java (original)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/ResultUtils.java Fri Jun  4 13:07:05 2010
@@ -40,6 +40,10 @@ import org.apache.james.imap.mailbox.Mes
 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;
 
 /**

Modified: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/StoreMailboxManager.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/StoreMailboxManager.java?rev=951398&r1=951397&r2=951398&view=diff
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/StoreMailboxManager.java (original)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/StoreMailboxManager.java Fri Jun  4 13:07:05 2010
@@ -71,43 +71,36 @@ public abstract class StoreMailboxManage
     private final Authenticator authenticator;    
     private final Subscriber subscriber;    
     private final char delimiter;
-
+    protected final MailboxSessionMapperFactory<Id> mailboxSessionMapperFactory;
     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;
     }
-
     /**
-     * Create a StoreMailbox for the given Mailbox
+     * Create a {@link StoreMessageManager} for the given Mailbox
      * 
      * @param mailboxRow
      * @return storeMailbox
      */
-    protected abstract StoreMessageManager<Id> createMailbox(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;
-    
+    protected abstract StoreMessageManager<Id> createMessageManager(MailboxEventDispatcher dispatcher, UidConsumer<Id> consumer, Mailbox<Id> mailboxRow, 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;
     
     
     /*
@@ -128,7 +121,7 @@ public abstract class StoreMailboxManage
      */
     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 +131,7 @@ public abstract class StoreMailboxManage
             } else {
                 getLog().debug("Loaded mailbox " + mailboxName);
 
-                StoreMessageManager<Id> result = createMailbox(dispatcher, consumer, mailboxRow, session);
+                StoreMessageManager<Id> result = createMessageManager(dispatcher, consumer, mailboxRow, session);
                 result.addListener(delegatingListener);
                 return result;
             }
@@ -173,7 +166,7 @@ public abstract class StoreMailboxManage
                         final String mailbox = namespaceName
                         .substring(0, index);
                         if (!mailboxExists(mailbox, mailboxSession)) {
-                            doCreate(mailbox, mailboxSession);
+                            doCreateMailbox(mailbox, mailboxSession);
                         }
                     }
                     index = namespaceName.indexOf(delimiter, ++index);
@@ -181,7 +174,7 @@ public abstract class StoreMailboxManage
                 if (mailboxExists(namespaceName, mailboxSession)) {
                     throw new MailboxExistsException(namespaceName); 
                 } else {
-                    doCreate(namespaceName, mailboxSession);
+                	doCreateMailbox(namespaceName, mailboxSession);
                 }
             }
         }
@@ -197,7 +190,7 @@ public abstract class StoreMailboxManage
         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 +221,7 @@ public abstract class StoreMailboxManage
                 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 {
@@ -314,7 +307,7 @@ public abstract class StoreMailboxManage
                 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 +347,7 @@ public abstract class StoreMailboxManage
      */
     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;
@@ -497,11 +490,10 @@ public abstract class StoreMailboxManage
 
 
     /**
-     * End processing of Request for session. Default is to do nothing.
-     * Implementations should override this if they need to do anything special
+     * End processing of Request for session
      */
     public void endProcessingRequest(MailboxSession session) {
-        // Default do nothing
+        mailboxSessionMapperFactory.endRequest(session);
     }
 
 

Modified: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/StoreMessageManager.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/StoreMessageManager.java?rev=951398&r1=951397&r2=951398&view=diff
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/StoreMessageManager.java (original)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/StoreMessageManager.java Fri Jun  4 13:07:05 2010
@@ -52,12 +52,13 @@ import org.apache.james.imap.mailbox.Sea
 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;
@@ -78,18 +79,21 @@ public abstract class StoreMessageManage
     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 StoreMessageManager(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 @@ public abstract class StoreMessageManage
     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 @@ public abstract class StoreMessageManage
      * @throws MailboxException
      */
     
-    protected Mailbox<Id> getMailboxEntity(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 @@ public abstract class StoreMessageManage
      * @return id
      */
     protected Id getMailboxId() {
-        return mailboxId;
+        return mailbox.getMailboxId();
     }
 
     /*
@@ -145,8 +140,7 @@ public abstract class StoreMessageManage
      * @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,10 +151,7 @@ public abstract class StoreMessageManage
             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), mailboxSession);
-        
+        final long uid = consumer.reserveNextUid(getMailboxEntity(), mailboxSession);
         
         File file = null;
         try {
@@ -282,14 +273,14 @@ public abstract class StoreMessageManage
             }
             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(), getMailboxEntity(mailboxSession).getName());
+            dispatcher.added(uid, mailboxSession.getSessionId(), getMailboxEntity().getName());
             return uid;
         } catch (IOException e) {
             e.printStackTrace();
@@ -387,8 +378,7 @@ public abstract class StoreMessageManage
     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 @@ public abstract class StoreMessageManage
     }
 
     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 @@ public abstract class StoreMessageManage
 
     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 @@ public abstract class StoreMessageManage
     }
 
     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 @@ public abstract class StoreMessageManage
 
     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(getMailboxId(), message);
                 }  
             }
             
@@ -495,7 +480,7 @@ public abstract class StoreMessageManage
         
         Iterator<Long> uidIt = uids.iterator();
         while(uidIt.hasNext()) {
-            dispatcher.expunged(uidIt.next(), mailboxSession.getSessionId(), getMailboxEntity(mailboxSession).getName());
+            dispatcher.expunged(uidIt.next(), mailboxSession.getSessionId(), getMailboxEntity().getName());
         }
         return uids.iterator();
     }
@@ -511,13 +496,12 @@ public abstract class StoreMessageManage
 
     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 @@ public abstract class StoreMessageManage
                         member.setFlags(current);
                     }
                     newFlagsByUid.put(member.getUid(), member.createFlags());
-                    mapper.save(member);
+                    messageMapper.save(getMailboxId(), member);
                 }
             }
             
@@ -541,7 +525,7 @@ public abstract class StoreMessageManage
         Iterator<Long> it = newFlagsByUid.keySet().iterator();
         while (it.hasNext()) {
             Long uid = it.next();
-            dispatcher.flagsUpdated(uid, mailboxSession.getSessionId(), getMailboxEntity(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 @@ public abstract class StoreMessageManage
     }
 
     private long getUidValidity(MailboxSession mailboxSession) throws MailboxException {
-        final long result = getMailboxEntity(mailboxSession).getUidValidity();
+        final long result = getMailboxEntity().getUidValidity();
         return result;
     }
 
     private long getUidNext(MailboxSession mailboxSession) throws MailboxException {
-        Mailbox<Id> mailbox = getMailboxEntity(mailboxSession);
+        Mailbox<Id> mailbox = getMailboxEntity();
         if (mailbox == null) {
             throw new MailboxNotFoundException("Mailbox has been deleted");
         } else {
@@ -571,8 +555,7 @@ public abstract class StoreMessageManage
      * @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,46 +577,33 @@ public abstract class StoreMessageManage
         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(getMailboxEntity(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(), getMailboxEntity(session).getName());
+                dispatcher.added(newMember.getUid(), session.getSessionId(), getMailboxEntity().getName());
             }
-            
         } catch (MessagingException e) {
             throw new MailboxException(HumanReadableText.FAILURE_MAIL_PARSE, e);
         }
@@ -649,9 +619,7 @@ public abstract class StoreMessageManage
      */
     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 @@ public abstract class StoreMessageManage
                 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;
-    
 
-}
+}
\ No newline at end of file

Modified: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/StoreSubscriptionManager.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/StoreSubscriptionManager.java?rev=951398&r1=951397&r2=951398&view=diff
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/StoreSubscriptionManager.java (original)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/StoreSubscriptionManager.java Fri Jun  4 13:07:05 2010
@@ -32,28 +32,22 @@ import org.apache.james.imap.store.user.
 /**
  * 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();
-    }
-
-    /**
-     * Create the SubscriptionMapper to use
-     * 
-     * @return mapper
-     */
-    protected abstract SubscriptionMapper createMapper(MailboxSession session) throws SubscriptionException;
+    protected MailboxSessionMapperFactory<Id> mapperFactory;
     
+    public StoreSubscriptionManager(final MailboxSessionMapperFactory<Id> mapperFactory) {
+        this.mapperFactory = mapperFactory;
+    }
 
     /*
      * (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 @@ public abstract class StoreSubscriptionM
         } catch (MailboxException e) {
             throw new SubscriptionException(e.getKey(), e);
         }
-
-
     }
 
     /**
@@ -80,14 +72,14 @@ public abstract class StoreSubscriptionM
      * @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 @@ public abstract class StoreSubscriptionM
      * @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() {
 

Modified: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/MailboxMapper.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/MailboxMapper.java?rev=951398&r1=951397&r2=951398&view=diff
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/MailboxMapper.java (original)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/MailboxMapper.java Fri Jun  4 13:07:05 2010
@@ -30,7 +30,7 @@ import org.apache.james.imap.store.trans
  * 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

Modified: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/MessageMapper.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/MessageMapper.java?rev=951398&r1=951397&r2=951398&view=diff
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/MessageMapper.java (original)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/MessageMapper.java Fri Jun  4 13:07:05 2010
@@ -42,7 +42,7 @@ public interface MessageMapper<Id> exten
      * @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 @@ public interface MessageMapper<Id> exten
      * @throws StorageException
      */
     public abstract List<MailboxMembership<Id>> findMarkedForDeletionInMailbox(
-            final MessageRange set)
+            Id mailboxId, final MessageRange set)
             throws StorageException;
 
     /**
@@ -62,7 +62,7 @@ public interface MessageMapper<Id> exten
      * @return count
      * @throws StorageException
      */
-    public abstract long countMessagesInMailbox()
+    public abstract long countMessagesInMailbox(Id mailboxId)
             throws StorageException;
 
     /**
@@ -71,7 +71,7 @@ public interface MessageMapper<Id> exten
      * @return unseenCount
      * @throws StorageException
      */
-    public abstract long countUnseenMessagesInMailbox()
+    public abstract long countUnseenMessagesInMailbox(Id mailboxId)
             throws StorageException;
 
     /**
@@ -81,7 +81,7 @@ public interface MessageMapper<Id> exten
      * @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}
@@ -89,7 +89,7 @@ public interface MessageMapper<Id> exten
      * @param message
      * @throws StorageException
      */
-    public abstract void delete(MailboxMembership<Id> message) throws StorageException;
+    public abstract void delete(Id mailboxId, MailboxMembership<Id> message) throws StorageException;
 
     /**
      * Return a List of {@link MailboxMembership} which are unseen. 
@@ -98,7 +98,7 @@ public interface MessageMapper<Id> exten
      * @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 @@ public interface MessageMapper<Id> exten
      * @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 @@ public interface MessageMapper<Id> exten
      * @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

Modified: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/model/AbstractDocument.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/model/AbstractDocument.java?rev=951398&r1=951397&r2=951398&view=diff
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/model/AbstractDocument.java (original)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/model/AbstractDocument.java Fri Jun  4 13:07:05 2010
@@ -21,9 +21,9 @@ package org.apache.james.imap.store.mail
 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;
 
 
 /**

Modified: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/model/Document.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/model/Document.java?rev=951398&r1=951397&r2=951398&view=diff
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/model/Document.java (original)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/mail/model/Document.java Fri Jun  4 13:07:05 2010
@@ -21,7 +21,7 @@ package org.apache.james.imap.store.mail
 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)

Added: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/AbstractFullContent.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/AbstractFullContent.java?rev=951398&view=auto
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/AbstractFullContent.java (added)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/AbstractFullContent.java Fri Jun  4 13:07:05 2010
@@ -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;
+
+    
+}

Added: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/AbstractRewindableInputStream.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/AbstractRewindableInputStream.java?rev=951398&view=auto
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/AbstractRewindableInputStream.java (added)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/AbstractRewindableInputStream.java Fri Jun  4 13:07:05 2010
@@ -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;
+    }
+}

Added: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/ByteContent.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/ByteContent.java?rev=951398&view=auto
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/ByteContent.java (added)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/ByteContent.java Fri Jun  4 13:07:05 2010
@@ -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
+        }
+    }
+}

Added: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/CRLFOutputStream.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/CRLFOutputStream.java?rev=951398&view=auto
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/CRLFOutputStream.java (added)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/CRLFOutputStream.java Fri Jun  4 13:07:05 2010
@@ -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;
+        }
+    }
+}

Added: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/ConfigurableMimeTokenStream.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/ConfigurableMimeTokenStream.java?rev=951398&view=auto
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/ConfigurableMimeTokenStream.java (added)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/ConfigurableMimeTokenStream.java Fri Jun  4 13:07:05 2010
@@ -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);
+    }
+}

Added: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/CountingInputStream.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/CountingInputStream.java?rev=951398&view=auto
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/CountingInputStream.java (added)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/CountingInputStream.java Fri Jun  4 13:07:05 2010
@@ -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);
+    }
+}

Added: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/DelegatingRewindableInputStream.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/DelegatingRewindableInputStream.java?rev=951398&view=auto
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/DelegatingRewindableInputStream.java (added)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/DelegatingRewindableInputStream.java Fri Jun  4 13:07:05 2010
@@ -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();
+    }
+
+}

Added: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/FileRewindableInputStream.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/FileRewindableInputStream.java?rev=951398&view=auto
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/FileRewindableInputStream.java (added)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/FileRewindableInputStream.java Fri Jun  4 13:07:05 2010
@@ -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;
+    }
+}

Added: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/FullByteContent.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/FullByteContent.java?rev=951398&view=auto
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/FullByteContent.java (added)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/FullByteContent.java Fri Jun  4 13:07:05 2010
@@ -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();
+    }
+
+}

Added: james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/InMemoryRewindableInputStream.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/InMemoryRewindableInputStream.java?rev=951398&view=auto
==============================================================================
--- james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/InMemoryRewindableInputStream.java (added)
+++ james/imap/trunk/store/src/main/java/org/apache/james/imap/store/streaming/InMemoryRewindableInputStream.java Fri Jun  4 13:07:05 2010
@@ -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;
+    }
+
+}



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