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 }