/*
* [CachedMailProber.java]
*
* Summary: A persistent cache of DomainStatuses.
*
* Copyright: (c) 2002-2017 Roedy Green, Canadian Mind Products, http://mindprod.com
*
* Licence: This software may be copied and used freely for any purpose but military.
* http://mindprod.com/contact/nonmil.html
*
* Requires: JDK 1.8+
*
* Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/
*
* Version History:
* 1.0 2002-04-13 original
*/
package com.mindprod.bulk;
import com.mindprod.common18.EIO;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Iterator;
import static com.mindprod.bulk.CustConfig.CUST_ABBREVIATION;
import static com.mindprod.bulk.CustConfig.TREAT_AS_BAD_DOMAINS;
import static com.mindprod.bulk.CustConfig.TREAT_AS_GOOD_DOMAINS;
import static java.lang.System.*;
/**
* A persistent cache of DomainStatuses.
*
* e.g. where a given domain has a working mailserver.
* Has provision to cull deadwood. Uses serialisation.
* The idea is to avoid the overhead of probing a mailserver for every email validation.
*
* @author Roedy Green, Canadian Mind Products
* @version 1.0 2002-04-13 original
* @since 2002-04-13
*/
public final class CachedMailProber
{
/**
* name of the file where we cache status of various email domains.
*/
private static final String DOMAIN_CACHE_FILE_NAME =
CUST_ABBREVIATION + "-domain-cache.ser";
/**
* collection of previously probed Domains along with their statuses.
*/
private static HashMap domainCache;
static
{
/* load up serialised domainCache from before */
fireup();
}
/**
* Called when class is shut down to save the domainCache in serialised form.
*/
private static void close()
{
flush();
domainCache = null;
}
/**
* Called when class is loaded to reconstitute the serialised domainCache. Called automatically when class is
* loaded.
*/
@SuppressWarnings( "unchecked" )
private static void fireup()
{
try
{
// O P E N
ObjectInputStream ois = EIO.getObjectInputStream( new File( DOMAIN_CACHE_FILE_NAME ), 4 * 1024, false );
// R E A D
domainCache = ( HashMap ) ois.readObject();
// C L O S E
ois.close();
}
catch ( Exception e )
{
out.println( "Troubles restoring the "
+ DOMAIN_CACHE_FILE_NAME
+ " file. Not to worry, starting afresh." );
domainCache = new HashMap<>( 2053, 0.75f );
}
/* seed the special exceptions. Might be already there, no problem */
for ( String treatAsGoodDomain : TREAT_AS_GOOD_DOMAINS )
{
domainCache.put( treatAsGoodDomain,
new DomainStatus( treatAsGoodDomain, true ) );
}
for ( String treatAsBadDomain : TREAT_AS_BAD_DOMAINS )
{
domainCache.put( treatAsBadDomain,
new DomainStatus( treatAsBadDomain, false ) );
}
} // end fireup
/**
* Test the mailserver status of a domain.
*
* @param domain name of domain, (will be automatically trimmed and converted internally to lower case), whose
* status we are interested in e.g. mindprod.com or oberon.ark.com, not the mailserver name, not an
* email address.
*
* @return true if that domain existed in DNS records at the last probe, and one of whose mailservers responded at
* least one in recent probes. Reprobes as necessary.
*/
private static boolean isMailServerForDomainAlive( String domain )
{
if ( domain == null )
{
return false;
}
domain = domain.trim().toLowerCase();
DomainStatus d = domainCache.get( domain );
if ( d == null )
{
/* not in domainCache yet, put it there. */
d = new DomainStatus( domain );
domainCache.put( domain, d );
}
return d.isGood();
}
/**
* Tests if mailserver corresponding to that email is up and running.
*
* @param email email address you are proposing to send to.
*
* @return true if that the corresponding mailserver is working, or was working recently.
*/
@SuppressWarnings( { "ConstantConditions", "PointlessBooleanExpression" } )
static boolean isMailServerForEmailAlive( String email )
{
if ( !CustConfig.VALIDATE_EMAIL_SERVERS )
{
// If can't access mail servers directly, just assume all is ox.
return true;
}
if ( email == null )
{
return false;
}
email = email.trim().toLowerCase();
int lastAt = email.lastIndexOf( '@' );
if ( lastAt < 0 )
{
return false;
}
String domain = email.substring( lastAt + 1 );
return isMailServerForDomainAlive( domain );
}
/**
* save the domainCache in serialised form.
*/
public static void flush()
{
try
{
// C U L L
for ( Iterator iter =
domainCache.values().iterator(); iter.hasNext(); )
{
DomainStatus d = ( DomainStatus ) iter.next();
if ( d.shouldCull() )
{
iter.remove();// avoid ConcurrentModificationException
}
} // end for
// O P E N
FileOutputStream fos =
new FileOutputStream( DOMAIN_CACHE_FILE_NAME, false
/* append */ );
ObjectOutputStream oos = new ObjectOutputStream( fos );
// W R I T E
oos.writeObject( domainCache );
// C L O S E
oos.close();
}
catch ( IOException e )
{
err.println();
e.printStackTrace( err );
err.println( "Troubles writing out the "
+ DOMAIN_CACHE_FILE_NAME
+ " file" );
err.println();
}
} // end close
/**
* test driver
*
* @param args sample email addresses to test for working mailservers
*/
public static void main( String[] args )
{
for ( String email : args )
{
out.println( email
+ " "
+ isMailServerForEmailAlive( email ) );
}
close();
}
}