root/trunk/LogicMail/src/org/logicprobe/LogicMail/model/MailManager.java

Revision 704, 14.1 KB (checked in by octorian, 28 hours ago)

Cleanup of inappropriate getAccountConfig() calls

Line 
1/*-
2 * Copyright (c) 2008, Derek Konigsberg
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the project nor the names of its
15 *    contributors may be used to endorse or promote products derived
16 *    from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31package org.logicprobe.LogicMail.model;
32
33import java.util.Vector;
34
35import org.logicprobe.LogicMail.conf.AccountConfig;
36import org.logicprobe.LogicMail.conf.MailSettings;
37import org.logicprobe.LogicMail.conf.MailSettingsEvent;
38import org.logicprobe.LogicMail.conf.MailSettingsListener;
39import org.logicprobe.LogicMail.conf.OutgoingConfig;
40import org.logicprobe.LogicMail.mail.AbstractMailSender;
41import org.logicprobe.LogicMail.mail.MailConnectionListener;
42import org.logicprobe.LogicMail.mail.MailConnectionLoginEvent;
43import org.logicprobe.LogicMail.mail.MailConnectionManager;
44import org.logicprobe.LogicMail.mail.MailConnectionStateEvent;
45import org.logicprobe.LogicMail.mail.MailConnectionStatusEvent;
46import org.logicprobe.LogicMail.mail.MailFactory;
47import org.logicprobe.LogicMail.mail.NetworkMailSender;
48import org.logicprobe.LogicMail.mail.NetworkMailStore;
49import org.logicprobe.LogicMail.util.EventListenerList;
50
51/**
52 * Singleton that provides external access to the mail data model.
53 * Ensures that clients have a fully controlled point from which
54 * to get their instances of data and utility classes.
55 */
56public class MailManager {
57        private static MailManager instance = null;
58        private EventListenerList listenerList = new EventListenerList();
59        private MailRootNode mailRootNode;
60        private MailSettings mailSettings;
61        private OutboxMailboxNode outboxMailboxNode;
62       
63        /**
64         * Constructor.
65         */
66        private MailManager() {
67                mailSettings = MailSettings.getInstance();
68                mailRootNode = new MailRootNode();
69
70                // Make sure the initial configuration is loaded
71                updateMailModelAccountList();
72               
73                // Register a listener for configuration changes
74                MailSettings.getInstance().addMailSettingsListener(new MailSettingsListener() {
75                        public void mailSettingsSaved(MailSettingsEvent e) {
76                            mailSettings_MailSettingsSaved(e);
77                        }
78                });
79               
80                MailConnectionManager.getInstance().addMailConnectionListener(new MailConnectionListener() {
81                        public void mailConnectionStateChanged(MailConnectionStateEvent e) {
82                                mailConnectionManager_MailConnectionStateChanged(e);
83                        }
84                        public void mailConnectionStatus(MailConnectionStatusEvent e) { }
85                        public void mailConnectionError(MailConnectionStatusEvent e) { }
86                        public void mailConnectionLogin(MailConnectionLoginEvent e) { }
87                });
88               
89                // Refresh data from local account node
90                LocalAccountNode localAccount = mailRootNode.getLocalAccount();
91                localAccount.refreshMailboxes();
92                localAccount.refreshMailboxStatus();
93
94                MailboxNode[] localMailboxes = mailRootNode.getLocalAccount().getRootMailbox().getMailboxes();
95                for(int i=0; i<localMailboxes.length; i++) {
96                // Find the outbox node, and save a reference to it for easy access
97                        if(localMailboxes[i] instanceof OutboxMailboxNode) {
98                                outboxMailboxNode = (OutboxMailboxNode)localMailboxes[i];
99                        }
100                       
101                        // Refresh messages for local mailboxes
102                        localMailboxes[i].refreshMessages();
103                }
104        }
105       
106        private void refreshMailboxTypes() {
107                int num = mailSettings.getNumAccounts();
108                for(int i=0; i<num; i++) {
109                        AccountConfig accountConfig = mailSettings.getAccountConfig(i);
110                        MailboxNode mailbox;
111                        mailbox = accountConfig.getDraftMailbox();
112                        if(mailbox != null) { mailbox.setType(MailboxNode.TYPE_DRAFTS); }
113                        mailbox = accountConfig.getSentMailbox();
114                        if(mailbox != null) { mailbox.setType(MailboxNode.TYPE_SENT); }
115                }
116        }
117       
118        /**
119         * First time initialization sequence, should only be invoked on
120         * application startup.
121         */
122        public static void initialize() {
123                MailManager mailManager = MailManager.getInstance();
124                mailManager.refreshMailboxTypes();
125        }
126       
127        /**
128         * Gets the mail manager instance.
129         *
130         * @return The instance.
131         */
132        public static synchronized MailManager getInstance() {
133                if(instance == null) {
134                        instance = new MailManager();
135                }
136                return instance;
137        }
138       
139        /**
140         * Gets the mail root node.
141         * Also performs any necessary initialization on
142         * the first call.
143         *
144         * @return Mail root node.
145         */
146        public synchronized MailRootNode getMailRootNode() {
147                return mailRootNode;
148        }
149
150        /**
151         * Gets the outbox node within the local account.
152         *
153         * @return Outbox node.
154         */
155        public OutboxMailboxNode getOutboxMailboxNode() {
156                return outboxMailboxNode;
157        }
158
159        private void mailSettings_MailSettingsSaved(MailSettingsEvent e) {
160        // This logic is rather crude, and will trigger a full refresh
161        // under a wide variety of circumstances.  Its major intent is
162        // to avoid a refresh in a few situations where a minor
163        // configuration change affects future behavior and not
164        // current state.
165       
166        boolean shouldRefreshAccounts =
167            connectionListChanged(e) || accountChangeRequiringRefresh(e);
168       
169        // Trigger a refresh if appropriate
170        if(shouldRefreshAccounts) {
171            updateMailModelAccountList();
172            refreshMailboxTypes();
173        }
174        }
175
176    private boolean connectionListChanged(MailSettingsEvent e) {
177        int listChange = e.getListChange();
178        return (listChange & MailSettingsEvent.LIST_CHANGED_ACCOUNT) != 0
179                || (listChange & MailSettingsEvent.LIST_CHANGED_OUTGOING) != 0;
180    }
181       
182    private boolean accountChangeRequiringRefresh(MailSettingsEvent e) {
183        boolean refreshRequired = false;
184        int num = mailSettings.getNumAccounts();
185        for(int i=0; i<num; i++) {
186            AccountConfig accountConfig = mailSettings.getAccountConfig(i);
187            int accountChange = e.getConfigChange(accountConfig);
188            if((accountChange & AccountConfig.CHANGE_TYPE_NAME) != 0
189                    || (accountChange & AccountConfig.CHANGE_TYPE_MAILBOXES) != 0
190                    || (accountChange & AccountConfig.CHANGE_TYPE_OUTGOING) != 0) {
191                refreshRequired = true;
192                break;
193            }
194            OutgoingConfig outgoingConfig = accountConfig.getOutgoingConfig();
195            if(outgoingConfig != null
196                    && (e.getConfigChange(outgoingConfig) & OutgoingConfig.CHANGE_TYPE_CONNECTION) != 0) {
197                refreshRequired = true;
198                break;
199            }
200        }
201        return refreshRequired;
202    }
203   
204    /**
205     * Called when the account configuration has changed,
206     * to cause the mail model to update its account list.
207     */
208    private synchronized void updateMailModelAccountList() {
209        // Build the new account list from the configuration and
210        // the existing account nodes.  This works by checking to see
211        // if an account already exists, and only creating new nodes
212        // for new accounts.
213        NetworkAccountNode[] existingAccounts = mailRootNode.getNetworkAccounts();
214        NetworkAccountNode[] newAccounts = getNewNetworkAccountNodes();
215
216        // Remove and replace all account nodes from the root node.
217        // This approach is taken to preserve any ordering which may
218        // have been changed in the configuration.
219        mailRootNode.removeAccounts(existingAccounts);
220        mailRootNode.addAccounts(newAccounts);
221
222        // Clear deleted accounts from the MailFactory and persistent storage
223        clearDeletedAccounts(existingAccounts, newAccounts);
224
225        // Get the newly updated account list, and determine whether
226        // we need to update any mail senders.
227        NetworkAccountNode[] updatedAccounts = mailRootNode.getNetworkAccounts();
228        updateAccountMailSenders(updatedAccounts);
229
230        //TODO: Clear deleted senders from the MailFactory
231
232        // Notify any listeners
233        fireMailConfigurationChanged();
234    }
235
236        private NetworkAccountNode[] getNewNetworkAccountNodes() {
237            Vector newAccounts = new Vector();
238
239            int num = mailSettings.getNumAccounts();
240            for(int i=0; i<num; i++) {
241                AccountConfig accountConfig = mailSettings.getAccountConfig(i);
242                NetworkAccountNode existingAccountNode = mailRootNode.findAccountForConfig(accountConfig);
243
244                if(existingAccountNode != null) {
245                    newAccounts.addElement(existingAccountNode);
246                }
247                else {
248                    AccountNode newAccountNode = new NetworkAccountNode((NetworkMailStore) MailFactory.createMailStore(accountConfig));
249                    newAccountNode.load();
250                    newAccounts.addElement(newAccountNode);
251                }
252            }
253            NetworkAccountNode[] newAccountsArray = new NetworkAccountNode[newAccounts.size()];
254            newAccounts.copyInto(newAccountsArray);
255            return newAccountsArray;
256        }
257       
258    private void clearDeletedAccounts(NetworkAccountNode[] existingAccounts, NetworkAccountNode[] newAccounts) {
259        for(int i=0; i<existingAccounts.length; i++) {
260            boolean accountDeleted = true;
261            for(int j=0; j<newAccounts.length; j++) {
262                NetworkAccountNode newAccount = newAccounts[j];
263                if(newAccount == existingAccounts[i]) {
264                    accountDeleted = false;
265                    break;
266                }
267            }
268            if(accountDeleted) {
269                existingAccounts[i].removeSavedData();
270                MailFactory.clearMailStore(existingAccounts[i].getAccountConfig());
271            }
272        }
273    }
274
275    private void updateAccountMailSenders(NetworkAccountNode[] updatedAccounts) {
276        for(int i=0; i<updatedAccounts.length; i++) {
277            NetworkAccountNode networkAccount = updatedAccounts[i];
278            AbstractMailSender mailSender = networkAccount.getMailSender();
279            OutgoingConfig outgoingConfig = networkAccount.getAccountConfig().getOutgoingConfig();
280            if(outgoingConfig == null) {
281                if(mailSender != null) {
282                    mailSender.shutdown(false);
283                }
284                networkAccount.setMailSender(null);
285            }
286            else if((mailSender instanceof NetworkMailSender
287                    &&((NetworkMailSender)mailSender).getOutgoingConfig() != outgoingConfig)) {
288                mailSender.shutdown(false);
289                networkAccount.setMailSender(MailFactory.createMailSender(networkAccount.getAccountConfig().getOutgoingConfig()));
290            }
291            else if(mailSender == null) {
292                networkAccount.setMailSender(MailFactory.createMailSender(networkAccount.getAccountConfig().getOutgoingConfig()));
293            }
294        }
295    }
296
297        /**
298         * Handle connection state changes by updating the
299         * appropriate account nodes.
300         *
301         * @param e Event data.
302         */
303        private void mailConnectionManager_MailConnectionStateChanged(MailConnectionStateEvent e) {
304                // Find the account node associated with this event
305                AccountNode matchingAccount = mailRootNode.findAccountForConfig(
306                        (AccountConfig)e.getConnectionConfig());
307               
308                // Update account state
309                if(matchingAccount != null) {
310                        int state = e.getState();
311                        if(state == MailConnectionStateEvent.STATE_CONNECTED) {
312                                matchingAccount.setStatus(AccountNode.STATUS_ONLINE);
313                        }
314                        else if(state == MailConnectionStateEvent.STATE_DISCONNECTED) {
315                                matchingAccount.setStatus(AccountNode.STATUS_OFFLINE);
316                        }
317                }
318        }
319       
320        /**
321     * Adds a <tt>MailManagerListener</tt> to the mail manager.
322     *
323     * @param l The <tt>MailManagerListener</tt> to be added.
324     */
325    public void addMailManagerListener(MailManagerListener l) {
326        listenerList.add(MailManagerListener.class, l);
327    }
328
329    /**
330     * Removes a <tt>MailManagerListener</tt> from the mail manager.
331     *
332     * @param l The <tt>MailManagerListener</tt> to be removed.
333     */
334    public void removeMailManagerListener(MailManagerListener l) {
335        listenerList.remove(MailManagerListener.class, l);
336    }
337   
338    /**
339     * Returns an array of all <tt>MailManagerListener</tt>s
340     * that have been added to this mail manager.
341     *
342     * @return All the <tt>MailManagerListener</tt>s that have been added,
343     * or an empty array if no listeners have been added.
344     */
345    public MailManagerListener[] getMailManagerListeners() {
346        return (MailManagerListener[])listenerList.getListeners(MailManagerListener.class);
347    }
348   
349    /**
350     * Notifies all registered <tt>MailManagerListener</tt>s that
351     * the mail system configuration has changed.
352     */
353    private void fireMailConfigurationChanged() {
354        Object[] listeners = listenerList.getListeners(MailManagerListener.class);
355        MailManagerEvent e = null;
356        for(int i=0; i<listeners.length; i++) {
357            if(e == null) {
358                e = new MailManagerEvent(this);
359            }
360            ((MailManagerListener)listeners[i]).mailConfigurationChanged(e);
361        }
362    }
363
364}
Note: See TracBrowser for help on using the browser.