/**
  * Writes the mail message to the given mail node.
  *
  * @param node mail node
  * @param mail mail message
  * @throws MessagingException if a messaging error occurs
  * @throws RepositoryException if a repository error occurs
  * @throws IOException if an IO error occurs
  */
 private void setMail(Node node, Mail mail)
     throws MessagingException, RepositoryException, IOException {
   setState(node, mail.getState());
   setLastUpdated(node, mail.getLastUpdated());
   setError(node, mail.getErrorMessage());
   setRemoteHost(node, mail.getRemoteHost());
   setRemoteAddr(node, mail.getRemoteAddr());
   setSender(node, mail.getSender());
   setRecipients(node, mail.getRecipients());
   setMessage(node, mail.getMessage());
   setAttributes(node, mail);
 }
 /**
  * Process this mail message by the appropriate processor as designated in the state of the Mail
  * object.
  *
  * @param mail the mail message to be processed
  */
 protected void process(Mail mail) {
   while (true) {
     String processorName = mail.getState();
     if (processorName.equals(Mail.GHOST)) {
       // This message should disappear
       return;
     }
     try {
       LinearProcessor processor = (LinearProcessor) processors.get(processorName);
       if (processor == null) {
         StringBuffer exceptionMessageBuffer =
             new StringBuffer(128)
                 .append("Unable to find processor ")
                 .append(processorName)
                 .append(" requested for processing of ")
                 .append(mail.getName());
         String exceptionMessage = exceptionMessageBuffer.toString();
         getLogger().debug(exceptionMessage);
         mail.setState(Mail.ERROR);
         throw new MailetException(exceptionMessage);
       }
       StringBuffer logMessageBuffer = null;
       if (getLogger().isDebugEnabled()) {
         logMessageBuffer =
             new StringBuffer(64)
                 .append("Processing ")
                 .append(mail.getName())
                 .append(" through ")
                 .append(processorName);
         getLogger().debug(logMessageBuffer.toString());
       }
       processor.service(mail);
       if (getLogger().isDebugEnabled()) {
         logMessageBuffer =
             new StringBuffer(128)
                 .append("Processed ")
                 .append(mail.getName())
                 .append(" through ")
                 .append(processorName);
         getLogger().debug(logMessageBuffer.toString());
         getLogger().debug("Result was " + mail.getState());
       }
       return;
     } catch (Throwable e) {
       // This is a strange error situation that shouldn't ordinarily
       // happen
       StringBuffer exceptionBuffer =
           new StringBuffer(64)
               .append("Exception in processor <")
               .append(processorName)
               .append(">");
       getLogger().error(exceptionBuffer.toString(), e);
       if (processorName.equals(Mail.ERROR)) {
         // We got an error on the error processor...
         // kill the message
         mail.setState(Mail.GHOST);
         mail.setErrorMessage(e.getMessage());
       } else {
         // We got an error... send it to the requested processor
         if (!(e instanceof MessagingException)) {
           // We got an error... send it to the error processor
           mail.setState(Mail.ERROR);
         }
         mail.setErrorMessage(e.getMessage());
       }
     }
     if (getLogger().isErrorEnabled()) {
       StringBuffer logMessageBuffer =
           new StringBuffer(128)
               .append("An error occurred processing ")
               .append(mail.getName())
               .append(" through ")
               .append(processorName);
       getLogger().error(logMessageBuffer.toString());
       getLogger().error("Result was " + mail.getState());
     }
   }
 }
  /** This routinely checks the message spool for messages, and processes them as necessary */
  public void run() {

    if (getLogger().isInfoEnabled()) {
      getLogger().info("Run JamesSpoolManager: " + Thread.currentThread().getName());
      getLogger().info("Spool=" + spool.getClass().getName());
    }

    numActive++;
    while (active) {
      String key = null;
      try {
        Mail mail = (Mail) spool.accept();
        key = mail.getName();
        if (getLogger().isDebugEnabled()) {
          StringBuffer debugBuffer =
              new StringBuffer(64)
                  .append("==== Begin processing mail ")
                  .append(mail.getName())
                  .append("====");
          getLogger().debug(debugBuffer.toString());
        }
        process(mail);
        // Only remove an email from the spool is processing is
        // complete, or if it has no recipients
        if ((Mail.GHOST.equals(mail.getState()))
            || (mail.getRecipients() == null)
            || (mail.getRecipients().size() == 0)) {
          ContainerUtil.dispose(mail);
          spool.remove(key);
          if (getLogger().isDebugEnabled()) {
            StringBuffer debugBuffer =
                new StringBuffer(64)
                    .append("==== Removed from spool mail ")
                    .append(key)
                    .append("====");
            getLogger().debug(debugBuffer.toString());
          }
        } else {
          // spool.remove() has a side-effect!  It unlocks the
          // message so that other threads can work on it!  If
          // we don't remove it, we must unlock it!
          spool.store(mail);
          ContainerUtil.dispose(mail);
          spool.unlock(key);
          // Do not notify: we simply updated the current mail
          // and we are able to reprocess it now.
        }
        mail = null;
      } catch (InterruptedException ie) {
        getLogger().info("Interrupted JamesSpoolManager: " + Thread.currentThread().getName());
      } catch (Throwable e) {
        if (getLogger().isErrorEnabled()) {
          getLogger()
              .error(
                  "Exception processing " + key + " in JamesSpoolManager.run " + e.getMessage(), e);
        }
        /* Move the mail to ERROR state?  If we do, it could be
         * deleted if an error occurs in the ERROR processor.
         * Perhaps the answer is to resolve that issue by
         * having a special state for messages that are not to
         * be processed, but aren't to be deleted?  The message
         * would already be in the spool, but would not be
         * touched again.
        if (mail != null) {
            try {
                mail.setState(Mail.ERROR);
                spool.store(mail);
            }
        }
        */
      }
    }
    if (getLogger().isInfoEnabled()) {
      getLogger().info("Stop JamesSpoolManager: " + Thread.currentThread().getName());
    }
    numActive--;
  }