I said that the world has seemingly decided collectively that annotations are the cat’s meow, to coin a phrase, so who am I to question the wisdom of the Java developer community as a whole? Why, I’m a guy writing a book, that’s who!
Some people feel that annotations have their place for sure in the toolbox of the Java developer, but that they aren’t the be-all and end-all of things (this is my opinion, but it is shared by many others, as a few min- utes with Google will convince you).
The key question to ask about annotations is what they really are. Sun has always claimed they were metadata, an extension to the existing metadata in the Java APIs. Is that really what they are though? Don’t they in fact decorate an object’s blueprint? They tell Java something extra about your code, how to compile it, things like that. It’s not data about data, which is the academic definition of the term metadata.
Let’s forget that though, because it’s largely a philosophical debate. The real question, and the point at which I have some reservations about annotations, is that they represent hard-coded configuration informa- tion. For how many years have we tried to abstract things like configuration out of our code? That was the
whole point of externalized configuration files in the first place. Remember that when an annotation changes, you have to recompile and in most cases redeploy the application. Isn’t this the exact polar opposite of what we’ve been trying to do all these years? When did we decide that was the wrong direction?
Let me be clear, I’m not saying annotations are evil and should never be used. What I amsaying, however, is that this sudden drive toward doing everythingwith annotations to me is misguided. View anno- tations like you would a screwdriver: sure, you can use it as a chisel, but it’s not the right tool for the job (most likely). Don’t just jump on the annotation bandwagon because everyone seems to be doing it . . . unless you’re prepared to follow them in their jump off the Brooklyn Bridge too (and no, I’m not likening annotations to jumping to one’s death, it’s not thatbad, I’m just making the comparison in terms of simply doing what everyone else is doing for the sake of doing what everyone else is doing!).
The first step to using annotations with DWR is to use a new DWR controller servlet, spec- ified in web.xmlas follows:
<servlet>
<description>DWR controller servlet</description>
<servlet-name>DWR controller servlet</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>classes</param-name>
<param-value>
com.example.RemoteFunctions, com.example.RemoteBean
</param-value>
</init-param>
</servlet>
The new classesinit parameter is a comma-separated list of all classes you intend to remote that contain annotations. Note that if you need to specify an inner class, you need to use the $notation rather than dot notation.
The actual annotations couldn’t be simpler. Let’s start with a simple class that we wish to remote, as shown in Listing 3-4.
Listing 3-4.A Simple Class That We’ll Configure with Annotations public class RemoteClass {
public String myMethod(String inParam) { return inParam + " returned";
} }
Now, to annotate this and prepare it for DWR use, we have only to add a few annotations, the result being the code in Listing 3-5.
Listing 3-5.That Same Simple Class All Annotated for DWR’s Gratification
@RemoteProxy
public class RemoteClass {
@RemoteMethod
public String myMethod(String inParam) { return inParam + " returned";
} }
And just like that, we can now call the myMethod()method of the RemoteClassclass using DWR! The @RemoteProxyannotation indicates the class can be remoted, and the @RemoteMethod annotation indicates the method can be called.
Any method in the class not annotated will not be available to DWR. If you wish to have a different JavaScript object name than the name of the class (RemoteClassin this case), you add anameattribute to the @RemoteProxyannotation like so:
@RemoteProxy(name="SomeClassName")
When you need to deal with beans that you want to allow DWR to convert, there are the
@DataTransferObjectand @RemotePropertyannotations, their usage shown in Listing 3-6.
Listing 3-6.A Simple Bean Annotated for DWR’s Use As a Convertible Type
@DataTransferObject public class MyBean {
@RemoteProperty
private String firstName;
public String getFirstName() { return firstName;
} }
The @DataTransferObjectannotation indicates the bean can be marshaled by DWR, and the @RemotePropertyannotation indicates that the property firstNameshould be marshaled.
So, if you wish to have some members of the bean that are not transmitted back and forth between client and server, simply leave off the corresponding @RemotePropertyannotation, and you’re all set.
Note that there is an optional converterattribute to the @DataTransferObjectannotation that can specify the type of converter to use to marshal the class. Documentation was a little sparse on this attribute frankly, so I hesitate to show an example, lest it be wrong. I can tell you that the default converter used is the ubiquitous BeanConverter, so in most cases you won’t need this anyway, but if you do, I suggest pinging the DWR mailing list to get a description of what the attribute does. We won’t need it in any of the projects in this book, so I think I can cop out a little bit here!
Incidentally, this is one of those times where using annotations doesn’t hurt my head very much. I think specifying that an object is or isn’t remotable, that a method is or isn’t remotable, is a good use of annotations. Please do form your own opinion though! For what it’s worth, you’ll be seeing both the configuration file approach and the annotations approach in the projects in this book, so you’ll have a good basis to form that opinion on anyway.
Summary
In this chapter, we took a look at some topics in the DWR world that are somewhat more
“advanced” in the sense that you won’t always need these things to write a DWR-based appli- cation (although perhaps more often than not you will). We examined how you can introduce robust security into a DWR application, and how to handle all sorts of error/exception situa- tions. We discussed how we can access other parts of an existing web application in the course of our DWR processing. We also discussed reverse Ajax, the newer sibling to big brother Ajax.
We then saw how we can integrate DWR with other frameworks to gain all sorts of added value, and finally, how we can use Java 5 annotation support in DWR to configure our applica- tions in a more streamlined way.
And with the close of this chapter, we now move on to the second part of the book, which is comprised of the applications. Strap yourself in; it’s bound to be a wild ride!
The Projects
All I need to know about life I learned by reading poster sigs on Slashdot.
—Frank W. Zammetti
Always program as if the person who will be maintaining your program is a violent psychopath that knows where you live.
—Martin Golding
Any sufficiently advanced bug is indistinguishable from a feature.
—Bruce Brown Once you’re done writing the code, never open it again unless you want to see how incomprehensible and utterly ridiculous it really is.
—Raphael Sazonov Documentation is like sex: when it is good, it is very, very good; and when it is bad, it is better than nothing.
—Dick Brandon To err is human—and to blame it on a computer is even more so.
—Robert Orben
The secret of creativity is knowing how to hide your sources.
—Albert Einstein They have computers, and they may have other weapons of mass destruction.
—Janet Reno
All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value.
—Carl Sagan
P A R T 2
InstaMail: An Ajax-Based Webmail Client
This chapter will introduce an application called InstaMail, which is an Ajax-based webmail application. DWR will form the foundation of the server side of things as usual, and we’ll also use some client-side DOM scripting and CSS to make this application a little more “pretty”
than it otherwise might be. In the end, we’ll have a web application that you can run on a server and that will give you remote access to your POP3 account from anywhere. Although it will not be as full featured as Microsoft Outlook, it will be more than capable of performing the basics.
Application Requirements and Goals
A while back, access to e-mail accounts was always through some bulky fat-client application.
AOL was and still is perhaps the most famous; you may recall others like CompuServe and Delphi (true, these services have always been far more than just e-mail, however, we’re dis- cussing e-mail after all, and that’s one part of the services they provided, so allow me the minor inaccuracy, won’t you?). Later on, and still to this day, we have applications like Microsoft Outlook and Outlook Express, Thunderbird, and Eudora, just to name a few.
More recently though, over the past three to four years perhaps, people have started to realize that it would be nice to have e-mail available to them anywhere, not just on a PC or laptop with the client installed. That realization, along with the advent of the Internet and always-on access for many people, heralded the birth of the webmail client.
A webmail client is nothing more than a web application that runs on a server and acts essentially as a proxy between you and your POP3/IMAP account. POP3 is the most popular -mail protocol out there for mail retrieval, and Simple Mail Transfer Protocol (SMTP) is the most common for mail transmission. Webmail usually contains some basic functions, and increasingly even more advanced functions. Clearly it has to be able to send and receive mes- sages from a POP3/SMTP account, and usually it will have some form of address book as well.
Those are pretty much the basics that everyone expects to find. Things like multiple folder support, grouping of e-mail “conversations,” rich e-mail editing, file attachments, and alerts are some of the more advanced features that can be found in many webmail applications today.
129
C H A P T E R 4
Here, we’ll build ourselves a webmail client that covers those basics. Because the advanced features generally require knowing a little more about the server the application runs on than I can safely assume in the context of this book, we won’t delve into many, if any, of those advanced features. However, as I am sure you can guess, they make for a very nice, easy list of suggested enhancements for you at the end!
Let’s now codify the features this webmail application will support, and the general design goals:
• We want the user interface (UI) to be somewhat “pretty.” Not just a boring, simplistic HTML page, but something a little easier on the eyes.
• We should, of course, be able to view our POP3 Inbox and read messages in it, as well as delete messages.
• Sending a message as well is an obvious goal. We should be able to compose a new e-mail, either to a contact in our address book or to someone else, and we should also be able to reply to a received message, complete with quoting of the original message.
• To make things simple and stay focused on what we should be focused on, InstaMail will support a single e-mail client for a single user, and there will be no security per se, i.e., no username and password will be required to access InstaMail (they will still, of course, be required, usually to access the POP3/SMTP servers).
• We’ll provide an address book from which a new message can be started. We’ll store just some basic information for each contact, namely first name, last name, e-mail address, and comment. Comment can be any note you want to make about the contact.
• In addition to access to the Inbox, we’ll maintain all sent messages locally.
• We’ll be able to delete the message currently being read, or select a batch to delete from the Inbox view.
• In addition to the UI being a bit “pretty,” we want to exercise some DHTML (Dynamic HTML) and CSS skills and incorporate some slightly “fancy” features, things like some button mouse-over effects and a Please Wait float-over. We won’t go completely crazy, but just enough to have fun!
That list should give us more than enough to do. It should also be a bit of a fun project to dissect, so without delay, let’s get to it!
Dissecting InstaMail
Let’s begin by getting a feel for the overall structure of InstaMail by looking at the file layout, shown in Figure 4-1.
Figure 4-1.Directory structure of InstaMail
InstaMail consists of a single JSP page, index.jsp. All of the markup for the entire applica- tion is in that one file. This file imports the style sheet file styles.cssin the /cssdirectory. It also makes use of all the images in the /imgdirectory, which I have not expanded here in the interest of keeping this layout image small (there are a rather large number of images involved, and listing them all would have more than doubled the height of this figure). All of the JavaScript for InstaMail, save a single init()function in index.jsp, is contained in the script.jsfile in the /jsdirectory, which is also imported by index.jsp. We can also see here nine classes that make up the server side of the application in the WEB-INF/classesdirectory, in a typical package directory structure. Lastly, we can see the libraries that InstaMail makes use of in the WEB-INF/libdirectory, and they are described in Table 4-1.
Table 4-1.The JARs InstaMail Depends on, Found in WEB-INF/lib
JAR Description
activation.jar JavaBeans Activation Framework, needed by the JavaMail API.
commons-logging.jar Jakarta Commons Logging is an abstraction layer that sits on top of a true logging implementation (like Log4J), which allows you to switch the underlying logging implementation without affecting your application code. It also provides a simple logger that outputs to System.out, which is what this application uses.
dwr.jar The JAR containing all the DWR classes.
Continued
Table 4-1.Continued
JAR Description
mailapi.jar The JavaMail API, the Sun-standard library for performing mail functions.
pop3.jar JavaMail extensions for dealing with POP3 mail servers.
smtp.jar JavaMail extensions for dealing with SMTP mail servers.
The WEB-INF/srcdirectory contains all the source code for this project, including the Ant build script.
Configuration Files
The first thing we’ll look at with InstaMail is the configuration files that tell the servlet con- tainer, and DWR, how the application works.
web.xml
First up is web.xml, shown in Listing 4-1.
Listing 4-1.InstaMail’s web.xmlConfig File
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app id="instamail" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>InstaMail</display-name>
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
<!-- Session timeout config. -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<!-- Welcome file config. -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Well, there certainly is not much to it, is there? The most important item is the DWR servlet definition. Here we are mapping it to the path /dwr/*and telling it we want to see debug information. Beyond that we are simply setting a session timeout of 30 minutes and setting index.jspas our welcome page. Very concise indeed!
dwr.xml
Next up is dwr.xml, which is the DWR configuration file that was described in previous chap- ters, shown in Listing 4-2.
Listing 4-2.dwr.xmlfor InstaMail
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"
"http://getahead.org/dwr/dwr20.dtd">
<dwr>
<allow>
<convert converter="bean"
match="com.apress.dwrprojects.instamail.MessageDTO" />
<convert converter="bean"
match="com.apress.dwrprojects.instamail.OptionsDTO" />
<convert converter="bean"
match="com.apress.dwrprojects.instamail.ContactDTO" />
<create creator="new" javascript="OptionsManager">
<param name="class"
value="com.apress.dwrprojects.instamail.OptionsManager" />
</create>
<create creator="new" javascript="MailRetriever">
<param name="class"
value="com.apress.dwrprojects.instamail.MailRetriever" />
</create>
<create creator="new" javascript="MailSender">
<param name="class"
value="com.apress.dwrprojects.instamail.MailSender" />
</create>
<create creator="new" javascript="MailDeleter">
<param name="class"
value="com.apress.dwrprojects.instamail.MailDeleter" />
</create>
<create creator="new" javascript="AddressBookManager">
<param name="class"
value="com.apress.dwrprojects.instamail.AddressBookManager" />
</create>
</allow>
</dwr>
Like web.xml, this is not exactly a War and Peace–sized piece of code! To remind you, dwr.xmlbasically tells DWR, among other things, what classes it is allowed to create and access, and also what objects it can convert to and from JavaScript and Java. In this case we are listing the Data Transfer Objects (DTOs) that InstaMail uses as convertible, and we are list- ing the five main classes that contain the server-side functionality of the application. We’ll of course be looking at them in detail soon, but their names alone should give you a very clear idea of what they do. Note that as shown here, there is no limitation on what methods or prop- erties of the classes can be accessed. The only limitation is on those classes not listed, which cannot be remotely called at all.
The Client-Side Code
Before we dive into the code that makes up the client side of InstaMail, let’s take our first brief look at the application itself, as shown in Figure 4-2. This is the first screen you should see upon running InstaMail for the very first time.
Figure 4-2.The InstaMail “intro” view