📄 remotedelivery.java
字号:
/**************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * * or more contributor license agreements. See the NOTICE file * * distributed with this work for additional information * * regarding copyright ownership. The ASF licenses this file * * to you 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 org.apache.avalon.cornerstone.services.store.Store;import org.apache.avalon.framework.configuration.DefaultConfiguration;import org.apache.avalon.framework.container.ContainerUtil;import org.apache.avalon.framework.service.ServiceException;import org.apache.avalon.framework.service.ServiceManager;import org.apache.james.Constants;import org.apache.james.services.SpoolRepository;import org.apache.mailet.GenericMailet;import org.apache.mailet.HostAddress;import org.apache.mailet.Mail;import org.apache.mailet.MailAddress;import org.apache.mailet.MailetContext;import org.apache.oro.text.regex.MalformedPatternException;import org.apache.oro.text.regex.MatchResult;import org.apache.oro.text.regex.Pattern;import org.apache.oro.text.regex.Perl5Compiler;import org.apache.oro.text.regex.Perl5Matcher;import com.sun.mail.smtp.SMTPAddressFailedException;import com.sun.mail.smtp.SMTPAddressSucceededException;import com.sun.mail.smtp.SMTPSendFailedException;import com.sun.mail.smtp.SMTPTransport;import javax.mail.Address;import javax.mail.MessagingException;import javax.mail.SendFailedException;import javax.mail.Session;import javax.mail.Transport;import javax.mail.internet.InternetAddress;import javax.mail.internet.MimeMessage;import javax.mail.internet.MimeMultipart;import javax.mail.internet.MimePart;import javax.mail.internet.ParseException;import java.io.IOException;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.ArrayList;import java.util.Arrays;import java.util.Collection;import java.util.Date;import java.util.HashMap;import java.util.Hashtable;import java.util.Iterator;import java.util.Locale;import java.util.Properties;import java.util.StringTokenizer;import java.util.Vector;/** * 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: 494056 $ $Date: 2007-01-08 14:15:03 +0100 (Mo, 08 Jan 2007) $ */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); // If the retries count is 0 we should try to send the mail now! if (retries == 0) return true; 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 = 180000; //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 authUser = null; // auth for gateway server private String authPass = null; // password for gateway server 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 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 private Properties defprops = new Properties(); // default properties for the javamail Session /** * 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")); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -