View Javadoc

1   /****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  
21  
22  package org.apache.james.mailrepository;
23  
24  import org.apache.avalon.cornerstone.services.store.Store;
25  import org.apache.avalon.framework.activity.Initializable;
26  import org.apache.avalon.framework.configuration.Configurable;
27  import org.apache.avalon.framework.logger.AbstractLogEnabled;
28  import org.apache.avalon.framework.service.ServiceException;
29  import org.apache.avalon.framework.service.ServiceManager;
30  import org.apache.avalon.framework.service.Serviceable;
31  import org.apache.james.services.MailRepository;
32  import org.apache.james.util.Lock;
33  import org.apache.mailet.Mail;
34  
35  import javax.mail.MessagingException;
36  
37  import java.io.IOException;
38  import java.util.Collection;
39  import java.util.Iterator;
40  
41  /**
42   * This class represent an AbstractMailRepository. All MailRepositories should extend this class. 
43   */
44  public abstract class AbstractMailRepository extends AbstractLogEnabled
45          implements MailRepository, Serviceable, Configurable, Initializable {
46  
47      /**
48       * Whether 'deep debugging' is turned on.
49       */
50      protected static final boolean DEEP_DEBUG = false;
51      
52      /**
53       * A lock used to control access to repository elements, locking access
54       * based on the key 
55       */
56      private Lock lock;
57  
58      protected Store store; // variable is not used beyond initialization
59      
60      /**
61       * Set the Store to use
62       * 
63       * @param store the Store
64       */
65      void setStore(Store store) {
66          this.store = store;
67      }
68  
69  
70      /**
71       * @see org.apache.avalon.framework.activity.Initializable#initialize()
72       */
73      public void initialize() throws Exception {
74          lock = new Lock();
75      }
76  
77  
78      /**
79       * @see org.apache.avalon.framework.service.Serviceable#service(ServiceManager )
80       */
81      public void service( final ServiceManager componentManager )
82              throws ServiceException {
83          setStore((Store)componentManager.lookup( Store.ROLE ));
84      }
85  
86      /**
87       * @see org.apache.james.services.MailRepository#unlock(String)
88       */
89      public boolean unlock(String key) {
90          if (lock.unlock(key)) {
91              if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
92                  StringBuffer debugBuffer =
93                      new StringBuffer(256)
94                              .append("Unlocked ")
95                              .append(key)
96                              .append(" for ")
97                              .append(Thread.currentThread().getName())
98                              .append(" @ ")
99                              .append(new java.util.Date(System.currentTimeMillis()));
100                 getLogger().debug(debugBuffer.toString());
101             }
102             return true;
103         } else {
104             return false;
105         }
106     }
107 
108     /**
109      * @see org.apache.james.services.MailRepository#lock(String)
110      */
111     public boolean lock(String key) {
112         if (lock.lock(key)) {
113             if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
114                 StringBuffer debugBuffer =
115                     new StringBuffer(256)
116                             .append("Locked ")
117                             .append(key)
118                             .append(" for ")
119                             .append(Thread.currentThread().getName())
120                             .append(" @ ")
121                             .append(new java.util.Date(System.currentTimeMillis()));
122                 getLogger().debug(debugBuffer.toString());
123             }
124             return true;
125         } else {
126             return false;
127         }
128     }
129 
130 
131     /**
132      * @see org.apache.james.services.MailRepository#store(Mail)
133      */
134     public void store(Mail mc) throws MessagingException {
135         boolean wasLocked = true;
136         String key = mc.getName();
137         try {
138             synchronized(this) {
139                   wasLocked = lock.isLocked(key);
140                   if (!wasLocked) {
141                       //If it wasn't locked, we want a lock during the store
142                       lock(key);
143                   }
144             }
145             internalStore(mc);
146             if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
147                 StringBuffer logBuffer =
148                     new StringBuffer(64)
149                             .append("Mail ")
150                             .append(key)
151                             .append(" stored.");
152                 getLogger().debug(logBuffer.toString());
153             }
154         } catch (MessagingException e) {
155             getLogger().error("Exception caught while storing mail "+key,e);
156             throw e;
157         } catch (Exception e) {
158             getLogger().error("Exception caught while storing mail "+key,e);
159             throw new MessagingException("Exception caught while storing mail "+key,e);
160         } finally {
161             if (!wasLocked) {
162                 // If it wasn't locked, we need to unlock now
163                 unlock(key);
164                 synchronized (this) {
165                     notify();
166                 }
167             }
168         }
169     }
170 
171 
172     /**
173      * @see #store(Mail)
174      */
175     protected abstract void internalStore(Mail mc) throws MessagingException, IOException;
176 
177 
178     /**
179      * @see org.apache.james.services.MailRepository#remove(Mail)
180      */
181     public void remove(Mail mail) throws MessagingException {
182         remove(mail.getName());
183     }
184 
185 
186     /**
187      * @see org.apache.james.services.MailRepository#remove(Collection)
188      */
189     public void remove(Collection mails) throws MessagingException {
190         Iterator delList = mails.iterator();
191         while (delList.hasNext()) {
192             remove((Mail)delList.next());
193         }
194     }
195 
196     /**
197      * @see org.apache.james.services.MailRepository#remove(String)
198      */
199     public void remove(String key) throws MessagingException {
200         if (lock(key)) {
201             try {
202                 internalRemove(key);
203             } finally {
204                 unlock(key);
205             }
206         } else {
207             StringBuffer exceptionBuffer =
208                 new StringBuffer(64)
209                         .append("Cannot lock ")
210                         .append(key)
211                         .append(" to remove it");
212             throw new MessagingException(exceptionBuffer.toString());
213         }
214     }
215 
216 
217     /**
218      * @see #remove(String)
219      */
220     protected abstract void internalRemove(String key) throws MessagingException;
221 
222 
223 }