Source Code Cross Referenced for MBoxMailRepository.java in  » Net » james-2.3.1 » org » apache » james » mailrepository » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Net » james 2.3.1 » org.apache.james.mailrepository 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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:         ****************************************************************/package org.apache.james.mailrepository;
019:
020:        import org.apache.avalon.framework.activity.Initializable;
021:        import org.apache.avalon.framework.service.ServiceException;
022:        import org.apache.avalon.framework.service.ServiceManager;
023:        import org.apache.avalon.framework.service.Serviceable;
024:        import org.apache.avalon.framework.configuration.Configurable;
025:        import org.apache.avalon.framework.configuration.Configuration;
026:        import org.apache.avalon.framework.configuration.ConfigurationException;
027:        import org.apache.avalon.framework.logger.AbstractLogEnabled;
028:        import org.apache.james.core.MailImpl;
029:        import org.apache.james.services.MailRepository;
030:        import org.apache.mailet.Mail;
031:        import org.apache.oro.text.regex.MalformedPatternException;
032:        import org.apache.oro.text.regex.Perl5Compiler;
033:        import org.apache.oro.text.regex.Pattern;
034:        import org.apache.oro.text.regex.Perl5Matcher;
035:
036:        import javax.mail.MessagingException;
037:        import javax.mail.Session;
038:        import javax.mail.internet.MimeMessage;
039:
040:        import java.io.ByteArrayInputStream;
041:        import java.io.ByteArrayOutputStream;
042:        import java.io.File;
043:        import java.io.FileNotFoundException;
044:        import java.io.IOException;
045:        import java.io.RandomAccessFile;
046:        import java.security.NoSuchAlgorithmException;
047:        import java.security.MessageDigest;
048:        import java.text.SimpleDateFormat;
049:        import java.util.ArrayList;
050:        import java.util.Calendar;
051:        import java.util.Collection;
052:        import java.util.Hashtable;
053:        import java.util.Iterator;
054:        import java.util.Locale;
055:        import java.util.Properties;
056:
057:        /**
058:         * Implementation of a MailRepository using UNIX mbox files.
059:         *
060:         * <p>Requires a configuration element in the .conf.xml file of the form:
061:         *  <br>&lt;repository destinationURL="mbox://&lt;directory&gt;"
062:         *  <br>            type="MAIL"
063:         *  <br>&lt;/directory&gt; is where the individual mbox files are read from/written to
064:         * <br>Type can ONLY be MAIL (SPOOL is NOT supported)
065:         *
066:         * <p>Requires a logger called MailRepository.
067:         *
068:         * <p> Implementation notes:
069:         * <p>
070:         * This class keeps an internal store of the mbox file
071:         * When the internal mbox file is updated (added/deleted)
072:         * then the file will be re-read from disk and then written back.
073:         * This is a bit inefficent but means that the file on disk
074:         * should be correct.
075:         * <p>
076:         * The mbox store is mainly meant to be used as a one-way street.
077:         * Storing new emails is very fast (append to file) whereas reading them (via POP3) is
078:         * slower (read from disk and parse).
079:         * Therefore this implementation is best suited to people who wish to use the mbox format
080:         * for taking data out of James and into something else (IMAP server or mail list displayer)
081:         *
082:         * @version CVS $Revision: 495537 $
083:         */
084:
085:        public class MBoxMailRepository extends AbstractLogEnabled implements 
086:                MailRepository, Serviceable, Configurable, Initializable {
087:
088:            static final SimpleDateFormat dy = new SimpleDateFormat(
089:                    "EE MMM dd HH:mm:ss yyyy", Locale.US);
090:            static final String LOCKEXT = ".lock";
091:            static final String WORKEXT = ".work";
092:            static final int LOCKSLEEPDELAY = 2000; // 2 second back off in the event of a problem with the lock file
093:            static final int MAXSLEEPTIMES = 100; //
094:            static final long MLISTPRESIZEFACTOR = 10 * 1024; // The hash table will be loaded with a initial capacity of  filelength/MLISTPRESIZEFACTOR
095:            static final long DEFAULTMLISTCAPACITY = 20; // Set up a hashtable to have a meaningful default
096:
097:            /**
098:             * Whether line buffering is turned used.
099:             */
100:            private static boolean BUFFERING = true;
101:
102:            /**
103:             * Whether 'deep debugging' is turned on.
104:             */
105:            private static final boolean DEEP_DEBUG = true;
106:
107:            /**
108:             * The internal list of the emails
109:             * The key is an adapted MD5 checksum of the mail
110:             */
111:            private Hashtable mList = null;
112:            /**
113:             * The filename to read & write the mbox from/to
114:             */
115:            private String mboxFile;
116:
117:            /**
118:             * A callback used when a message is read from the mbox file
119:             */
120:            public interface MessageAction {
121:                public boolean isComplete(); // *** Not valid until AFTER each call to messageAction(...)!
122:
123:                public MimeMessage messageAction(String messageSeparator,
124:                        String bodyText, long messageStart);
125:            }
126:
127:            /**
128:             * Convert a MimeMessage into raw text
129:             * @param mc The mime message to convert
130:             * @return A string representation of the mime message
131:             * @throws IOException
132:             * @throws MessagingException
133:             */
134:            private String getRawMessage(MimeMessage mc) throws IOException,
135:                    MessagingException {
136:
137:                ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
138:                mc.writeTo(rawMessage);
139:                return rawMessage.toString();
140:            }
141:
142:            /**
143:             * Parse a text block as an email and convert it into a mime message
144:             * @param emailBody The headers and body of an email. This will be parsed into a mime message and stored
145:             */
146:            private MimeMessage convertTextToMimeMessage(String emailBody) {
147:                //this.emailBody = emailBody;
148:                MimeMessage mimeMessage = null;
149:                // Parse the mime message as we have the full message now (in string format)
150:                ByteArrayInputStream mb = new ByteArrayInputStream(emailBody
151:                        .getBytes());
152:                Properties props = System.getProperties();
153:                Session session = Session.getDefaultInstance(props);
154:                try {
155:                    mimeMessage = new MimeMessage(session, mb);
156:
157:                } catch (MessagingException e) {
158:                    getLogger().error("Unable to parse mime message!", e);
159:                }
160:
161:                if (mimeMessage == null && getLogger().isDebugEnabled()) {
162:                    StringBuffer logBuffer = new StringBuffer(128).append(
163:                            this .getClass().getName()).append(
164:                            " Mime message is null");
165:                    getLogger().debug(logBuffer.toString());
166:                }
167:
168:                /*
169:                String toAddr = null;
170:                try {
171:                    // Attempt to read the TO field and see if it errors
172:                    toAddr = mimeMessage.getRecipients(javax.mail.Message.RecipientType.TO).toString();
173:                } catch (Exception e) {
174:                    // It has errored, so time for plan B
175:                    // use the from field I suppose
176:                    try {
177:                        mimeMessage.setRecipients(javax.mail.Message.RecipientType.TO, mimeMessage.getFrom());
178:                        if (getLogger().isDebugEnabled()) {
179:                            StringBuffer logBuffer =
180:                                    new StringBuffer(128)
181:                                    .append(this.getClass().getName())
182:                                    .append(" Patching To: field for message ")
183:                                    .append(" with  From: field");
184:                            getLogger().debug(logBuffer.toString());
185:                        }
186:                    } catch (MessagingException e1) {
187:                        getLogger().error("Unable to set to: field to from: field", e);
188:                    }
189:                } */
190:                return mimeMessage;
191:            }
192:
193:            /**
194:             * Generate a hex representation of an MD5 checksum on the emailbody
195:             * @param emailBody
196:             * @return A hex representation of the text
197:             * @throws NoSuchAlgorithmException
198:             */
199:            private String generateKeyValue(String emailBody)
200:                    throws NoSuchAlgorithmException {
201:                // MD5 the email body for a reilable (ha ha) key
202:                byte[] digArray = MessageDigest.getInstance("MD5").digest(
203:                        emailBody.getBytes());
204:                StringBuffer digest = new StringBuffer();
205:                for (int i = 0; i < digArray.length; i++) {
206:                    digest.append(Integer.toString(digArray[i],
207:                            Character.MAX_RADIX).toUpperCase(Locale.US));
208:                }
209:                return digest.toString();
210:            }
211:
212:            /**
213:             * Parse the mbox file.
214:             * @param ins The random access file to load. Note that the file may or may not start at offset 0 in the file
215:             * @param messAct The action to take when a message is found
216:             */
217:            private MimeMessage parseMboxFile(RandomAccessFile ins,
218:                    MessageAction messAct) {
219:                if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
220:                    StringBuffer logBuffer = new StringBuffer(128).append(
221:                            this .getClass().getName())
222:                            .append(" Start parsing ").append(mboxFile);
223:
224:                    getLogger().debug(logBuffer.toString());
225:                }
226:                try {
227:
228:                    Perl5Compiler sepMatchCompiler = new Perl5Compiler();
229:                    Pattern sepMatchPattern = sepMatchCompiler
230:                            .compile("^From (.*) (.*):(.*):(.*)$");
231:                    Perl5Matcher sepMatch = new Perl5Matcher();
232:
233:                    int c;
234:                    boolean inMessage = false;
235:                    StringBuffer messageBuffer = new StringBuffer();
236:                    String previousMessageSeparator = null;
237:                    boolean foundSep = false;
238:
239:                    long prevMessageStart = ins.getFilePointer();
240:                    if (BUFFERING) {
241:                        String line = null;
242:                        while ((line = ins.readLine()) != null) {
243:                            foundSep = sepMatch.contains(line + "\n",
244:                                    sepMatchPattern);
245:
246:                            if (foundSep && inMessage) {
247:                                //                    if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
248:                                //                        getLogger().debug(this.getClass().getName() + " Invoking " + messAct.getClass() + " at " + prevMessageStart);
249:                                //                    }
250:                                MimeMessage endResult = messAct.messageAction(
251:                                        previousMessageSeparator, messageBuffer
252:                                                .toString(), prevMessageStart);
253:                                if (messAct.isComplete()) {
254:                                    // I've got what I want so just exit
255:                                    return endResult;
256:                                }
257:                                previousMessageSeparator = line;
258:                                prevMessageStart = ins.getFilePointer()
259:                                        - line.length();
260:                                messageBuffer = new StringBuffer();
261:                                inMessage = true;
262:                            }
263:                            // Only done at the start (first header)
264:                            if (foundSep && !inMessage) {
265:                                previousMessageSeparator = line.toString();
266:                                inMessage = true;
267:                            }
268:                            if (!foundSep && inMessage) {
269:                                messageBuffer.append(line).append("\n");
270:                            }
271:                        }
272:                    } else {
273:                        StringBuffer line = new StringBuffer();
274:                        while ((c = ins.read()) != -1) {
275:                            if (c == 10) {
276:                                foundSep = sepMatch.contains(line.toString(),
277:                                        sepMatchPattern);
278:                                if (foundSep && inMessage) {
279:                                    //                        if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
280:                                    //                            getLogger().debug(this.getClass().getName() + " Invoking " + messAct.getClass() + " at " + prevMessageStart);
281:                                    //                        }
282:                                    MimeMessage endResult = messAct
283:                                            .messageAction(
284:                                                    previousMessageSeparator,
285:                                                    messageBuffer.toString(),
286:                                                    prevMessageStart);
287:                                    if (messAct.isComplete()) {
288:                                        // I've got what I want so just exit
289:                                        return endResult;
290:                                    }
291:                                    previousMessageSeparator = line.toString();
292:                                    prevMessageStart = ins.getFilePointer()
293:                                            - line.length();
294:                                    messageBuffer = new StringBuffer();
295:                                    inMessage = true;
296:                                }
297:                                // Only done at the start (first header)
298:                                if (foundSep && inMessage == false) {
299:                                    previousMessageSeparator = line.toString();
300:                                    inMessage = true;
301:                                }
302:                                if (!foundSep) {
303:                                    messageBuffer.append(line).append((char) c);
304:                                }
305:                                line = new StringBuffer(); // Reset buffer
306:                            } else {
307:                                line.append((char) c);
308:                            }
309:                        }
310:                    }
311:
312:                    if (messageBuffer.length() != 0) {
313:                        // process last message
314:                        return messAct.messageAction(previousMessageSeparator,
315:                                messageBuffer.toString(), prevMessageStart);
316:                    }
317:                } catch (IOException ioEx) {
318:                    getLogger().error(
319:                            "Unable to write file (General I/O problem) "
320:                                    + mboxFile, ioEx);
321:                } catch (MalformedPatternException e) {
322:                    getLogger().error("Bad regex passed " + mboxFile, e);
323:                } finally {
324:                    if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
325:                        StringBuffer logBuffer = new StringBuffer(128).append(
326:                                this .getClass().getName()).append(
327:                                " Finished parsing ").append(mboxFile);
328:
329:                        getLogger().debug(logBuffer.toString());
330:                    }
331:                }
332:                return null;
333:            }
334:
335:            /**
336:             * Find a given message
337:             * This method will first use selectMessage(key) to see if the key/offset combination allows us to skip
338:             * parts of the file and only load the message we are interested in
339:             *
340:             * @param key The key of the message to find
341:             */
342:            private MimeMessage findMessage(String key) {
343:                MimeMessage foundMessage = null;
344:
345:                // See if we can get the message by using the cache position first
346:                foundMessage = selectMessage(key);
347:                if (foundMessage == null) {
348:                    // If the message is not found something has changed from
349:                    // the cache.  The cache may have been invalidated by
350:                    // another method, or the file may have been replaced from
351:                    // underneath us.  Reload the cache, and try again.
352:                    mList = null;
353:                    loadKeys();
354:                    foundMessage = selectMessage(key);
355:                }
356:                return foundMessage;
357:            }
358:
359:            /**
360:             * Quickly find a message by using the stored message offsets
361:             * @param key  The key of the message to find
362:             */
363:            private MimeMessage selectMessage(final String key) {
364:                MimeMessage foundMessage = null;
365:                // Can we find the key first
366:                if (mList == null || !mList.containsKey(key)) {
367:                    // Not initiailised so no point looking
368:                    if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
369:                        StringBuffer logBuffer = new StringBuffer(128).append(
370:                                this .getClass().getName()).append(
371:                                " mList - key not found ").append(mboxFile);
372:
373:                        getLogger().debug(logBuffer.toString());
374:                    }
375:                    return foundMessage;
376:                }
377:                long messageStart = ((Long) mList.get(key)).longValue();
378:                if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
379:                    StringBuffer logBuffer = new StringBuffer(128).append(
380:                            this .getClass().getName()).append(
381:                            " Load message starting at offset ").append(
382:                            messageStart).append(" from file ")
383:                            .append(mboxFile);
384:
385:                    getLogger().debug(logBuffer.toString());
386:                }
387:                // Now try and find the position in the file
388:                RandomAccessFile ins = null;
389:                try {
390:                    ins = new RandomAccessFile(mboxFile, "r");
391:                    if (messageStart != 0) {
392:                        ins.seek(messageStart - 1);
393:                    }
394:                    MessageAction op = new MessageAction() {
395:                        public boolean isComplete() {
396:                            return true;
397:                        }
398:
399:                        public MimeMessage messageAction(
400:                                String messageSeparator, String bodyText,
401:                                long messageStart) {
402:                            try {
403:                                if (key.equals(generateKeyValue(bodyText))) {
404:                                    getLogger()
405:                                            .debug(
406:                                                    this .getClass().getName()
407:                                                            + " Located message. Returning MIME message");
408:                                    return convertTextToMimeMessage(bodyText);
409:                                }
410:                            } catch (NoSuchAlgorithmException e) {
411:                                getLogger().error("MD5 not supported! ", e);
412:                            }
413:                            return null;
414:                        }
415:                    };
416:                    foundMessage = this .parseMboxFile(ins, op);
417:                } catch (FileNotFoundException e) {
418:                    getLogger().error(
419:                            "Unable to save(open) file (File not found) "
420:                                    + mboxFile, e);
421:                } catch (IOException e) {
422:                    getLogger().error(
423:                            "Unable to write file (General I/O problem) "
424:                                    + mboxFile, e);
425:                } finally {
426:                    if (foundMessage == null) {
427:                        if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
428:                            StringBuffer logBuffer = new StringBuffer(128)
429:                                    .append(this .getClass().getName()).append(
430:                                            " select - message not found ")
431:                                    .append(mboxFile);
432:
433:                            getLogger().debug(logBuffer.toString());
434:                        }
435:                    }
436:                    if (ins != null)
437:                        try {
438:                            ins.close();
439:                        } catch (IOException e) {
440:                            getLogger().error(
441:                                    "Unable to close file (General I/O problem) "
442:                                            + mboxFile, e);
443:                        }
444:                }
445:                return foundMessage;
446:            }
447:
448:            /**
449:             * Load the message keys and file pointer offsets from disk
450:             */
451:            private synchronized void loadKeys() {
452:                if (mList != null) {
453:                    return;
454:                }
455:                RandomAccessFile ins = null;
456:                try {
457:                    ins = new RandomAccessFile(mboxFile, "r");
458:                    long initialCapacity = (ins.length() > MLISTPRESIZEFACTOR ? ins
459:                            .length()
460:                            / MLISTPRESIZEFACTOR
461:                            : 0);
462:                    if (initialCapacity < DEFAULTMLISTCAPACITY) {
463:                        initialCapacity = DEFAULTMLISTCAPACITY;
464:                    }
465:                    if (initialCapacity > Integer.MAX_VALUE) {
466:                        initialCapacity = Integer.MAX_VALUE - 1;
467:                    }
468:                    this .mList = new Hashtable((int) initialCapacity);
469:                    this .parseMboxFile(ins, new MessageAction() {
470:                        public boolean isComplete() {
471:                            return false;
472:                        }
473:
474:                        public MimeMessage messageAction(
475:                                String messageSeparator, String bodyText,
476:                                long messageStart) {
477:                            try {
478:                                String key = generateKeyValue(bodyText);
479:                                mList.put(key, new Long(messageStart));
480:                                if ((DEEP_DEBUG)
481:                                        && (getLogger().isDebugEnabled())) {
482:                                    getLogger().debug(
483:                                            this .getClass().getName() + " Key "
484:                                                    + key + " at "
485:                                                    + messageStart);
486:                                }
487:
488:                            } catch (NoSuchAlgorithmException e) {
489:                                getLogger().error("MD5 not supported! ", e);
490:                            }
491:                            return null;
492:                        }
493:                    });
494:                    //System.out.println("Done Load keys!");
495:                } catch (FileNotFoundException e) {
496:                    getLogger().error(
497:                            "Unable to save(open) file (File not found) "
498:                                    + mboxFile, e);
499:                    this .mList = new Hashtable((int) DEFAULTMLISTCAPACITY);
500:                } catch (IOException e) {
501:                    getLogger().error(
502:                            "Unable to write file (General I/O problem) "
503:                                    + mboxFile, e);
504:                } finally {
505:                    if (ins != null)
506:                        try {
507:                            ins.close();
508:                        } catch (IOException e) {
509:                            getLogger().error(
510:                                    "Unable to close file (General I/O problem) "
511:                                            + mboxFile, e);
512:                        }
513:                }
514:            }
515:
516:            /**
517:             * Store the given email in the current mbox file
518:             * @param mc The mail to store
519:             */
520:            public void store(Mail mc) {
521:
522:                if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
523:                    StringBuffer logBuffer = new StringBuffer(128).append(
524:                            this .getClass().getName()).append(
525:                            " Will store message to file ").append(mboxFile);
526:
527:                    getLogger().debug(logBuffer.toString());
528:                }
529:                this .mList = null;
530:                // Now make up the from header
531:                String fromHeader = null;
532:                String message = null;
533:                try {
534:                    message = getRawMessage(mc.getMessage());
535:                    // check for nullsender
536:                    if (mc.getMessage().getFrom() == null) {
537:                        fromHeader = "From   "
538:                                + dy.format(Calendar.getInstance().getTime());
539:                    } else {
540:                        fromHeader = "From " + mc.getMessage().getFrom()[0]
541:                                + " "
542:                                + dy.format(Calendar.getInstance().getTime());
543:                    }
544:
545:                } catch (IOException e) {
546:                    getLogger().error(
547:                            "Unable to parse mime message for " + mboxFile, e);
548:                } catch (MessagingException e) {
549:                    getLogger().error(
550:                            "Unable to parse mime message for " + mboxFile, e);
551:                }
552:                // And save only the new stuff to disk
553:                RandomAccessFile saveFile = null;
554:                try {
555:                    saveFile = new RandomAccessFile(mboxFile, "rw");
556:                    saveFile.seek(saveFile.length()); // Move to the end
557:                    saveFile.writeBytes((fromHeader + "\n"));
558:                    saveFile.writeBytes((message + "\n"));
559:                    saveFile.close();
560:
561:                } catch (FileNotFoundException e) {
562:                    getLogger().error(
563:                            "Unable to save(open) file (File not found) "
564:                                    + mboxFile, e);
565:                } catch (IOException e) {
566:                    getLogger().error(
567:                            "Unable to write file (General I/O problem) "
568:                                    + mboxFile, e);
569:                }
570:            }
571:
572:            /**
573:             * Return the list of the current messages' keys
574:             * @return A list of the keys of the emails currently loaded
575:             */
576:            public Iterator list() {
577:                loadKeys();
578:
579:                if (mList.keySet().isEmpty() == false) {
580:                    // find the first message.  This is a trick to make sure that if
581:                    // the file is changed out from under us, we will detect it and
582:                    // correct for it BEFORE we return the iterator.
583:                    findMessage((String) mList.keySet().iterator().next());
584:                }
585:                if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
586:                    StringBuffer logBuffer = new StringBuffer(128).append(
587:                            this .getClass().getName()).append(" ").append(
588:                            mList.size()).append(" keys to be iterated over.");
589:
590:                    getLogger().debug(logBuffer.toString());
591:                }
592:                return mList.keySet().iterator();
593:            }
594:
595:            /**
596:             * Get a message from the backing store (disk)
597:             * @param key
598:             * @return The mail found from the key. Returns null if the key is not found
599:             */
600:            public Mail retrieve(String key) {
601:
602:                loadKeys();
603:                MailImpl res = null;
604:                try {
605:                    MimeMessage foundMessage = findMessage(key);
606:                    if (foundMessage == null) {
607:                        getLogger().error("found message is null!");
608:                        return null;
609:                    }
610:                    res = new MailImpl(foundMessage);
611:                    res.setName(key);
612:                    if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
613:                        StringBuffer logBuffer = new StringBuffer(128).append(
614:                                this .getClass().getName()).append(
615:                                " Retrieving entry for key ").append(key);
616:
617:                        getLogger().debug(logBuffer.toString());
618:                    }
619:                } catch (MessagingException e) {
620:                    getLogger().error(
621:                            "Unable to parse mime message for " + mboxFile
622:                                    + "\n" + e.getMessage(), e);
623:                }
624:                return res;
625:            }
626:
627:            /**
628:             * Remove an existing message
629:             * @param mail
630:             */
631:            public void remove(Mail mail) {
632:                ArrayList remArray = new ArrayList();
633:                remArray.add(mail);
634:                remove(remArray);
635:            }
636:
637:            /**
638:             * Attempt to get a lock on the mbox by creating
639:             * the file mboxname.lock
640:             * @throws Exception
641:             */
642:            private void lockMBox() throws Exception {
643:                // Create the lock file (if possible)
644:                String lockFileName = mboxFile + LOCKEXT;
645:                int sleepCount = 0;
646:                File mBoxLock = new File(lockFileName);
647:                if (!mBoxLock.createNewFile()) {
648:                    // This is not good, somebody got the lock before me
649:                    // So wait for a file
650:                    while (!mBoxLock.createNewFile()
651:                            && sleepCount < MAXSLEEPTIMES) {
652:                        try {
653:                            if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
654:                                StringBuffer logBuffer = new StringBuffer(128)
655:                                        .append(this .getClass().getName())
656:                                        .append(" Waiting for lock on file ")
657:                                        .append(mboxFile);
658:
659:                                getLogger().debug(logBuffer.toString());
660:                            }
661:
662:                            Thread.sleep(LOCKSLEEPDELAY);
663:                            sleepCount++;
664:                        } catch (InterruptedException e) {
665:                            getLogger().error(
666:                                    "File lock wait for " + mboxFile
667:                                            + " interrupted!", e);
668:
669:                        }
670:                    }
671:                    if (sleepCount >= MAXSLEEPTIMES) {
672:                        throw new Exception("Unable to get lock on file "
673:                                + mboxFile);
674:                    }
675:                }
676:            }
677:
678:            /**
679:             * Unlock a previously locked mbox file
680:             */
681:            private void unlockMBox() {
682:                // Just delete the MBOX file
683:                String lockFileName = mboxFile + LOCKEXT;
684:                File mBoxLock = new File(lockFileName);
685:                if (!mBoxLock.delete()) {
686:                    StringBuffer logBuffer = new StringBuffer(128).append(
687:                            this .getClass().getName()).append(
688:                            " Failed to delete lock file ")
689:                            .append(lockFileName);
690:                    getLogger().error(logBuffer.toString());
691:                }
692:            }
693:
694:            /**
695:             * Remove a list of messages from disk
696:             * The collection is simply a list of mails to delete
697:             * @param mails
698:             */
699:            public void remove(final Collection mails) {
700:                if ((DEEP_DEBUG) && (getLogger().isDebugEnabled())) {
701:                    StringBuffer logBuffer = new StringBuffer(128).append(
702:                            this .getClass().getName()).append(
703:                            " Removing entry for key ").append(mails);
704:
705:                    getLogger().debug(logBuffer.toString());
706:                }
707:                // The plan is as follows:
708:                // Attempt to locate the message in the file
709:                // by reading through the
710:                // once we've done that then seek to the file
711:                try {
712:                    RandomAccessFile ins = new RandomAccessFile(mboxFile, "r"); // The source
713:                    final RandomAccessFile outputFile = new RandomAccessFile(
714:                            mboxFile + WORKEXT, "rw"); // The destination
715:                    parseMboxFile(ins, new MessageAction() {
716:                        public boolean isComplete() {
717:                            return false;
718:                        }
719:
720:                        public MimeMessage messageAction(
721:                                String messageSeparator, String bodyText,
722:                                long messageStart) {
723:                            // Write out the messages as we go, until we reach the key we want
724:                            try {
725:                                String currentKey = generateKeyValue(bodyText);
726:                                boolean foundKey = false;
727:                                Iterator mailList = mails.iterator();
728:                                String key;
729:                                while (mailList.hasNext()) {
730:                                    // Attempt to find the current key in the array
731:                                    key = ((Mail) mailList.next()).getName();
732:                                    if (key.equals(currentKey)) {
733:                                        // Don't write the message to disk
734:                                        foundKey = true;
735:                                        break;
736:                                    }
737:                                }
738:                                if (foundKey == false) {
739:                                    // We didn't find the key in the array so we will keep it
740:                                    outputFile.writeBytes(messageSeparator
741:                                            + "\n");
742:                                    outputFile.writeBytes(bodyText);
743:
744:                                }
745:                            } catch (NoSuchAlgorithmException e) {
746:                                getLogger().error("MD5 not supported! ", e);
747:                            } catch (IOException e) {
748:                                getLogger().error(
749:                                        "Unable to write file (General I/O problem) "
750:                                                + mboxFile, e);
751:                            }
752:                            return null;
753:                        }
754:                    });
755:                    ins.close();
756:                    outputFile.close();
757:                    // Delete the old mbox file
758:                    File mbox = new File(mboxFile);
759:                    mbox.delete();
760:                    // And rename the lock file to be the new mbox
761:                    mbox = new File(mboxFile + WORKEXT);
762:                    if (!mbox.renameTo(new File(mboxFile))) {
763:                        System.out.println("Failed to rename file!");
764:                    }
765:
766:                    // Now delete the keys in mails from the main hash
767:                    Iterator mailList = mails.iterator();
768:                    String key;
769:                    while (mailList.hasNext()) {
770:                        // Attempt to find the current key in the array
771:                        key = ((Mail) mailList.next()).getName();
772:                        mList.remove(key);
773:                    }
774:
775:                } catch (FileNotFoundException e) {
776:                    getLogger().error(
777:                            "Unable to save(open) file (File not found) "
778:                                    + mboxFile, e);
779:                } catch (IOException e) {
780:                    getLogger().error(
781:                            "Unable to write file (General I/O problem) "
782:                                    + mboxFile, e);
783:                }
784:            }
785:
786:            /**
787:             * Remove a mail from the mbox file
788:             * @param key The key of the mail to delete
789:             */
790:            public void remove(String key) {
791:                loadKeys();
792:                try {
793:                    lockMBox();
794:                } catch (Exception e) {
795:                    getLogger().error("Lock failed!", e);
796:                    return; // No lock, so exit
797:                }
798:                ArrayList keys = new ArrayList();
799:                keys.add(retrieve(key));
800:
801:                this .remove(keys);
802:                unlockMBox();
803:            }
804:
805:            /**
806:             * Not implemented
807:             * @param key
808:             * @return
809:             */
810:            public boolean lock(String key) {
811:                return false;
812:            }
813:
814:            /**
815:             * Not implemented
816:             * @param key
817:             * @return
818:             */
819:            public boolean unlock(String key) {
820:                return false;
821:            }
822:
823:            /**
824:             * @see org.apache.avalon.framework.service.Serviceable#compose(ServiceManager )
825:             */
826:            public void service(final ServiceManager componentManager)
827:                    throws ServiceException {
828:            }
829:
830:            /**
831:             * Configure the component
832:             * @param conf
833:             * @throws ConfigurationException
834:             */
835:            public void configure(Configuration conf)
836:                    throws ConfigurationException {
837:                String destination;
838:                this .mList = null;
839:                BUFFERING = conf.getAttributeAsBoolean("BUFFERING", true);
840:                destination = conf.getAttribute("destinationURL");
841:                if (destination.charAt(destination.length() - 1) == '/') {
842:                    // Remove the trailing / as well as the protocol marker
843:                    mboxFile = destination.substring("mbox://".length(),
844:                            destination.lastIndexOf("/"));
845:                } else {
846:                    mboxFile = destination.substring("mbox://".length());
847:                }
848:
849:                if (getLogger().isDebugEnabled()) {
850:                    getLogger()
851:                            .debug(
852:                                    "MBoxMailRepository.destinationURL: "
853:                                            + destination);
854:                }
855:
856:                String checkType = conf.getAttribute("type");
857:                if (!(checkType.equals("MAIL") || checkType.equals("SPOOL"))) {
858:                    String exceptionString = "Attempt to configure MboxMailRepository as "
859:                            + checkType;
860:                    if (getLogger().isWarnEnabled()) {
861:                        getLogger().warn(exceptionString);
862:                    }
863:                    throw new ConfigurationException(exceptionString);
864:                }
865:            }
866:
867:            /**
868:             * Initialise the component
869:             * @throws Exception
870:             */
871:            public void initialize() throws Exception {
872:            }
873:
874:            public static void main(String[] args) {
875:                // Test invocation
876:                MBoxMailRepository mbx = new MBoxMailRepository();
877:                mbx.mboxFile = "C:\\java\\test\\1998-05.txt";
878:                Iterator mList = mbx.list();
879:                while (mList.hasNext()) {
880:                    //String key = (String) mList.next();
881:                    //System.out.println("key=" + key);
882:                    /*MailImpl mi =  mbx.retrieve(key);
883:                    try
884:                    {
885:                        System.out.println("Subject : " +  (mi.getMessage()).getSubject());
886:                    }
887:                    catch (MessagingException e)
888:                    {
889:                        e.printStackTrace();  //To change body of catch statement use Options | File Templates.
890:                    } */
891:
892:                }
893:
894:                /*        MailImpl mi = mbx.retrieve("ffffffb4ffffffe2f59fffffff291dffffffde4366243ffffff971d1f24");
895:                 try {
896:                 System.out.println("Subject : " + (mi.getMessage()).getSubject());
897:                 } catch (MessagingException e) {
898:                 e.printStackTrace();  //To change body of catch statement use Options | File Templates.
899:                 }
900:                 mbx.remove("ffffffb4ffffffe2f59fffffff291dffffffde4366243ffffff971d1f24");*/
901:            }
902:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.