You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ba...@apache.org on 2008/06/24 12:34:17 UTC

svn commit: r671119 [2/2] - in /james/server/trunk/mailets-function/src/test/java/org: ./ apache/ apache/james/ apache/james/transport/ apache/james/transport/mailets/ apache/james/transport/remotedeliverytester/

Added: james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/Tester.java
URL: http://svn.apache.org/viewvc/james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/Tester.java?rev=671119&view=auto
==============================================================================
--- james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/Tester.java (added)
+++ james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/Tester.java Tue Jun 24 03:34:16 2008
@@ -0,0 +1,659 @@
+/****************************************************************
+ * 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.remotedeliverytester;
+
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.james.core.MailImpl;
+import org.apache.james.dnsserver.TemporaryResolutionException;
+import org.apache.james.services.DNSServer;
+import org.apache.mailet.HostAddress;
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+
+import javax.mail.Address;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.NoSuchProviderException;
+import javax.mail.Provider;
+import javax.mail.SendFailedException;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.URLName;
+import javax.mail.Provider.Type;
+import javax.mail.internet.MimeMessage;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Vector;
+
+/**
+ * Email lifecycle 
+ * - in mailet.service it is accepted and sent to outgoing spool (an outgoing.store for each recipient).
+ * - another thread pool, in mailtet.run it is accepted from the outgoing spool and sent to the "deliver" method.
+ * - "deliver" calls transport.connect and transport.sendMessage from javaMail
+ * - on delivery error a call to "failMessage" is done. failMessage will call mailetContext.sendMail or mailetContext.bounce to send a delivery failure receipt.
+ * - Back to "run" results in outgoing.remove (permanent result) or outgoing.store (temporary failure)
+ */
+public class Tester {
+    private RemoteDeliveryTestable remoteDelivery;
+    private TesterMailetConfig mailetConfig;
+    
+    private HashMap procMails = new HashMap(); 
+    private HashMap procMailsByName = new HashMap();
+    
+    private TransportRule genericRule = null;
+    private Hashtable serverRules = new Hashtable();
+    private TestStatus testStatus = new TestStatus();
+
+    private Hashtable hostAddresses = new Hashtable();
+    private Hashtable domainsAssociated = new Hashtable();
+    private DNSServer dnsServer = new DNSServer() {
+
+        public Collection findMXRecords(String hostname)
+                throws TemporaryResolutionException {
+            throw new UnsupportedOperationException("DNSServer stub");
+        }
+
+        public Collection findTXTRecords(String hostname) {
+            throw new UnsupportedOperationException("DNSServer stub");
+        }
+
+        public InetAddress[] getAllByName(String host)
+                throws UnknownHostException {
+            throw new UnsupportedOperationException("DNSServer stub");
+        }
+
+        public InetAddress getByName(String host)
+                throws UnknownHostException {
+            throw new UnsupportedOperationException("DNSServer stub");
+        }
+
+        public String getHostName(InetAddress addr) {
+            throw new UnsupportedOperationException("DNSServer stub");
+        }
+
+        public InetAddress getLocalHost() throws UnknownHostException {
+            throw new UnsupportedOperationException("DNSServer stub");
+        }
+
+        public Iterator getSMTPHostAddresses(final String domainName)
+                throws TemporaryResolutionException {
+            return onMailetContextGetSMTPHostAddresses(domainName);
+        }
+        
+    };
+    
+    private static Tester instance;
+    
+    /**
+     * Get the last static instance.
+     * Works only in a single Tester environment.
+     */
+    public static Tester getInstance() {
+        return instance;
+    }
+
+    public Tester(RemoteDeliveryTestable remoteDelivery) {
+        this.remoteDelivery = remoteDelivery;
+        remoteDelivery.setRemoteDeliveryTester(this);
+        
+        //if (Tester.instance == null) 
+        Tester.instance = this;
+    }
+        
+    public void init(ServiceManager serviceManager, Properties mailetConfigProperties) throws MessagingException {
+        mailetConfig = new TesterMailetConfig(this, mailetConfigProperties, serviceManager);
+        remoteDelivery.init(mailetConfig);
+        // do this after the init because init would override it.
+        remoteDelivery.setDNSServer(dnsServer);
+        
+        if (mailetConfig.getWrappedSpoolRepository() != null) log("DEBUG", "Init WrappedSpoolRepository OK");
+        else {
+            log("WARN", "Init WrappedSpoolRepository ERROR");
+            //throw new IllegalStateException();
+        }
+        
+        Session session = obtainSession(new Properties());
+        Transport t = session.getTransport("smtp");
+        if (t instanceof SMTPTransport) log("DEBUG", "Init WrappedSMTPTransport OK");
+        else {
+            log("ERROR", "Init WrappedSMTPTransport ERROR");
+            throw new IllegalStateException();
+        }
+    }
+    
+    public Session obtainSession(Properties props) {
+        /**
+         * Javamail1.4 allows for providers to be specified
+         */
+        
+        props.put("mail.smtp.class", SMTPTransport.class.getName());
+        props.put("Tester", this);
+        Session s = Session.getInstance(props);
+        // Session s = Session.getDefaultInstance(props);
+        try {
+            if (!((s.getTransport("smtp")) instanceof SMTPTransport))
+                s.setProvider(new Provider(Type.TRANSPORT, "smtp", SMTPTransport.class.getName(), "test", "0"));
+        } catch (NoSuchProviderException e) {
+          // Let's do it twice, don't remember why.
+          try {
+                        s.setProvider(new Provider(Type.TRANSPORT, "smtp", SMTPTransport.class.getName(), "test", "0"));
+                    } catch (NoSuchProviderException e1) {
+                        e1.printStackTrace();
+                    }
+            e.printStackTrace();
+        }
+        return s;
+    }
+
+    protected void log(String type, String message) {
+        System.out.println("<RDT:" + type + "> " + message);
+    }
+    
+    public ProcMail.Listing service(String name, String fromMail, String toMail, String body) throws MessagingException {
+        return service(name, fromMail, new String[] {toMail}, body, null);
+    }
+        
+    public ProcMail.Listing service(String name, String fromMail, String toMail, String body, TransportRule rule) throws MessagingException {
+        return service(name, fromMail, new String[] {toMail}, body, rule);
+    }
+
+    public ProcMail.Listing service(String name, String fromMail, String[] toMail, String body) throws MessagingException {
+        return service(name, fromMail, toMail, body, null);
+    }
+        
+    public ProcMail.Listing service(String name, String fromMail, String[] toMail, String body, TransportRule rule) throws MessagingException {
+        MimeMessage mm = new MimeMessage(Session.getInstance(new Properties()));
+        mm.setSubject(name);
+        mm.setText(body);
+//      MimeMessageInputStreamSource mmis = new MimeMessageInputStreamSource("test", new SharedByteArrayInputStream((body).getBytes()));
+        Collection recipients = new ArrayList();
+        for (int i = 0; i < toMail.length; i++) recipients.add(new MailAddress(toMail[i]));
+//      MailImpl mail = new MailImpl(name, new MailAddress(fromMail), recipients, new MimeMessageWrapper(mmis));
+        MailImpl mail = new MailImpl(name, new MailAddress(fromMail), recipients, mm);
+        return service(mail, rule);
+    }
+    
+    public ProcMail.Listing service(Mail mail) throws MessagingException {
+        return service(mail, null);
+    }
+
+    public ProcMail.Listing service(Mail mail, TransportRule rule) throws MessagingException {
+        ProcMail.Listing listing = new ProcMail.Listing();
+        Iterator recipients = mail.getRecipients().iterator();
+        while (recipients.hasNext()) {
+            MailAddress address = (MailAddress)recipients.next();
+            ProcMail pmail = new ProcMail(this, mail, address);
+            pmail.setTransportRule(rule);
+            storeProcMail(pmail);
+            listing.add(pmail);
+        }
+        remoteDelivery.service(mail);
+        return listing;
+    }
+
+    public TestStatus getTestStatus() {
+        return testStatus;
+    }
+
+    public Collection getProcMails() {
+        return procMails.values();
+    }
+    
+    public ProcMail getProcMail(Mail mail, MailAddress recipient) {
+        return getProcMailByKey(ProcMail.getKey(mail, recipient));
+    }
+    
+    public ProcMail getProcMail(Message message, Address address) {
+        return getProcMailByKey(ProcMail.getKey(message, address));
+    }
+        
+    public ProcMail getProcMailByKey(String key) {
+        return (ProcMail) procMails.get(key);
+    }
+    
+    public ProcMail getProcMail(String name) {
+        return (ProcMail) procMailsByName.get(name);
+    }
+
+    public void storeProcMail(ProcMail pmail) {
+        procMails.put(pmail.getKey(), pmail);
+        procMailsByName.put(pmail.getMailName(), pmail);
+        log("DEBUG", "Stored procmail: "+pmail.getKey());
+    }
+    
+    private String getServerName(URLName urlname) {
+        return urlname.toString();
+    }
+    
+    public void setGenericRule(TransportRule rule) {
+        genericRule = rule;
+    }
+
+    public void addDomainServer(String domain, String url) {
+        if (!hostAddresses.containsKey(domain)) hostAddresses.put(domain, new Vector());
+        ((Vector)hostAddresses.get(domain)).add(new HostAddress(domain, url));
+        domainsAssociated.put(url, domain);
+    }
+
+    public void addServerRule(String url, TransportRule rule) {
+        serverRules.put(getServerName(new URLName(url)), rule);
+    }
+
+    public void addDomainServer(String domain, String url, TransportRule rule) {
+        addDomainServer(domain, url);
+        addServerRule(url, rule);
+    }
+    
+    public String getDomainAssociated(String server) {
+        return (String) domainsAssociated.get(server);
+    }
+
+    public Iterator onMailetContextGetSMTPHostAddresses(String domainName) {
+        return ((List)hostAddresses.get(domainName)).iterator();
+    }
+    
+    public void onTransportConnect(SMTPTransport tester) throws MessagingException {
+        String server = getServerName(tester.getURLName());
+        log("TRANSPORT", "Connection to " + server);
+        
+        Exception ex = null;
+        try {
+            if (serverRules.containsKey(server)) ((TransportRule)serverRules.get(server)).onConnect(testStatus, server);
+            if (genericRule != null) genericRule.onConnect(testStatus, server);
+        } catch (MessagingException e) {
+            ex = e;
+        } catch (RuntimeException e) {
+            ex = e;
+        }
+
+        testStatus.incTransportConnectionCount(1);
+        testStatus.incTransportServerConnectionCount(server, 1);
+
+        if (ex != null) {
+            if (ex instanceof MessagingException) throw (MessagingException)ex;
+            if (ex instanceof RuntimeException) throw (RuntimeException)ex;
+        }
+    }
+
+    public void onTransportSendMessage(SMTPTransport tester, Message message, Address[] recipients) throws MessagingException, SendFailedException {
+        String server = getServerName(tester.getURLName());
+        ProcMail.Listing listing = new ProcMail.Listing();
+        Vector rules = new Vector();
+        for (int i = 0; i < recipients.length; i++) {
+            ProcMail pmail = getProcMail(message, recipients[i]);
+            log("TRANSPORT.SEND", "Preparing send " + pmail.getKey() + " to " + server);
+            
+            if (pmail == null) throw new IllegalStateException("Unknow mail for " + recipients[i]);
+            listing.add(pmail);
+            if (pmail.getTransportRule() != null && !rules.contains(pmail.getTransportRule())) rules.add(pmail.getTransportRule());
+        }
+        
+        Exception ex = null;
+        try {
+            
+            log("TRANSPORT.SEND", "Sending to " + server + ", applying " + rules.size() + " mail rules");
+            for (int i = 0; i < rules.size(); i++) ((TransportRule) rules.get(i)).onSendMessage(testStatus, server, listing); 
+            
+            if (serverRules.containsKey(server)) ((TransportRule)serverRules.get(server)).onSendMessage(testStatus, server, listing);
+            if (genericRule != null) genericRule.onSendMessage(testStatus, server, listing);
+            
+        } catch (SendFailedException e) {
+            ex = e;
+        } catch (MessagingException e) {
+            ex = e;
+        } catch (RuntimeException e) {
+            ex = e;
+        }
+        
+        if (ex != null) log("TRANSPORT.SEND", "Got Exception " + dumpException(ex));
+        
+        // If we got a sendFailed then the specific recipient could be OK
+        Address[] validAddresses = ex instanceof SendFailedException ? ((SendFailedException)ex).getValidSentAddresses() : null;
+        for (int i = 0; i < listing.size(); i++) {
+            ProcMail pmail = listing.get(i);
+            boolean valid = false;
+            if (validAddresses != null) 
+                for (int j = 0; !valid && j < validAddresses.length; j++)
+                    valid = pmail.getRecipient().toString().equals(validAddresses[j].toString());
+            
+            pmail.sent(server, !valid ? ex : null);
+//          System.out.println("--------------------\r\n");
+//          System.out.println("0. " + server + " " + pmail + " " + pmail.getKey() + " " + pmail.getSendCount() + valid + "\r\n");
+//          System.out.println("--------------------\r\n");
+
+            testStatus.incTransportSendCount(1);
+            testStatus.incTransportServerSendCount(server, 1);
+            if (ex == null || valid) {
+                testStatus.incTransportSendSuccessfullCount(1);
+                testStatus.incTransportServerSendSuccessfullCount(server, 1);
+            } else {
+                testStatus.incTransportSendFailedCount(1);
+                testStatus.incTransportServerSendFailedCount(server, 1);
+            }
+        }
+
+        if (ex != null) {
+            if (ex instanceof SendFailedException) throw (SendFailedException)ex;
+            if (ex instanceof MessagingException) throw (MessagingException)ex;
+            if (ex instanceof RuntimeException) throw (RuntimeException)ex;
+        }
+
+    }
+
+    private String dumpException(Exception ex) {
+        if (!(ex instanceof MessagingException)) return ex.toString();
+        
+        StringBuffer res = new StringBuffer();
+        String exs = ex.getMessage();
+        int p = exs.indexOf("nested exception is:");
+        if (p >= 0) exs = exs.substring(0, p - 3);
+        res.append(exs);
+        //res.append(ex.toString());
+        
+        while (ex != null && (ex instanceof MessagingException)) {
+            res.append(" > ");
+            if (ex instanceof SMTPSendFailedException) res.append("smtpsfe" + ((SMTPSendFailedException)ex).getReturnCode()); else
+            if (ex instanceof SMTPAddressFailedException) res.append("smtpafe" + ((SMTPAddressFailedException)ex).getReturnCode()); else
+            if (ex instanceof SMTPAddressSucceededException) res.append("smtpase" + ((SMTPAddressSucceededException)ex).getReturnCode()); else
+            if (ex instanceof SendFailedException) res.append("sfe"); else
+            if (ex instanceof NullPointerException) res.append("null"); else 
+            res.append("me");
+            ex = ((MessagingException)ex).getNextException();
+        }
+        
+        return res.toString();
+    }
+
+    public void onTransportClose(SMTPTransport tester) throws MessagingException {
+        String server = getServerName(tester.getURLName());
+        log("TRANSPORT", "Closing connection to " + server);
+        
+        Exception ex = null;
+        try {
+            if (serverRules.containsKey(server)) ((TransportRule)serverRules.get(server)).onClose(testStatus, server);
+            if (genericRule != null) genericRule.onClose(testStatus, server);
+        } catch (MessagingException e) {
+            ex = e;
+        } catch (RuntimeException e) {
+            ex = e;
+        }
+
+        testStatus.incTransportCloseCount(1);
+        testStatus.incTransportServerCloseCount(server, 1);
+
+        if (ex != null) {
+            if (ex instanceof MessagingException) throw (MessagingException)ex;
+            if (ex instanceof RuntimeException) throw (RuntimeException)ex;
+        }
+    }
+
+    public boolean OnTransportSupportsExtension(SMTPTransport tester, String arg0) {
+        String server = getServerName(tester.getURLName());
+        log("TRANSPORT", "Asking if " + server + " supports " + arg0);
+        
+        boolean value = false;
+        if (serverRules.containsKey(server)) value = ((TransportRule)serverRules.get(server)).onSupportsExtension(testStatus, server, arg0, value);
+        if (genericRule != null) value = genericRule.onSupportsExtension(testStatus, server, arg0, value);
+        
+        return value;
+    }
+    
+    public void onMailetContextBounce(Mail mail, String message) {
+        throw new UnsupportedOperationException("Not supported old bounce method");
+    }
+
+    public void onMailetContextSendMail(Mail mail) {
+        Iterator recipients = mail.getRecipients().iterator();
+        while (recipients.hasNext()) {
+            MailAddress address = (MailAddress)recipients.next();
+            ProcMail pmail = getProcMail(mail, address);
+            if (pmail != null) onMailetContextSendMail(pmail, mail);
+            else throw new IllegalStateException("No ProcMail on " + address);
+        }
+    }
+    
+    public void onMailetContextSendMail(ProcMail pmail, Mail mail) {
+        pmail.bounced(mail);
+        testStatus.incBouncedCount(1);
+    }
+
+    protected void onOutgoingStore(Mail mail) {
+//  acceptedProcMailList.set(null);
+//  
+//  Iterator recipients = mail.getRecipients().iterator();
+//  while (recipients.hasNext()) {
+//      MailAddress address = (MailAddress)recipients.next();
+//      ProcMail pmail = getProcMail(mail, address);
+//      if (pmail == null) {
+//          // (1) Chiamato per primo quando la mail viene accettata e messa nello spool
+//          pmail = new ProcMail(this, mail, address);
+//          storeProcMail(pmail);
+//          onOutgoingStoreStart(pmail, mail);
+//      } else {
+//          // (5b) E anche per ultimo se la mail ha degli errori temporanei
+//          onOutgoingStoreEnd(pmail, mail);
+//      }
+//  }
+}
+
+protected void onOutgoingAccept(Mail mail) {
+//  Vector l = new Vector();
+//  acceptedProcMailList.set(l);
+//  
+//  // (2) Chiamato per secondo, quando la mail viene presa in carico per la spedizione
+//  Iterator recipients = mail.getRecipients().iterator();
+//  while (recipients.hasNext()) {
+//      MailAddress address = (MailAddress)recipients.next();
+//      ProcMail pmail = getProcMail(mail, address);
+//      if (pmail != null) {
+//          onOutgoingAccept(pmail, mail);
+//          l.add(new Object[] {pmail, mail});
+//      }
+//      else throw new IllegalStateException("No ProcMail on " + address);
+//  }
+}
+
+protected void onOutgoingRemove(Mail mail) {
+//  // (5a) Chiamato per ultimo se la mail è OK o ha avuto errori permanenti 
+//  Iterator recipients = mail.getRecipients().iterator();
+//  while (recipients.hasNext()) {
+//      MailAddress address = (MailAddress)recipients.next();
+//      ProcMail pmail = getProcMail(mail, address);
+//      if (pmail != null) onOutgoingRemove(pmail, mail);
+//      else throw new IllegalStateException("No ProcMail on " + address);
+//  }
+}
+
+protected void onOutgoingRemove(String key) {
+//  // (5a) Chiamato per ultimo se la mail è OK o ha avuto errori permanenti
+//  
+//  // Cerca la stessa chiave tra le ultime accettate (dovrebbero averla tutte)
+//  Vector l = (Vector) acceptedProcMailList.get();
+//  if (l != null) 
+//      for (int i = 0; i < l.size(); i++) {
+//          ProcMail pmail = (ProcMail)((Object[])l.get(i))[0];
+//          Mail mail = (Mail)((Object[])l.get(i))[1];
+//          if (!pmail.getMailName().equals(key)) throw new IllegalStateException("Mail not recognized."); 
+//          onOutgoingRemove(pmail, mail);
+//      }
+}
+
+//protected void onOutgoingStoreStart(ProcMail pmail, Mail mail) {
+//  // (1) Chiamato per primo quando la mail viene accettata e messa nello spool
+//  log("DEBUG", "onOutgoingStore(start) "+pmail.getKey());
+//  pmail.spool(mail);
+//}
+//
+//protected void onOutgoingAccept(ProcMail pmail, Mail mail) {
+//  // (2) Chiamato per secondo, quando la mail viene presa in carico per la spedizione 
+//  log("DEBUG", "onOutgoingAccept "+pmail.getKey());
+//  pmail.fetchFromSpool(mail);
+//}
+//
+//protected void onTransportConnect(ProcMail pmail, Exception e) {
+//  // (3) Chiamata per inizializzare la connessione, in realtà non è un evento
+//  //     strettamento legato alla mail
+//  log("DEBUG", "onTransportConnect "+pmail.getKey());
+//  pmail.setState(ProcMail.STATE_SENDING);
+//  if (e != null) pmail.setConnectException(e);
+//}
+//
+//protected void onTransportSend(ProcMail pmail, Exception e) {
+//  // (4) Invio vero e proprio del messaggio
+//  log("DEBUG", "onTransportSend "+pmail.getKey());
+//  pmail.setState(ProcMail.STATE_SENDTERMINATED);
+//  if (e != null) pmail.setSendException(e);
+//}
+//
+//protected void onOutgoingRemove(ProcMail pmail, Mail mail) {
+//  // (5a) Chiamato per ultimo se la mail è OK o ha avuto errori permanenti 
+//  log("DEBUG", "onOutgoingRemove "+pmail.getKey());
+//  pmail.terminate(mail, true);
+//}
+//
+//protected void onOutgoingStoreEnd(ProcMail pmail, Mail mail) {
+//  // (5b) Chiamato per ultimo se la mail ha degli errori temporanei
+//  log("DEBUG", "onOutgoingStore(end) "+pmail.getKey());
+//  pmail.terminate(mail, false);
+//}
+
+    /**
+     * Runtime status of test.
+     * <p>Contains test statistics.
+     */
+    public class TestStatus {
+        private int transportConnectionCount = 0;
+        private int transportSendCount = 0;
+        private int transportSendSuccessfullCount = 0;
+        private int transportSendFailedCount = 0;
+        private int transportCloseCount = 0;
+        private Map transportServerConnectionCount = new HashMap();
+        private Map transportServerSendCount = new HashMap();
+        private Map transportServerSendSuccessfullCount = new HashMap();
+        private Map transportServerSendFailedCount = new HashMap();
+        private Map transportServerCloseCount = new HashMap();
+        private int bouncedCount = 0;
+        
+        public int getIntMapValue(Map map, String key) {
+            return map.containsKey(key) ? ((Integer) map.get(key)).intValue() : 0;
+        }
+        public void setIntMapValue(Map map, String key, int v) {
+            map.put(key, new Integer(v));
+        }
+        public void incIntMapValue(Map map, String key, int v) {
+            setIntMapValue(map, key, getIntMapValue(map, key) + v);
+        }
+        
+        public int getBouncedCount() {
+            return bouncedCount;
+        }
+        public int incBouncedCount(int v) {
+            return (bouncedCount += v);
+        }
+        public void setBouncedCount(int bouncedCount) {
+            this.bouncedCount = bouncedCount;
+        }
+        public int getTransportCloseCount() {
+            return transportCloseCount;
+        }
+        public int incTransportCloseCount(int v) {
+            return (transportCloseCount += v);
+        }
+        public void setTransportCloseCount(int transportCloseCount) {
+            this.transportCloseCount = transportCloseCount;
+        }
+        public int getTransportConnectionCount() {
+            return transportConnectionCount;
+        }
+        public int incTransportConnectionCount(int v) {
+            return (transportConnectionCount += v);
+        }
+        public void setTransportConnectionCount(int transportConnectionCount) {
+            this.transportConnectionCount = transportConnectionCount;
+        }
+        public int getTransportSendCount() {
+            return transportSendCount;
+        }
+        public int incTransportSendCount(int v) {
+            return (transportSendCount += v);
+        }
+        public void setTransportSendCount(int transportSendCount) {
+            this.transportSendCount = transportSendCount;
+        }
+        public int getTransportSendSuccessfullCount() {
+            return transportSendSuccessfullCount;
+        }
+        public int incTransportSendSuccessfullCount(int v) {
+            return (transportSendSuccessfullCount += v);
+        }
+        public void setTransportSendSuccessfullCount(int transportSendSuccessfullCount) {
+            this.transportSendSuccessfullCount = transportSendSuccessfullCount;
+        }
+        public int getTransportSendFailedCount() {
+            return transportSendFailedCount;
+        }
+        public int incTransportSendFailedCount(int v) {
+            return (transportSendFailedCount += v);
+        }
+        public void setTransportSendFailedCount(int transportSendFailedCount) {
+            this.transportSendFailedCount = transportSendFailedCount;
+        }
+        public int getTransportServerCloseCount(String server) {
+            return getIntMapValue(transportServerCloseCount, server);
+        }
+        public void incTransportServerCloseCount(String server, int v) {
+            incIntMapValue(transportServerCloseCount, server, v);
+        }
+        public int getTransportServerSendCount(String server) {
+            return getIntMapValue(transportServerSendCount, server);
+        }
+        public void incTransportServerSendCount(String server, int v) {
+            incIntMapValue(transportServerSendCount, server, v);
+        }
+        public int getTransportServerSendSuccessfullCount(String server) {
+            return getIntMapValue(transportServerSendSuccessfullCount, server);
+        }
+        public void incTransportServerSendSuccessfullCount(String server, int v) {
+            incIntMapValue(transportServerSendSuccessfullCount, server, v);
+        }
+        public int getTransportServerSendFailedCount(String server) {
+            return getIntMapValue(transportServerSendFailedCount, server);
+        }
+        public void incTransportServerSendFailedCount(String server, int v) {
+            incIntMapValue(transportServerSendFailedCount, server, v);
+        }
+        public int getTransportServerConnectionCount(String server) {
+            return getIntMapValue(transportServerConnectionCount, server);
+        }
+        public void incTransportServerConnectionCount(String server, int v) {
+            incIntMapValue(transportServerConnectionCount, server, v);
+        }
+        
+    }
+}

Propchange: james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/Tester.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/Tester.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/TesterMailetConfig.java
URL: http://svn.apache.org/viewvc/james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/TesterMailetConfig.java?rev=671119&view=auto
==============================================================================
--- james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/TesterMailetConfig.java (added)
+++ james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/TesterMailetConfig.java Tue Jun 24 03:34:16 2008
@@ -0,0 +1,293 @@
+/****************************************************************
+ * 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.remotedeliverytester;
+
+import org.apache.avalon.cornerstone.services.store.Store;
+import org.apache.avalon.framework.configuration.Configuration;
+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.james.test.mock.mailet.MockMailContext;
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+import org.apache.mailet.MailetConfig;
+import org.apache.mailet.MailetContext;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Properties;
+
+public class TesterMailetConfig implements MailetConfig {
+
+    private class MailetContextTester extends MockMailContext {
+        private TesterMailetConfig owner;
+        private ServiceManager serviceManager;
+        private ServiceManager wrappedServiceManager;
+        
+        public MailetContextTester(TesterMailetConfig owner, ServiceManager serviceManager) {
+            this.owner = owner;
+            this.serviceManager = serviceManager;
+        }
+
+        public Object getAttribute(String name) {
+            if (name.equals(Constants.AVALON_COMPONENT_MANAGER)) {
+                if (wrappedServiceManager == null) wrappedServiceManager = new ServiceManagerWrapper(owner, serviceManager);
+                return wrappedServiceManager;
+            } else if (name.equals(Constants.HELLO_NAME)) {
+                return "hello.name.com";
+            }
+            return null;
+        }
+
+        public MailetContext setServiceManager(ServiceManager serviceManager) {
+            this.serviceManager = serviceManager;
+            return this;
+        }
+
+        public void log(String message, Throwable t) {
+            log(message);
+            t.printStackTrace();
+        }
+
+        public void log(String message) {
+            System.out.println(message);
+        }
+
+        public Iterator getSMTPHostAddresses(String domainName) {
+            return owner.onMailetContextGetSMTPHostAddresses(domainName);
+        }
+
+        public void bounce(Mail mail, String message, MailAddress bouncer) throws MessagingException {
+            throw new UnsupportedOperationException();
+        }
+
+        public void bounce(Mail mail, String message) throws MessagingException {
+            owner.onMailetContextBounce(mail, message);
+        }
+
+        public Collection getMailServers(String host) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void sendMail(Mail mail) throws MessagingException {
+            owner.onMailetContextSendMail(mail);
+        }
+
+        public void sendMail(MailAddress sender, Collection recipients, MimeMessage msg, String state) throws MessagingException {
+            throw new UnsupportedOperationException();
+        }
+
+        public void sendMail(MailAddress sender, Collection recipients, MimeMessage msg) throws MessagingException {
+            throw new UnsupportedOperationException();
+        }
+
+        public void sendMail(MimeMessage msg) throws MessagingException {
+            throw new UnsupportedOperationException();
+        }
+
+        public void storeMail(MailAddress sender, MailAddress recipient, MimeMessage msg) throws MessagingException {
+            throw new UnsupportedOperationException();
+        }
+
+    }
+
+    private class ServiceManagerWrapper implements ServiceManager {
+        private TesterMailetConfig owner;
+        private ServiceManager wrapped;
+        private Store wrappedStore;
+
+        public ServiceManagerWrapper(TesterMailetConfig owner, ServiceManager wrapped) {
+            this.owner = owner;
+            this.wrapped = wrapped;
+        }
+
+        public Object lookup(String arg0) throws ServiceException {
+            if (arg0.equals("org.apache.avalon.cornerstone.services.store.Store")) {
+                if (wrappedStore == null) wrappedStore = new StoreWrapper(owner, (Store) wrapped.lookup("org.apache.avalon.cornerstone.services.store.Store"));
+                return wrappedStore;
+            }
+            return wrapped.lookup(arg0);
+        }
+
+        public boolean hasService(String arg0) {
+            return wrapped.hasService(arg0);
+        }
+
+        public void release(Object arg0) {
+            wrapped.release(arg0);
+        }
+    }
+
+    private class StoreWrapper implements Store {
+        private TesterMailetConfig owner;
+        private Store wrapped;
+        private SpoolRepository wrappedSpoolRepository;
+
+        public StoreWrapper(TesterMailetConfig owner, Store wrapped) {
+            this.owner = owner;
+            this.wrapped = wrapped;
+        }
+
+        public Object select(Object arg0) throws ServiceException {
+            if ((arg0 instanceof Configuration) && ((Configuration) arg0).getLocation().equals("generated:RemoteDelivery.java")) {
+                if (wrappedSpoolRepository == null) wrappedSpoolRepository = new SpoolRepositoryWrapper(owner, (SpoolRepository) wrapped.select(arg0));
+                return wrappedSpoolRepository;
+            }
+            return wrapped.select(arg0);
+        }
+
+        public boolean isSelectable(Object arg0) {
+            return wrapped.isSelectable(arg0);
+        }
+
+        public void release(Object arg0) {
+            wrapped.release(arg0);
+        }
+    }
+
+    private class SpoolRepositoryWrapper implements SpoolRepository {
+        private TesterMailetConfig owner;
+        private SpoolRepository wrapped;
+
+        public SpoolRepositoryWrapper(TesterMailetConfig owner, SpoolRepository wrapped) {
+            this.owner = owner;
+            this.wrapped = wrapped;
+            owner.setWrappedSpoolRepository(this);
+        }
+
+        public void store(Mail mc) throws MessagingException {
+            owner.onOutgoingStore(mc);
+            wrapped.store(mc);
+        }
+
+        public void remove(Mail mail) throws MessagingException {
+            owner.onOutgoingRemove(mail);
+            wrapped.remove(mail);
+        }
+
+        public void remove(String key) throws MessagingException {
+            owner.onOutgoingRemove(key);
+            wrapped.remove(key);
+        }
+
+        public Mail accept(AcceptFilter filter) throws InterruptedException {
+            Mail mail = wrapped.accept(filter);
+            if (mail != null) owner.onOutgoingAccept(mail);
+            return mail;
+        }
+
+        public Mail accept() throws InterruptedException {
+            return wrapped.accept();
+        }
+
+        public Mail accept(long delay) throws InterruptedException {
+            return wrapped.accept(delay);
+        }
+
+        public Iterator list() throws MessagingException {
+            return wrapped.list();
+        }
+
+        public boolean lock(String key) throws MessagingException {
+            return wrapped.lock(key);
+        }
+
+        public void remove(Collection mails) throws MessagingException {
+            wrapped.remove(mails);
+        }
+
+        public Mail retrieve(String key) throws MessagingException {
+            return wrapped.retrieve(key);
+        }
+
+        public boolean unlock(String key) throws MessagingException {
+            return wrapped.unlock(key);
+        }
+    }
+
+    private Tester owner;
+    private Properties parameters;
+    private MailetContextTester mailetContext;
+    
+    // wrappedSpoolRepository verrà settato solo se si decide di gestire l'outgoing
+    private SpoolRepository wrappedSpoolRepository;
+
+    public TesterMailetConfig(Tester owner, Properties properties, ServiceManager serviceManager) {
+        this.owner = owner;
+        this.parameters = properties;
+        mailetContext = new MailetContextTester(this, serviceManager);
+    }
+
+    public SpoolRepository getWrappedSpoolRepository() {
+        return wrappedSpoolRepository;
+    }
+
+    public void setWrappedSpoolRepository(SpoolRepository wrappedSpoolRepository) {
+        this.wrappedSpoolRepository = wrappedSpoolRepository;
+    }
+
+    public String getInitParameter(String name) {
+        return (String) parameters.get(name);
+    }
+
+    public Iterator getInitParameterNames() {
+        return parameters.keySet().iterator();
+    }
+
+    public MailetContext getMailetContext() {
+        return mailetContext;
+    }
+
+    public String getMailetName() {
+        return "Test";
+    }
+
+    public Iterator onMailetContextGetSMTPHostAddresses(String domainName) {
+        return owner.onMailetContextGetSMTPHostAddresses(domainName);
+    }
+    
+    public void onMailetContextBounce(Mail mail, String message) {
+        owner.onMailetContextBounce(mail, message);
+    }
+
+    public void onMailetContextSendMail(Mail mail) {
+        owner.onMailetContextSendMail(mail);
+    }
+
+    public void onOutgoingAccept(Mail mail) {
+        owner.onOutgoingAccept(mail);
+    }
+
+    public void onOutgoingRemove(String key) {
+        owner.onOutgoingRemove(key);
+    }
+
+    public void onOutgoingRemove(Mail mail) {
+        owner.onOutgoingRemove(mail);
+    }
+
+    public void onOutgoingStore(Mail mc) {
+        owner.onOutgoingStore(mc);
+    }
+}

Propchange: james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/TesterMailetConfig.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/TesterMailetConfig.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/TransportRule.java
URL: http://svn.apache.org/viewvc/james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/TransportRule.java?rev=671119&view=auto
==============================================================================
--- james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/TransportRule.java (added)
+++ james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/TransportRule.java Tue Jun 24 03:34:16 2008
@@ -0,0 +1,333 @@
+/****************************************************************
+ * 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.remotedeliverytester;
+
+import org.apache.james.transport.remotedeliverytester.ProcMail.Listing;
+import org.apache.james.transport.remotedeliverytester.Tester.TestStatus;
+
+import javax.mail.Address;
+import javax.mail.MessagingException;
+import javax.mail.SendFailedException;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Vector;
+
+/**
+ * The TransportRule is a rule for the tester.
+ * It define the behaviour of a given server.
+ */
+public interface TransportRule {
+    void onConnect(TestStatus status, String server) throws MessagingException;
+    void onSendMessage(TestStatus status, String server, ProcMail.Listing pmails) throws MessagingException, SendFailedException;
+    void onClose(TestStatus status, String server) throws MessagingException;
+    boolean onSupportsExtension(TestStatus status, String server, String ext, boolean value);
+
+
+    public abstract class Default implements TransportRule {
+        public void onConnect(TestStatus status, String server) throws MessagingException {
+        }
+        public void onSendMessage(TestStatus status, String server, ProcMail.Listing pmails) throws MessagingException, SendFailedException {
+        }
+        public void onClose(TestStatus status, String server) throws MessagingException {
+        }
+        public boolean onSupportsExtension(TestStatus status, String server, String ext, boolean value) {
+            return value;
+        }
+    }
+    
+    /**
+     * Server rule string format:
+     * id-rule.[*-userrule].[match*-userrule].string
+     * 
+     * - id-rule are for "connect"-time exceptions
+     * - *-userrule are for "send"-time exceptions involving every mail (not depending on the recipients address)
+     * - match*-userrule are for "send"-time exceptions involving specific recipients (starting with match - ** to match every address)
+     * 
+     * Available rules:
+     * - me[v]: MessagingException
+     * - sfe[v]: SendFailedException
+     * - smtpafeXXX[v]: SMTPAddressFailedException with XXX returnCode
+     * - smtpaseXXX[v]: SMTPAddressSuccededException with XXX returnCode
+     * - smtpsfeXXX[v]: SMTPSendFailedException with XXX returnCode
+     * - null: NullPointerException
+     * - io: IOException (nested in a MessagingException)
+     * - rpt: repeat the previous rule pattern 
+     * - (*) if a "mail" rule (one involving addresses) ends with "v" resulting in a "valid" address (the failure is about some other error: valid unsent)
+     */
+    public class NameExpression extends Default {
+        
+        // Se false ai recipient validi non vengono effettivamente fatti invii 
+        private boolean propSendValid = true;
+        
+        public NameExpression(boolean sendValid) {
+            propSendValid = sendValid;
+        }
+        
+        /**
+         * Take a string like "name-action[-count]-[action2[-count2]...]"
+         * and convert it in a list "name, action, action, ..., action2, action2, ..., ..."
+         * @param data
+         * @return
+         */
+        private String[] getRules(String data) {
+            String[] pieces = data.toLowerCase().split("-");
+            Vector actions = new Vector();
+            actions.add(pieces[0]);
+            for (int i = 1; i < pieces.length; i += 2) {
+                int cnt = i + 1 < pieces.length ? Integer.parseInt(pieces[i + 1]) : 1;
+                for (int j = 0; j < cnt; j++) actions.add(pieces[i]);
+            }
+            return (String[]) actions.toArray(new String[0]);
+        }
+        
+        private MessagingException getException(String[] actions, int idx, ProcMail pmail, String prefix) {
+            MessagingException result = null;
+            if (idx + 1 >= actions.length && actions[actions.length - 1].equals("rpt")) idx = 1 + (idx % actions.length - 2);
+            String action = idx + 1 < actions.length ? (String) actions[idx + 1] : actions[actions.length - 1];
+            if (action.equals("me") || action.equals("ex")) {
+                String flag = action.substring(2).trim();
+                boolean valid = flag != null && flag.equalsIgnoreCase("v"); 
+                result = new MessagingException("000" + (valid ? "V " : "I ") + prefix + "#" + idx);
+            } else if (action.equals("sfe")) {
+                String flag = action.substring(3).trim();
+                boolean valid = flag != null && flag.equalsIgnoreCase("v"); 
+                result = new SendFailedException("000" + (valid ? "V " : "I ") + prefix + "#" + idx);
+            } else if (action.startsWith("smtpafe")) {
+                String retcodes = action.substring(7, 10).trim();
+                int retcode = 500;
+                if (retcodes != null && retcodes.length() == 3) retcode = Integer.parseInt(retcodes);
+                String flag = action.substring(10).trim();
+                boolean valid = flag != null && flag.equalsIgnoreCase("v"); 
+                result = new SMTPAddressFailedException(pmail.getRecipient().toInternetAddress(), "CMD", retcode, retcode + (valid ? "V " : "I ") + pmail.getRecipient().toString()+ ":"+ prefix + "#" + idx);
+            } else if (action.startsWith("smtpase")) {
+                String retcodes = action.substring(7).trim();
+                int retcode = 200;
+                if (retcodes != null && retcodes.length() == 3) retcode = Integer.parseInt(retcodes);
+                String flag = action.substring(10).trim();
+                boolean valid = flag != null && flag.equalsIgnoreCase("v"); 
+                result = new SMTPAddressSucceededException(pmail.getRecipient().toInternetAddress(), "CMD", retcode, retcode + (valid ? "V " : "I ") + pmail.getRecipient().toString()+ ":"+ prefix + "#" + idx);
+            } else if (action.startsWith("smtpsfe")) {
+                String retcodes = action.substring(7).trim();
+                int retcode = 500;
+                if (retcodes != null && retcodes.length() == 3) retcode = Integer.parseInt(retcodes);
+                String flag = action.substring(10).trim();
+                boolean valid = flag != null && flag.equalsIgnoreCase("v"); 
+                result = new SMTPSendFailedException("CMD", retcode, retcode + (valid ? "V " : "I ") + prefix + "#" + idx, null, null, null, null);
+                
+            } else if (action.startsWith("null")) {
+                result = new NullMessagingException();
+                
+            } else if (action.startsWith("io")) {
+                result = new IOMessagingException();
+            }
+            
+            return result;
+        }
+        
+        private boolean isValid(Exception ex) {
+            return ex != null && ex.getMessage() != null && ex.getMessage().length() > 4 && ex.getMessage().charAt(3) == 'V';
+        }
+        
+        /**
+         * Calculate the priority of an exception (in order to choose the right exception on multiple/conflicts)
+         * @param ex
+         * @return
+         */
+        private int getPrio(Exception ex) {
+            // Addresses exceptions are low priority
+            // Take care of exception hierarchy: parents are the last in this ifs list
+            if (ex instanceof NullMessagingException) return 7000;
+            if (ex instanceof IOMessagingException) return 6000;
+            if (ex instanceof SMTPSendFailedException) return 5000 + ((SMTPAddressFailedException)ex).getReturnCode();
+            if (ex instanceof SMTPAddressFailedException) return 2000 + ((SMTPAddressFailedException)ex).getReturnCode();
+            if (ex instanceof SMTPAddressSucceededException) return 1000 + ((SMTPAddressSucceededException)ex).getReturnCode();
+            if (ex instanceof SendFailedException) return 4000;
+            if (ex instanceof MessagingException) return 3000;
+            return -1;
+        }
+        
+        /**
+         * Returns the exception with the greatest priority.
+         * @param newex
+         * @param oldex
+         * @return
+         */
+        private MessagingException getMajor(MessagingException newex, MessagingException oldex) {
+            if (newex == null) return oldex;
+            if (oldex == null) return newex;
+            return getPrio(newex) >= getPrio(oldex) ? newex : oldex;
+        }
+
+        private void addException(HashMap map, MessagingException ex, Address recipient) {
+            if (map.get(recipient) != null) {
+                MessagingException oldex = (MessagingException) map.get(recipient);
+                ex = getMajor(ex, oldex);
+            }
+            map.put(recipient, ex);
+        }
+        
+        /**
+         * Clone the exception, sets the "invalid" addresses as invalidAddress (in the clone)
+         * If the exception does not support "invalidaddress" declaration rethrow the original exception.
+         * @return
+         */
+        private MessagingException generateClone(Exception ex, Address[] validUnsent, Address[] invalid, MessagingException next) {
+            // Attenzione: le eccezioni devono essere in ordine di gerarchia (le + generiche - MessagingException - per ultime)  
+            if (ex instanceof SMTPSendFailedException) {
+                return new SMTPSendFailedException(((SMTPSendFailedException)ex).getCommand(), ((SMTPSendFailedException)ex).getReturnCode(), ex.getMessage(), next, new Address[0], validUnsent, invalid);
+                
+            } else if (ex instanceof SendFailedException) {
+                return new SendFailedException(ex.getMessage(), next, new Address[0], validUnsent, invalid);
+                
+            } else if ((ex instanceof MessagingException) || (ex instanceof SMTPAddressSucceededException) || (ex instanceof SMTPAddressFailedException)) {
+                //if (next != null) ex.setNextException(next);
+                return (MessagingException) ex;
+            } 
+            return null;
+        }
+        
+        private MessagingException generateParent(Exception majorChildEx, Address[] validSent, Address[] validUnsent, Address[] invalid, MessagingException next) {
+            // NOTE: exceptions must be checked considering their hierarchy
+            if (majorChildEx instanceof SMTPAddressSucceededException) {
+                // If the major exception is an address exception we generate a SendFailedException (non SMTP). If we generate an SMTP exception the return code must be 2xx (e.g: 250)
+                // ERR return new SMTPSendFailedException(((SMTPAddressSucceededException)majorChildEx).getCommand(), ((SMTPAddressSucceededException)majorChildEx).getReturnCode(), majorChildEx.getMessage(), next, validSent, validUnsent, invalid);
+                //return new SMTPSendFailedException(((SMTPAddressSucceededException)majorChildEx).getCommand(), 250, "250 "+majorChildEx.getMessage(), next, validSent, validUnsent, invalid);
+                return new SendFailedException(majorChildEx.getMessage(), next, validSent, validUnsent, invalid);
+                
+            } else if (majorChildEx instanceof SMTPAddressFailedException) {
+                // ERR: return new SMTPSendFailedException(((SMTPAddressFailedException)majorChildEx).getCommand(), ((SMTPAddressFailedException)majorChildEx).getReturnCode(), majorChildEx.getMessage(), next, validSent, validUnsent, invalid);
+                //return new SMTPSendFailedException(((SMTPAddressFailedException)majorChildEx).getCommand(), 250, "250 "+majorChildEx.getMessage(), next, validSent, validUnsent, invalid);
+                return new SendFailedException(majorChildEx.getMessage(), next, validSent, validUnsent, invalid);
+                
+            } else if (majorChildEx instanceof SMTPSendFailedException) {
+                return new SMTPSendFailedException(((SMTPSendFailedException)majorChildEx).getCommand(), ((SMTPSendFailedException)majorChildEx).getReturnCode(), majorChildEx.getMessage(), next, validSent, validUnsent, invalid);
+                
+            } else if (majorChildEx instanceof SendFailedException) {
+                return new SendFailedException(majorChildEx.getMessage(), next, validSent, validUnsent, invalid);
+                
+            } else if (majorChildEx instanceof MessagingException) {
+                //if (next != null) majorChildEx.setNextException(next);
+                return (MessagingException) majorChildEx;
+            } 
+            
+            return null;
+        }
+        
+        private MessagingException getRootException(HashMap map) {
+            // x recipient: sfe (generate an sfe in root), smtpase (generate an smtafe), smtpafe (generate an smtafe), 
+            // x root: me, sfe, smtpafe
+            
+            MessagingException current = null, prev = null, major = null;
+            Vector invalid = new Vector();
+            Vector validSent = new Vector();
+            Vector validUnsent = new Vector();
+            Iterator i = map.keySet().iterator();
+            while (i.hasNext()) {
+                Address address = (Address) i.next();
+                if (address != null) {
+                    current = (MessagingException) map.get(address);
+                    if (current != null) {
+                        if (prev != null) current.setNextException(prev);
+                        if (major != null) major = getMajor(major, current);
+                        else major = current;
+                        prev = current;
+                        
+                        if (!(current instanceof SMTPAddressSucceededException)) {
+                            if (isValid(current)) validUnsent.add(address);
+                            else invalid.add(address);
+                        } 
+                        else if (propSendValid) validSent.add(address); else validUnsent.add(address);
+                    } 
+                    else if (propSendValid) validSent.add(address); else validUnsent.add(address);
+                }
+            }
+            
+            // on generic exception (not a per-recipient exception) clone it with all "unsents" (validSent -> validUnsent)
+            MessagingException ex1 = (MessagingException) map.get(null);
+            if (ex1 != null) {
+                validUnsent.addAll(validSent);
+                ex1 = generateClone(ex1, (Address[]) validUnsent.toArray(new Address[0]), (Address[]) invalid.toArray(new Address[0]), prev);
+            }
+            
+            // Create a container exception for the above exceptions
+            MessagingException ex2 = major != null ? (MessagingException) generateParent(major, (Address[]) validSent.toArray(new Address[0]), (Address[]) validUnsent.toArray(new Address[0]), (Address[]) invalid.toArray(new Address[0]), prev) : null;
+            
+            return getMajor(ex1, ex2);
+            
+        }
+        
+        public void onConnect(TestStatus status, String server) throws MessagingException {
+            String serverData = server;
+            if (serverData.indexOf("://") >= 0) serverData = serverData.substring(serverData.indexOf("://") + 3);
+            if (serverData.indexOf(":") >= 0) serverData = serverData.substring(0, serverData.indexOf(":"));
+            String[] pieces = serverData.split("\\.");
+            String[] actions = getRules(pieces[0]);
+            int idx = status.getTransportServerConnectionCount(server);
+            
+            MessagingException ex = getException(actions, idx, null, server);
+            if (ex != null) throwME(ex);
+        }
+
+        public void onSendMessage(TestStatus status, String server, Listing pmails) throws MessagingException, SendFailedException {
+            String serverData = server;
+            if (serverData.indexOf("://") >= 0) serverData = serverData.substring(serverData.indexOf("://") + 3);
+            if (serverData.indexOf(":") >= 0) serverData = serverData.substring(0, serverData.indexOf(":"));
+            String[] serverPieces = serverData.split("\\.");
+            
+            HashMap exceptionMap = new HashMap();
+            int idx = status.getTransportServerSendCount(server);
+            
+            for (int i = 1; i < serverPieces.length - 1; i++) {
+                String[] actions = getRules(serverPieces[i]);
+                if (actions[0].endsWith("*") && actions[0].length() > 1) {
+                    String match = actions[0].substring(0, actions[0].length() - 1);
+                    for (int j = 0; j < pmails.size(); j++) if (pmails.get(j).getRecipient().toString().startsWith(match) || match.equals("*")) {
+                        MessagingException ex = getException(actions, idx, pmails.get(j), server);
+                        addException(exceptionMap, ex, pmails.get(j).getRecipient().toInternetAddress());
+                    } else addException(exceptionMap, null, pmails.get(j).getRecipient().toInternetAddress());
+                }
+            }
+            
+            for (int i = 1; i < serverPieces.length - 1; i++) {
+                String[] actions = getRules(serverPieces[i]);
+                if (actions[0].equals("*")) {
+                    MessagingException ex = getException(actions, idx, null, server);
+                    addException(exceptionMap, ex, null);
+                }
+            }
+            
+            MessagingException ex = getRootException(exceptionMap);
+            if (ex != null) throwME(ex);
+        }
+
+        public void throwME(MessagingException ex) throws MessagingException {
+            if (ex instanceof NullMessagingException) throw new NullPointerException();
+            if (ex instanceof IOMessagingException) {
+                MessagingException me = new MessagingException();
+                me.setNextException(new IOException());
+                throw me;
+            }
+            throw ex;
+        }
+    }
+    
+}

Propchange: james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/TransportRule.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/server/trunk/mailets-function/src/test/java/org/apache/james/transport/remotedeliverytester/TransportRule.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org