INTEXT-6 - Add AWS SES Samples

* Add SES JavaMailSender Sample
* Add SES Spring Integration Sample
* Refactor DefaultAmazonSESMailSender to implement JavaMailSender and delegate to JavaMailSenderImpl rather than extending it
* Cleanup
This commit is contained in:
Gunnar Hillert
2013-01-17 17:14:54 -05:00
parent 639d4b27e0
commit 897fc0e9b4
34 changed files with 929 additions and 311 deletions

View File

@@ -23,7 +23,7 @@ import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHa
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public class AWSNamespaceHandler extends

View File

@@ -29,7 +29,7 @@ import org.w3c.dom.Element;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public abstract class AbstractAWSOutboundChannelAdapterParser extends

View File

@@ -28,7 +28,7 @@ import org.w3c.dom.Element;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public final class AmazonWSParserUtils {

View File

@@ -23,7 +23,7 @@ import com.amazonaws.AmazonWebServiceClient;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public interface AWSClientFactory<T extends AmazonWebServiceClient> {

View File

@@ -20,7 +20,7 @@ package org.springframework.integration.aws.core;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public interface AWSCredentials {

View File

@@ -20,7 +20,7 @@ package org.springframework.integration.aws.core;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public class AWSOperationException extends RuntimeException {

View File

@@ -34,7 +34,7 @@ import com.amazonaws.AmazonWebServiceClient;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public abstract class AbstractAWSClientFactory<T extends AmazonWebServiceClient> implements AWSClientFactory<T> {

View File

@@ -15,13 +15,15 @@
*/
package org.springframework.integration.aws.core;
import org.springframework.util.Assert;
/**
* The basic implementation class holding the Access key and the secret
* key for the AWS account .
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public class BasicAWSCredentials implements AWSCredentials {
@@ -45,12 +47,15 @@ public class BasicAWSCredentials implements AWSCredentials {
}
/**.
* The constructor accepting the access and secret key
* @param accessKey
* @param secretKey
* The constructor accepting the access and secret key.
*
* @param accessKey Must not be null or empty
* @param secretKey Must not be null or empty
*/
public BasicAWSCredentials(String accessKey, String secretKey) {
super();
Assert.hasText(accessKey, "The accessKey parameter must not be null or empty.");
Assert.hasText(secretKey, "The secretKey parameter must not be null or empty.");
this.accessKey = accessKey;
this.secretKey = secretKey;
}
@@ -68,6 +73,7 @@ public class BasicAWSCredentials implements AWSCredentials {
* @param accessKey
*/
public void setAccessKey(String accessKey) {
Assert.hasText(accessKey, "The accessKey parameter must not be null or empty.");
this.accessKey = accessKey;
}
@@ -84,6 +90,7 @@ public class BasicAWSCredentials implements AWSCredentials {
* @param secretKey
*/
public void setSecretKey(String secretKey) {
Assert.hasText(secretKey, "The secretKey parameter must not be null or empty.");
this.secretKey = secretKey;
}
}

View File

@@ -20,7 +20,7 @@ package org.springframework.integration.aws.core;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public class InvalidAWSCredentialsException extends RuntimeException {

View File

@@ -21,6 +21,7 @@ import java.util.Properties;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
@@ -30,7 +31,7 @@ import org.springframework.util.StringUtils;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public class PropertiesAWSCredentials extends BasicAWSCredentials implements InitializingBean {
@@ -44,11 +45,13 @@ public class PropertiesAWSCredentials extends BasicAWSCredentials implements Ini
private String propertyFileName;
/**.
* Constructor accepting the properties file
* @param propertyFileName
* Constructor accepting the properties file.
*
* @param propertyFileName Must not be null or empty
*/
public PropertiesAWSCredentials(String propertyFileName) {
super();
Assert.hasText(propertyFileName, "The propertyFileName parameter must not be null or empty.");
this.propertyFileName = propertyFileName;
}
@@ -95,10 +98,12 @@ public class PropertiesAWSCredentials extends BasicAWSCredentials implements Ini
}
/**.
* Sets the name of the file that will hold the AW credentials
* @param propertyFileName
* Sets the name of the file that will hold the AW credentials.
*
* @param propertyFileName Must not be null or empty
*/
public void setPropertyFileName(String propertyFileName) {
Assert.hasText(propertyFileName, "The propertyFileName parameter must not be null or empty.");
this.propertyFileName = propertyFileName;
}

View File

@@ -26,7 +26,7 @@ import org.springframework.mail.javamail.JavaMailSender;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public class AmazonSESMessageHandler extends MailSendingMessageHandler {

View File

@@ -25,7 +25,7 @@ import org.springframework.integration.core.MessageHandler;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public class AmazonSESOutboundAdapterParser extends

View File

@@ -24,7 +24,7 @@ import org.springframework.integration.aws.core.AWSOperationException;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public class AmazonSESMailSendException extends AWSOperationException {

View File

@@ -15,94 +15,107 @@
*/
package org.springframework.integration.aws.ses.core;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.io.InputStream;
import java.util.Properties;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.MimeMessage;
import org.springframework.integration.aws.core.AWSCredentials;
import org.springframework.integration.aws.core.AWSOperationException;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessagePreparator;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClient;
import com.amazonaws.services.simpleemail.model.RawMessage;
import com.amazonaws.services.simpleemail.model.SendRawEmailRequest;
import com.amazonaws.services.simpleemail.AWSJavaMailTransport;
/**
* The implementation class for sending mail using the Amazon SES service
*
* @author Amol Nayak
* @author Gunnar Hillert
*
* @since 1.0
* @since 0.5
*
*/
public class DefaultAmazonSESMailSender extends JavaMailSenderImpl {
/**.
* The API class used for sending email using Amazon SES
*/
private final AmazonSimpleEmailServiceClient emailService;
private final AWSCredentials credentials;
public class DefaultAmazonSESMailSender implements JavaMailSender {
public DefaultAmazonSESMailSender(AWSCredentials credentials) {
if(credentials == null)
if(credentials == null) {
throw new AWSOperationException(null, "Credentials cannot be null, provide a non null valid set of credentials");
this.credentials = credentials;
}
/*
* Setup JavaMail to use the Amazon Simple Email Service by specifying
* the "aws" protocol.
*/
Properties properties = new Properties();
properties.setProperty("mail.transport.protocol", "aws");
properties.setProperty(AWSJavaMailTransport.AWS_ACCESS_KEY_PROPERTY, credentials.getAccessKey());
properties.setProperty(AWSJavaMailTransport.AWS_SECRET_KEY_PROPERTY, credentials.getSecretKey());
javaMailSender.setJavaMailProperties(properties);
emailService = new AmazonSimpleEmailServiceClient(
new BasicAWSCredentials(credentials.getAccessKey(),
credentials.getSecretKey()));
}
private JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl() {
@Override
protected Transport getTransport(Session session)
throws NoSuchProviderException {
return new AWSJavaMailTransport(session, null);
}
};
/**
* The Actual implementation of the sending of the mail message using the AWS SES
* SDK
*/
@Override
protected void doSend(MimeMessage[] mimeMessages, Object[] originalMessages)
public void send(SimpleMailMessage simpleMessage) throws MailException {
javaMailSender.send(simpleMessage);
}
@Override
public void send(SimpleMailMessage[] simpleMessages) throws MailException {
javaMailSender.send(simpleMessages);
}
@Override
public MimeMessage createMimeMessage() {
return javaMailSender.createMimeMessage();
}
@Override
public MimeMessage createMimeMessage(InputStream contentStream)
throws MailException {
Map<Object, Exception> failedMessageMap = new HashMap<Object, Exception>();
if(mimeMessages != null && mimeMessages.length > 0) {
int index = 0;
for(MimeMessage mailMessage:mimeMessages) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mailMessage.writeTo(baos);
RawMessage rawMessage = new RawMessage(ByteBuffer.wrap(baos.toByteArray()));
SendRawEmailRequest rawMail = new SendRawEmailRequest(rawMessage);
emailService.sendRawEmail(rawMail);
index++;
} catch (Exception e) {
failedMessageMap.put(originalMessages != null? originalMessages[index]:mailMessage, e);
}
}
}
if(!failedMessageMap.isEmpty()) {
throw new AmazonSESMailSendException(credentials.getAccessKey(),
"Exception while sending one or more messages, see failedMessages for more details",
failedMessageMap);
}
return javaMailSender.createMimeMessage(contentStream);
}
@Override
public void setPort(int port) {
throw new UnsupportedOperationException("AWS SES Implementation of mail " +
"sender does not allow setting the port number");
public void send(MimeMessage mimeMessage) throws MailException {
javaMailSender.send(mimeMessage);
}
@Override
public void setHost(String host) {
throw new UnsupportedOperationException("AWS SES Implementation of mail " +
"sender does not allow setting the host name. It is already configured with an endpoint");
public void send(MimeMessage[] mimeMessages) throws MailException {
javaMailSender.send(mimeMessages);
}
@Override
public void send(MimeMessagePreparator mimeMessagePreparator)
throws MailException {
javaMailSender.send(mimeMessagePreparator);
}
@Override
public void send(MimeMessagePreparator[] mimeMessagePreparators)
throws MailException {
javaMailSender.send(mimeMessagePreparators);
}
//Should we disallow setSession?
}

View File

@@ -28,7 +28,7 @@ import com.amazonaws.services.sqs.AmazonSQSClient;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public class AWSClientFactoryTest {

View File

@@ -24,7 +24,7 @@ import java.util.Properties;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public abstract class BaseTestCase {

View File

@@ -32,7 +32,7 @@ import org.springframework.integration.test.util.TestUtils;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public abstract class AbstractAWSOutboundChannelAdapterParserTests<T extends MessageHandler> {

View File

@@ -30,7 +30,7 @@ import com.amazonaws.AmazonWebServiceClient;
* The abstract test class for Amazon WebService client factory tests
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public abstract class AbstractAWSClientFactoryTests<T extends AmazonWebServiceClient> {

View File

@@ -48,7 +48,7 @@ import org.springframework.mail.javamail.JavaMailSender;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public class AmazonSESMessageHandlerTests {

View File

@@ -15,22 +15,25 @@
*/
package org.springframework.integration.aws.ses.config.xml;
import java.util.Properties;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.aws.core.AWSCredentials;
import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.test.util.TestUtils;
import com.amazonaws.services.simpleemail.AWSJavaMailTransport;
/**
* The test class for the AmazonSESOutboundAdapterParser
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public class AmazonSESOutboundAdapterParserTests {
@@ -79,10 +82,11 @@ public class AmazonSESOutboundAdapterParserTests {
Assert.assertNotNull("Expected a non null EventDrivenConsumer", consumer);
MessageHandler handler = TestUtils.getPropertyValue(consumer, "handler", MessageHandler.class);
Assert.assertNotNull("Expected a non null messagehandler", handler);
AWSCredentials credentials = TestUtils.getPropertyValue(handler, "mailSender.credentials", AWSCredentials.class);
Assert.assertNotNull("Expected a non null instance of credentials", credentials);
Assert.assertEquals("dummy", credentials.getAccessKey());
Assert.assertEquals("dummy", credentials.getSecretKey());
Properties properties = TestUtils.getPropertyValue(handler, "mailSender.javaMailSender.javaMailProperties", Properties.class);
Assert.assertNotNull("Expected a non null instance of credentials", properties);
Assert.assertEquals("dummy", properties.getProperty(AWSJavaMailTransport.AWS_ACCESS_KEY_PROPERTY));
Assert.assertEquals("dummy", properties.getProperty(AWSJavaMailTransport.AWS_SECRET_KEY_PROPERTY));
}
/**

View File

@@ -15,7 +15,6 @@
*/
package org.springframework.integration.aws.ses.core;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import org.junit.BeforeClass;
@@ -38,7 +37,7 @@ import org.springframework.mail.javamail.MimeMessageHelper;
*
* @author Amol Nayak
*
* @since 1.0
* @since 0.5
*
*/
public class DefaultAmazonSESMailSenderAWSTests {
@@ -96,8 +95,7 @@ public class DefaultAmazonSESMailSenderAWSTests {
*/
@Test
public void sendMimeMessage() throws Exception {
Session session = sender.getSession();
MimeMessageHelper helper = new MimeMessageHelper(new MimeMessage(session));
MimeMessageHelper helper = new MimeMessageHelper(sender.createMimeMessage());
helper.setText("Some HTML Text", true);
helper.setTo(TO_EMAIL_ID);
helper.setFrom(TO_EMAIL_ID);
@@ -111,16 +109,15 @@ public class DefaultAmazonSESMailSenderAWSTests {
*/
@Test
public void sendMimeMessageArray() throws Exception {
Session session = sender.getSession();
MimeMessage[] messages = new MimeMessage[2];
MimeMessageHelper helper = new MimeMessageHelper(new MimeMessage(session));
MimeMessageHelper helper = new MimeMessageHelper(sender.createMimeMessage());
helper.setText("Some HTML Text One", true);
helper.setTo(TO_EMAIL_ID);
helper.setFrom(TO_EMAIL_ID);
helper.setSubject("Some HTML Message's Subject Line One");
MimeMessage message = helper.getMimeMessage();
messages[0] = message;
helper = new MimeMessageHelper(new MimeMessage(session));
helper = new MimeMessageHelper(sender.createMimeMessage());
helper.setText("Some HTML Text Two", true);
helper.setTo(TO_EMAIL_ID);
helper.setFrom(TO_EMAIL_ID);