Subversion Repositories javautils

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
  3.  * Copyright 2009 Jason Mehrens. All Rights Reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  *   - Redistributions of source code must retain the above copyright
  10.  *     notice, this list of conditions and the following disclaimer.
  11.  *
  12.  *   - Redistributions in binary form must reproduce the above copyright
  13.  *     notice, this list of conditions and the following disclaimer in the
  14.  *     documentation and/or other materials provided with the distribution.
  15.  *
  16.  *   - Neither the name of Sun Microsystems nor the names of its
  17.  *     contributors may be used to endorse or promote products derived
  18.  *     from this software without specific prior written permission.
  19.  *
  20.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  21.  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  22.  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  24.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  28.  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  29.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  30.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31.  */
  32.  
  33.  
  34. import java.io.*;
  35. import java.security.*;
  36. import java.util.logging.*;
  37.  
  38. /**
  39.  * An error manager used to store mime messages from the <tt>MailHandler</tt>
  40.  * to the file system when the email server is unavailable or unreachable.
  41.  * The code to manually setup this error manager can be as simple as the
  42.  * following:
  43.  * <tt><pre>
  44.  *      File dir = new File("path to dir");
  45.  *      FileErrorManager em = new FileErrorManager(dir);
  46.  * </pre></tt>
  47.  *
  48.  * <p>
  49.  * <b>Configuration:</b>
  50.  * The code to setup this error manager via the logging properties
  51.  * can be as simple as the following:
  52.  * <tt><pre>
  53.  *      #Default FileErrorManager settings.
  54.  *      com.sun.mail.util.logging.FileErrorManager.pattern = path to directory
  55.  * </pre></tt>
  56.  *
  57.  * If properties are not defined, or contain invalid values, then the specified
  58.  * default values are used.
  59.  * <ul>
  60.  * <li>com.sun.mail.util.logging.FileErrorManager.pattern the absolute file path
  61.  * to the directory which will store any failed email messages. (defaults
  62.  * to the value of the system property <tt>java.io.tmpdir</tt>)
  63.  * </ul>
  64.  *
  65.  * @author Jason Mehrens
  66.  */
  67. public class FileErrorManager extends ErrorManager {
  68.  
  69.     /**
  70.      * Stores the LogManager.
  71.      */
  72.     private static final LogManager manager = LogManager.getLogManager();
  73.     /**
  74.      * Used to report internal errors.
  75.      */
  76.     private final ErrorManager internal = new ErrorManager();
  77.     /**
  78.      * Directory of the email store.
  79.      */
  80.     private final File emailStore;
  81.  
  82.     /**
  83.      * Creates a new error manager.  Files are stored in the users temp
  84.      * directory.
  85.      * @exception SecurityException if unable to access system properties or
  86.      * if a security manager is present and unable to read or write to users
  87.      * temp directory.
  88.      */
  89.     public FileErrorManager() {
  90.         this.emailStore = getEmailStore();
  91.         init();
  92.     }
  93.  
  94.     /**
  95.      * Creates a new error manager.
  96.      * @param dir a directory to store the email files.
  97.      * @throws NullPointerException if <tt>dir</tt> is <tt>null</tt>
  98.      * @throws IllegalArgumentException if <tt>dir</tt> is a
  99.      * <tt>java.io.File</tt> subclass, not a directory, or is not an absolute
  100.      * path.
  101.      * @throws SecurityException if a security manager is present and unable
  102.      * to read or write to a given directory.
  103.      */
  104.     public FileErrorManager(File dir) {
  105.         this.emailStore = dir;
  106.         init();
  107.     }
  108.  
  109.     /**
  110.      * If the message parameter is a raw email, and passes the store term, then
  111.      * this method will store the email to the file system.  If the message
  112.      * parameter is not a raw email then the message is forwarded to the super
  113.      * class. If an email is written to the filesystem without error, then the
  114.      * orignal reported error is ignored.
  115.      * @param msg String raw email or plain error message.
  116.      * @param ex Exception that occured in the mail handler.
  117.      * @param code int error manager code.
  118.      */
  119.     public void error(String msg, Exception ex, int code) {
  120.         if (isRawEmail(msg, ex, code)) {
  121.             try {
  122.                 storeEmail(msg);
  123.             } catch (final IOException IOE) {
  124.                 super.error(msg, ex, code);
  125.                 internal.error(emailStore.toString(), IOE, ErrorManager.WRITE_FAILURE);
  126.             } catch (final RuntimeException RE) {
  127.                 super.error(msg, ex, code);
  128.                 internal.error(emailStore.toString(), RE, ErrorManager.WRITE_FAILURE);
  129.             }
  130.         } else {
  131.             super.error(msg, ex, code);
  132.         }
  133.     }
  134.  
  135.     private void init() {
  136.         File dir = this.emailStore;
  137.         if (dir.getClass() != File.class) { //for security.
  138.             throw new IllegalArgumentException(dir.getClass().getName());
  139.         }
  140.  
  141.         if (!dir.isDirectory()) {
  142.             throw new IllegalArgumentException("File must be a directory.");
  143.         }
  144.  
  145.         //For now, only absolute paths are allowed.
  146.         if (!dir.isAbsolute()) {
  147.             throw new IllegalArgumentException("Only absolute paths are allowed.");
  148.         }
  149.  
  150.         if (!dir.canRead()) { //Can throw under a security manager.
  151.             internal.error(dir.getAbsolutePath(),
  152.                     new SecurityException("read"), ErrorManager.OPEN_FAILURE);
  153.         }
  154.  
  155.         if (!dir.canWrite()) { //Can throw under a security manager.
  156.             internal.error(dir.getAbsolutePath(),
  157.                     new SecurityException("write"), ErrorManager.OPEN_FAILURE);
  158.         }
  159.     }
  160.  
  161.     private String prefixName() {
  162.         return "FileErrorManager";
  163.     }
  164.  
  165.     private String suffixName() {
  166.         return ".eml";
  167.     }
  168.  
  169.     private boolean isRawEmail(String msg, Exception ex, int code) {
  170.         if (msg != null && msg.length() > 0) {
  171.             return !msg.startsWith(Level.SEVERE.getName());
  172.         }
  173.         return false;
  174.     }
  175.  
  176.     private void storeEmail(String email) throws IOException {
  177.         File tmp = null;
  178.         FileOutputStream out = null;
  179.         for (;;) {
  180.             tmp = File.createTempFile(prefixName(), suffixName(), emailStore);
  181.             try {
  182.                 out = new FileOutputStream(tmp);
  183.                 break;
  184.             } catch (FileNotFoundException FNFE) {
  185.                 if (!tmp.exists()) { //retry if file is locked
  186.                     throw FNFE;
  187.                 }
  188.             }
  189.         }
  190.  
  191.         try {
  192.             PrintStream ps = new PrintStream(new NewlineOutputStream(out));
  193.             ps.print(email);
  194.             ps.flush();
  195.             tmp = null; //Don't delete 'tmp' if all bytes were written.
  196.             ps.close();
  197.  
  198.         } finally {
  199.             close(out);
  200.             delete(tmp); //Only deletes if not null.
  201.         }
  202.     }
  203.  
  204.     private void close(OutputStream out) {
  205.         if (out != null) {
  206.             try {
  207.                 out.close();
  208.             } catch (IOException IOE) {
  209.                 internal.error(out.toString(), IOE, ErrorManager.CLOSE_FAILURE);
  210.             }
  211.         }
  212.     }
  213.  
  214.     private void delete(File tmp) {
  215.         if (tmp != null) {
  216.             try {
  217.                 if (!tmp.delete() && tmp.exists()) {
  218.                     try {
  219.                         tmp.deleteOnExit();
  220.                     } catch (final RuntimeException shutdown) {
  221.                         if (!tmp.delete()) {
  222.                             internal.error(tmp.getAbsolutePath(), shutdown, ErrorManager.CLOSE_FAILURE);
  223.                         }
  224.                     }
  225.                 }
  226.             } catch (SecurityException SE) {
  227.                 internal.error(tmp.toString(), SE, ErrorManager.CLOSE_FAILURE);
  228.             }
  229.         }
  230.     }
  231.  
  232.     /**
  233.      * Gets the location of the email store.
  234.      * @return the File location.
  235.      */
  236.     private File getEmailStore() {
  237.         String dir = manager.getProperty(
  238.                 getClass().getName().concat(".pattern"));
  239.         if (dir == null) {
  240.             dir = (String) AccessController.doPrivileged(new PrivilegedAction() {
  241.  
  242.                 public Object run() {
  243.                     return System.getProperty("java.io.tmpdir", "");
  244.                 }
  245.             });
  246.         }
  247.         return new File(dir);
  248.     }
  249. }
  250.