Author: dkuleshov
Date: 2012-02-14 04:37:23 -0500 (Tue, 14 Feb 2012)
New Revision: 5628
Modified:
kernel/branches/2.4.x/exo.kernel.component.common/pom.xml
kernel/branches/2.4.x/exo.kernel.component.common/src/main/java/org/exoplatform/services/mail/MailService.java
kernel/branches/2.4.x/exo.kernel.component.common/src/main/java/org/exoplatform/services/mail/impl/MailServiceImpl.java
kernel/branches/2.4.x/exo.kernel.component.common/src/main/java/org/exoplatform/services/net/impl/NetServiceImpl.java
kernel/branches/2.4.x/exo.kernel.component.common/src/test/java/org/exoplatform/services/mail/test/TestMailService.java
kernel/branches/2.4.x/exo.kernel.component.common/src/test/resources/conf/portal/test-configuration.xml
kernel/branches/2.4.x/exo.kernel.component.common/src/test/resources/test.policy
kernel/branches/2.4.x/pom.xml
Log:
EXOJCR-1733: added the ability to send messages via mail service asynchronously
Modified: kernel/branches/2.4.x/exo.kernel.component.common/pom.xml
===================================================================
--- kernel/branches/2.4.x/exo.kernel.component.common/pom.xml 2012-02-13 15:35:28 UTC (rev
5627)
+++ kernel/branches/2.4.x/exo.kernel.component.common/pom.xml 2012-02-14 09:37:23 UTC (rev
5628)
@@ -106,6 +106,11 @@
<artifactId>transactions-jta</artifactId>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>dumbster</groupId>
+ <artifactId>dumbster</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
Modified:
kernel/branches/2.4.x/exo.kernel.component.common/src/main/java/org/exoplatform/services/mail/MailService.java
===================================================================
---
kernel/branches/2.4.x/exo.kernel.component.common/src/main/java/org/exoplatform/services/mail/MailService.java 2012-02-13
15:35:28 UTC (rev 5627)
+++
kernel/branches/2.4.x/exo.kernel.component.common/src/main/java/org/exoplatform/services/mail/MailService.java 2012-02-14
09:37:23 UTC (rev 5628)
@@ -18,23 +18,98 @@
*/
package org.exoplatform.services.mail;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
/**
+ * Interface provides basic operations for sending mail messages and mail service
+ * configuration data retrieval. Defines synchronous and asynchronous methods
+ * responsible for sending mail message. They can receive parameters of different types
+ * to create a mail send. You can pass {@link Message}, {@link MimeMessage}
+ * or specify mail message data explicitly via {@String} parameters.
* @author Tuan Nguyen (tuan08(a)users.sourceforge.net)
* @since Oct 13, 2004
* @version $Id: MailService.java 5332 2006-04-29 18:32:44Z geaz $
*/
public interface MailService
{
+ /**
+ * Provides {@link Session} instance, which is to be used throughout {@link
MailService} methods
+ * @return {@link Session}
+ */
public Session getMailSession();
+ /**
+ * Provides outgoing server information, which is basically its hostname or ip
address.
+ * This server is used as transceiver for mail messages. {@link MailService} should
send message
+ * to the server first and than server will resend messages to the receivers.
+ * @return
+ */
public String getOutgoingMailServer();
+ /**
+ * Sends mail message based on passed {@link String} parameters.
+ * @param from - {@link String} identificator of mail sender. For example
'test.sender(a)test.test'
+ * @param to - {@link String} identificator of mail receiver. For example
'test.receiver(a)test.test'
+ * @param subject - {@link String} subject of mail message
+ * @param body - {@link String} contents of mail message
+ * @throws Exception is thrown if something's gone wrong during mail send
procedure
+ */
public void sendMessage(String from, String to, String subject, String body) throws
Exception;
+ /**
+ * Sends mail message based on {@link Message} instance
+ * @param message - {@link Message} provides mail message related data (e.g. subject,
content etc.)
+ * @throws Exception is thrown if something's gone wrong during mail send
procedure
+ */
public void sendMessage(Message message) throws Exception;
+ /**
+ * Sends mail message based on {@link MimeMessage} instance
+ * @param message - {@link MimeMessage} provides mail message related data (e.g.
subject, content etc.)
+ * @throws Exception is thrown if something's gone wrong during mail send
procedure
+ */
public void sendMessage(MimeMessage message) throws Exception;
+
+ /**
+ * Asynchronous variant of {@link MailService#sendMessage(String, String, String,
String)}.
+ * Returns {@link Future} object, which allows to track mail sending result. Calling
{@link Future#get()}
+ * for this object returns {@link Boolean#TRUE} if mail is sent successfully,
+ * throws {@link ExecutionException} if some exception occured during mail sending.
+ * Calling {@link ExecutionException#getCause()} for the thrown exception object
provides the exception,
+ * which indeed occured during sending mail.
+ * @param from - {@link String} identificator of mail sender. For example
'test.sender(a)test.test'
+ * @param to - {@link String} identificator of mail receiver. For example
'test.receiver(a)test.test'
+ * @param subject - {@link String} subject of mail message
+ * @param body - {@link String} contents of mail message
+ * @return {@link Future} object to watch the result of asynchronous calculation
+ */
+ public Future<Boolean> sendMessageAsynch(String from, String to, String subject,
String body);
+
+ /**
+ * Asynchronous variant of {@link MailService#sendMessage(Message)}.
+ * Returns {@link Future} object, which allows to track mail sending result. Calling
{@link Future#get()}
+ * for this object returns {@link Boolean#TRUE} if mail is sent successfully,
+ * throws {@link ExecutionException} if some exception occured during mail sending.
+ * Calling {@link ExecutionException#getCause()} for the thrown exception object
provides the exception,
+ * which indeed occured during sending mail.
+ * @param message - {@link Message} provides mail message related data (e.g. subject,
content etc.)
+ * @return {@link Future} object to watch the result of asynchronous calculation
+ */
+ public Future<Boolean> sendMessageAsynch(Message message);
+
+ /**
+ * Asynchronous variant of {@link MailService#sendMessage(MimeMessage)}.
+ * Returns {@link Future} object, which allows to track mail sending result. Calling
{@link Future#get()}
+ * for this object returns {@link Boolean#TRUE} if mail is sent successfully,
+ * throws {@link ExecutionException} if some exception occured during mail sending.
+ * Calling {@link ExecutionException#getCause()} for the thrown exception object
provides the exception,
+ * which indeed occured during sending mail.
+ * @param message - {@link MimeMessage} provides mail message related data (e.g.
subject, content etc.)
+ * @return {@link Future} object to watch the result of asynchronous calculation
+ */
+ public Future<Boolean> sendMessageAsynch(MimeMessage message);
}
Modified:
kernel/branches/2.4.x/exo.kernel.component.common/src/main/java/org/exoplatform/services/mail/impl/MailServiceImpl.java
===================================================================
---
kernel/branches/2.4.x/exo.kernel.component.common/src/main/java/org/exoplatform/services/mail/impl/MailServiceImpl.java 2012-02-13
15:35:28 UTC (rev 5627)
+++
kernel/branches/2.4.x/exo.kernel.component.common/src/main/java/org/exoplatform/services/mail/impl/MailServiceImpl.java 2012-02-14
09:37:23 UTC (rev 5628)
@@ -20,6 +20,7 @@
import org.exoplatform.commons.utils.PrivilegedSystemHelper;
import org.exoplatform.commons.utils.SecurityHelper;
+import org.exoplatform.container.ExoContainer;
import org.exoplatform.container.xml.InitParams;
import org.exoplatform.services.mail.Attachment;
import org.exoplatform.services.mail.MailService;
@@ -30,6 +31,12 @@
import java.util.Date;
import java.util.List;
import java.util.Properties;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.ThreadFactory;
import javax.activation.DataHandler;
import javax.mail.Part;
@@ -43,16 +50,39 @@
import javax.mail.util.ByteArrayDataSource;
/**
+ * Basically this is {@link MailService} implementation build on top of javax.mail
package.
+ * You may define the behaviour of the service via {@link InitParams}, which can
+ * be set in configuration file of the {@link ExoContainer}.
+ * <p>
+ * Note: To be able to send mails you must provide active SMTP server and
+ * mention it in service configuration.
+ * <p>
* Created by The eXo Platform SAS Author : Phung Hai Nam phunghainam(a)gmail.com
* Dec 23, 2005
*/
public class MailServiceImpl implements MailService
{
+ /**
+ * String mapping of configuration parameter to define maximal number
+ * of threads for asynchronous mail message sending
+ */
+ static final String MAX_THREAD_NUMBER = "mail.max.thread.number";
private Session mailSession_;
private Properties props_;
+ /**
+ * Provides thread pool routines for asynchronous mail message sending
+ */
+ private ExecutorService executorService;
+
+ /**
+ * Track current threads number used for asynchronouys mail send
+ * to set explicit thread names.
+ */
+ private static volatile int mailServiceThreadCounter = 0;
+
public MailServiceImpl(InitParams params) throws Exception
{
props_ = new Properties(PrivilegedSystemHelper.getProperties());
@@ -80,18 +110,38 @@
}
});
}
+ int threadNumber =
+ props_.getProperty(MAX_THREAD_NUMBER) != null ?
Integer.valueOf(props_.getProperty(MAX_THREAD_NUMBER))
+ : Runtime.getRuntime().availableProcessors();
+
+ executorService = Executors.newFixedThreadPool(threadNumber, new ThreadFactory()
+ {
+ public Thread newThread(Runnable arg0)
+ {
+ return new Thread(arg0, "MailServiceThread-" +
mailServiceThreadCounter++);
+ }
+ });
}
+ /**
+ * {@inheritDoc}
+ */
public Session getMailSession()
{
return mailSession_;
}
+ /**
+ * {@inheritDoc}
+ */
public String getOutgoingMailServer()
{
return props_.getProperty("mail.smtp.host");
}
+ /**
+ * {@inheritDoc}
+ */
public void sendMessage(String from, String to, String subject, String body) throws
Exception
{
Message message = new Message();
@@ -102,6 +152,9 @@
sendMessage(message);
}
+ /**
+ * {@inheritDoc}
+ */
public void sendMessage(Message message) throws Exception
{
MimeMessage mimeMessage = new MimeMessage(getMailSession());
@@ -190,17 +243,82 @@
sendMessage(mimeMessage);
}
+ /**
+ * {@inheritDoc}
+ */
public void sendMessage(MimeMessage message) throws Exception
{
Transport.send(message);
}
- private String[] getArrs(String toArray)
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Future<Boolean> sendMessageAsynch(final String from, final String to,
final String subject,
+ final String body)
{
+ FutureTask<Boolean> ft = new FutureTask<Boolean>(new
Callable<Boolean>()
+ {
+ @Override
+ public Boolean call() throws Exception
+ {
+ sendMessage(from, to, subject, body);
+ return true;
+ }
+ });
+
+ executorService.execute(ft);
+ return ft;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Future<Boolean> sendMessageAsynch(final Message message)
+ {
+ FutureTask<Boolean> ft = new FutureTask<Boolean>(new
Callable<Boolean>()
+ {
+ @Override
+ public Boolean call() throws Exception
+ {
+ sendMessage(message);
+ return true;
+ }
+ });
+
+ executorService.execute(ft);
+ return ft;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Future<Boolean> sendMessageAsynch(final MimeMessage message)
+ {
+ FutureTask<Boolean> ft = new FutureTask<Boolean>(new
Callable<Boolean>()
+ {
+ @Override
+ public Boolean call() throws Exception
+ {
+ sendMessage(message);
+ return true;
+ }
+ });
+
+ executorService.execute(ft);
+ return ft;
+ }
+
+ protected String[] getArrs(String toArray)
+ {
if (toArray != null && !toArray.equals(""))
{
return toArray.split(",");
}
return null;
}
+
}
Modified:
kernel/branches/2.4.x/exo.kernel.component.common/src/main/java/org/exoplatform/services/net/impl/NetServiceImpl.java
===================================================================
---
kernel/branches/2.4.x/exo.kernel.component.common/src/main/java/org/exoplatform/services/net/impl/NetServiceImpl.java 2012-02-13
15:35:28 UTC (rev 5627)
+++
kernel/branches/2.4.x/exo.kernel.component.common/src/main/java/org/exoplatform/services/net/impl/NetServiceImpl.java 2012-02-14
09:37:23 UTC (rev 5628)
@@ -47,6 +47,7 @@
}
});
endTime = System.currentTimeMillis();
+ socket.close();
}
catch (PrivilegedActionException e)
{
Modified:
kernel/branches/2.4.x/exo.kernel.component.common/src/test/java/org/exoplatform/services/mail/test/TestMailService.java
===================================================================
---
kernel/branches/2.4.x/exo.kernel.component.common/src/test/java/org/exoplatform/services/mail/test/TestMailService.java 2012-02-13
15:35:28 UTC (rev 5627)
+++
kernel/branches/2.4.x/exo.kernel.component.common/src/test/java/org/exoplatform/services/mail/test/TestMailService.java 2012-02-14
09:37:23 UTC (rev 5628)
@@ -18,6 +18,9 @@
*/
package org.exoplatform.services.mail.test;
+import com.dumbster.smtp.SimpleSmtpServer;
+import com.dumbster.smtp.SmtpMessage;
+
import org.exoplatform.container.PortalContainer;
import org.exoplatform.services.mail.Attachment;
import org.exoplatform.services.mail.MailService;
@@ -26,10 +29,16 @@
import org.exoplatform.test.BasicTestCase;
import java.io.ByteArrayInputStream;
+import java.util.Iterator;
import java.util.Properties;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
import javax.mail.Flags;
+import javax.mail.MessagingException;
import javax.mail.Session;
+import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
@@ -39,14 +48,58 @@
*/
public class TestMailService extends BasicTestCase
{
- static private String EMAIL = "<exo@PC01>";
+ /**
+ * Test email subject used throughout the test cases
+ */
+ static private String MAIL_SUBJECT = "eXo Test Subject";
+
+ /**
+ * Test email contents used throughout the test cases
+ */
+ static private String MAIL_CONTENTS = "eXo Mail Service Test Content";
- static private int MAIL_PORT = 25;
+ /**
+ * Test email attachment used throughout the test cases
+ */
+ static private String ATTACHMENT = "eXo Mail Service Test Attachment";
- private MailService service_;
+ /**
+ * Mime-type corresponding to plain text documents
+ */
+ static private String TEXT_PLAIN = "text/plain";
- private NetService nservice_;
+ /**
+ * Mime-type corresponding to html documents
+ */
+ static private String TEXT_HTML = "text/html";
+ /**
+ * Time we assume to be enough to wait for server to receive sent emails
+ */
+ static private long ONE_SECOND = 1000l;
+
+ /**
+ * SMTP server prot, used for mail session
+ * and {@link SimpleSmtpServer} configuration
+ * Though the default port is 25, to run server
+ * with default port you must have root privilegies
+ */
+ static private int SMTP_PORT = 2525;
+
+ /**
+ * Thread number for asynchronous message send tests
+ */
+ static private int THREAD_NUMBER = 4;
+
+ /**
+ * SMTP mail server instance, to emulate basic SMTP mail server functions
+ */
+ protected SimpleSmtpServer mailServer;
+
+ private MailService service;
+
+ private NetService netService;
+
public TestMailService(String name)
{
super(name);
@@ -54,78 +107,409 @@
public void setUp() throws Exception
{
- if (service_ == null)
+ if (service == null)
{
PortalContainer pcontainer = PortalContainer.getInstance();
- service_ =
(MailService)pcontainer.getComponentInstanceOfType(MailService.class);
- nservice_ =
(NetService)pcontainer.getComponentInstanceOfType(NetService.class);
+ service =
(MailService)pcontainer.getComponentInstanceOfType(MailService.class);
+ netService =
(NetService)pcontainer.getComponentInstanceOfType(NetService.class);
}
+ // starting dummy SMTP Server
+ if (mailServer == null)
+ {
+ mailServer = SimpleSmtpServer.start(SMTP_PORT);
+ }
}
- public void testSendMineMessage() throws Exception
+ public void tearDown() throws Exception
{
+ mailServer.stop();
+ }
+
+ public void testSendMimeMessage() throws Exception
+ {
if (!pingMailServer())
- return;
- Properties props = new Properties(System.getProperties());
- Session session = Session.getDefaultInstance(props, null);
- session.setDebug(true);
- MimeMessage message = new MimeMessage(session);
- message.setFrom(new InternetAddress("exo@PC01"));
- message.setRecipients(javax.mail.Message.RecipientType.TO, EMAIL);
- message.setSubject("Test Java Mail Service");
- message.setContent("This is the contents of the Java Mail !",
"text/plain");
+ {
+ fail();
+ }
+
+ MimeMessage message = new MimeMessage(service.getMailSession());
+ message.setFrom(new InternetAddress(generateRandomEmailSender()));
+ message.setRecipients(javax.mail.Message.RecipientType.TO,
generateRandomEmailRecipient());
+ message.setSubject(MAIL_SUBJECT);
+ message.setContent(MAIL_CONTENTS, TEXT_PLAIN);
Flags flags = new Flags();
flags.add(Flags.Flag.RECENT);
message.setFlags(flags, true);
- service_.sendMessage(message);
+
+ cleanEmailMessages();
+ assertEquals("SMTP server should be now empty", 0,
mailServer.getReceivedEmailSize());
+ assertFalse(isEmailMessageSent(MAIL_SUBJECT));
+ service.sendMessage(message);
+ Thread.sleep(ONE_SECOND);
+ assertEquals("SMTP server should have one message", 1,
mailServer.getReceivedEmailSize());
+ assertTrue(isEmailMessageSent(MAIL_SUBJECT));
}
public void testSendMessage() throws Exception
{
if (!pingMailServer())
- return;
- ByteArrayInputStream is = new ByteArrayInputStream("===> Attachement
text".getBytes());
- String TO = "<exo@PC01>";
- String FROM = TO;
- String CC = "<exo@PC01>, <exo@PC01>";
- String BCC = "<exo@PC01>, <exo@PC01>";
- String subject = "Subject test";
- String contents = "This is test sendMessage method !";
- String mimeType = "text/html";
+ {
+ fail();
+ }
+
Message message = new Message();
- message.setFrom(FROM);
- message.setTo(TO);
- message.setCC(CC);
- message.setBCC(BCC);
- message.setSubject(subject);
- message.setBody(contents);
- message.setMimeType(mimeType);
+ message.setFrom(generateRandomEmailSender());
+ message.setTo(generateRandomEmailRecipient());
+ message.setCC(generateRandomEmailRecipient() + "," +
generateRandomEmailRecipient());
+ message.setBCC(generateRandomEmailRecipient() + "," +
generateRandomEmailRecipient());
+ message.setSubject(MAIL_SUBJECT);
+ message.setBody(MAIL_CONTENTS);
+ message.setMimeType(TEXT_HTML);
Attachment attachment = new Attachment();
- attachment.setInputStream(is);
- attachment.setMimeType("text/plain");
+ attachment.setInputStream(new ByteArrayInputStream(ATTACHMENT.getBytes()));
+ attachment.setMimeType(TEXT_PLAIN);
message.addAttachment(attachment);
- service_.sendMessage(message);
+
+ cleanEmailMessages();
+ assertEquals("SMTP server should be now empty", 0,
mailServer.getReceivedEmailSize());
+ assertFalse(isEmailMessageSent(MAIL_SUBJECT));
+ service.sendMessage(message);
+ Thread.sleep(ONE_SECOND);
+ assertEquals("SMTP server should have one message", 1,
mailServer.getReceivedEmailSize());
+ assertTrue(isEmailMessageSent(MAIL_SUBJECT));
}
- public void testSendMessageWithInfo() throws Exception
+ public void testSendSimplMessage() throws Exception
{
if (!pingMailServer())
- return;
- String TO = "<exo@PC01>";
- String FROM = TO;
- String subject = "Subject test";
- String contents = "This is test sendMessage method with 4 parameter !";
- service_.sendMessage(FROM, TO, subject, contents);
+ {
+ fail();
+ }
+
+ cleanEmailMessages();
+ assertEquals("SMTP server should be now empty", 0,
mailServer.getReceivedEmailSize());
+ assertFalse(isEmailMessageSent(MAIL_SUBJECT));
+ service.sendMessage(generateRandomEmailSender(), generateRandomEmailRecipient(),
MAIL_SUBJECT, MAIL_CONTENTS);
+ Thread.sleep(ONE_SECOND);
+ assertEquals("SMTP server should have one message", 1,
mailServer.getReceivedEmailSize());
+ assertTrue(isEmailMessageSent(MAIL_SUBJECT));
}
+ /**
+ * Here we test asynchronous email sending explicitly defined by sender,
+ * recipient, subject and content parameters.
+ * We check if we can get real cause of exception, if that occurs during
+ * message sending process.
+ */
+ public void testSendSimpleMessageAsynchExceptionCause() throws Exception
+ {
+ if (!pingMailServer())
+ {
+ fail();
+ }
+
+ Future<Boolean> future =
+ service.sendMessageAsynch("!@#$%^&*()",
generateRandomEmailSender(), MAIL_SUBJECT, MAIL_CONTENTS);
+
+ try
+ {
+ future.get();
+ fail();
+ }
+ catch (ExecutionException ee)
+ {
+ assertEquals("We tried to send mail with malformed sender field,"
+ + " so we expect an AdressException to be the real cause of
ExecutionException", ee.getCause().getClass(),
+ AddressException.class);
+ }
+ }
+
+ /**
+ * Here we test asynchronous email sending explicitly defined by sender,
+ * recipient, subject and content parameters.
+ * We check concurrent execution of {@link FutureTask}
+ */
+ public void testSendSimpleMessageAsynch() throws Exception
+ {
+ if (!pingMailServer())
+ {
+ fail();
+ }
+
+ @SuppressWarnings("unchecked")
+ Future<Boolean>[] futures = new Future[THREAD_NUMBER];
+
+ cleanEmailMessages();
+
+ assertEquals("SMTP server should be now empty", 0,
mailServer.getReceivedEmailSize());
+ for (int i = 0; i < THREAD_NUMBER; i++)
+ {
+ assertFalse(isEmailMessageSent(MAIL_SUBJECT + i));
+ futures[i] =
+ service.sendMessageAsynch(generateRandomEmailSender(),
generateRandomEmailRecipient(), MAIL_SUBJECT + i,
+ MAIL_CONTENTS + i);
+ }
+
+ for (int i = 0; i < THREAD_NUMBER; i++)
+ {
+ assertTrue(futures[i].get());
+ assertTrue(isEmailMessageSent(MAIL_SUBJECT + i));
+ }
+ //we assume that one thread sends one email
+ assertEquals("SMTP server should have" + THREAD_NUMBER + " message
(asynchronously sent)", THREAD_NUMBER,
+ mailServer.getReceivedEmailSize());
+ }
+
+
+ /**
+ * Here we test asynchronous email sending of {@link MimeMessage}.
+ * We check if we can get real cause of exception, if that occurs during
+ * message sending process.
+ */
+ public void testSendMimeMessageAsynchExceptionCause() throws Exception
+ {
+ if (!pingMailServer())
+ {
+ fail();
+ }
+
+ Flags flags = new Flags();
+ flags.add(Flags.Flag.RECENT);
+
+ Properties props = new Properties(System.getProperties());
+ props.put("mail.smtp.port", SMTP_PORT + 1);
+ Session session = Session.getDefaultInstance(props, null);
+
+ MimeMessage message = new MimeMessage(session);
+ message.setFrom(new InternetAddress(generateRandomEmailSender()));
+ message.setRecipients(javax.mail.Message.RecipientType.TO,
generateRandomEmailRecipient());
+ message.setSubject(MAIL_SUBJECT);
+ message.setContent(MAIL_CONTENTS, TEXT_PLAIN);
+ message.setFlags(flags, true);
+
+ Future<Boolean> future = service.sendMessageAsynch(message);
+
+ try
+ {
+ future.get();
+ fail();
+ }
+ catch (ExecutionException ee)
+ {
+ assertEquals("We tried to send mail with malformed SMTP port (" +
SMTP_PORT + 1
+ + "), so we expect a MessagingException to be the real cause of
ExecutionException", ee.getCause()
+ .getClass(), MessagingException.class);
+ }
+ }
+
+ /**
+ * Here we test asynchronous email sending of {@link MimeMessage}.
+ * We check concurrent execution of {@link FutureTask}
+ */
+ public void testSendMimeMessageAsynch() throws Exception
+ {
+ if (!pingMailServer())
+ {
+ fail();
+ }
+
+ @SuppressWarnings("unchecked")
+ Future<Boolean>[] futures = new Future[THREAD_NUMBER];
+ MimeMessage message;
+ Flags flags = new Flags(Flags.Flag.RECENT);
+ Session session = service.getMailSession();
+
+ cleanEmailMessages();
+
+ assertEquals("SMTP server should be now empty", 0,
mailServer.getReceivedEmailSize());
+
+ for (int i = 0; i < THREAD_NUMBER; i++)
+ {
+ assertFalse(isEmailMessageSent(MAIL_SUBJECT + i));
+
+ message = new MimeMessage(session);
+ message.setFrom(new InternetAddress(generateRandomEmailSender()));
+ message.setRecipients(javax.mail.Message.RecipientType.TO,
generateRandomEmailRecipient());
+ message.setSubject(MAIL_SUBJECT + i);
+ message.setContent(MAIL_CONTENTS + i, TEXT_PLAIN);
+ message.setFlags(flags, true);
+
+ futures[i] = service.sendMessageAsynch(message);
+ }
+
+ for (int i = 0; i < THREAD_NUMBER; i++)
+ {
+ assertTrue(futures[i].get());
+ assertTrue(isEmailMessageSent(MAIL_SUBJECT + i));
+ }
+ //we assume that one thread sends one email
+ assertEquals("SMTP server should have" + THREAD_NUMBER + " message
(asynchronously sent)", THREAD_NUMBER,
+ mailServer.getReceivedEmailSize());
+ }
+
+ /**
+ * Here we test asynchronous email sending of {@link Message}.
+ * We check if we can get real cause of exception, if that occurs during
+ * message sending process.
+ */
+ public void testSendMessageAsynchExceptionCause() throws Exception
+ {
+ if (!pingMailServer())
+ {
+ fail();
+ }
+
+ Attachment attachment = new Attachment();
+ attachment.setInputStream(new ByteArrayInputStream(ATTACHMENT.getBytes()));
+ attachment.setMimeType(TEXT_PLAIN);
+
+ Message message = new Message();
+ message.setFrom("!@#$%^&*()");
+ message.setTo(generateRandomEmailRecipient());
+ message.setCC(generateRandomEmailRecipient() + "," +
generateRandomEmailRecipient());
+ message.setBCC(generateRandomEmailRecipient() + "," +
generateRandomEmailRecipient());
+ message.setSubject(MAIL_SUBJECT);
+ message.setBody(MAIL_CONTENTS);
+ message.setMimeType(TEXT_HTML);
+ message.addAttachment(attachment);
+
+ Future<Boolean> future = service.sendMessageAsynch(message);
+
+ try
+ {
+ future.get();
+ fail();
+ }
+ catch (ExecutionException ee)
+ {
+ assertEquals("We tried to send mail with malformed sender field,"
+ + " so we expect an AdressException to be the real cause of
ExecutionException", ee.getCause().getClass(),
+ AddressException.class);
+ }
+ }
+
+ /**
+ * Here we test asynchronous email sending of {@link Message}.
+ * We check concurrent execution of {@link FutureTask}
+ */
+ public void testSendMessageInFuture() throws Exception
+ {
+ if (!pingMailServer())
+ {
+ fail();
+ }
+
+ Message message;
+
+ Attachment attachment = new Attachment();
+ attachment.setInputStream(new ByteArrayInputStream(ATTACHMENT.getBytes()));
+ attachment.setMimeType(TEXT_PLAIN);
+
+ @SuppressWarnings("unchecked")
+ Future<Boolean>[] futures = new Future[THREAD_NUMBER];
+
+ cleanEmailMessages();
+
+ assertEquals("SMTP server should be now empty", 0,
mailServer.getReceivedEmailSize());
+
+ for (int i = 0; i < THREAD_NUMBER; i++)
+ {
+ assertFalse(isEmailMessageSent(MAIL_SUBJECT + i));
+
+ message = new Message();
+ message.setFrom(generateRandomEmailSender());
+ message.setTo(generateRandomEmailRecipient());
+ message.setCC(generateRandomEmailRecipient() + "," +
generateRandomEmailRecipient());
+ message.setBCC(generateRandomEmailRecipient() + "," +
generateRandomEmailRecipient());
+ message.setSubject(MAIL_SUBJECT + i);
+ message.setBody(MAIL_CONTENTS + i);
+ message.setMimeType(TEXT_HTML);
+ message.addAttachment(attachment);
+
+ futures[i] = service.sendMessageAsynch(message);
+ assertFalse(futures[i].isDone());
+ }
+
+ for (int i = 0; i < THREAD_NUMBER; i++)
+ {
+ assertTrue(futures[i].get());
+ assertTrue(isEmailMessageSent(MAIL_SUBJECT + i));
+ }
+ //we assume that one thread sends one email
+ assertEquals("SMTP server should have" + THREAD_NUMBER + " message
(asynchronously sent)", THREAD_NUMBER,
+ mailServer.getReceivedEmailSize());
+ }
+
private boolean pingMailServer() throws Exception
{
- String mailServer = service_.getOutgoingMailServer();
- if (nservice_.ping(mailServer, MAIL_PORT) < 0)
+ String mailServerName = service.getOutgoingMailServer();
+ if (netService.ping(mailServerName, SMTP_PORT) < 0)
{
- System.out.println("======>MailServer:" + mailServer + " and
on port:" + MAIL_PORT + " is not connected");
+ System.out.println("======>MailServer:" + mailServerName + "
and on port:" + SMTP_PORT + " is not connected");
return false;
}
return true;
}
+
+ /**
+ * Utility method to clean mail server.
+ * Removes all stored messages one by one.
+ */
+ private void cleanEmailMessages()
+ {
+ if (mailServer.getReceivedEmailSize() > 0)
+ {
+ @SuppressWarnings("unchecked")
+ Iterator<SmtpMessage> it = mailServer.getReceivedEmail();
+ while (it.hasNext())
+ {
+ it.next();
+ it.remove();
+ }
+ }
+ }
+
+ /**
+ * Utility method to check if you really sent message
+ * to dummy mail server. Basically it simply checks if
+ * there is an email with defined 'subject' header.
+ * @param subject
+ * @return
+ */
+ private boolean isEmailMessageSent(String subject)
+ {
+ if (mailServer.getReceivedEmailSize() > 0)
+ {
+ @SuppressWarnings("unchecked")
+ Iterator<SmtpMessage> it = mailServer.getReceivedEmail();
+ SmtpMessage message;
+ while (it.hasNext())
+ {
+ message = it.next();
+ if (message.getHeaderValue("Subject") != null &&
message.getHeaderValue("Subject").equals(subject))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Utility method to generate random email sender String
+ * @return {@link String} random email sender
+ */
+ private String generateRandomEmailSender()
+ {
+ return "<exo-sender" + System.currentTimeMillis() +
"@localhost>";
+ }
+
+ /**
+ * Utility method to generate random email recipient String
+ * @return {@link String} random email recipient
+ */
+ private String generateRandomEmailRecipient()
+ {
+ return "<exo-recipient" + System.currentTimeMillis() +
"@localhost>";
+ }
}
Modified:
kernel/branches/2.4.x/exo.kernel.component.common/src/test/resources/conf/portal/test-configuration.xml
===================================================================
---
kernel/branches/2.4.x/exo.kernel.component.common/src/test/resources/conf/portal/test-configuration.xml 2012-02-13
15:35:28 UTC (rev 5627)
+++
kernel/branches/2.4.x/exo.kernel.component.common/src/test/resources/conf/portal/test-configuration.xml 2012-02-14
09:37:23 UTC (rev 5628)
@@ -57,13 +57,16 @@
<init-params>
<properties-param>
<name>config</name>
- <property name="mail.smtp.host" value="PC01" />
- <property name="mail.smtp.port" value="25" />
+ <property name="mail.smtp.host" value="localhost"
/>
+ <property name="mail.smtp.port" value="2525" />
<property name="mail.transport.protocol" value="smtp"
/>
<property name="mail.smtp.auth" value="false" />
<property name="mail.smtp.auth.username" value="exo"
/>
<property name="mail.smtp.auth.password" value="exo"
/>
+
+ <property name="mail.max.thread.number" value="4"
/>
+
</properties-param>
</init-params>
</component>
Modified:
kernel/branches/2.4.x/exo.kernel.component.common/src/test/resources/test.policy
===================================================================
---
kernel/branches/2.4.x/exo.kernel.component.common/src/test/resources/test.policy 2012-02-13
15:35:28 UTC (rev 5627)
+++
kernel/branches/2.4.x/exo.kernel.component.common/src/test/resources/test.policy 2012-02-14
09:37:23 UTC (rev 5628)
@@ -12,6 +12,8 @@
grant codeBase "@TEST_CLASSES@-"{
permission java.lang.RuntimePermission "manageContainer";
+ permission java.net.SocketPermission "127.0.0.1:2526", "connect,
resolve";
+ permission java.net.SocketPermission "127.0.0.1:2525", "connect,
resolve";
};
grant codeBase "@MAIN_CLASSES@../../../exo.kernel.commons.test/-"{
Modified: kernel/branches/2.4.x/pom.xml
===================================================================
--- kernel/branches/2.4.x/pom.xml 2012-02-13 15:35:28 UTC (rev 5627)
+++ kernel/branches/2.4.x/pom.xml 2012-02-14 09:37:23 UTC (rev 5628)
@@ -240,6 +240,12 @@
<artifactId>transactions-jta</artifactId>
<version>3.7.0</version>
</dependency>
+ <dependency>
+ <groupId>dumbster</groupId>
+ <artifactId>dumbster</artifactId>
+ <version>1.6</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</dependencyManagement>