📄 remotedelivery.java
字号:
/*********************************************************************** * Copyright (c) 2000-2004 The Apache Software Foundation. * * All rights reserved. * * ------------------------------------------------------------------- * * Licensed under the Apache License, Version 2.0 (the "License"); you * * may not use this file except in compliance with the License. You * * may obtain a copy of the License at: * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * * implied. See the License for the specific language governing * * permissions and limitations under the License. * ***********************************************************************/package org.apache.james.transport.mailets;import java.io.PrintWriter;import java.io.StringWriter;import java.net.ConnectException;import java.net.InetAddress;import java.net.SocketException;import java.net.UnknownHostException;import java.util.Arrays;import java.util.Collection;import java.util.Date;import java.util.Hashtable;import java.util.HashMap;import java.util.Iterator;import java.util.Locale;import java.util.Properties;import java.util.StringTokenizer;import java.util.Vector;import java.util.ArrayList;import javax.mail.Address;import javax.mail.MessagingException;import javax.mail.SendFailedException;import javax.mail.Session;import javax.mail.Transport;import javax.mail.URLName;import javax.mail.internet.AddressException;import javax.mail.internet.InternetAddress;import javax.mail.internet.MimeMessage;import javax.mail.internet.ParseException;import org.apache.avalon.framework.component.ComponentException;import org.apache.avalon.framework.component.ComponentManager;import org.apache.avalon.framework.configuration.DefaultConfiguration;import org.apache.james.Constants;import org.apache.james.core.MailImpl;import org.apache.james.services.MailServer;import org.apache.james.services.MailStore;import org.apache.james.services.SpoolRepository;import org.apache.mailet.MailetContext;import org.apache.mailet.GenericMailet;import org.apache.mailet.HostAddress;import org.apache.mailet.Mail;import org.apache.mailet.MailAddress;import org.apache.oro.text.regex.MalformedPatternException;import org.apache.oro.text.regex.Pattern;import org.apache.oro.text.regex.Perl5Compiler;import org.apache.oro.text.regex.Perl5Matcher;import org.apache.oro.text.regex.MatchResult;/** * Receives a MessageContainer from JamesSpoolManager and takes care of delivery * the message to remote hosts. If for some reason mail can't be delivered * store it in the "outgoing" Repository and set an Alarm. After the next "delayTime" the * Alarm will wake the servlet that will try to send it again. After "maxRetries" * the mail will be considered undeliverable and will be returned to sender. * * TO DO (in priority): * 1. Support a gateway (a single server where all mail will be delivered) (DONE) * 2. Provide better failure messages (DONE) * 3. More efficiently handle numerous recipients * 4. Migrate to use Phoenix for the delivery threads * * You really want to read the JavaMail documentation if you are * working in here, and you will want to view the list of JavaMail * attributes, which are documented here: * * http://java.sun.com/products/javamail/1.3/docs/javadocs/com/sun/mail/smtp/package-summary.html * * as well as other places. * * @version CVS $Revision: 1.33.4.21 $ $Date: 2004/05/02 06:08:37 $ */public class RemoteDelivery extends GenericMailet implements Runnable { private static final long DEFAULT_DELAY_TIME = 21600000; // default is 6*60*60*1000 millis (6 hours) private static final String PATTERN_STRING = "\\s*([0-9]*\\s*[\\*])?\\s*([0-9]+)\\s*([a-z,A-Z]*)\\s*";//pattern to match //[attempts*]delay[units] private static Pattern PATTERN = null; //the compiled pattern of the above String private static final HashMap MULTIPLIERS = new HashMap (10); //holds allowed units for delaytime together with //the factor to turn it into the equivalent time in msec /* * Static initializer.<p> * Compiles pattern for processing delaytime entries.<p> * Initializes MULTIPLIERS with the supported unit quantifiers */ static { try { Perl5Compiler compiler = new Perl5Compiler(); PATTERN = compiler.compile(PATTERN_STRING, Perl5Compiler.READ_ONLY_MASK); } catch(MalformedPatternException mpe) { //this should not happen as the pattern string is hardcoded. System.err.println ("Malformed pattern: " + PATTERN_STRING); mpe.printStackTrace (System.err); } //add allowed units and their respective multiplier MULTIPLIERS.put ("msec", new Integer (1)); MULTIPLIERS.put ("msecs", new Integer (1)); MULTIPLIERS.put ("sec", new Integer (1000)); MULTIPLIERS.put ("secs", new Integer (1000)); MULTIPLIERS.put ("minute", new Integer (1000*60)); MULTIPLIERS.put ("minutes", new Integer (1000*60)); MULTIPLIERS.put ("hour", new Integer (1000*60*60)); MULTIPLIERS.put ("hours", new Integer (1000*60*60)); MULTIPLIERS.put ("day", new Integer (1000*60*60*24)); MULTIPLIERS.put ("days", new Integer (1000*60*60*24)); } /** * This filter is used in the accept call to the spool. * It will select the next mail ready for processing according to the mails * retrycount and lastUpdated time **/ private class MultipleDelayFilter implements SpoolRepository.AcceptFilter { /** * holds the time to wait for the youngest mail to get ready for processing **/ long youngest = 0; /** * Uses the getNextDelay to determine if a mail is ready for processing based on the delivered parameters * errorMessage (which holds the retrycount), lastUpdated and state * @param key the name/key of the message * @param state the mails state * @param lastUpdated the mail was last written to the spool at this time. * @param errorMessage actually holds the retrycount as a string (see failMessage below) **/ public boolean accept (String key, String state, long lastUpdated, String errorMessage) { if (state.equals(Mail.ERROR)) { //Test the time... int retries = Integer.parseInt(errorMessage); long delay = getNextDelay (retries); long timeToProcess = delay + lastUpdated; if (System.currentTimeMillis() > timeToProcess) { //We're ready to process this again return true; } else { //We're not ready to process this. if (youngest == 0 || youngest > timeToProcess) { //Mark this as the next most likely possible mail to process youngest = timeToProcess; } return false; } } else { //This mail is good to go... return the key return true; } } /** * @return the optimal time the SpoolRepository.accept(AcceptFilter) method should wait before * trying to find a mail ready for processing again. **/ public long getWaitTime () { if (youngest == 0) { return 0; } else { long duration = youngest - System.currentTimeMillis(); youngest = 0; //get ready for next run return duration <= 0 ? 1 : duration; } } } /** * Controls certain log messages */ private boolean isDebug = false; private SpoolRepository outgoing; // The spool of outgoing mail private long[] delayTimes; //holds expanded delayTimes private int maxRetries = 5; // default number of retries private long smtpTimeout = 600000; //default number of ms to timeout on smtp delivery private boolean sendPartial = false; // If false then ANY address errors will cause the transmission to fail private int connectionTimeout = 60000; // The amount of time JavaMail will wait before giving up on a socket connect() private int deliveryThreadCount = 1; // default number of delivery threads private Collection gatewayServer = null; // the server(s) to send all email to private String bindAddress = null; // JavaMail delivery socket binds to this local address. If null the JavaMail default will be used. private boolean isBindUsed = false; // true, if the bind configuration // parameter is supplied, RemoteDeliverySocketFactory // will be used in this case private Collection deliveryThreads = new Vector(); private MailServer mailServer; private volatile boolean destroyed = false; //Flag that the run method will check and end itself if set to true private String bounceProcessor = null; // the processor for creating Bounces private Perl5Matcher delayTimeMatcher; //matcher use at init time to parse delaytime parameters private MultipleDelayFilter delayFilter = new MultipleDelayFilter ();//used by accept to selcet the next mail ready for processing /** * Initialize the mailet */ public void init() throws MessagingException { isDebug = (getInitParameter("debug") == null) ? false : new Boolean(getInitParameter("debug")).booleanValue(); ArrayList delay_times_list = new ArrayList(); try { if (getInitParameter("delayTime") != null) { delayTimeMatcher = new Perl5Matcher(); String delay_times = getInitParameter("delayTime"); //split on comma's StringTokenizer st = new StringTokenizer (delay_times,","); while (st.hasMoreTokens()) { String delay_time = st.nextToken(); delay_times_list.add (new Delay(delay_time)); } } else { //use default delayTime. delay_times_list.add (new Delay()); } } catch (Exception e) { log("Invalid delayTime setting: " + getInitParameter("delayTime")); } try { if (getInitParameter("maxRetries") != null) { maxRetries = Integer.parseInt(getInitParameter("maxRetries")); } //check consistency with delay_times_list attempts int total_attempts = calcTotalAttempts (delay_times_list); if (total_attempts > maxRetries) { log("Total number of delayTime attempts exceeds maxRetries specified. Increasing maxRetries from "+maxRetries+" to "+total_attempts); maxRetries = total_attempts; } else { int extra = maxRetries - total_attempts; if (extra != 0) { log("maxRetries is larger than total number of attempts specified. Increasing last delayTime with "+extra+" attempts "); if (delay_times_list.size() != 0) { Delay delay = (Delay)delay_times_list.get (delay_times_list.size()-1); //last Delay delay.setAttempts (delay.getAttempts()+extra); log("Delay of "+delay.getDelayTime()+" msecs is now attempted: "+delay.getAttempts()+" times"); } else { log ("NO, delaytimes cannot continue"); } } } delayTimes = expandDelays (delay_times_list); } catch (Exception e) { log("Invalid maxRetries setting: " + getInitParameter("maxRetries")); } try { if (getInitParameter("timeout") != null) { smtpTimeout = Integer.parseInt(getInitParameter("timeout")); } } catch (Exception e) { log("Invalid timeout setting: " + getInitParameter("timeout")); } try { if (getInitParameter("connectiontimeout") != null) { connectionTimeout = Integer.parseInt(getInitParameter("connectiontimeout")); } } catch (Exception e) { log("Invalid timeout setting: " + getInitParameter("timeout")); } sendPartial = (getInitParameter("sendpartial") == null) ? false : new Boolean(getInitParameter("sendpartial")).booleanValue(); bounceProcessor = getInitParameter("bounceProcessor"); String gateway = getInitParameter("gateway"); String gatewayPort = getInitParameter("gatewayPort");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -