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 bt...@apache.org on 2018/12/04 08:48:59 UTC

[6/8] james-project git commit: MAILBOX-292 Make Maildir Mailbox Id persistent

MAILBOX-292 Make Maildir Mailbox Id persistent


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/7e32da51
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/7e32da51
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/7e32da51

Branch: refs/heads/master
Commit: 7e32da51a29bee1c732b2b13708bb4b986140119
Parents: d9bcebc
Author: Benoit Tellier <bt...@linagora.com>
Authored: Fri Nov 30 16:00:34 2018 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Dec 4 15:47:46 2018 +0700

----------------------------------------------------------------------
 .../james/mailbox/maildir/MaildirFolder.java    | 54 +++++++++++++++-
 .../apache/james/mailbox/maildir/MaildirId.java |  7 ++
 .../james/mailbox/maildir/MaildirStore.java     |  1 +
 .../mailbox/maildir/mail/MailboxCache.java      | 68 --------------------
 .../maildir/mail/MaildirMailboxMapper.java      | 63 ++++++++++--------
 .../DomainUserMaildirMailboxManagerTest.java    |  9 ---
 .../FullUserMaildirMailboxManagerTest.java      | 10 ---
 .../maildir/src/test/resources/logback-test.xml | 28 ++++++++
 8 files changed, 125 insertions(+), 115 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/7e32da51/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/MaildirFolder.java
----------------------------------------------------------------------
diff --git a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/MaildirFolder.java b/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/MaildirFolder.java
index 4982726..b31b522 100644
--- a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/MaildirFolder.java
+++ b/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/MaildirFolder.java
@@ -58,6 +58,7 @@ public class MaildirFolder {
     public static final String VALIDITY_FILE = "james-uidvalidity";
     public static final String UIDLIST_FILE = "james-uidlist";
     public static final String ACL_FILE = "james-acl";
+    public static final String MAILBOX_ID_FILE = "james-mailboxId";
     public static final String CUR = "cur";
     public static final String NEW = "new";
     public static final String TMP = "tmp";
@@ -68,7 +69,8 @@ public class MaildirFolder {
     private final File tmpFolder;
     private final File uidFile;
     private final File aclFile;
-    
+    private final File mailboxIdFile;
+
     private Optional<MessageUid> lastUid;
     private int messageCount = 0;
     private long uidValidity = -1;
@@ -91,6 +93,7 @@ public class MaildirFolder {
         this.tmpFolder = new File(rootFolder, TMP);
         this.uidFile = new File(rootFolder, UIDLIST_FILE);
         this.aclFile = new File(rootFolder, ACL_FILE);
+        this.mailboxIdFile = new File(rootFolder, MAILBOX_ID_FILE);
         this.locker = locker;
         this.path = path;
         this.lastUid = Optional.empty();
@@ -163,6 +166,10 @@ public class MaildirFolder {
     public File getCurFolder() {
         return curFolder;
     }
+
+    public File getMailboxIdFile() {
+        return mailboxIdFile;
+    }
     
     /**
      * Returns the ./new folder of this Maildir folder.
@@ -294,6 +301,51 @@ public class MaildirFolder {
             fos.write(String.valueOf(uidValidity).getBytes());
         }
     }
+
+    /**
+     * Sets the mailboxId for this mailbox and writes it to the file system
+     * @param mailboxId
+     * @throws IOException
+     */
+    public void setMailboxId(MaildirId mailboxId) throws IOException {
+        saveMailboxId(mailboxId);
+    }
+
+    /**
+     * Read the mailboxId of the given mailbox from the file system.
+     * If the respective file is not yet there, it gets created and
+     * filled with a brand new uidValidity.
+     * @return The uidValidity
+     * @throws IOException if there are problems with the validity file
+     */
+    public MaildirId readMailboxId() throws IOException {
+        if (!mailboxIdFile.exists()) {
+            MaildirId maildirId = MaildirId.random();
+            saveMailboxId(maildirId);
+            return maildirId;
+        }
+        try (FileInputStream fis = new FileInputStream(mailboxIdFile);
+             InputStreamReader isr = new InputStreamReader(fis)) {
+            char[] mailboxId = new char[20];
+            int len = isr.read(mailboxId);
+            int idAsInt = Integer.parseInt(String.valueOf(mailboxId, 0, len).trim());
+            return MaildirId.of(idAsInt);
+        }
+    }
+
+    /**
+     * Save the given MaildirId to the file system
+     * @param id
+     * @throws IOException
+     */
+    private void saveMailboxId(MaildirId id) throws IOException {
+        if (!mailboxIdFile.createNewFile()) {
+            throw new IOException("Could not create file " + mailboxIdFile);
+        }
+        try (FileOutputStream fos = new FileOutputStream(mailboxIdFile)) {
+            fos.write(String.valueOf(id.getRawId()).getBytes());
+        }
+    }
     
     /**
      * Sets and returns a new uidValidity for this folder.

http://git-wip-us.apache.org/repos/asf/james-project/blob/7e32da51/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/MaildirId.java
----------------------------------------------------------------------
diff --git a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/MaildirId.java b/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/MaildirId.java
index 69de83f..18df444 100644
--- a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/MaildirId.java
+++ b/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/MaildirId.java
@@ -19,6 +19,7 @@
 package org.apache.james.mailbox.maildir;
 
 import java.io.Serializable;
+import java.security.SecureRandom;
 
 import org.apache.james.mailbox.model.MailboxId;
 
@@ -31,6 +32,12 @@ public class MaildirId implements MailboxId, Serializable {
         }
     }
 
+    private static final SecureRandom RANDOM = new SecureRandom();
+
+    public static MaildirId random() {
+        return MaildirId.of(Math.abs(RANDOM.nextInt()));
+    }
+
     public static MaildirId of(int id) {
         return new MaildirId(id);
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/7e32da51/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/MaildirStore.java
----------------------------------------------------------------------
diff --git a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/MaildirStore.java b/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/MaildirStore.java
index f7a2d8d..b0a3192 100644
--- a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/MaildirStore.java
+++ b/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/MaildirStore.java
@@ -132,6 +132,7 @@ public class MaildirStore implements UidProvider, ModSeqProvider {
         folder.setMessageNameStrictParse(isMessageNameStrictParse());
         try {
             Mailbox loadedMailbox = new SimpleMailbox(mailboxPath, folder.getUidValidity());
+            loadedMailbox.setMailboxId(folder.readMailboxId());
             loadedMailbox.setACL(folder.getACL(session));
             return loadedMailbox;
         } catch (IOException e) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/7e32da51/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MailboxCache.java
----------------------------------------------------------------------
diff --git a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MailboxCache.java b/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MailboxCache.java
deleted file mode 100644
index cf04c1e..0000000
--- a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MailboxCache.java
+++ /dev/null
@@ -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.mailbox.maildir.mail;
-
-import java.util.ArrayList;
-
-import org.apache.james.mailbox.exception.MailboxNotFoundException;
-import org.apache.james.mailbox.maildir.MaildirId;
-import org.apache.james.mailbox.store.mail.model.Mailbox;
-import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox;
-
-public class MailboxCache {
-    /**
-     * A request-scoped list of mailboxes in order to refer to them via id
-     */
-    private final ArrayList<Mailbox> mailboxCache = new ArrayList<>();
-
-    /**
-     * Stores a copy of a mailbox in a cache valid for one request. This is to enable
-     * referring to renamed mailboxes via id.
-     * @param mailbox The mailbox to cache
-     * @return the cached mailbox
-     */
-    public synchronized Mailbox cacheMailbox(Mailbox mailbox) {
-        mailboxCache.add(new SimpleMailbox(mailbox));
-        int id = mailboxCache.size() - 1;
-        mailbox.setMailboxId(MaildirId.of(id));
-        return mailbox;
-    }
-
-    /**
-     * Retrieves a mailbox from the cache
-     * @param mailboxId The id of the mailbox to retrieve
-     * @return The mailbox
-     * @throws MailboxNotFoundException If the mailboxId is not in the cache
-     */
-    public synchronized Mailbox getCachedMailbox(MaildirId mailboxId) throws MailboxNotFoundException {
-        if (mailboxId == null) {
-            throw new MailboxNotFoundException("null");
-        }
-        try {
-            return mailboxCache.get(mailboxId.getRawId());
-        } catch (IndexOutOfBoundsException e) {
-            throw new MailboxNotFoundException(mailboxId);
-        }
-    }
-
-    public synchronized void clear() {
-        mailboxCache.clear();
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/7e32da51/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMailboxMapper.java
----------------------------------------------------------------------
diff --git a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMailboxMapper.java b/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMailboxMapper.java
index b1b83f9..454d857 100644
--- a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMailboxMapper.java
+++ b/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMailboxMapper.java
@@ -23,6 +23,8 @@ import java.io.FilenameFilter;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
+import java.util.Random;
 import java.util.regex.Pattern;
 
 import org.apache.commons.io.FileUtils;
@@ -55,18 +57,12 @@ public class MaildirMailboxMapper extends NonTransactionalMapper implements Mail
      * The {@link MaildirStore} the mailboxes reside in
      */
     private final MaildirStore maildirStore;
-    
-    /**
-     * A request-scoped list of mailboxes in order to refer to them via id
-     */
-    private final MailboxCache mailboxCache;
 
     private final MailboxSession session;
     
     public MaildirMailboxMapper(MaildirStore maildirStore, MailboxSession session) {
         this.maildirStore = maildirStore;
         this.session = session;
-        this.mailboxCache = new MailboxCache();
     }
 
     @Override
@@ -109,14 +105,18 @@ public class MaildirMailboxMapper extends NonTransactionalMapper implements Mail
     @Override
     public Mailbox findMailboxByPath(MailboxPath mailboxPath)
             throws MailboxException, MailboxNotFoundException {      
-        Mailbox mailbox = maildirStore.loadMailbox(session, mailboxPath);
-        return mailboxCache.cacheMailbox(mailbox);
+        return maildirStore.loadMailbox(session, mailboxPath);
     }
     
     @Override
     public Mailbox findMailboxById(MailboxId id) throws MailboxException, MailboxNotFoundException {
-        MaildirId mailboxId = (MaildirId)id;
-        return mailboxCache.getCachedMailbox(mailboxId);
+        if (id == null) {
+            throw new MailboxNotFoundException("null");
+        }
+        return list().stream()
+            .filter(mailbox -> mailbox.getMailboxId().equals(id))
+            .findAny()
+            .orElseThrow(() -> new MailboxNotFoundException(id));
     }
     
     @Override
@@ -131,13 +131,13 @@ public class MaildirMailboxMapper extends NonTransactionalMapper implements Mail
         for (File folder : folders) {
             if (folder.isDirectory()) {
                 Mailbox mailbox = maildirStore.loadMailbox(session, root, mailboxPath.getNamespace(), mailboxPath.getUser(), folder.getName());
-                mailboxList.add(mailboxCache.cacheMailbox(mailbox));
+                mailboxList.add(mailbox);
             }
         }
         // INBOX is in the root of the folder
         if (Pattern.matches(mailboxPath.getName().replace(MaildirStore.WILDCARD, ".*"), MailboxConstants.INBOX)) {
             Mailbox mailbox = maildirStore.loadMailbox(session, root, mailboxPath.getNamespace(), mailboxPath.getUser(), "");
-            mailboxList.add(0, mailboxCache.cacheMailbox(mailbox));
+            mailboxList.add(0, mailbox);
         }
         return mailboxList;
     }
@@ -152,8 +152,11 @@ public class MaildirMailboxMapper extends NonTransactionalMapper implements Mail
 
     @Override
     public MailboxId save(Mailbox mailbox) throws MailboxException {
+        MaildirId maildirId = Optional.ofNullable(mailbox.getMailboxId())
+            .map(mailboxId -> (MaildirId) mailboxId)
+            .orElseGet(MaildirId::random);
         try {
-            Mailbox originalMailbox = mailboxCache.getCachedMailbox((MaildirId) mailbox.getMailboxId());
+            Mailbox originalMailbox = findMailboxById(mailbox.getMailboxId());
             MaildirFolder folder = maildirStore.createMaildirFolder(mailbox);
             // equals with null check
             if (originalMailbox.getName() == null ? mailbox.getName() != null : !originalMailbox.getName().equals(mailbox.getName())) {
@@ -171,6 +174,9 @@ public class MaildirMailboxMapper extends NonTransactionalMapper implements Mail
                         if (!originalFolder.getCurFolder().renameTo(folder.getCurFolder())) {
                             throw new IOException("Could not rename folder " + originalFolder.getCurFolder() + " to " + folder.getCurFolder());
                         }
+                        if (!originalFolder.getMailboxIdFile().renameTo(folder.getMailboxIdFile())) {
+                            throw new IOException("Could not rename folder " + originalFolder.getCurFolder() + " to " + folder.getCurFolder());
+                        }
                         if (!originalFolder.getNewFolder().renameTo(folder.getNewFolder())) {
                             throw new IOException("Could not rename folder " + originalFolder.getNewFolder() + " to " + folder.getNewFolder());
                         }
@@ -192,6 +198,7 @@ public class MaildirMailboxMapper extends NonTransactionalMapper implements Mail
                         FileUtils.forceMkdir(originalFolder.getCurFolder());
                         FileUtils.forceMkdir(originalFolder.getNewFolder());
                         FileUtils.forceMkdir(originalFolder.getTmpFolder());
+                        originalFolder.setMailboxId(MaildirId.of(Math.abs(new Random().nextInt())));
                     } catch (IOException e) {
                         throw new MailboxException("Failed to save Mailbox " + mailbox, e);
                     }
@@ -224,14 +231,14 @@ public class MaildirMailboxMapper extends NonTransactionalMapper implements Mail
             }
             try {
                 folder.setUidValidity(mailbox.getUidValidity());
+                folder.setMailboxId(maildirId);
             } catch (IOException ioe) {
                 throw new MailboxException("Failed to save Mailbox " + mailbox, ioe);
 
             }
             folder.setACL(session, mailbox.getACL());
         }
-        mailboxCache.cacheMailbox(mailbox);
-        return mailbox.getMailboxId();
+        return maildirId;
     }
 
     @Override
@@ -240,26 +247,28 @@ public class MaildirMailboxMapper extends NonTransactionalMapper implements Mail
        File maildirRoot = maildirStore.getMaildirRoot();
        List<Mailbox> mailboxList = new ArrayList<>();
         
-       if (maildirStore.getMaildirLocation().endsWith("/" + MaildirStore.PATH_FULLUSER)) {
-           File[] users = maildirRoot.listFiles();
-           visitUsersForMailboxList(null, users, mailboxList);
+
+
+       if (maildirStore.getMaildirLocation().endsWith("/" + MaildirStore.PATH_DOMAIN + "/" + MaildirStore.PATH_USER)) {
+           File[] domains = maildirRoot.listFiles();
+           for (File domain : domains) {
+               File[] users = domain.listFiles();
+               visitUsersForMailboxList(domain, users, mailboxList);
+           }
            return mailboxList;
        }
-       
-       File[] domains = maildirRoot.listFiles();
-       for (File domain: domains) {
-           File[] users = domain.listFiles();
-           visitUsersForMailboxList(domain, users, mailboxList);
-       }
-       return mailboxList;
+
+        File[] users = maildirRoot.listFiles();
+        visitUsersForMailboxList(null, users, mailboxList);
+        return mailboxList;
         
     }
 
     @Override
     public void endRequest() {
-        mailboxCache.clear();
+
     }
-    
+
     private void visitUsersForMailboxList(File domain, File[] users, List<Mailbox> mailboxList) throws MailboxException {
         
         String userName = null;

http://git-wip-us.apache.org/repos/asf/james-project/blob/7e32da51/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java
----------------------------------------------------------------------
diff --git a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java
index 508fc54..cc494f1 100644
--- a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java
+++ b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java
@@ -18,13 +18,9 @@
  ****************************************************************/
 package org.apache.james.mailbox.maildir;
 
-import java.io.UnsupportedEncodingException;
-
 import org.apache.james.junit.TemporaryFolderExtension;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxManagerTest;
-import org.apache.james.mailbox.exception.MailboxException;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
 public class DomainUserMaildirMailboxManagerTest extends MailboxManagerTest {
@@ -41,9 +37,4 @@ public class DomainUserMaildirMailboxManagerTest extends MailboxManagerTest {
         }
     }
 
-    @Disabled("https://issues.apache.org/jira/browse/MAILBOX-292")
-    @Override
-    public void createMailboxShouldReturnRightId() throws MailboxException, UnsupportedEncodingException {
-
-    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/7e32da51/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java
----------------------------------------------------------------------
diff --git a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java
index b69f30f..e08097f 100644
--- a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java
+++ b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java
@@ -18,13 +18,9 @@
  ****************************************************************/
 package org.apache.james.mailbox.maildir;
 
-import java.io.UnsupportedEncodingException;
-
 import org.apache.james.junit.TemporaryFolderExtension;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxManagerTest;
-import org.apache.james.mailbox.exception.MailboxException;
-import org.junit.Ignore;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
 public class FullUserMaildirMailboxManagerTest extends MailboxManagerTest {
@@ -39,10 +35,4 @@ public class FullUserMaildirMailboxManagerTest extends MailboxManagerTest {
             throw new RuntimeException(e);
         }
     }
-
-    @Ignore("https://issues.apache.org/jira/browse/MAILBOX-292")
-    @Override
-    public void createMailboxShouldReturnRightId() throws MailboxException, UnsupportedEncodingException {
-
-    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/7e32da51/mpt/impl/imap-mailbox/maildir/src/test/resources/logback-test.xml
----------------------------------------------------------------------
diff --git a/mpt/impl/imap-mailbox/maildir/src/test/resources/logback-test.xml b/mpt/impl/imap-mailbox/maildir/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..b02f0d8
--- /dev/null
+++ b/mpt/impl/imap-mailbox/maildir/src/test/resources/logback-test.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+        <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
+                <resetJUL>true</resetJUL>
+        </contextListener>
+
+        <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+                <encoder>
+                        <pattern>%d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx</pattern>
+                        <immediateFlush>false</immediateFlush>
+                </encoder>
+        </appender>
+
+        <root level="WARN">
+                <appender-ref ref="CONSOLE" />
+        </root>
+
+
+        <logger name="org.apache.james" level="WARN" >
+                <appender-ref ref="CONSOLE" />
+        </logger>
+
+        <logger name="org.apache.james.backends.cassandra.DockerCassandraRule" level="WARN" >
+                <appender-ref ref="CONSOLE" />
+        </logger>
+
+</configuration>


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