A Reusable Email Service: Corba Meets JavaMail

  Daniel Lipton is a consultant with Random Walk Computing in New York City. He develops Java, CORBA, and XML-based applications for the financial industry. He can be contacted at [email protected].

CODE-REUSE HAS been a promising and often elusive goal of developers. Too often, reuse simply means snipping code out of one program and jamming it into another. This has been problematic, to say the least, and inefficient. Object-oriented software methodology promised much and arguably delivered less. Now there's a new way to save time and effort: CORBA.

My company recently developed a suite of CORBA services for a client that delivers often-used functionality. Some of these CORBA services are client-specific but others are not. The idea is simple: If you are going to do the same thing over and over again, do it once, do it right, and wrap it in a CORBA service. Then you can re-use that functionality on virtually any platform and with any language. The client part of the service can be wrapped as either a JavaBean for use in IDEs, such as Symantec's Café or wrapped as an ActiveX control.

As we finished our project, I thought of other things that we often use in our programs. Email, in particular, stood out. Quite frequently, it is desirable for applications to be able to send email. For example, if an enterprise application throws an exception indicating that there's a bug, notification could be sent directly to support staff. Alternatively, if a program takes an action and needs to notify a group of people, it can be sent automatically via email. There are many uses for such a service.

Let's review another way of sending email from an application. A module could be programmed in the client program's language. First, a library must be found to send email. If one can't be found, it will have to be written from scratch. The next time email functionality is needed in a program it will have to be written in the exact same language and on the same platform.

Next comes the issue of what kind of platform it will need to run on. The program probably is going to be distributed on a number of machines with an unknown environment. The machines might have Sendmail or some other SMTP program but might not. If an SMTP host (or POP, IMAP, etc.) is specified, then that machine's name or address will have to be hardwired into the client program. Then, if the mail host goes down or moves, the email functionality will not work correctly.

If the program is written as a CORBA service, client applications can take advantage of the email functions in it without many of the headaches that come from writing it from scratch. The reason is that the object semantics are already implemented and encapsulated in the server object. This is a common idea in object-oriented programming. If a class already implements what you need, then there's no reason to write it again. CORBA allows you to easily present that object to other programs on the network. That's the idea behind setting up the email-sending capability as a CORBA service. The developer of the client just wants to send email. He or she doesn't necessarily want to know how the email system works or the support policies or network practices behind it.

The first step in writing the email service is deciding on an interface. CORBA interfaces are written in a language called CORBA IDL. I leaned toward simplicity when designing the interface (see Listing 1).

There is only one operation, send, defined by the interface. It sends an email and may raise an exception. When the service cannot send the message, the exception provides an explanation of why the service couldn't send it. I used the typedef facility to declare StringList as a sequence of Strings (an IDL sequence is similar to a Java array). I named the module RWEMail after my company. I could have added much more, but I didn't want to unnecessarily complicate the interface.

In writing the code for this article, I used Inprise's Visigenic for Java CORBA Object Request Broker (ORB). If you are using another vendor's product (like Iona) then you may need to change some of the example code. Later, I discuss some of the issues of portability between ORBs.

After writing the interface, it must be compiled into stubs and skeletons for the client and server, respectively. First, let's look at the client (see Listing 2). The most important pieces are the send and the bindToService methods. The bindToService method finds a service object and binds to it. In other words, the client object gains what appears to be a regular object reference. The client may call methods on the server object just like it would on any other. CORBA works the magic behind the scenes, such as marshaling and unmarshaling parameters and sending data across the network. This is the most vendor-specific part of the program. Again, if you are writing this yourself, you may need to check your CORBA vendor's manual to see how they locate and bind to the service object.

After an application creates an RWEMailClient object, it just calls the send method with the recipients, the subject, and the email's text. The recipients are provided as an array of strings in the to and cc fields (see Listing 3). Applications don't need to use the RWEMailClient class. They can bind directly to the service using ORB APIs. If you are writing a client application in another language, then you will need to compile the interface into the stubs in that language.

The service implementation is broken into two parts. The first is RWEMailServer (see Listing 4), which is the entry point and scaffolding for the service. It delegates the responsibility of implementing the RWEMailInterface to RWEMailImpl (see Listing 5). The server creates an instance of the service implementation and then uses the services of the BOA (basic object adapter) to register the implementation with the ORB and enable it to receive incoming requests. This is another part you might have to change if you are using a different vendor's CORBA product. The server also registers the service with Visigenic's locator service.

For the implementation, I used the new JavaMail API. It provides another level of abstraction between your program and the platform's email system. The JavaMail API provides a set of classes and interfaces to send and receive email independent of the underlying protocol. It provides access to SMTP, IMAP, and soon POP. This implementation uses SMTP.

For this service implementation to work, you'll need to download the JavaMail 1.1 jar and the Java Activation Framework, which is used by JavaMail. The server this runs on will also need an SMTP server. That may seem like a great deal, but that's exactly the point. If you're going to go through all of the trouble of downloading, installing, and configuring the necessary third-party modules and services, then you might as well do it once on the server instead of on every client.

The service doesn't have to be implemented in Java. It can be written in any language that the CORBA vendor supports (such as C++). The interface must be compiled into skeleton classes and then extended in the implementation. You can also send email via any application protocol and through any API or system call, custom or otherwise; the JavaMail API is a matter of convenience. For instance, you can connect to a POP server and send the email or you could write your own SMTP server.

CORBA provides quite a bit of useful functionality to the service. For example, many vendors sell an SSL pack that provides data encryption. If that's important to you, then CORBA easily supports it. A CORBA service can also do load-balancing or automatic fail-over. If one mail server fails, then CORBA can automatically route to a backup mail server. This can be very powerful but could be non-trivial to implement on your own. I recommend that you go to vendors' Web sites for more information.

Another advantage to sending email through a CORBA service is that all processing goes through a set of known machines. If mail can only come from a set of pre-defined machines (e.g., destined to go through a firewall), then the addresses of the hosts sending email are known in advance. The email service can also incorporate other services. For example, an auditing service can log all email transmissions. The service can also authenticate from whom the email is coming.

For many readers, this code can be used as-is as long as you have the proper libraries (Visibroker for Java 3.2, JavaMail 1.1, JAF, and JDK 1.1.x). If you are using another vendor's CORBA implementation other than Inprise, then you may need to rewrite certain parts of the example code. The server may need to be configured for your specific machine as well. When I was running the service, I had to move it from a Windows NT machine to Solaris because Windows NT Workstation doesn't provide an SMTP server.

You may want to add more functionality to the service if you have specific needs for your company, such as a proprietary email protocol that needs more information for the header. You can also add more methods to the interface, such as an asynchronous callback mechanism to let the client know that the email was delivered. Perhaps you want authentication before you allow a program to use the service. My only suggestion is that you keep it as generic as possible so that any application you may write can easily use it.

NOW WHAT? Perhaps in your job you will see things which you use in your programs quite often. There may be common functionality that would be useful if it was available over your network to other programs. Chances are that it could benefit from becoming a CORBA service. As the example I've presented here shows, it's probably simpler than you think, and it will save you time in the long run.



Java Activation Framework (AQ)

JavaMail 1.1 jar



Quantity reprints of this article can be purchased by phone: 717.560.2001, ext.39 or by email: [email protected].