com.github.sleroy.junit.mail.server.MailSaver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fakesmtp-junit-runner Show documentation
Show all versions of fakesmtp-junit-runner Show documentation
JUnit Rule to create a FakeSmtp server to write mailing integration tests
/*
*
*/
package com.github.sleroy.junit.mail.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Observable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.sleroy.fakesmtp.core.ServerConfiguration;
import com.github.sleroy.fakesmtp.model.EmailModel;
import com.github.sleroy.junit.mail.server.events.NewMailEvent;
import com.github.sleroy.junit.mail.server.events.RejectedMailEvent;
/**
* Saves emails and notifies components so they can refresh their views with new
* data.
*
* @author Nilhcem
* @since 1.0
*/
public final class MailSaver extends Observable implements MailSaverInterface {
/** The Constant LOGGER. */
protected static final Logger LOGGER = LoggerFactory.getLogger(MailSaver.class);
/** The Constant LINE_SEPARATOR. */
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
/** The Constant SUBJECT_PATTERN. */
// This can be a static variable since it is Thread Safe
private static final Pattern SUBJECT_PATTERN = Pattern.compile("^Subject: (.*)$");
protected Charset storageCharSet;
/** The date format. */
protected final SimpleDateFormat dateFormat = new SimpleDateFormat("ddMMyyhhmmssSSS");
private final ServerConfiguration serverConfiguration;
/**
* Instantiates a new mail saver.
*
* @param serverConfiguration
* the server configuration
*/
public MailSaver(final ServerConfiguration serverConfiguration) {
this.serverConfiguration = serverConfiguration;
storageCharSet = serverConfiguration.getStorageCharset();
Validate.notNull(serverConfiguration);
Validate.notNull(storageCharSet);
}
/**
* Converts an {@code InputStream} into a {@code String} object.
*
* The method will not copy the first 4 lines of the input stream.
* These 4 lines are SubEtha SMTP additional information.
*
*
* @param is
* the InputStream to be converted.
* @return the converted string object, containing data from the InputStream
* passed in parameters.
*/
private String convertStreamToString(final InputStream is) {
final long lineNbToStartCopy = 4; // Do not copy the first 4 lines
// (received part)
final BufferedReader reader = new BufferedReader(new InputStreamReader(is, storageCharSet));
final StringBuilder sb = new StringBuilder();
String line;
long lineNb = 0;
try {
while ((line = reader.readLine()) != null) {
if (++lineNb > lineNbToStartCopy) {
sb.append(line).append(LINE_SEPARATOR);
}
}
} catch (final IOException e) {
LOGGER.error("Could not convert the stream.", e);
}
return sb.toString();
}
/**
* Returns a lock object.
*
* This lock will be used to make the application thread-safe, and avoid
* receiving and deleting emails in the same time.
*
*
* @return a lock object (which is actually the current instance of the
* {@code MailSaver} object).
*/
public Object getLock() {
return this;
}
/**
* Gets the subject from the email data passed in parameters.
*
* @param data
* a string representing the email content.
* @return the subject of the email, or an empty subject if not found.
*/
private String getSubjectFromStr(final String data) {
try {
final BufferedReader reader = new BufferedReader(new StringReader(data));
String line;
while ((line = reader.readLine()) != null) {
final Matcher matcher = SUBJECT_PATTERN.matcher(line);
if (matcher.matches()) {
return matcher.group(1);
}
}
} catch (final IOException e) {
LOGGER.error("Cannot obtain the subject", e);
}
return "";
}
/**
* Checks if is matching relay domains.
*
* @param to
* the to
* @param relayDomains
* the relay domains
* @return true, if is matching relay domains
*/
private boolean isMatchingRelayDomains(final String to, final List relayDomains) {
if (relayDomains != null) {
LOGGER.debug("Relay domains are defined : ", relayDomains);
boolean matches = false;
for (final String domain : relayDomains) {
if (to.endsWith(domain)) {
LOGGER.debug("The domain is matching : ", domain);
matches = true;
break;
}
}
if (!matches) {
LOGGER.debug("Destination {} doesn't match relay domains", to);
return false;
}
} else {
LOGGER.debug("No relay domain has been defined, no filtering");
}
return true;
}
/*
* (non-Javadoc)
*
* @see
* com.github.sleroy.junit.mail.server.MailSaverInterface#saveEmailAndNotify
* (java. lang.String, java.lang.String, java.io.InputStream)
*/
@Override
public void saveEmailAndNotify(final String from, final String to, final InputStream data) {
final List relayDomains = serverConfiguration.getRelayDomains();
// We move everything that we can move outside the synchronized block to
// limit the impact
final EmailModel model = new EmailModel();
model.setFrom(from);
model.setTo(to);
final String mailContent = convertStreamToString(data);
model.setSubject(getSubjectFromStr(mailContent));
model.setEmailStr(mailContent);
model.setReceivedDate(new Date());
// Controls the relay domain
if (!isMatchingRelayDomains(to, relayDomains)) {
setChanged();
notifyObservers(new RejectedMailEvent(model));
return;
}
synchronized (getLock()) {
setChanged();
notifyObservers(new NewMailEvent(model));
}
}
}