October 22, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Working with Design Pattern: Decorator

  • July 18, 2007
  • By Jeff Langr
  • Send Email »
  • More Articles »

Introduction

I'm interested in building a better email client. Email clients today are not much different than email clients from fifteen years ago! I have a number of interesting ideas that I'd like to build into such an application.

The core of the application is an Email object. The Email class, presented here, is capable of sending an email via SMTP. It requires the JavaMail API and the JavaBeans Activation Framework (JAF), which are distributed in the JARs mail.jar and activation.jar (freely available for download from Sun). It's not the best code I've written, but it works:

import javax.mail.*;
import javax.mail.internet.*;

public class Email {
   public void send(String toAddress, String fromAddress,
                    String subject, String content)
      throws AddressException, MessagingException {
      Authenticator authenticator = new Authenticator() {
         protected PasswordAuthentication
            getPasswordAuthentication() {
            return new PasswordAuthentication(getSMTPUser(),
                                              getSMTPPassword());
         }
      };
      Session session =
         Session.getDefaultInstance(System.getProperties(),
            authenticator);

      Message message = constructMailMessage(session, toAddress,
         fromAddress, subject, content);
      Transport.send(message);
   }

   private Message constructMailMessage(
         Session session, String toAddress, String fromAddress,
         String subject, String content)
         throws AddressException, MessagingException {
      Message message = new MimeMessage(session);

      message.setRecipient(Message.RecipientType.TO,
                           new InternetAddress(
            toAddress));
      message.setText(content);
      message.setFrom(new InternetAddress(fromAddress));
      message.setSubject(subject);
      return message;
   }

   private String getSMTPPassword() {
      return System.getProperty("mail.smtp.password");
   }

   private String getSMTPUser() {
      return System.getProperty("mail.smtp.user");
   }
}

To send messages, you'll need to specify a number of configuration properties. Of course, Java gives you many ways to do so. You can set properties programmatically, you can load them from a properties file, or you can pass them to the application via -D command-line arguments to the Java VM. Here are the properties I had to set, using -D, to get the Email class actually working:

-Dmail.transport.protocol=smtp
-Dmail.smtp.host=someserver.lunarpages.com
-Dmail.smtp.user=jeffuser@langrsoft.com
-Dmail.smtp.from=jeffuser@langrsoft.com
-Dmail.smtp.auth=true
-Dmail.smtp.password=somePass

If you want to watch the interaction between the JavaMail client and your mail server, you can turn on debug mode:

-Dmail.debug=true

Adding Features

I'd like to add a number of features to the Email class. For example, I'd like to be able to initiate the spell checker when I'm about to send, but only for certain recipients. I'd like to be able to log emails to other recipients. I might want to censor other emails for content. I might like an attachment verifier—something that scans the email for the words "attached" or "attachment," and asks whether I forgot an attachment if one is not provided. I might like auto CCing capabilities for certain emails.

All of these features would be great, at least from my standpoint. I could build them all into my Email class, but that would result in a pretty bloated class, with lots of if statements. I'm also not totally oblivious to the needs of others—many people would want to turn off my pet features. An inheritance hierarchy would certainly be unworkable. What I want is the ability to dynamically specialize email handling—something that the decorator design pattern affords.

Using the Decorator Design Pattern

With an inheritance hieararchy, I would extend from Email and override the send method. Using the decorator pattern instead, I would first define a common interface, perhaps named Sendable, declaring the method send. I'd then build a number of classes implementing this interface. These Sendable implementations would be decorators of the core Email class. Within their implemention of the send method, each decorator would invoke its own special behavior. A decorator also would contain a reference to another Sendable object that it decorated, or wrapped. As part of its implementation of send, the decorator would need to delegate to the contained object's send method.

As usual, it's often easier to see this in code. The first step is to extract an appropriate interface from the Email class:

import javax.mail.*;
import javax.mail.internet.*;

public interface Sendable {
   void send(String toAddress, String fromAddress, String subject,
      String content) throws AddressException, MessagingException;
}

The Email class must declare that it implements this interface:

public class Email implements Sendable

Now, I can write a test for my first decorator. I'd like a simple filter that censors emails, removing the words "the," "a," and "an." Some of my recipients bristle whenever I use articles!

import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import org.junit.*;

public class CensoringEmailTest {
   @Test
   public void create() throws AddressException,
      MessagingException {
      final List<String> sentEmails = new ArrayList<String>();
      Sendable wrappedEmail = new Email() {
         @Override
         public void send(String to, String from, String subject,
            String content) {
            sentEmails.add(content);
         }
      };
      String content = "the foxes quickly jumped over a lazy dog";
      CensoringEmail email = new CensoringEmail(wrappedEmail);
      email.send("to", "from", "subject", content);
      assertEquals(1, sentEmails.size());
      assertEquals("foxes quickly jumped over lazy dog",
                   sentEmails.get(0));
   }
}

The implementation for CensoringEmail:

import javax.mail.*;
import javax.mail.internet.*;

public class CensoringEmail implements Sendable {
   private Sendable wrappedEmail;

   public CensoringEmail(Sendable wrappedEmail) {
      this.wrappedEmail = wrappedEmail;
   }

   public void send(String toAddress, String fromAddress,
         String subject, String content) throws AddressException,
         MessagingException {
         wrappedEmail.send(toAddress, fromAddress, subject,
         filter(content));
   }

   private String filter(String content) {
      return content.replaceAll("(the|a|an) ", "");
   }
}

CensoringEmail's implementation for the send method simply calls the filter method against the email content before passing it on to the wrapped email's send method.





Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel