10.4 Performance Optimization

I l @ ve RuBoard

We've looked at performance enhancement techniques throughout this chapter. In this section, we'll conclude our discussion with a few more strategies to make your JavaMail systems more efficient.

10.4.1 Use Fetch Profiles

When performing any network operation, particularly high-volume applications such as downloading email from a message store, it always makes sense to take only what you need. JavaMail supports this by implementing most messages as "lazy" objects. When you call the getMessages( ) method of a folder, JavaMail does not automatically fetch all the messages in the folder, with all their content. Instead, it creates a set of "lazy-load" objects that access the server as necessary to retrieve particular message components . The efficacy of all this will vary depending on the message store type and implementation.

Sometimes it's desirable to skip the lazy-load and retrieve larger quantities of message information at once. In JavaMail, you can accomplish this via a fetch profile . Fetch profiles allow you to specify the components of a message that will be downloaded when the message is initially retrieved from the remote message store. The FetchProfile.Item object defines three constants: ENVELOPE (for message headers), FLAGS (for mailsystem status flags), and CONTENT_INFO (for headers defining the content of message parts ). You can add any or all of these items to a fetch profile, which will instruct the server, where possible, to retrieve all the information in the profile for every message retrieved. This information can then be reviewed without further network access. When you try to access data not included in the fetch profile, the implementation will retrieve it in the normal way.

Here's how to preload all the envelope information for a folder:

 Message messages[  ] = folder.getMessages(  ); FetchProfile profile = new FetchProfile(  ); profile.add(FetchProfile.Item.ENVELOPE); folder.fetch(messages, profile); 

Fetch profiles affect only message headers, not content, which will be retrieved from the server only upon request. When possible, check the message headers before retrieving the message content and verify that the message is one you're actually interested in processing. This helps minimize the effect of accidental or intentional denial of service attacks levied against your system.

10.4.2 Manage Attachments in Memory

File attachments can be a real drain on system performance. They can be arbitrarily big, and most methods for handling them involve writing them out to disk. This requires access to a directory on the server and can impose all sorts of performance penalties.

JavaMail, oddly, doesn't support nontext MIME parts based on objects in memory. JAF DataHandler objects can be retrieved only from a file or URL. This means that even if you've generated the attachment in memory, you still have to write it out to disk and then attach the ondisk file to your email. The exception, as you've seen, is when you already have a DataHandler object, such as when you receive an incoming SOAP message via JAXM.

Example 10-7 shows how to get around this limitation by subclassing the MimeBodyPart object. The standard MimeBodyPart implementation includes a protected field, contents , that contains the raw content of the MIME part. The JavaMail API also includes a utility class, MimeUtility , that can encode content streams in a variety of ways, including with the base64 and the older UUEncode standards. You can use these two features to create your own MIME encoding system, bypassing JAF altogether.

The StreamBasedMimeBodyPart class has a constructor that accepts an InputStream , a content type, and a filename. The filename is associated with the file attachment so that the recipient can open it easily. Because this is a simple example, the constructor contains all the logic, setting the necessary headers, encoding the input stream into a byte array, and setting the byte array as the content of the MimeBodyPart .

Example 10-7. StreamBasedMimeBodyPart
 import javax.mail.*; import javax.mail.internet.*; import java.io.*;  . . .  public class StreamBasedMimeBodyPart extends MimeBodyPart  {   public StreamBasedMimeBodyPart(InputStream in, String type,         String filename)   {     super(  );          try {       ByteArrayOutputStream bos = new ByteArrayOutputStream(  );       OutputStream out = MimeUtility.encode(bos, "base64");       byte[  ] b = new byte[1024];       while(in.read(b) > 0)          out.write(b);       this.content = bos.toByteArray(  );            setHeader("Content-Type", type + "; name=\""+filename+"\"");       setHeader("Content-Transfer-Encoding", "base64");       setDisposition("attachment");       setFileName(filename);     } catch (IOException e) {       // Handle it.     } catch (MessagingException e) {       // Handle it.     }   } } 

Using the class is simple. You just create a new instance of it, passing in your content, content type, and filename, and add the part to a Multipart object just like any other MimeBodyPart (this approach is much more useful, obviously, when the content originates somewhere other than a file because you can just as easily use a regular DataHandler ):

 FileInputStream fIn = new FileInputStream("c:\inline.gif");  . . .  StreamBasedMimeBodyPart bbp = new StreamBasedMimeBodyPart(         fIn, "image/gif", "inline.gif");        myMultipart.addBodyPart(bbp); 

Even though you aren't reading a filename from the disk, you still provide a filename to the MIME header; this allows the client displaying the email to provide the user with a way to save the file, and is sometimes required for the client to handle the attachment, even if the content type has been specified.

Before trying this in a production environment, add some error checking.

10.4.3 Use JavaMail to Search

Efficient searching is vital for many email-based applications, particularly when more than one application shares an email address. The simplest way to find a message in a folder is to retrieve all of them and loop through the resulting Message object array, examining the relevant fields and selecting the messages that are interesting. JavaMail provides a mechanism for searching messages from a message store, using SearchTerm functionality. The SearchTerm object and its descendents are found in the javax.mail.search package. The various SearchTerm objects perform a particular comparison. FromStringTerm , for instance, performs a substring search on a message's From header. All string comparisons are case-insensitive.

More complex search terms can be created via the AndTerm , OrTerm , and NotTerm objects, which develop arbitrarily complex search criteria. Here's how I tell when I'm in trouble:

 SearchTerm t = new AndTerm(new FromStringTerm("editor@oreilly.com"),                             new SubjectTerm("late book")); Message[  ] msgs = folder.search(t); 

What to do after receiving the message is left as an exercise. For maximum performance, search terms should be used wherever possible. This is because more advanced message storage protocols, including IMAP, have native search capabilities. When these are available the JavaMail provider implementation can translate the search terms into a native search command, transmit that command to the server, and have the server do the heavy lifting . For example, if you include a BodyTerm , and 1 message in a folder of 200 has a multiple-megabyte file attachment, retrieving all the message bodies and searching on the client will be far less efficient than a search based on the server.

When using message stores (such as POP3) that don't support server-side searching, the implementation will have to download all the messages to perform the search, but it still makes sense to use JavaMail search terms whenever possible, both for convenience and readability and to make upgrades to more capable message stores easier later on.

I l @ ve RuBoard

The OReilly Java Authors - JavaT Enterprise Best Practices
The OReilly Java Authors - JavaT Enterprise Best Practices
Year: 2002
Pages: 96

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net