Changeset 259

Show
Ignore:
Timestamp:
08/01/08 10:18:16 PM (4 months ago)
Author:
octorian
Message:

Mailbox node serialization

Location:
trunk/LogicMail/src/org/logicprobe/LogicMail
Files:
10 modified

Legend:

Unmodified
Added
Removed
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/AbstractMailStore.java

    r253 r259  
    112112     
    113113    /** 
    114      * Requests the current message counts of a folder or 
    115      * group of folders. 
    116      *  
    117      * <p>Successful completion is indicated by a call to 
     114     * Requests the current message counts of a group of folders. 
     115     *  
     116     * <p>Successful completion is indicated by calls to 
    118117     * {@link FolderListener#folderStatusChanged(FolderEvent)}. 
    119118     *  
    120      * @param root The root node of the folder tree to refresh. 
    121      */ 
    122     public abstract void requestFolderStatus(FolderTreeItem root); 
     119     * @param folders The folder tree items to refresh. 
     120     */ 
     121    public abstract void requestFolderStatus(FolderTreeItem[] folders); 
    123122     
    124123    /** 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/FolderTreeItem.java

    r221 r259  
    9191     
    9292    /** 
     93     * Create a folder tree item that is a clone of the source item, 
     94     * but has none of the references to parent or children items. 
     95     *  
     96     * @param source The source item. 
     97     */ 
     98    public FolderTreeItem(FolderTreeItem source) { 
     99        this.uniqueId = UniqueIdGenerator.getInstance().getUniqueId(); 
     100        this.name = source.name; 
     101        this.path = source.path; 
     102        this.delim = source.delim; 
     103        this.selectable = source.selectable; 
     104        this.msgCount = source.msgCount; 
     105        this.unseenCount = source.unseenCount; 
     106    } 
     107     
     108    /** 
    93109     * Creates an uninitialized folder tree item. 
    94110     * Only for use during deserialization. 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/imap/ImapClient.java

    r253 r259  
    325325        } 
    326326 
    327     public void refreshFolderStatus(FolderTreeItem root) throws IOException, MailException { 
    328         // Flatten the tree for easy batching of the status refresh 
    329         Vector folders = new Vector(); 
    330         flattenFolderTree(folders, root); 
    331          
     327    public void refreshFolderStatus(FolderTreeItem[] folders) throws IOException, MailException { 
    332328        // Construct an array of mailbox paths to match the folder vector 
    333         int size = folders.size(); 
    334329        Vector mboxPaths = new Vector(); 
    335330        Hashtable mboxMap = new Hashtable(); 
    336331        int i; 
    337         for(i=0; i<size; i++) { 
    338             FolderTreeItem item = (FolderTreeItem)folders.elementAt(i); 
     332        for(i=0; i<folders.length; i++) { 
     333            FolderTreeItem item = folders[i]; 
    339334            if(item.isSelectable()) { 
    340335                mboxPaths.addElement(item.getPath()); 
     
    355350        } 
    356351    } 
    357      
    358     /** 
    359      * Recursively walk the folder tree, populating a flat vector of 
    360      * FolderTreeItem objects. 
    361      * 
    362      * @param folders An initialized Vector to populate 
    363      * @param node The FolderTreeItem to start from 
    364      */ 
    365     private void flattenFolderTree(Vector folders, FolderTreeItem node) { 
    366         // Avoid adding the invisible root node 
    367         if(node.getPath().length() > 0) { 
    368             folders.addElement(node); 
    369         } 
    370          
    371         if(node.hasChildren()) { 
    372             FolderTreeItem[] children = node.children(); 
    373             for(int i = 0; i < children.length; i++) { 
    374                 flattenFolderTree(folders, children[i]); 
    375             } 
    376         } 
    377     } 
    378      
    379352     
    380353    public FolderTreeItem getActiveFolder() { 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/IncomingMailClient.java

    r172 r259  
    8484     
    8585    /** 
    86      * Refresh the folder status across the folder tree. 
     86     * Refresh the folder status. 
    8787     * 
    88      * @param root The root of the folder tree 
     88     * @param folders The folders to refresh 
    8989     * @throw IOException on I/O errors 
    9090     * @throw MailException on protocol errors 
    9191     */ 
    92     public abstract void refreshFolderStatus(FolderTreeItem root) 
     92    public abstract void refreshFolderStatus(FolderTreeItem[] folders) 
    9393        throws IOException, MailException; 
    9494     
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/IncomingMailConnectionHandler.java

    r253 r259  
    7575                        break; 
    7676                case REQUEST_FOLDER_STATUS: 
    77                         handleRequestFolderStatus((FolderTreeItem)params[0]); 
     77                        handleRequestFolderStatus((FolderTreeItem[])params[0]); 
    7878                        break; 
    7979                case REQUEST_FOLDER_MESSAGES_RANGE: 
     
    126126        } 
    127127         
    128         private void handleRequestFolderStatus(FolderTreeItem root) throws IOException, MailException { 
    129                 incomingClient.refreshFolderStatus(root); 
    130                  
    131                 MailConnectionHandlerListener listener = getListener(); 
    132                 if(listener != null) { 
    133                         listener.mailConnectionRequestComplete(REQUEST_FOLDER_STATUS, root); 
     128        private void handleRequestFolderStatus(FolderTreeItem[] folders) throws IOException, MailException { 
     129                incomingClient.refreshFolderStatus(folders); 
     130                 
     131                MailConnectionHandlerListener listener = getListener(); 
     132                if(listener != null) { 
     133                        listener.mailConnectionRequestComplete(REQUEST_FOLDER_STATUS, folders); 
    134134                } 
    135135        } 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/NetworkMailStore.java

    r253 r259  
    109109        } 
    110110 
    111         public void requestFolderStatus(FolderTreeItem root) { 
    112                 connectionHandler.addRequest(IncomingMailConnectionHandler.REQUEST_FOLDER_STATUS, new Object[] { root }); 
     111        public void requestFolderStatus(FolderTreeItem[] folders) { 
     112                connectionHandler.addRequest(IncomingMailConnectionHandler.REQUEST_FOLDER_STATUS, new Object[] { folders }); 
    113113        } 
    114114 
     
    165165                        break; 
    166166                case IncomingMailConnectionHandler.REQUEST_FOLDER_STATUS: 
    167                         fireFolderStatusChanged((FolderTreeItem)result); 
     167                        FolderTreeItem[] folders = (FolderTreeItem[])result; 
     168                        for(int i=0; i<folders.length; i++) { 
     169                                fireFolderStatusChanged(folders[i]); 
     170                        } 
    168171                        break; 
    169172                case IncomingMailConnectionHandler.REQUEST_FOLDER_MESSAGES_RANGE: 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/pop/PopClient.java

    r245 r259  
    214214    } 
    215215 
    216     public void refreshFolderStatus(FolderTreeItem root) throws IOException, MailException { 
     216    public void refreshFolderStatus(FolderTreeItem[] folders) throws IOException, MailException { 
    217217        // Only one mailbox can exist, so we just pull the message counts 
    218218        activeMailbox.setMsgCount(popProtocol.executeStat()); 
     219        if(folders.length == 1 && folders[0] != activeMailbox) { 
     220                folders[0].setMsgCount(activeMailbox.getMsgCount()); 
     221        } 
    219222    } 
    220223 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/model/AccountNode.java

    r256 r259  
    3131package org.logicprobe.LogicMail.model; 
    3232 
     33import java.util.Enumeration; 
    3334import java.util.Hashtable; 
    3435import java.util.Vector; 
     
    5152import org.logicprobe.LogicMail.message.Message; 
    5253import org.logicprobe.LogicMail.message.MessageFlags; 
     54import org.logicprobe.LogicMail.util.DataStore; 
     55import org.logicprobe.LogicMail.util.DataStoreFactory; 
    5356import org.logicprobe.LogicMail.util.EventListenerList; 
    5457 
     
    7477        private Vector outboundNewMessages = new Vector(); 
    7578        private Hashtable outboundMessageReplies = new Hashtable();  
    76          
     79        private DataStore accountDataStore; 
     80 
    7781        public final static int STATUS_LOCAL   = 0; 
    7882        public final static int STATUS_OFFLINE = 1; 
     
    132136                        // Create the fake INBOX node for non-folder-capable mail stores 
    133137                        this.rootMailbox = new MailboxNode(new FolderTreeItem("", "", ""), -1); 
     138                        this.rootMailbox.setParentAccount(this); 
    134139                        MailboxNode inboxNode = new MailboxNode(new FolderTreeItem("INBOX", "INBOX", ""), MailboxNode.TYPE_INBOX); 
    135140                        inboxNode.setParentAccount(this); 
     
    137142                        pathMailboxMap.put("INBOX", inboxNode); 
    138143                } 
     144                 
     145                // Load any saved tree data 
     146                load(); 
    139147        } 
    140148         
     
    333341         */ 
    334342        public void refreshMailboxStatus() { 
    335                 MailboxNode mailbox; 
    336                 synchronized(rootMailboxLock) { 
    337                         mailbox = this.rootMailbox; 
    338                 } 
    339                 mailStore.requestFolderStatus(mailbox.getFolderTreeItem()); 
     343                int size = pathMailboxMap.size(); 
     344                FolderTreeItem[] folders = new FolderTreeItem[size]; 
     345                Enumeration e = pathMailboxMap.keys(); 
     346                for(int i=0; i<size; i++) { 
     347                        folders[i] = ((MailboxNode)pathMailboxMap.get(e.nextElement())).getFolderTreeItem(); 
     348                } 
     349                mailStore.requestFolderStatus(folders); 
    340350        } 
    341351 
     
    408418                } 
    409419                 
     420                save(); 
    410421                fireAccountStatusChanged(AccountNodeEvent.TYPE_MAILBOX_TREE); 
    411422        } 
     
    431442                } 
    432443        } 
    433          
     444 
    434445        private void populateMailboxNodes(FolderTreeItem folderTreeItem, MailboxNode currentMailbox, Hashtable remainingMailboxMap) { 
    435446                pathMailboxMap.put(folderTreeItem.getPath(), currentMailbox); 
     
    681692        } 
    682693    } 
     694     
     695    /** 
     696     * Saves the mailbox tree to persistent storage. 
     697     */ 
     698        private void save() { 
     699                if(accountConfig == null) { 
     700                        return; 
     701                } 
     702                if(accountDataStore == null) { 
     703                        long accountId = accountConfig.getUniqueId(); 
     704                        accountDataStore = DataStoreFactory.getConnectionCacheStore(accountId); 
     705                        accountDataStore.load(); 
     706                } 
     707                 
     708                accountDataStore.putNamedObject("ROOT_MAILBOX", rootMailbox); 
     709                accountDataStore.save(); 
     710        } 
     711         
     712        /** 
     713         * Loads the mailbox tree from persistent storage. 
     714         */ 
     715        private void load() { 
     716                if(accountConfig == null) { 
     717                        return; 
     718                } 
     719                if(accountDataStore == null) { 
     720                        long accountId = accountConfig.getUniqueId(); 
     721                        accountDataStore = DataStoreFactory.getConnectionCacheStore(accountId); 
     722                        accountDataStore.load(); 
     723                } 
     724 
     725                Object loadedObject = accountDataStore.getNamedObject("ROOT_MAILBOX"); 
     726                if(loadedObject instanceof MailboxNode) { 
     727                        synchronized(rootMailboxLock) { 
     728                                this.rootMailbox = (MailboxNode)loadedObject; 
     729                                this.rootMailbox.setParentAccount(this); 
     730                                prepareDeserializedMailboxNode(rootMailbox); 
     731                        } 
     732                } 
     733        } 
     734         
     735        //TODO: Handle deleted account nodes 
     736         
     737        /** 
     738         * Traverses the deserialized mailbox nodes, populates any necessary 
     739         * data structures in the account node, and sets the mailbox parent 
     740         * account references.  
     741         * 
     742         * @param mailboxNode The mailbox node. 
     743         */ 
     744        private void prepareDeserializedMailboxNode(MailboxNode mailboxNode) { 
     745                mailboxNode.setParentAccount(this); 
     746                FolderTreeItem item = mailboxNode.getFolderTreeItem(); 
     747                if(item != null && item.getPath().length() > 0) { 
     748                        this.pathMailboxMap.put(item.getPath(), mailboxNode); 
     749                } 
     750                MailboxNode[] children = mailboxNode.getMailboxes(); 
     751                for(int i=0; i<children.length; i++) { 
     752                        prepareDeserializedMailboxNode(children[i]); 
     753                } 
     754        } 
    683755} 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/model/MailboxNode.java

    r256 r259  
    3131package org.logicprobe.LogicMail.model; 
    3232 
     33import java.io.DataInputStream; 
     34import java.io.DataOutputStream; 
     35import java.io.IOException; 
    3336import java.util.Hashtable; 
    3437import java.util.Vector; 
     
    3740import org.logicprobe.LogicMail.mail.FolderTreeItem; 
    3841import org.logicprobe.LogicMail.util.EventListenerList; 
     42import org.logicprobe.LogicMail.util.Serializable; 
     43import org.logicprobe.LogicMail.util.UniqueIdGenerator; 
    3944 
    4045/** 
     
    4348 * <tt>MessageNode</tt> instances as its children. 
    4449 */ 
    45 public class MailboxNode implements Node { 
     50public class MailboxNode implements Node, Serializable { 
     51        private long uniqueId; 
    4652        private AccountNode parentAccount; 
    4753        private MailboxNode parentMailbox; 
     
    5965        public final static int TYPE_TRASH  = 4; 
    6066 
     67        /** 
     68         * Initializes a new instance of <tt>MailboxNode</tt>. 
     69         *  
     70         * @param folderTreeItem The folder item this node wraps. 
     71         * @param type The type of mailbox this is representing. 
     72         */ 
    6173        MailboxNode(FolderTreeItem folderTreeItem, int type) { 
     74                this.uniqueId = UniqueIdGenerator.getInstance().getUniqueId(); 
    6275                this.mailboxes = new Vector(); 
    6376                this.messages = new Vector(); 
    6477                this.messageMap = new Hashtable(); 
    65                 this.folderTreeItem = folderTreeItem; 
     78                if(folderTreeItem != null) { 
     79                        this.setFolderTreeItem(new FolderTreeItem(folderTreeItem)); 
     80                } 
    6681                this.type = type; 
    6782        } 
    6883         
     84        /** 
     85         * Initializes a new instance of <tt>MailboxNode</tt>. 
     86         *  
     87         * @param folderTreeItem The folder item this node wraps. 
     88         */ 
    6989        MailboxNode(FolderTreeItem folderTreeItem) { 
    7090                this(folderTreeItem, TYPE_NORMAL); 
    7191        } 
    7292         
    73         MailboxNode() { 
     93        /** 
     94         * Initializes a new instance of <tt>MailboxNode</tt>. 
     95         *  
     96         * <p><i>Note:</i> This constructor is only exposed for 
     97         * serialization purposes, and should never be called from 
     98         * outside this package for any other reason. 
     99         */ 
     100        public MailboxNode() { 
    74101                this(null, TYPE_NORMAL); 
    75102        } 
     
    121148         * that maintain cache data for it. 
    122149         *  
     150         * <p><i>Note:</i> The actual <tt>FolderTreeItem</tt> used by this 
     151         * class is a deep copy of the one passed to this method.  It is 
     152         * implemented this way since we need a standalone object that 
     153         * is not part of a tree.  This is necessary to avoid excessive 
     154         * recursion during serialization. 
     155         *  
    123156         * @param folderTreeItem Folder tree item. 
    124157         */ 
    125158        void setFolderTreeItem(FolderTreeItem folderTreeItem) { 
    126                 this.folderTreeItem = folderTreeItem; 
     159                this.folderTreeItem = new FolderTreeItem(folderTreeItem); 
    127160        } 
    128161         
     
    452485        } 
    453486    } 
     487 
     488        public long getUniqueId() { 
     489                return uniqueId; 
     490        } 
     491         
     492        public void serialize(DataOutputStream output) throws IOException { 
     493                output.writeLong(uniqueId); 
     494                output.writeInt(type); 
     495                folderTreeItem.serialize(output); 
     496                synchronized(mailboxes) { 
     497                        int size = mailboxes.size(); 
     498                        output.writeInt(size); 
     499                        for(int i=0; i<size; i++) { 
     500                                ((MailboxNode)mailboxes.elementAt(i)).serialize(output); 
     501                        } 
     502                } 
     503        } 
     504         
     505        public void deserialize(DataInputStream input) throws IOException { 
     506                uniqueId = input.readLong(); 
     507                type = input.readInt(); 
     508                folderTreeItem = new FolderTreeItem(); 
     509                folderTreeItem.deserialize(input); 
     510                synchronized(mailboxes) { 
     511                        int size = input.readInt(); 
     512                        for(int i=0; i<size; i++) { 
     513                                MailboxNode child = new MailboxNode(); 
     514                                child.deserialize(input); 
     515                                child.parentMailbox = this; 
     516                                mailboxes.addElement(child); 
     517                        } 
     518                } 
     519        } 
    454520} 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/model/MailManager.java

    r256 r259  
    108108                return mailRootNode; 
    109109        } 
    110          
    111          
     110 
    112111        /** 
    113112         * Called when the account configuration has changed,