001    /****************************************************************
002     * Licensed to the Apache Software Foundation (ASF) under one   *
003     * or more contributor license agreements.  See the NOTICE file *
004     * distributed with this work for additional information        *
005     * regarding copyright ownership.  The ASF licenses this file   *
006     * to you under the Apache License, Version 2.0 (the            *
007     * "License"); you may not use this file except in compliance   *
008     * with the License.  You may obtain a copy of the License at   *
009     *                                                              *
010     *   http://www.apache.org/licenses/LICENSE-2.0                 *
011     *                                                              *
012     * Unless required by applicable law or agreed to in writing,   *
013     * software distributed under the License is distributed on an  *
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015     * KIND, either express or implied.  See the License for the    *
016     * specific language governing permissions and limitations      *
017     * under the License.                                           *
018     ****************************************************************/
019    
020    package org.apache.james.mailrepository.lib;
021    
022    import org.apache.commons.configuration.ConfigurationException;
023    import org.apache.commons.configuration.HierarchicalConfiguration;
024    import org.apache.james.lifecycle.api.Configurable;
025    import org.apache.james.lifecycle.api.LogEnabled;
026    import org.apache.james.mailrepository.api.MailRepository;
027    import org.apache.mailet.Mail;
028    import org.slf4j.Logger;
029    
030    import javax.mail.MessagingException;
031    
032    import java.io.IOException;
033    import java.util.Collection;
034    import java.util.Iterator;
035    
036    /**
037     * This class represent an AbstractMailRepository. All MailRepositories should
038     * extend this class.
039     */
040    public abstract class AbstractMailRepository implements MailRepository, LogEnabled, Configurable {
041    
042        /**
043         * Whether 'deep debugging' is turned on.
044         */
045        protected static final boolean DEEP_DEBUG = false;
046    
047        /**
048         * A lock used to control access to repository elements, locking access
049         * based on the key
050         */
051        private final Lock lock = new Lock();;
052    
053        private Logger logger;
054    
055        public void setLog(Logger logger) {
056            this.logger = logger;
057        }
058    
059        protected Logger getLogger() {
060            return logger;
061        }
062    
063        public void configure(HierarchicalConfiguration configuration) throws ConfigurationException {
064            doConfigure(configuration);
065        }
066    
067        protected void doConfigure(HierarchicalConfiguration config) throws ConfigurationException {
068    
069        }
070    
071        /**
072         * @see org.apache.james.mailrepository.api.MailRepository#unlock(String)
073         */
074        public boolean unlock(String key) {
075            if (lock.unlock(key)) {
076                if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
077                    StringBuffer debugBuffer = new StringBuffer(256).append("Unlocked ").append(key).append(" for ").append(Thread.currentThread().getName()).append(" @ ").append(new java.util.Date(System.currentTimeMillis()));
078                    getLogger().debug(debugBuffer.toString());
079                }
080                return true;
081            } else {
082                return false;
083            }
084        }
085    
086        /**
087         * @see org.apache.james.mailrepository.api.MailRepository#lock(String)
088         */
089        public boolean lock(String key) {
090            if (lock.lock(key)) {
091                if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
092                    StringBuffer debugBuffer = new StringBuffer(256).append("Locked ").append(key).append(" for ").append(Thread.currentThread().getName()).append(" @ ").append(new java.util.Date(System.currentTimeMillis()));
093                    getLogger().debug(debugBuffer.toString());
094                }
095                return true;
096            } else {
097                return false;
098            }
099        }
100    
101        /**
102         * @see org.apache.james.mailrepository.api.MailRepository#store(Mail)
103         */
104        public void store(Mail mc) throws MessagingException {
105            boolean wasLocked = true;
106            String key = mc.getName();
107            try {
108                synchronized (this) {
109                    wasLocked = lock.isLocked(key);
110                    if (!wasLocked) {
111                        // If it wasn't locked, we want a lock during the store
112                        lock(key);
113                    }
114                }
115                internalStore(mc);
116                if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
117                    StringBuffer logBuffer = new StringBuffer(64).append("Mail ").append(key).append(" stored.");
118                    getLogger().debug(logBuffer.toString());
119                }
120            } catch (MessagingException e) {
121                getLogger().error("Exception caught while storing mail " + key, e);
122                throw e;
123            } catch (Exception e) {
124                getLogger().error("Exception caught while storing mail " + key, e);
125                throw new MessagingException("Exception caught while storing mail " + key, e);
126            } finally {
127                if (!wasLocked) {
128                    // If it wasn't locked, we need to unlock now
129                    unlock(key);
130                    synchronized (this) {
131                        notify();
132                    }
133                }
134            }
135        }
136    
137        /**
138         * @see #store(Mail)
139         */
140        protected abstract void internalStore(Mail mc) throws MessagingException, IOException;
141    
142        /**
143         * @see org.apache.james.mailrepository.api.MailRepository#remove(Mail)
144         */
145        public void remove(Mail mail) throws MessagingException {
146            remove(mail.getName());
147        }
148    
149        /**
150         * @see org.apache.james.mailrepository.api.MailRepository#remove(Collection)
151         */
152        public void remove(Collection<Mail> mails) throws MessagingException {
153            Iterator<Mail> delList = mails.iterator();
154            while (delList.hasNext()) {
155                remove(delList.next());
156            }
157        }
158    
159        /**
160         * @see org.apache.james.mailrepository.api.MailRepository#remove(String)
161         */
162        public void remove(String key) throws MessagingException {
163            if (lock(key)) {
164                try {
165                    internalRemove(key);
166                } finally {
167                    unlock(key);
168                }
169            } else {
170                StringBuffer exceptionBuffer = new StringBuffer(64).append("Cannot lock ").append(key).append(" to remove it");
171                throw new MessagingException(exceptionBuffer.toString());
172            }
173        }
174    
175        /**
176         * @see #remove(String)
177         */
178        protected abstract void internalRemove(String key) throws MessagingException;
179    
180    }