Changeset 585


Ignore:
Timestamp:
12/30/09 17:21:21 (2 years ago)
Author:
octorian
Message:

Post-expunge cleanup of cache and sync of object model (should fix strange delete issues)

Location:
trunk
Files:
12 edited

Legend:

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

    r582 r585  
    141141     *  
    142142     * <p>Successful completion is indicated by a call to 
    143      * {@link FolderListener#folderStatusChanged(FolderEvent)}. 
     143     * {@link FolderListener#folderExpunged(FolderEvent)}. 
    144144     *  
    145145     * @param folder The folder to expunge 
     
    420420    /** 
    421421     * Notifies all registered <tt>FolderListener</tt>s that 
    422      * the the status of a folder has changed. 
     422     * the status of a folder has changed. 
    423423     *  
    424424     * @param root The root node of the updated folder tree 
     
    451451            } 
    452452            ((FolderListener)listeners[i]).folderMessagesAvailable(e); 
     453        } 
     454    } 
     455     
     456    /** 
     457     * Notifies all registered <tt>FolderListener</tt>s that 
     458     * the folder has been expunged. 
     459     *  
     460     * @param root The root node of the updated folder tree 
     461     */ 
     462    protected void fireFolderExpunged(FolderTreeItem root) { 
     463        Object[] listeners = listenerList.getListeners(FolderListener.class); 
     464        FolderEvent e = null; 
     465        for(int i=0; i<listeners.length; i++) { 
     466            if(e == null) { 
     467                e = new FolderEvent(this, root); 
     468            } 
     469            ((FolderListener)listeners[i]).folderExpunged(e); 
    453470        } 
    454471    } 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/FolderListener.java

    r220 r585  
    5151         */ 
    5252        public void folderMessagesAvailable(FolderMessagesEvent e); 
     53         
     54    /** 
     55     * Invoked when a folder has been expunged. 
     56     *  
     57     * @param e Folder event data 
     58     */ 
     59    public void folderExpunged(FolderEvent e); 
    5360} 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/LocalMailStore.java

    r582 r585  
    148148             
    149149            if(folderMessages != null) { 
    150                 fireFolderStatusChanged(requestFolder); 
     150                fireFolderExpunged(requestFolder); 
    151151            } 
    152152        } 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/NetworkMailStore.java

    r582 r585  
    195195                        break; 
    196196                case IncomingMailConnectionHandler.REQUEST_FOLDER_EXPUNGE: 
    197                     fireFolderStatusChanged((FolderTreeItem)result); 
     197                    fireFolderExpunged((FolderTreeItem)result); 
    198198                    break; 
    199199                case IncomingMailConnectionHandler.REQUEST_FOLDER_STATUS: 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/model/AccountNode.java

    r582 r585  
    136136                    mailStore_FolderMessagesAvailable(e); 
    137137                } 
     138 
     139                public void folderExpunged(FolderEvent e) { 
     140                    mailStore_FolderExpunged(e); 
     141                } 
    138142            }); 
    139143 
     
    603607                                // information, such as POP message indices 
    604608                                messageNode.getMessageToken().updateToken(folderMessages[i].getMessageToken()); 
     609                                messageNode.setExistsOnServer(true); 
    605610                        } 
    606611                        else { 
     
    621626         
    622627                    for (int i = 0; i < folderMessages.length; i++) { 
    623                         addedMessages.addElement(new MessageNode(folderMessages[i])); 
     628                        MessageNode messageNode = new MessageNode(folderMessages[i]); 
     629                        messageNode.setExistsOnServer(true); 
     630                        addedMessages.addElement(messageNode); 
    624631                    } 
    625632         
     
    631638        else { 
    632639            synchronized(folderMessagesToFetch) { 
    633                 Vector messagesToFetch = (Vector)folderMessagesToFetch.remove(e.getFolder()); 
     640                FolderTreeItem fetchFolder = e.getFolder(); 
     641                 
     642                // Clean out all messages that couldn't be verified against the server 
     643                MailboxNode mailboxNode = (MailboxNode) pathMailboxMap.get(fetchFolder.getPath()); 
     644                mailboxNode.removeMessagesNotOnServer(); 
     645                 
     646                // Queue a fetch for messages that do exist 
     647                Vector messagesToFetch = (Vector)folderMessagesToFetch.remove(fetchFolder); 
    634648                if(messagesToFetch != null) { 
    635649                    MessageToken[] fetchArray = new MessageToken[messagesToFetch.size()]; 
     
    639653            } 
    640654        } 
     655    } 
     656 
     657    /** 
     658     * Handles a folder being expunged. 
     659     * 
     660     * @param e Event data. 
     661     */ 
     662    private void mailStore_FolderExpunged(FolderEvent e) { 
     663        FolderTreeItem fetchFolder = e.getFolder(); 
     664        MailboxNode mailboxNode = (MailboxNode) pathMailboxMap.get(fetchFolder.getPath()); 
     665        mailboxNode.handleExpungeNotification(); 
    641666    } 
    642667 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/model/MailFileManager.java

    r568 r585  
    9494         * Refreshes the configuration based on any system configuration changes. 
    9595         */ 
    96         void refreshConfiguration() { 
     96        synchronized void refreshConfiguration() { 
    9797                String localDataLocation = mailSettings.getGlobalConfig().getLocalDataLocation(); 
    9898                String newCacheUrl = localDataLocation + CACHE_PREFIX; 
     
    131131         * @throws IOException Signals that an I/O exception has occurred. 
    132132         */ 
    133         public void writeMessage(MessageNode messageNode) throws IOException { 
     133        public synchronized void writeMessage(MessageNode messageNode) throws IOException { 
    134134                if(cacheUrl == null) { return; } 
    135135                 
     
    171171         * @throws IOException Signals that an I/O exception has occurred. 
    172172         */ 
    173         public MessageToken[] readMessageTokens(MailboxNode mailboxNode) throws IOException { 
     173        public synchronized MessageToken[] readMessageTokens(MailboxNode mailboxNode) throws IOException { 
    174174                if(cacheUrl == null) { return new MessageToken[0]; } 
    175175                 
     
    192192        } 
    193193         
    194         public MessageNode[] readMessageNodes(MailboxNode mailboxNode) throws IOException { 
     194        public synchronized MessageNode[] readMessageNodes(MailboxNode mailboxNode) throws IOException { 
    195195                if(cacheUrl == null) { return new MessageNode[0]; } 
    196196 
     
    210210        } 
    211211         
    212     public void readMessageNodes(MailboxNode mailboxNode, MessageNodeCallback callback) throws IOException { 
     212    public synchronized void readMessageNodes(MailboxNode mailboxNode, MessageNodeCallback callback) throws IOException { 
    213213        if(cacheUrl == null) { callback.messageNodeUpdated(null); } 
    214214         
     
    250250    } 
    251251     
    252         public MessageNode readMessageNode(MailboxNode mailboxNode, MessageToken messageToken, boolean loadContent) throws IOException { 
     252        public synchronized MessageNode readMessageNode(MailboxNode mailboxNode, MessageToken messageToken, boolean loadContent) throws IOException { 
    253253                if(cacheUrl == null) { return null; } 
    254254 
     
    270270        } 
    271271         
    272         public MimeMessageContent[] readMessageContent(MailboxNode mailboxNode, MessageToken messageToken) throws IOException { 
     272        public synchronized MimeMessageContent[] readMessageContent(MailboxNode mailboxNode, MessageToken messageToken) throws IOException { 
    273273                if(cacheUrl == null) { return null; } 
    274274                 
     
    391391                return result; 
    392392        } 
     393         
     394        public synchronized void removeMessageNodes(MailboxNode mailboxNode, MessageToken[] messageTokens) throws IOException { 
     395        if(cacheUrl == null) { return; } 
     396 
     397        FileConnection fileConnection = getMailboxFileConnection(mailboxNode); 
     398        String mailboxUrl = fileConnection.getURL(); 
     399        fileConnection.close(); 
     400         
     401        for(int i=0; i<messageTokens.length; i++) { 
     402            try { 
     403                FileConnection mailFileConnection = 
     404                    (FileConnection)Connector.open(mailboxUrl + messageTokens[i].getMessageUid() + MSG_SUFFIX); 
     405                if(mailFileConnection.exists() && !mailFileConnection.isDirectory() && mailFileConnection.canRead()) { 
     406                    mailFileConnection.delete(); 
     407                } 
     408                mailFileConnection.close(); 
     409            } catch (IOException exp) { 
     410                if (EventLogger.getMinimumLevel() >= EventLogger.DEBUG_INFO) { 
     411                    EventLogger.logEvent(AppInfo.GUID, 
     412                            ("Error deleting message from cache: " + exp.toString()).getBytes(), 
     413                            EventLogger.DEBUG_INFO); 
     414                } 
     415            } 
     416        } 
     417        } 
    393418} 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/model/MailboxNode.java

    r582 r585  
    3434import java.io.DataOutput; 
    3535import java.io.IOException; 
     36import java.util.Enumeration; 
    3637import java.util.Hashtable; 
    3738import java.util.Vector; 
     
    7273        private boolean hasAppend; 
    7374        private int unseenMessageCount; 
     75    private Vector pendingExpungeMessages = new Vector(); 
    7476         
    7577        private Object fetchLock = new Object(); 
     
    540542                } 
    541543        updateUnseenMessages(false); 
    542                 fireMailboxStatusChanged(MailboxNodeEvent.TYPE_STATUS, null); 
    543         } 
    544  
     544                fireMailboxStatusChanged(MailboxNodeEvent.TYPE_DELETED_MESSAGES, new MessageNode[] { message }); 
     545        } 
     546 
     547 
     548    /** 
     549     * Removes all messages not marked as existing on the server. 
     550     */ 
     551    void removeMessagesNotOnServer() { 
     552        synchronized(messages) { 
     553            Vector messagesToRemove = new Vector(); 
     554             
     555            // Populate a list of the messages to remove 
     556            int size = messages.size(); 
     557            for(int i=0; i<size; i++) { 
     558                MessageNode messageNode = (MessageNode)messages.elementAt(i); 
     559                if(!messageNode.existsOnServer()) { 
     560                    messagesToRemove.addElement(messageNode); 
     561                } 
     562            } 
     563             
     564            size = messagesToRemove.size(); 
     565            if(size == 0) { return; } 
     566             
     567            MessageNode[] removedMessageNodes = new MessageNode[size]; 
     568            MessageToken[] tokensToRemove = new MessageToken[size]; 
     569            for(int i=0; i<size; i++) { 
     570                MessageNode messageNode = (MessageNode)messagesToRemove.elementAt(i); 
     571                messages.removeElement(messageNode); 
     572                messageNode.setParent(null); 
     573                messageMap.remove(messageNode); 
     574                messageTokenMap.remove(messageNode.getMessageToken()); 
     575                tokensToRemove[i] = messageNode.getMessageToken(); 
     576                removedMessageNodes[i] = messageNode; 
     577            } 
     578             
     579            (new RemoveFromCacheThread(tokensToRemove)).start(); 
     580            updateUnseenMessages(false); 
     581            fireMailboxStatusChanged(MailboxNodeEvent.TYPE_DELETED_MESSAGES, removedMessageNodes); 
     582        } 
     583    } 
     584         
     585    private class RemoveFromCacheThread extends Thread { 
     586        private MessageToken[] messageTokens; 
     587         
     588        public RemoveFromCacheThread(MessageToken[] messageTokens) { 
     589            this.messageTokens = messageTokens; 
     590        } 
     591         
     592        public void run() { 
     593            yield(); 
     594            try { 
     595                MailFileManager.getInstance().removeMessageNodes(MailboxNode.this, messageTokens); 
     596            } catch (IOException e) { 
     597                EventLogger.logEvent(AppInfo.GUID, 
     598                        ("Unable to remove messages from the cache\r\n" 
     599                                + e.getMessage()).getBytes(), 
     600                                EventLogger.ERROR); 
     601            } 
     602        } 
     603    } 
     604 
     605    /** 
     606     * Called when the mail store notifies of a completed expunge operation on 
     607     * this folder, so anything we expected to be expunged can be cleaned out. 
     608     */ 
     609    void handleExpungeNotification() { 
     610        synchronized(messages) { 
     611            Enumeration e = pendingExpungeMessages.elements(); 
     612            while(e.hasMoreElements()) { 
     613                ((MessageNode)e.nextElement()).setExistsOnServer(false); 
     614            } 
     615            pendingExpungeMessages.removeAllElements(); 
     616            removeMessagesNotOnServer(); 
     617        } 
     618    } 
     619         
    545620        /** 
    546621         * Removes all messages from this mailbox. 
     
    710785        return hasDeleted; 
    711786    } 
    712  
     787     
    713788    /** 
    714789     * Tells the underlying mail store to expunge any deleted messages 
     
    716791     */ 
    717792    public void expungeDeletedMessages() { 
     793        synchronized(messages) { 
     794            int size = messages.size(); 
     795            for(int i=0; i<size; i++) { 
     796                MessageNode messageNode = (MessageNode)messages.elementAt(i); 
     797                int flags = messageNode.getFlags(); 
     798                if((flags & MessageNode.Flag.DELETED) != 0) { 
     799                    pendingExpungeMessages.addElement(messageNode); 
     800                } 
     801            } 
     802        } 
    718803        parentAccount.getMailStore().requestFolderExpunge(this.folderTreeItem); 
    719804    } 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/model/MailboxNodeEvent.java

    r232 r585  
    5353        public final static int TYPE_NEW_MESSAGES = 1; 
    5454         
     55    /** 
     56     * Messages have been deleted. 
     57     * The <tt>getAffectedMessages()</tt> method will return 
     58     * a list of deleted messages. 
     59     */ 
     60    public final static int TYPE_DELETED_MESSAGES = 2; 
     61         
    5562        /** Creates a new instance of MailboxNodeEvent */ 
    5663        public MailboxNodeEvent(Object source, int type, MessageNode[] affectedMessages) { 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/model/MessageNode.java

    r579 r585  
    130130        /** True if the message has cached content available for loading */ 
    131131        private boolean hasCachedContent; 
     132        /** True if the message has been verified to exist on a mail server */ 
     133        private boolean existsOnServer; 
    132134        /** Bit-field set of message flags. */ 
    133135        private int flags; 
     
    287289        } 
    288290         
     291        /** 
     292         * Sets whether this message has been verified to exist on a server. 
     293         *  
     294         * @param existsOnServer true if the message has been verified to exist on a server 
     295         */ 
     296        void setExistsOnServer(boolean existsOnServer) { 
     297            this.existsOnServer = existsOnServer; 
     298        } 
     299         
     300        /** 
     301         * Gets whether this message has been verified to exist on a server. 
     302         *  
     303         * @return true if the message has been verified to exist on a server or is on a local account 
     304         */ 
     305        public boolean existsOnServer() { 
     306            return existsOnServer; 
     307        } 
     308         
    289309        /* (non-Javadoc) 
    290310         * @see org.logicprobe.LogicMail.model.Node#accept(org.logicprobe.LogicMail.model.NodeVisitor) 
     
    301321        void setParent(MailboxNode parent) { 
    302322                this.parent = parent; 
     323                if(!isCachable()) { existsOnServer = true; } 
    303324        } 
    304325         
  • trunk/LogicMail/src/org/logicprobe/LogicMail/ui/MailboxMessageField.java

    r576 r585  
    155155        // Draw the message icon 
    156156        Bitmap messageIcon = NodeIcons.getIcon(messageNode); 
     157        int iconY = (lineHeight / 2) - (messageIcon.getHeight() / 2); 
    157158        graphics.drawBitmap( 
    158159                1, 
    159                 (lineHeight / 2) - (messageIcon.getHeight() / 2), 
     160                iconY, 
    160161                messageIcon.getWidth(), 
    161162                messageIcon.getHeight(), 
    162163                messageIcon, 0, 0); 
     164        if(!messageNode.existsOnServer()) { 
     165            graphics.setColor(Color.DARKGRAY); 
     166            graphics.drawRect(1, iconY, messageIcon.getWidth(), messageIcon.getHeight()); 
     167            graphics.setColor(originalColor); 
     168        } 
    163169         
    164170        if(attachmentIcon != null) { 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/ui/MailboxScreen.java

    r582 r585  
    323323     */ 
    324324    private void mailboxNode_MailboxStatusChanged(MailboxNodeEvent e) { 
    325         if(e.getType() == MailboxNodeEvent.TYPE_NEW_MESSAGES) { 
     325        int type = e.getType(); 
     326        if(type == MailboxNodeEvent.TYPE_NEW_MESSAGES) { 
    326327                MessageNode[] messageNodes = e.getAffectedMessages(); 
    327328                for(int i=0; i<messageNodes.length; i++) { 
     
    337338                        } 
    338339                } 
     340        } 
     341        else if(type == MailboxNodeEvent.TYPE_DELETED_MESSAGES) { 
     342            MessageNode[] messageNodes = e.getAffectedMessages(); 
     343            for(int i=0; i<messageNodes.length; i++) { 
     344                if(screen != null && screen.isDisplayed()) { 
     345                    messageNodes[i].removeMessageNodeListener(messageNodeListener); 
     346                } 
     347                removeDisplayableMessage(messageNodes[i])              ;   
     348                knownMessages.removeElement(messageNodes[i]); 
     349            } 
    339350        } 
    340351        } 
     
    407418    } 
    408419 
     420    /** 
     421     * Remove a message from the list and associated data structures, 
     422     * if that message exists in the list. 
     423     *  
     424     * @param messageNode Message to insert. 
     425     */ 
     426    private void removeDisplayableMessage(MessageNode messageNode) { 
     427        MailboxMessageField mailboxMessageField = (MailboxMessageField)messageFieldMap.remove(messageNode); 
     428        if(mailboxMessageField == null) { return; } 
     429 
     430        messageFieldManager.delete(mailboxMessageField); 
     431    } 
     432     
    409433    /** 
    410434     * Gets the last displayed message. 
  • trunk/LogicMailTests/src/org/logicprobe/LogicMail/mail/NetworkMailStoreTest.java

    r584 r585  
    9696                                eventFolderStatusChanged = e; 
    9797                        } 
     98            public void folderExpunged(FolderEvent e) { 
     99            } 
    98100        }); 
    99101         
Note: See TracChangeset for help on using the changeset viewer.