Skip to content

Commit

Permalink
The big one: added full support for config properties file. Furthermo…
Browse files Browse the repository at this point in the history
…re solved cyclic package dependencies and bugs from findbugs and Intellij analyses. Added a lot of junit tests
  • Loading branch information
bbottema committed Jun 19, 2016
1 parent 53e75b2 commit 91a9beb
Show file tree
Hide file tree
Showing 42 changed files with 1,142 additions and 450 deletions.
10 changes: 10 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,16 @@
<version>2.5.2</version>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<forkCount>4</forkCount>
<reuseForks>false</reuseForks>
</configuration>
</plugin>

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
Expand Down
18 changes: 3 additions & 15 deletions src/main/java/org/simplejavamail/MailException.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,13 @@
* @author Benny Bottema
*/
@SuppressWarnings("serial")
public class MailException extends RuntimeException {
public abstract class MailException extends RuntimeException {

static final String GENERIC_ERROR = "Third party error";
static final String INVALID_ENCODING = "Encoding not accepted";
static final String INVALID_RECIPIENT = "Invalid TO address: %s";
static final String INVALID_REPLYTO = "Invalid REPLY TO address: %s";
static final String INVALID_SENDER = "Invalid FROM address: %s";
static final String MISSING_SENDER = "Email is not valid: missing sender";
static final String MISSING_RECIPIENT = "Email is not valid: missing recipients";
static final String MISSING_SUBJECT = "Email is not valid: missing subject";
static final String MISSING_CONTENT = "Email is not valid: missing content body";
static final String INVALID_DOMAINKEY = "Error signing MimeMessage with DKIM: %s";
static final String INVALID_PROXY_SLL_COMBINATION = "Proxy is not supported for SSL connections (this is a limitation by the underlying JavaMail framework)";

MailException(final String message) {
protected MailException(final String message) {
super(message);
}

public MailException(final String message, final Exception cause) {
protected MailException(final String message, final Exception cause) {
super(message, cause);
}
}
52 changes: 0 additions & 52 deletions src/main/java/org/simplejavamail/ServerConfig.java

This file was deleted.

54 changes: 28 additions & 26 deletions src/main/java/org/simplejavamail/email/Email.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.simplejavamail.email;

import org.simplejavamail.internal.util.ConfigLoader;
import org.simplejavamail.internal.util.MimeMessageParser;

import javax.activation.DataSource;
Expand All @@ -13,6 +12,7 @@
import java.util.*;

import static java.lang.String.format;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.simplejavamail.internal.util.ConfigLoader.Property.*;
import static org.simplejavamail.internal.util.ConfigLoader.getProperty;
import static org.simplejavamail.internal.util.ConfigLoader.hasProperty;
Expand Down Expand Up @@ -102,13 +102,6 @@ public Email() {
}
}

/**
* @see #signWithDomainKey(InputStream, String, String)
*/
public void signWithDomainKey(final byte[] dkimPrivateKey, final String signingDomain, final String selector) {
signWithDomainKey(new ByteArrayInputStream(dkimPrivateKey), signingDomain, selector);
}

/**
* @see #signWithDomainKey(InputStream, String, String)
*/
Expand Down Expand Up @@ -211,8 +204,8 @@ public void addRecipient(final String name, final String address, final Recipien
}

/**
* Adds an embedded image (attachment type) to the email message and generates the necessary {@link DataSource} with the given byte data. Then delegates to
* {@link #addEmbeddedImage(String, DataSource)}. At this point the datasource is actually a {@link ByteArrayDataSource}.
* Adds an embedded image (attachment type) to the email message and generates the necessary {@link DataSource} with the given byte data. Then
* delegates to {@link #addEmbeddedImage(String, DataSource)}. At this point the datasource is actually a {@link ByteArrayDataSource}.
*
* @param name The name of the image as being referred to from the message content body (eg. '&lt;cid:signature&gt;').
* @param data The byte data of the image to be embedded.
Expand All @@ -238,8 +231,8 @@ public void addEmbeddedImage(final String name, final DataSource imagedata) {
}

/**
* Adds a header to the {@link #headers} list. The value is stored as a <code>String</code>.
* example: <code>email.addHeader("X-Priority", 2)</code>
* Adds a header to the {@link #headers} list. The value is stored as a <code>String</code>. example: <code>email.addHeader("X-Priority",
* 2)</code>
*
* @param name The name of the header.
* @param value The value of the header, which will be stored using {@link String#valueOf(Object)}.
Expand Down Expand Up @@ -438,11 +431,6 @@ public static class Builder {
*/
private InputStream dkimPrivateKeyInputStream;

/**
* A byte array containg the private key data to be used for signing with DKIM.
*/
private byte[] dkimPrivateKey;

/**
* The domain used for signing with DKIM.
*/
Expand Down Expand Up @@ -605,8 +593,8 @@ public Builder bcc(final Recipient recipient) {
}

/**
* Adds an embedded image (attachment type) to the email message and generates the necessary {@link DataSource} with the given byte data. Then delegates
* to {@link #addEmbeddedImage(String, DataSource)}. At this point the datasource is actually a {@link ByteArrayDataSource}.
* Adds an embedded image (attachment type) to the email message and generates the necessary {@link DataSource} with the given byte data. Then
* delegates to {@link #addEmbeddedImage(String, DataSource)}. At this point the datasource is actually a {@link ByteArrayDataSource}.
*
* @param name The name of the image as being referred to from the message content body (eg. '&lt;cid:signature&gt;').
* @param data The byte data of the image to be embedded.
Expand All @@ -632,8 +620,8 @@ public Builder embedImage(final String name, final DataSource imagedata) {
}

/**
* Adds a header to the {@link #headers} list. The value is stored as a <code>String</code>.
* example: <code>email.addHeader("X-Priority", 2)</code>
* Adds a header to the {@link #headers} list. The value is stored as a <code>String</code>. example: <code>email.addHeader("X-Priority",
* 2)</code>
*
* @param name The name of the header.
* @param value The value of the header, which will be stored using {@link String#valueOf(Object)}.
Expand Down Expand Up @@ -675,7 +663,17 @@ public Builder addAttachment(final String name, final DataSource filedata) {
* Sets all info needed for DKIM, using a byte array for private key data.
*/
public Builder signWithDomainKey(final byte[] dkimPrivateKey, final String signingDomain, final String selector) {
this.dkimPrivateKey = dkimPrivateKey.clone();
this.dkimPrivateKeyInputStream = new ByteArrayInputStream(dkimPrivateKey);
this.signingDomain = signingDomain;
this.selector = selector;
return this;
}

/**
* Sets all info needed for DKIM, using a byte array for private key data.
*/
public Builder signWithDomainKey(final String dkimPrivateKey, final String signingDomain, final String selector) {
this.dkimPrivateKeyInputStream = new ByteArrayInputStream(dkimPrivateKey.getBytes(UTF_8));
this.signingDomain = signingDomain;
this.selector = selector;
return this;
Expand Down Expand Up @@ -719,9 +717,7 @@ private Email(Builder builder) {
textHTML = builder.textHTML;
subject = builder.subject;

if (builder.dkimPrivateKey != null) {
signWithDomainKey(builder.dkimPrivateKey, builder.signingDomain, builder.selector);
} else if (builder.dkimPrivateKeyFile != null) {
if (builder.dkimPrivateKeyFile != null) {
signWithDomainKey(builder.dkimPrivateKeyFile, builder.signingDomain, builder.selector);
} else if (builder.dkimPrivateKeyInputStream != null) {
signWithDomainKey(builder.dkimPrivateKeyInputStream, builder.signingDomain, builder.selector);
Expand All @@ -736,11 +732,17 @@ private Email(Builder builder) {

/**
* Constructor for {@link javax.mail.internet.MimeMessage}.
* <p>
* <strong>Doen add default recipient that may have been provided in a config file.</strong>
*
* @param mimeMessage The MimeMessage from which to create the email.
*/
public Email(MimeMessage mimeMessage) {
this();
recipients = new ArrayList<>();
embeddedImages = new ArrayList<>();
attachments = new ArrayList<>();
headers = new HashMap<>();

try {
fillEmailFromMimeMessage(new MimeMessageParser(mimeMessage).parse());
} catch (MessagingException | IOException e) {
Expand Down
48 changes: 39 additions & 9 deletions src/main/java/org/simplejavamail/internal/util/ConfigLoader.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.simplejavamail.internal.util;

import org.simplejavamail.TransportStrategy;
import org.simplejavamail.mailer.TransportStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -10,6 +10,9 @@
import java.util.Map;
import java.util.Properties;

import static java.util.Collections.unmodifiableMap;
import static org.simplejavamail.internal.util.MiscUtil.checkArgumentNotEmpty;

/**
* Contains list of possible properties names and can produce a map of property values, if provided as file "{@value #FILENAME}" on the classpath or
* as environment property.
Expand All @@ -20,7 +23,20 @@ public class ConfigLoader {

private static final String FILENAME = "simplejavamail.properties";

private static final Map<Property, Object> RESOLVED_PROPERTIES = loadProperties(FILENAME);
/**
* Initially try to load properties from "{@value #FILENAME}".
*
* @see #loadProperties(String)
* @see #loadProperties(InputStream)
*/
private static final Map<Property, Object> RESOLVED_PROPERTIES = new HashMap<>();

static {
// static initializer block, because loadProperties needs to modify RESOLVED_PROPERTIES while loading
// this is not possible when we are initializing the same field.
// RESOLVED_PROPERTIES = loadProperties(FILENAME); <-- not possible
loadProperties(FILENAME);
}

public enum Property {
JAVAXMAIL_DEBUG("simplejavamail.javaxmail.debug"),
Expand Down Expand Up @@ -76,26 +92,28 @@ public static <T> T valueOrProperty(T value, Property property, T defaultValue)
}
}

public static boolean hasProperty(Property property) {
public static synchronized boolean hasProperty(Property property) {
return RESOLVED_PROPERTIES.containsKey(property);
}

public static <T> T getProperty(Property property) {
public static synchronized <T> T getProperty(Property property) {
//noinspection unchecked
return (T) RESOLVED_PROPERTIES.get(property);
}

/**
* Loads properties from property file on the classpath, if provided.
* Loads properties from property file on the classpath, if provided. Calling this method only has effect on new Email and Mailer instances after
* this.
* <p>
* This method the internal list of properties and also returns the list to the caller.
*/
static Map<Property, Object> loadProperties(String filename) {
public static Map<Property, Object> loadProperties(String filename) {
InputStream input = null;

try {
input = ConfigLoader.class.getClassLoader().getResourceAsStream(filename);
if (input != null) {
Properties prop = new Properties();
prop.load(input);
return readProperties(prop);
return loadProperties(input);
} else {
LOGGER.debug("Property file not found on classpath, skipping config file");
}
Expand All @@ -113,6 +131,18 @@ static Map<Property, Object> loadProperties(String filename) {
return new HashMap<>();
}

/**
* Loads properties from {@link InputStream}. Calling this method only has effect on new Email and Mailer instances after this.
*/
public static synchronized Map<Property, Object> loadProperties(InputStream input)
throws IOException {
Properties prop = new Properties();
prop.load(checkArgumentNotEmpty(input, "InputStream was null"));
RESOLVED_PROPERTIES.clear();
RESOLVED_PROPERTIES.putAll(readProperties(prop));
return unmodifiableMap(RESOLVED_PROPERTIES);
}

/**
* @return All properties in priority of System property > File properties.
*/
Expand Down
Loading

1 comment on commit 91a9beb

@bbottema
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implements #42

Please sign in to comment.