NIHVIVO-3489 When setting up the Email session, test to see whether the SMTP host will respond on the SMTP port with a valid SMTP header.

This commit is contained in:
j2blake 2012-01-31 18:25:41 +00:00
parent e273bc5f3e
commit cb5e2362b1

View file

@ -2,7 +2,15 @@
package edu.cornell.mannlib.vitro.webapp.email; package edu.cornell.mannlib.vitro.webapp.email;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Properties; import java.util.Properties;
import java.util.Scanner;
import javax.mail.Session; import javax.mail.Session;
import javax.mail.internet.AddressException; import javax.mail.internet.AddressException;
@ -53,11 +61,6 @@ public class FreemarkerEmailFactory {
factory.getReplyToAddress()); factory.getReplyToAddress());
} }
public static boolean isConfigured(HttpServletRequest req) {
FreemarkerEmailFactory factory = getFactory(req);
return (factory != null) && (factory.isConfigured());
}
/** /**
* Client code that does not use the FreemarkerEmailFactory can still use * Client code that does not use the FreemarkerEmailFactory can still use
* it's Email Session. * it's Email Session.
@ -69,6 +72,10 @@ public class FreemarkerEmailFactory {
return getFactory(req).getEmailSession(); return getFactory(req).getEmailSession();
} }
public static boolean isConfigured(HttpServletRequest req) {
return (getFactory(req) != null);
}
private static FreemarkerEmailFactory getFactory(HttpServletRequest req) { private static FreemarkerEmailFactory getFactory(HttpServletRequest req) {
ServletContext ctx = req.getSession().getServletContext(); ServletContext ctx = req.getSession().getServletContext();
return (FreemarkerEmailFactory) ctx.getAttribute(ATTRIBUTE_NAME); return (FreemarkerEmailFactory) ctx.getAttribute(ATTRIBUTE_NAME);
@ -84,12 +91,14 @@ public class FreemarkerEmailFactory {
public FreemarkerEmailFactory(ServletContext ctx) { public FreemarkerEmailFactory(ServletContext ctx) {
this.smtpHost = getSmtpHostFromConfig(ctx); this.smtpHost = getSmtpHostFromConfig(ctx);
new SmtpHostTester().test(this.smtpHost);
this.replyToAddress = getReplyToAddressFromConfig(ctx); this.replyToAddress = getReplyToAddressFromConfig(ctx);
this.emailSession = createEmailSession(this.smtpHost); this.emailSession = createEmailSession(smtpHost);
} }
boolean isConfigured() { String getSmtpHost() {
return (!smtpHost.isEmpty()) && (replyToAddress != null); return smtpHost;
} }
InternetAddress getReplyToAddress() { InternetAddress getReplyToAddress() {
@ -104,8 +113,7 @@ public class FreemarkerEmailFactory {
ConfigurationProperties config = ConfigurationProperties.getBean(ctx); ConfigurationProperties config = ConfigurationProperties.getBean(ctx);
String hostName = config.getProperty(SMTP_HOST_PROPERTY, ""); String hostName = config.getProperty(SMTP_HOST_PROPERTY, "");
if (hostName.isEmpty()) { if (hostName.isEmpty()) {
log.info("Configuration property for '" + SMTP_HOST_PROPERTY throw new NotConfiguredException(SMTP_HOST_PROPERTY);
+ "' is empty: email is disabled.");
} }
return hostName; return hostName;
} }
@ -114,22 +122,18 @@ public class FreemarkerEmailFactory {
ConfigurationProperties config = ConfigurationProperties.getBean(ctx); ConfigurationProperties config = ConfigurationProperties.getBean(ctx);
String rawAddress = config.getProperty(REPLY_TO_PROPERTY, ""); String rawAddress = config.getProperty(REPLY_TO_PROPERTY, "");
if (rawAddress.isEmpty()) { if (rawAddress.isEmpty()) {
log.info("Configuration property for '" + REPLY_TO_PROPERTY throw new NotConfiguredException(REPLY_TO_PROPERTY);
+ "' is empty: email is disabled.");
return null;
} }
try { try {
InternetAddress[] addresses = InternetAddress.parse(rawAddress, InternetAddress[] addresses = InternetAddress.parse(rawAddress,
false); false);
if (addresses.length == 0) { if (addresses.length == 0) {
throw new IllegalStateException( throw new BadPropertyValueException("No Reply-To address",
"No Reply-To address configured in '" REPLY_TO_PROPERTY);
+ REPLY_TO_PROPERTY + "'");
} else if (addresses.length > 1) { } else if (addresses.length > 1) {
throw new IllegalStateException( throw new BadPropertyValueException(
"More than one Reply-To address configured in '" "More than one Reply-To address", REPLY_TO_PROPERTY);
+ REPLY_TO_PROPERTY + "'");
} else { } else {
return addresses[0]; return addresses[0];
} }
@ -147,9 +151,93 @@ public class FreemarkerEmailFactory {
} }
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Setup class // Helper classes
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
public static class NotConfiguredException extends RuntimeException {
public NotConfiguredException(String property) {
super("Configuration property for '" + property
+ "' is empty - Email functions are disabled.");
}
}
public static class BadPropertyValueException extends RuntimeException {
public BadPropertyValueException(String problem, String property) {
super(problem + " configured in '" + property
+ "' - Email functions are disabled.");
}
}
public static class InvalidSmtpHost extends RuntimeException {
public InvalidSmtpHost(String smtpHost, String reason) {
super("Invalid SMTP host: '" + smtpHost + "': " + reason
+ " - Email functions are disabled.");
}
}
/**
* Checks to see whether the SMTP host will talk to us.
*/
public static class SmtpHostTester {
private static final int SMTP_PORT = 25;
private static final int SMTP_SUCCESS_CODE = 220;
/**
* Try to open a connection to the SMTP host and conduct an "empty"
* conversation using SMTP.
*
* @throws InvalidSmtpHost
* If anything goes wrong.
*/
public void test(String smtpHost) throws InvalidSmtpHost {
Socket socket = null;
PrintStream out = null;
Scanner in = null;
try {
InetAddress hostAddr = InetAddress.getByName(smtpHost);
socket = new Socket(hostAddr, SMTP_PORT);
out = new PrintStream(socket.getOutputStream());
in = new Scanner(new InputStreamReader(socket.getInputStream()));
int smtpCode = in.nextInt();
if (smtpCode != SMTP_SUCCESS_CODE) {
throw new InvalidSmtpHost(smtpHost,
"host will not converse: "
+ "SMTP initialization code is " + smtpCode);
}
out.println("QUIT");
} catch (UnknownHostException e) {
throw new InvalidSmtpHost(smtpHost,
"host name is not recognized");
} catch (ConnectException e) {
throw new InvalidSmtpHost(smtpHost,
"refused connection on port " + SMTP_PORT);
} catch (IOException e) {
throw new RuntimeException("unrecognized problem: ", e);
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
if ((socket != null) && (!socket.isClosed())) {
try {
socket.close();
} catch (IOException e) {
log.error("failed to close socket", e);
}
}
}
}
}
/**
* Tries to create a FreemarkerEmailFactory bean and store it in the servlet
* context.
*/
public static class Setup implements ServletContextListener { public static class Setup implements ServletContextListener {
@Override @Override
public void contextInitialized(ServletContextEvent sce) { public void contextInitialized(ServletContextEvent sce) {
@ -159,14 +247,16 @@ public class FreemarkerEmailFactory {
try { try {
FreemarkerEmailFactory factory = new FreemarkerEmailFactory(ctx); FreemarkerEmailFactory factory = new FreemarkerEmailFactory(ctx);
ctx.setAttribute(ATTRIBUTE_NAME, factory); ctx.setAttribute(ATTRIBUTE_NAME, factory);
ss.info(this,
if (factory.isConfigured()) { "The system will send email from '"
ss.info(this, "The system is configured to " + factory.getReplyToAddress() + "' through '"
+ "send mail to users."); + factory.getSmtpHost() + "'.");
} else { } catch (NotConfiguredException e) {
ss.info(this, "Configuration parameters are missing: " ss.info(this, e.getMessage());
+ "the system will not send mail to users."); } catch (BadPropertyValueException e) {
} ss.warning(this, e.getMessage());
} catch (InvalidSmtpHost e) {
ss.warning(this, e.getMessage());
} catch (Exception e) { } catch (Exception e) {
ss.warning(this, ss.warning(this,
"Failed to initialize FreemarkerEmailFactory. " "Failed to initialize FreemarkerEmailFactory. "