KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jsmtpd > core > send > QueueService


1 /*
2  *
3  * Jsmtpd, Java SMTP daemon
4  * Copyright (C) 2005 Jean-Francois POUX, jf.poux@laposte.net
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  */

21 package org.jsmtpd.core.send;
22
23 import java.io.File JavaDoc;
24 import java.io.FileFilter JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.LinkedList JavaDoc;
29 import java.util.List JavaDoc;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.jsmtpd.config.ReadConfig;
34 import org.jsmtpd.core.mail.Email;
35
36 /**
37  * queueMail holds a number of pending mails loaded (for perfs reasons)
38  * others are stored on disk<br>
39  *
40  * when a mail has to be requeued, it is directly writen to disk
41  *
42  * @author Jean-Francois POUX
43  */

44 public class QueueService {
45
46     /**
47      * mail here will be kept loaded
48      */

49     private List JavaDoc<Email> directService = Collections.synchronizedList(new LinkedList JavaDoc<Email>());
50     private static QueueService instance = null;
51     private String JavaDoc tempPath;
52     private File JavaDoc retryDir;
53     private File JavaDoc pendingDir;
54     private Log log = LogFactory.getLog(QueueService.class);
55     private boolean running = true;
56     private long retryDelay;
57     private long currentDiskSize = 0;
58     private long maxDiskSize = 0;
59     // Optim
60

61     private int fastServ;
62
63     private boolean safeMode = false;
64     private String JavaDoc safeModePath = "";
65     private FileFilter JavaDoc filter = new EmailFileFilter();
66
67     public static synchronized QueueService getInstance() {
68         if (instance == null)
69             instance = new QueueService();
70         return instance;
71     }
72
73     /**
74      * Adds a mail on the queue, in ram if the server can afford it, or written on disk
75      * @param input the mail to queue for delivery
76      * @return false if it can't be queued
77      */

78     public synchronized boolean queueMail(Email input) {
79         if (running == false)
80             return false;
81         log.debug("Queuing new mail "+input.getDiskName()+", Disk usage "+getStorageStats());
82         // if safe mode, write down the mail to specified location.
83
if (safeMode) {
84             try {
85                 Email.save(safeModePath + "/" + input.getDiskName(), input);
86                 log.info("SafeMode on : written mail to " + safeModePath + "/" + input.getDiskName());
87             } catch (IOException JavaDoc e) {
88                 log.error("SafeMode on : can't write mail to " + safeModePath + "/" + input.getDiskName(), e);
89             }
90         }
91         // We keep big mails on disk, whereas small are kept in ram
92
if ((directService.size() < 20) && (input.getSize() < 512000)) {
93             directService.add(input);
94             return true;
95         } else {
96             if ((directService.size() < 5) && (input.getSize() > 512000)) { // If we have a low number of mail on queue, keep big ones anyway
97
directService.add(input);
98                 return true;
99             } else {
100                 if ((currentDiskSize + input.getSize()) > maxDiskSize) {
101                     log.warn("Can't store anymore incomming mails, storage size exceeded");
102                     return false;
103                 }
104                 try {
105                     Email.save(tempPath + "mqueue/pending/" + input.getDiskName(), input);
106                     File JavaDoc tmp = new File JavaDoc(tempPath + "mqueue/pending/" + input.getDiskName());
107                     currentDiskSize += tmp.length();
108                     return true;
109                 } catch (IOException JavaDoc e) {
110                 }
111             }
112
113             return false;
114         }
115     }
116
117     /**
118      * If a mail temporary fails, this method will store it for later delivery
119      * @param input the mail to requeue
120      * @return false if can't be queued
121      */

122     public synchronized boolean requeueMail(Email input) {
123         if (running == false)
124             return false;
125         log.debug("DSVC> Re-queuing new mail "+input.getDiskName()+", Disk usage "+getStorageStats());
126         try {
127             input.increaseAttempts();
128             Email.save(tempPath + "mqueue/retry/" + input.getDiskName(), input);
129             File JavaDoc tmp = new File JavaDoc(tempPath + "mqueue/retry/" + input.getDiskName());
130             currentDiskSize += tmp.length();
131             return true;
132         } catch (IOException JavaDoc e) {
133
134         }
135         return false;
136     }
137
138     /**
139      * Gets a mail for delivering<br>
140      * Mail is picked on retried mails, then from the RAM linked list, and from the pending queue on disk
141      * @return the email instance picked from the queues
142      */

143     public synchronized Email getEmail() {
144         /**
145          * pickRetry();
146          * pickDirect();
147          * pickPending();
148          */

149         if (running == false)
150             return null;
151         Email tmp = null;
152         tmp = pickRetry();
153         if (tmp != null)
154             return tmp;
155
156         if (directService.size() > 0) {
157             tmp = (Email) directService.remove(0);
158             return tmp;
159         }
160         tmp = pickPending();
161         if (tmp != null)
162             return tmp;
163
164         return null;
165     }
166
167     /**
168      * picks a mail in the pending mqueue directory
169      * @return instance of a mail, or null if queue empty
170      */

171     private Email pickPending() {
172
173         File JavaDoc[] pendingMails = pendingDir.listFiles(filter);
174
175         if ((pendingMails != null) && pendingMails.length != 0) {
176             try {
177                 Email ret = Email.load(pendingMails[0].toString());
178                 currentDiskSize -= pendingMails[0].length();
179                 pendingMails[0].delete();
180                 return ret;
181             } catch (IOException JavaDoc e) {
182                 File JavaDoc tmp = new File JavaDoc(tempPath + "/" + pendingMails[0].getName() + "-Bogus");
183                 pendingMails[0].renameTo(tmp);
184                 log.error("Cant load mail " + pendingMails[0].toString() + ", error: " + e);
185                 log.error("Mail moved to bogus");
186             }
187         }
188         return null;
189     }
190
191     /**
192      * pick a mail in the retry mqueue folder
193      * @return the instance or null if queue is empty
194      */

195     private Email pickRetry() {
196         File JavaDoc[] pendingMails = retryDir.listFiles(filter);
197
198         if (pendingMails != null) {
199             for (int i = 0; i < pendingMails.length; i++) {
200                 long timeOffset = pendingMails[i].lastModified() + retryDelay;
201                 if (timeOffset < System.currentTimeMillis()) {
202                     try {
203                         Email ret = Email.load(pendingMails[0].toString());
204                         currentDiskSize -= pendingMails[0].length();
205                         pendingMails[0].delete();
206                         return ret;
207                     } catch (IOException JavaDoc e) {
208                         File JavaDoc tmp = new File JavaDoc(tempPath + "/" + pendingMails[0].getName() + "-Bogus");
209                         pendingMails[0].renameTo(tmp);
210                         log.error("Cant load mail " + pendingMails[0].toString() + ", error: " + e);
211                         log.error("Mail moved to bogus");
212                     }
213                 }
214             }
215
216         }
217         return null;
218     }
219
220     private QueueService() {
221         ReadConfig cfg = ReadConfig.getInstance();
222         tempPath = cfg.getTempPath();
223         retryDelay = cfg.getDelayRetry() * 60 * 1000;
224         retryDir = new File JavaDoc(tempPath + "/mqueue/retry");
225         pendingDir = new File JavaDoc(tempPath + "/mqueue/pending");
226         fastServ = cfg.getDMaxInstances() * 2;
227         log.debug("Buffer set to " + fastServ + " messages max for immediate processing");
228         maxDiskSize = cfg.getMaxTemporarySize() * 1048576;
229         initDiskCount(new File JavaDoc(tempPath));
230         log.debug("Storage usage "+getStorageStats());
231         safeMode = cfg.getSafeMode();
232         if (safeMode)
233             log.info("Safe Mode on");
234         safeModePath = cfg.getSafeModePath();
235     }
236     private String JavaDoc getStorageStats () {
237         String JavaDoc out = Math.round((float) currentDiskSize / 1048576) + "/"
238         + Math.round((float) maxDiskSize / 1048576) + " (in Mo)";
239         return out;
240     }
241     private void initDiskCount(File JavaDoc input) {
242         if (input.isFile())
243             currentDiskSize += input.length();
244         else {
245             File JavaDoc[] sub = input.listFiles();
246             for (int i = 0; i < sub.length; i++) {
247                 File JavaDoc file = sub[i];
248                 initDiskCount(file);
249             }
250         }
251     }
252
253     public void shutdownService() {
254         running = false;
255         for (Iterator JavaDoc iter = directService.iterator(); iter.hasNext();) {
256             Email element = (Email) iter.next();
257             try {
258                 Email.save(tempPath + "mqueue/retry/" + element.getDiskName(), element);
259                 log.debug("Shutdown : " + element.getDiskName() + " written to retry");
260             } catch (IOException JavaDoc e) {
261                 log.debug("Cant save mail on shutdown, mail " + element.getDiskName() + " is lost due to: " + e.getCause());
262             }
263         }
264     }
265
266 }
Popular Tags