/* * Copyright (C) 1996 - 2011 Alan Williamson * * This file is part of Mail25 Mailet Container. * * Mail25 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * Free Software Foundation,version 3. * * Mail25 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Mail25. If not, see http://www.gnu.org/licenses/ * * http://alan.blog-city.com/ * * $Id: Chain.java 1745 2011-10-25 15:43:15Z alan $ */ package org.alanwilliamson.mail25.chain; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Properties; import java.util.StringTokenizer; import javax.mail.MessagingException; import org.alanwilliamson.mail25.mailet.CaughtMail; import org.alanwilliamson.mail25.mailet.Mail25Config; import org.alanwilliamson.mail25.mailet.MatcherConfigConcrete; import org.alanwilliamson.mail25.server.Mail25; import org.apache.mailet.Mail; import org.apache.mailet.MailAddress; import org.apache.mailet.Mailet; import org.apache.mailet.Matcher; public class Chain extends Object { private ArrayList matcherList; private ArrayList mailetList; private Mail25 mail25; private String chainName; public Chain( String chainName, Properties config, Mail25 mail25 ) throws Exception{ this.chainName = chainName; this.mail25 = mail25; //-- Setup the chain matcherList = new ArrayList(); mailetList = new ArrayList(); //-- Need to run through looking for the parameters String matchers = config.getProperty( "spoolchain." + chainName + ".matchers" ); if ( matchers == null ) throw new Exception( "ChainCreationException: [spoolchain." + chainName + ".matchers] was not defined" ); StringTokenizer st = new StringTokenizer( matchers, "," ); while ( st.hasMoreTokens() ){ String matcherName = st.nextToken(); //- Pull out the matcher class String matcherClass = config.getProperty( "matcher." + matcherName ); if ( matcherClass == null ) throw new Exception( "ChainCreationException: [matcher." + matcherName + "] was not defined. Should be a class name" ); //- Pull out the matcher condition, which can be null; thats valid String matcherCondition = config.getProperty( "matcher." + matcherName + ".condition" ); //- Pull out the mailet details String mailetClass = config.getProperty( "matcher." + matcherName + ".mailet" ); if ( mailetClass == null ) throw new Exception( "ChainCreationException: [matcher." + matcherName + ".mailet] was not defined. Should be a class name" ); //- Pull out the mailet params; null params is okay String mailetParams = config.getProperty( "matcher." + matcherName + ".mailetparams" ); //-- Let us attempt to create the Matcher class Matcher matcherInst; try{ Class c = Class.forName( matcherClass ); matcherInst = (Matcher)c.newInstance(); matcherInst.init( new MatcherConfigConcrete( matcherName, matcherCondition, mail25.getMailContext() ) ); }catch(Exception e){ throw new Exception( "ChainCreationException: [matcher." + matcherName + "] " + e.getMessage() ); } //-- Let us attempt to create the Mailet class Mailet mailetClassInst; try{ Class c = Class.forName( mailetClass ); mailetClassInst = (Mailet)c.newInstance(); mailetClassInst.init( new Mail25Config( mail25.getMailContext(), matcherName + "Mailet", mailetParams ) ); }catch(Exception e){ throw new Exception( "ChainCreationException: [matcher." + matcherName + ".mailet] " + mailetClass + ":" + e.getMessage() ); } //- Gets here, everything is good matcherList.add( matcherInst ); mailetList.add( mailetClassInst ); } } public String toString(){ return "Chain." + chainName + ":"; } public void shutdown(){ for ( int x=0; x<matcherList.size(); x++ ){ ((Matcher)matcherList.get(x)).destroy(); } for ( int x=0; x<mailetList.size(); x++ ){ ((Mailet)mailetList.get(x)).destroy(); } matcherList = null; mailetList = null; } public void acceptMail( CaughtMail mail ){ runMailThroughChain( mail ); } //------------------------------------------------------------------- //-- Private Methods private void runMailThroughChain( CaughtMail mail ){ for ( int x=0; x<matcherList.size(); x++ ){ Matcher matcher = (Matcher)matcherList.get(x); Collection matchedRecipients; //- Get the list of matched recipients try { matchedRecipients = matcher.match( mail ); //- No more recipents to match; its game over for this processing if ( matchedRecipients == null || matchedRecipients.size() == 0 ) return; if ( !checkRecipientTypes(matchedRecipients) ){ mail25.log( toString() + matcher.getMatcherInfo() + ": returned invalid objects as recipients"); return; } } catch (MessagingException e) { mail25.log( toString() + matcher.getMatcherInfo() + ": MessagingException: " + e.getMessage() ); return; } //- Set the mail recipents for this mail mail.setRecipients( matchedRecipients ); //- Run the mailet associated Mailet mailet = (Mailet)mailetList.get(x); String oldState = mail.getState(); try { long runTime = System.currentTimeMillis(); mailet.service( mail ); runTime = System.currentTimeMillis() - runTime; //- Set the attribute into the mailet incase it wants to see execution time mail.setAttribute( "MAILCATCHER.EXECTIME", String.valueOf(runTime) ); } catch (Exception e) { mail25.log( toString() + "[ERROR]=" + mailet.getMailetInfo() + "; from=" + mail.getSender() + "; Exception:" + e.getMessage() ); return; } if ( mail.getState().equals( Mail.GHOST) ){ //-- If the STATE is GHOST then we remove the mail from this process return; }else if ( mail.getState().equals( Mail.ERROR) ){ //- The Mailet indicated an error with this email; so disregard and log it mail25.log( toString() + "[STATE=ERROR]=" + mailet.getMailetInfo() + "; from=" + mail.getSender() + "; Error:" + mail.getErrorMessage() ); return; } else if ( !mail.getState().equals(oldState) ){ //- The mailet has decided it wants to move to another chain mail25.acceptMail( mail.getState(), mail ); return; } } } private boolean checkRecipientTypes(Collection r){ /* Since we are relying on a third party class to provide * us with the list of recipients of a mail message we * have to make sure they are giving us back the right * object types. */ Iterator it = r.iterator(); while (it.hasNext()){ if ( ! (it.next() instanceof MailAddress) ) return false; } return true; } }