ArsDigita Archives
 
 
   
 
spacer

Building Web-Based Communities with Java 2 Enterprise Edition

by Bill Schneider (bschneid@arsdigita.com)

Submitted on: 2000-07-13
Last updated: 2001-05-10

ArsDigita : ArsDigita Systems Journal : One article


The Java 2 Enterprise Edition (J2EE, see http://java.sun.com/products/j2ee) is a platform standard, established by Sun Microsystems, that brings the "write once, run anywhere" Java architecture to server-side and distributed applications. This contrasts with Java's first days, when the language made headlines for its client-side uses.

Java became well-known initially because of its virtual machine architecture, which makes it possible to build secure "sandboxes" for Java applets running in Web browsers, and to build graphical applications that are independent of the underlying processor or operating system on the user's machine. The same virtual machine architecture means that server-side or multi-tier applications written to the J2EE standard may run under any application server, on any hardware, and with any operating system that supports the J2EE API.

Because a significant portion of the J2EE platform is directed towards making web-enabled applications and integrating with relational databases, we can build a web-based community with J2EE. This article will give a brief description of J2EE, describe the requirements for a part of a web-based community application, and explain in depth the portions of J2EE that we could use to build such an application.

J2EE: What is it?

J2EE is a set of Java API standards for building Web and enterprise applications. A J2EE application runs inside a container or application server, which provides an implementation of the J2EE API services.

The following APIs are all components of J2EE; many of them, such as the servlet API and Java Database Connectivity (JDBC), were previously available and supported before the complete J2EE standard:

  • Servlets: Java's answer to CGI scripts, servlets are a standard API for writing server-side Web components.
  • Java Server Pages (JSP): a shorthand for writing servlets, where you can mix Java code and literal output
  • Enterprise Java Beans (EJB): an API for implementing and managing Java components in a distributed system.
  • Java Transactions: an API for managing distributed transactions
  • Java Database Connectivity (JDBC): an API for integrating Java with an RDBMS
  • Java Naming and Directory Interface (JNDI)
  • Java Messaging Service (JMS): an API for asynchronous messaging
  • JavaMail: a set of APIs for handling Internet e-mail
  • Java Naming and Directory Interface (JNDI): an API for directory lookup services in J2EE systems; also integrates with LDAP.

J2EE: What it isn't

J2EE is not an application server

While the J2EE consists of several powerful APIs, it is not an application server itself; rather, it is a standard that any application server vendor may implement, either in whole, or in part. Many application server vendors offer different levels of J2EE support within their own product line.

Sun makes a reference implementation (see http://java.sun.com/j2ee/download) of a J2EE server available for download. Some other J2EE server products include:

JDBC is not a database driver

Although the JDBC interface specifies the classes and methods that Java applications use to access a database, developers need to obtain the specific database driver for their RDBMS product and operating system. Many JDBC drivers are written partially in native code, for performance. There are, however, some pure-Java or "Type 4" JDBC drivers. Type 4 drivers may only be applicable for TCP/IP socket connections to the database; using IPC may require native calls, depending on the underlying operating system.

J2EE is not an application architecture

Many J2EE application servers expect to run three-tiered (client, server, RDBMS) applications, but not every J2EE application need be three-tiered. On the contrary, two-tier or even one-tier applications are possible.

Web-based Communities

An important aspect of any Web application is that it creates a virtual community of people of people from potentially all over the world who share something in common, whether it be photography, shopping for books, trading stocks, or working for the same company or in the same field. Consequently, one of the greatest powers of the Web is the way it enables people to interact. On many online bookstores, for example, you can share your opinion on a particular book with thousands of other people, and your opinion can persist for years after you've bought the book (assuming the site stays in business).

The types of collaboration that you can have over the web are too numerous to name here, so our discussion will focus on one of the most pervasive and basic forms of web collaboration, the discussion forum. Forums, or bulletin boards (bboards) are the essential component that turns a web site into a web community, and they are also one of the simplest to understand.

A J2EE discussion forum

Suppose we want to build a Web-based discussion forum using J2EE components. The first step in any software design process is defining requirements for the application; informally, we define a "discussion forum" to consist of a series of "messages," where a message is some textual content with some associated data such as the author, the date posted, and a subject line. We would like our forum application to allow users to do the following things:

  • post a new message
  • read an existing message
  • list all available messages
  • reply to messages posted by other users

The user interaction with the discussion forum will be via the Web (HTML over HTTP). The rest of our example will focus on two interactions, listing messages and reading a single message.

The web page to list available messages might look like this to an end-user:

Java Discussion Forum

List messages
Subject Author Date Posted
ACS on WebLogic? Bill Schneider 1/25/2001
CMS Java Karl Goldstein 1/24/2001
Test message Joe User 1/23/2001

The web page to show a single message might look like this:

Java Discussion Forum

List Messages | Read Message
Subject Test message
Author Joe User
Date Posted 1/23/2001

This is a test message. I'm just posting this to demonstrate how we can write a discussion forum with J2EE.

Now that we know what we want our discussion forum application to do and look like, we can start designing and implementing the application. This means we have to determine how we're representing and storing messages, and how we're going to retrieve them and display them over the Web.

Object design

The basic data structure in our forum application is a message, so we'll define a Java object skeleton to represent it, with "get" methods corresponding to its public attributes:

package forum;

public class Message { 

   // return the content of a message body
   public String getBody(); 

   // return the message subject
   public String getSubject();

   // return the date posted
   public String getPostDate();

   // return the name of the author
   public String getAuthorName();
}
We also need to represent a list of messages:
package forum;

public class MessageList {

   // return the number of messages in the forum
   public int getMessageCount();

   // return a message at the given index
   public Message getMessage(int i);
}

Database design

Web sites that need to store data persistently and reliably generally use a relational database product (RDBMS) like Oracle or PostgreSQL for their data storage. RDBMS'es have a lot of nice properties that make them well-suited for web applications and multi-user systems. It frees application authors from worrying about transaction isolation, and ensures that data can always be restored to some valid state even if the power to the server is cut at a critical moment. Imagine what could happen if you saved all your forum messages to an ASCII text file and the server crashes when the message is half written, or if two people try to post a message at the same time.

Let's assume that we're integrating our message forum into an existing data model to support a multi-user web site. So we already have a table in place to represent users:

CREATE TABLE USERS (
    user_id         integer primary key,
    first_name      varchar(100),
    last_name       varchar(100),
    ...
);
Next we'll create a table to represent the set of messages stored in our discussion forum:
CREATE TABLE MESSAGES (
    message_id         integer primary key,
    author_id          integer references users(user_id),
    post_date	       date,
    subject            varchar(100),
    -- simplification: assume "short" messages so we don't need to use CLOB
    body               varchar(4000)
);

Implementation: Putting it together

Now that we know what objects we need and how we're going to store them in the database, we're ready to start using J2EE components to put it all together. We can build a first pass of this system using just servlets, JSP, and JDBC, each of which pre-dates the full J2EE specification. Here we will describe each API in detail.

Java Database Connectivity

Java Database Connectivity (JDBC) is an API for connecting Java classes with relational databases. It defines an interface for connecting to the database, issuing SQL statements, and parsing results. Database and application server vendors generally provide JDBC drivers, which are database-specific implementations of the JDBC API. A different JDBC driver must be used for each database product.

Before the J2EE release, JDBC was part of the standard Java API, in package java.sql. The J2EE includes an enhanced JDBC interface, in package javax.sql. Some of the additional features include scrolling cursors, which allows random access to the rows returned from a query; batch updates; and a standard API for connection pooling.

This code shows how we can put JDBC into the Message and MessageList class we defined above to retrieve messages from persistent storage:

Listing: Message.java

package forum;

import java.sql.*;
import forum.util.ConnectionManager;

/** 
 * Represents a message in the forum and retrieves it from persistent
 * storage.
 **/
public class Message { 
   
   // private data members
   private String m_id;
   private String m_body;
   private String m_subject;
   private java.util.Date m_date;
   private String m_author_name;

   private static java.text.SimpleDateFormat df = 
      new java.text.SimpleDateFormat("M/d/yyyy");
    
   /** no-argument constructor */
   public Message () { }

   /**
    * Create a new Message object from the
    * input ResultSet.  The ResultSet must be pointing to a valid row, and 
    * must contain fields named subject, post_date, first_name, and 
    * last_name.  The "body" field is optional because we might not always
    * want to pull in the body content (e.g., if  we're pulling in lots 
    * of message headers to show in list format). 
    *
    * @exception throws java.sql.SQLException if the input result set doesn't
    * contain the required fields.
    */
    public Message(ResultSet rs) throws SQLException {
       fillAttributes(rs);
    }

   /**
    * fill attribute values for this Message object from the
    * input ResultSet.  The ResultSet must be pointing to a valid row, and 
    * must contain fields named subject, post_date, first_name, and 
    * last_name.  The "body" field is optional because we might not always
    * want to pull in the body content (e.g., if  we're pulling in lots 
    * of message headers to show in list format). 
    *
    * @exception throws java.sql.SQLException if the input result set doesn't
    * contain the required fields.
    */
   private void fillAttributes(ResultSet rs) throws SQLException {
      // loop over available columns to set optional attributes
      ResultSetMetaData rsmd = rs.getMetaData();
      for (int i = 1; i <= rsmd.getColumnCount(); i++) { 
          String column = rsmd.getColumnName(i).toLowerCase();
          if (column.equals("body")) {
             m_body = rs.getString(i);
          } 
          if (column.equals("message_id")) {
             m_id = rs.getString(i);
          } 
      }
      // mandatory attributes
      m_date = rs.getDate("post_date");
      m_author_name = rs.getString("first_name") + " " + rs.getString("last_name");
      m_subject = rs.getString("subject");
   }

   /**
    * Create a new Message object with attributes values from a row in the
    * database.
    * @param messageId the value of the message_id column to pick out of
    *  the MESSAGES table
    */

   public Message(String messageId) throws SQLException { 
       this();
       m_id = messageId;
       setMessageId(messageId);
   }

   /**
    * Fills this Message's attributes with values from the database.
    * @param messageId the value of the message_id column to pick out of
    * the MESSAGES table
    */
   public void setMessageId(String messageId) throws SQLException { 
      // hand-waving; assume connection management is centralized
      Connection conn = ConnectionManager.getConnection();
      PreparedStatement ps = conn.prepareStatement
        ("select messages.*, first_name, last_name "
         + "from messages, users " 
         + " where message_id = ?"
         + "   and author_id = user_id");
      ps.setObject(1, messageId);
      ResultSet rs = ps.executeQuery();
      if (rs.next()) { 
         fillAttributes(rs);
      }
      conn.close();
   }

   /** @return the content of a message body */
   public String getBody() { 
      return m_body; 
   }

   /** @return the message subject */
   public String getSubject() {
      return m_subject;
   }

   /** @return the date posted */
   public String getPostDate() { 
      return df.format(m_date);
   }

   /** @return the name of the author */
   public String getAuthorName() { 
      return m_author_name;
   }
}
Listing: MessageList.java

package forum;

import java.sql.*;
import java.util.ArrayList;
import forum.util.ConnectionManager;

/** A list of forum messages. */
public class MessageList {

   private ArrayList m_list;

   /**
    * Creates a new MessageList by querying the database.
    */
   public MessageList() throws SQLException {
      m_list = new ArrayList();
      // hand-waving; assume connection management is centralized
      Connection conn = ConnectionManager.getConnection();
      // query all fields except message body.
      PreparedStatement ps = conn.prepareStatement
        ("select message_id, subject, post_date, first_name, last_name "
         + "from messages, users " 
         + " where author_id = user_id");
      ResultSet rs = ps.executeQuery();
      while (rs.next()) { 
         m_list.add(new Message(rs));
      }
      conn.close();
   }

   /** @return the number of messages in the forum */
   public int getMessageCount() { 
      return m_list.size();
   }

   /** @return a message at the given index */
   public Message getMessage(int i) { 
      return (Message)m_list.get(i);
   }
}
There are many good tutorials for JDBC out there so we won't explain the code above in detail. We're assuming that we have a ConnectionManager class, which gives us JDBC Connections on demand. We'll nearly always want to centralize the details of connecting to the database (users, passwords, database URLs), and often this centralization comes with the use of an off-the-shelf connection pool.

One interesting thing to note above is the public Message(ResultSet) constructor. This allows us to create a new Message that takes its attribute values from an already-open query, which is useful if we're not creating Messages one at a time, but rather creating multiple Messages from a query already opened in another object like MessageList.

Another interesting thing to note is that we took the code for opening the database query out of the body of the Message(String messageId) constructor and put it into a public method called setMessageId. This allows us to instantiate a Message as a "bean" from a JSP page (more on that later), because bean classes are always instantiated via the default no-argument constructor; querying the database is now a side effect of setting the messageId property on a Message bean.

Also note that we query for the raw date and format using Java's SimpleDateFormat class, instead of using any available RDBMS functions for doing the same (e.g., Oracle's to_char). This makes our date formatting more flexible should we want to use a different date format depending on the end-user's locale; it also makes our Java object more re-usable because it is less dependent on any one vendor's RDBMS syntax.

Now that we have working classes for retrieving messages from the database, we're ready to start serving them over the web using Java servlets and JSPs.

Java Servlets

Just as a Java applet is an application that runs in a web client, a servlet is a Java class that runs in a web server. Servlets are similar to CGI programs; they handle an incoming server request, do some server-side processing, and return a response; the servlet API specifies a standard API for getting information from the request, like the URL, cookies, and form variables.

Each Java servlet request runs in its own thread under the same Java virtual machine (JVM) process; processing all requests under the same process allows servlets to save server-side state between requests, since all servlet requests share the same memory address space. All of the usual thread-safety pitfalls apply to any servlets that store state between requests.

The servlet specification also includes a standard convention for deploying servlet classes and mapping them to URLs, through a deployment descriptor file (web.xml). A set of servlets, web pages, and the classes they use, along with the deployment descriptor, comprise a web application or "webapp." This standardized deployment layout is essential for allowing cross-compatibility between application servers; you can develop an application on Tomcat and then deploy it on WebLogic, for instance. WebLogic may have a more sophisticated administration interface than Tomcat but it uses the same web.xml deployment descriptor and the same file layout under the hood.

The following code is a servlet that will read a message from the database and display it to the user's browser, taking the message_id field from the messageId URL variable:

package forum;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

public class ShowMessage extends HttpServlet {

   public void doGet(HttpServletRequest req, HttpServletResponse resp) 
      throws IOException, ServletException {
 
     Message m = null;
      try {
         m = new Message(req.getParameter("messageId"));
      } catch (SQLException e) { 
         // wrap database exception to show standard error page
         throw new ServletException(e);
      }
      resp.setContentType("text/html");
      resp.setStatus(200);
      PrintWriter out = new PrintWriter(resp.getWriter());
      out.println("<h2>JSP Discussion Forum </h2>");
      out.println("<a href=\"message-list\">List messages</a> | View message");
      out.println("<hr>");
      out.println("<table>");
      out.println("<tr><th>Subject</th><td>" + m.getSubject() + "</td></tr>");
      out.println("<tr><th>Author</th><td>" + m.getAuthorName() + "</td></tr>");
      out.println("<tr><th>Posted on</th><td>" + m.getPostDate() + "</td></tr>");
      out.println("</table>");
      out.println(m.getBody());
      out.close();
   }
}

The above code creates a Message using the messageId URL variable; it then generates HTML output to the user's browser. To make the above example code work, you'd need to create a webapp with all the necessary class files (Message.class, MessageList.class, and ShowMessage.class) under the webapp's WEB-INF/classes/forum directory (because all the classes are in the Java package "forum"); and, in the deployment descriptor (WEB-INF/web.xml) map a URL to the forum.ShowMessage class with the following lines:

 <servlet>
  <servlet-name>show-message</servlet-name>
  <servlet-class>forum.ShowMessage</servlet-class>
 </servlet>

 <servlet-mapping
  <servlet-name>show-message</servlet-name>
  <url-pattern>/message-show</url-pattern>
 </servlet>

Java Server Pages

The first thing most readers probably noticed about the above example is that it's cumbersome to write web applications exclusively with servlets. Generating HTML output as string literals is verbose; and you can't change the HTML output without editing, compiling, and deploying a Java class file. It's also cumbersome to add a new servlet to a running server, since you'd have to edit the deployment descriptor and often restart the servlet container.

Enter Java Server Pages (JSP). JSPs look like HTML pages that contain snippets of Java code to be executed on the server, but they are really just shorthand or syntactic sugar for servlets. The JSP container translates them as needed to Java servlet classes, and compiles the resulting Java code. Since each page is a new file on disk, and the .jsp files are in the same place as static .html files, we don't need to edit the deployment descriptor to add a new JSP page.

We could write the above servlet as a JSP:

<@ page import ="forum.Message" %>

<% Message m = new Message(req.getParameter("messageId")); %>

<h2>JSP Discussion Forum </h2>
<a href="message-list">List messages</a> | View message
<hr>
<table>
  <tr><th>Subject</th><td><%= m.getSubject() %></td></tr>
  <tr><th>Author</th><td><%= m.getAuthorName() %></td></tr>
  <tr><th>Posted on</th><td><%= m.getPostDate() %></td></tr>
</table>
<%= m.getBody() %>

JSPs make it easier to separate content and presentation since the HTML markup is out in the open, and the default state in a JSP is HTML output with escapes into Java code instead of the other way around. There are different notations for executing Java statement blocks (<% ... %>) and interpolating the values of Java expressions into the output (<%= ... %>).

J2EE also includes an API for creating new JSP tags and tag libraries. The syntax for user-defined tags is also legal XML, so the procedures that handle user-defined JSP tags serve a similar purpose to XML style sheets (XSLT). This allows other J2EE application components, such as EJBs, to represent complex data structures in XML, leaving the presentation-level HTML rendering to the JSP tag extensions.

One such tag library included by default as part of the JSP standard provides a way to instantiate and access Java classes within JSP without writing any Java code directly; this assumes that the Java class that you're accessing is a "bean." ("Beans" are just Java classes that follow a standard naming convention for the methods that get and set their properties.) The following code example shows the above servlet re-written entirely with JSP tags, with no explicit Java code:


<jsp:useBean class="forum.Message" id="msg" scope="page">
 <jsp:setProperty name="msg" property="*"/>
</jsp:useBean>


<h2>JSP Discussion Forum </h2>
<a href="message-list">List messages</a> | View message
<hr>
<table>
  <tr><th>Subject</th><td><jsp:getProperty name="msg" property="subject"/></td></tr>
  <tr><th>Author</th><td><jsp:getProperty name="msg" property="authorName"/></td></tr>
  <tr><th>Posted on</th><td><jsp:getProperty name="msg" property="postDate"/></td></tr>
</table>
<jsp:getProperty name="msg" property="body"/>
In this example, we are implicitly creating an instance of a Message with the jsp:useBean tag; and each jsp:getProperty tag translates into a call to msg.getXXXX (note that when property="foo" is specified, the first letter of the property name is capitalized in the corresponding method name, e.g., getFoo). The most interesting piece of magic is that jsp:setProperty property="*" introspects into the class, and calls the corresponding setXXXX method, if available, for every URL or form variable.

It is an ongoing debate whether JSP or servlets (combined with some other templating system to break out static HTML) are better, and most web applications use some combination of the two, since servlets can forward requests on to JSPs and vice versa. A common pattern is using a controller servlet to perform tasks common to a group of URLs (e.g., /path/*), which does some common processing like user authentication and then dispatches to a JSP to display a page.

Other J2EE APIs

So far we've only scratched the surface of J2EE with JDBC, servlets, and JSP. And if we're building strictly a Web-based system, that may be all we need to use. But there are many other APIs in J2EE that are also useful, depending on the class of problem.

Enterprise Java Beans

The Enterprise Java Beans (EJB) API is a major component of J2EE; EJB, servlets, JSP, and JDBC together form the core of the J2EE APIs. is a component architecture for distributed Java applications in heterogeneous computing environments. EJBs are JavaBeans classes that run inside an "EJB container," like servlets are Java classes that run inside a servlet engine. The EJB container is generally part of a comprehensive J2EE application server product, which will also include a web server, servlet engine, and JSP container.

EJBs are instantiated and accessed via Remote Method Invocation (RMI), so you can call methods on objects from an application regardless of whether the physical object lives in the same JVM or not. Since RMI in J2EE runs over the Object Management Group's Internet Inter-ORB Protocol (IIOP, see http://omg.com ), EJBs may also be accessed from non-Java client applications that are CORBA-compliant.

EJB provides a uniform standard for building a layer of abstraction between business logic and enterprise information systems, which include RDBMS systems like Oracle, Sybase, Microsoft SQL Server, etc.; ERP systems; legacy mainframe systems; and others. EJBs also can be used to build a layer of abstraction between server-side processing and client-side presentation. An EJB may be invoked from a stand-alone "thin" Java client application, a Java servlet, a JSP, or a CORBA application.

EJB Flavors

There are two flavors of EJBs: entity beans and session beans. Session beans do not have any persistent state. They may have temporary state, though; as the name implies, session beans are generally used to keep track of objects that are valid for a particular user session only, such as shopping carts or a temporary workspace. Session beans may access the same enterprise information systems as entity beans, though, and may retrieve entity bean instances.

Entity beans are persistently-stored objects. They can be thought of as object views of a row in a database whose properties correspond with column values. Entity beans that implement the EntityBean interface must provide methods for managing persistence which correspond to, and generally issue, the SQL INSERT, DELETE, SELECT, and UPDATE statements.

Entity bean persistence may either be managed by the bean itself, or by the EJB container. When persistence is bean-managed, the bean author must write the code to interface with the persistent store. Some EJB containers, though, support container-managed persistence; and it is possible to provide deployment tools to automatically generate SQL code for the above EJB methods.

It is important to remember, though, EJB is primarily for making distributed objects; it is not an API for object-relational mapping despite its support for persistent objects. As a general rule, EJB is not useful in cases where there is no use for RMI or remote procedure calls. If a particular solution does not require distributed objects, then EJB can add significant complexity and cost without providing any truly new functionality.

Applying EJB to the discussion forum application

In the discussion forum example, we could implement the Message class as an entity bean, and MessageList as a session bean. The EJB API for entity beans is a standardization so that classes like Message that access the database and map columns to object properties can be manipulated in an application-independent way. This allows for the possibility of RAD tools that can automate the generation of classes like Message.

EJB is really only useful in the discussion forum example, though, if we want to access Message object instances on a different JVM or machine than that which does the database query. For example, suppose we were to extend the discussion forum application so that messages would be viewable over both the web and from a standalone "thin" Java client application that doesn't connect to the database directly. A Message entity bean's methods, including the database queries, would run on the application server as they do in the web-only system; but the thin client can call accesor methods on the Message (actually, a stubbed interface) just as if it were an object local to the client.

Java Transactions

The J2EE includes the Java Transactions API (JTA) for performing distributed atomic transactions with enterprise information systems. This allows the programmer to ensure that a series of operations will either be entirely completed, or not done at all. Half-completed transactions are not allowed.

While most RDBMS packages include facilities for transaction management, they are limited to managing operations with that one RDBMS. The JTA can provide distributed transactions that consist of operations on multiple enterprise information systems.

Consider the following scenario:

  • Customer logs in to RDBMS-powered, e-commerce web site
  • Customer places order, order information stored in RDBMS
  • Order information also updated in legacy order-fulfillment system

In the preceding example, should something go wrong with the order-fulfillment operation, the customer's order should not be recorded in the RDBMS. The JTA allows these operations to be treated as a single atomic operation.

CORBA Compatibility

J2EE includes two-way compatibility between Java and CORBA objects; either one may call the other. The Java 2 Standard Edition (J2SE), a subset of J2EE, provides an Interface Definition Language (IDL) compiler, which generates Java stubs for calling remote CORBA objects from Java applications; and an Object Request Broker (ORB), which allows Java classes, including EJBs, to be called remotely from CORBA.

Java Naming and Directory Interface

The Java Naming and Directory Interface (JNDI) is an API for maintaining directories of name-to-object bindings. It may be used as the primary means of storing user information in a Java enterprise application, or it may be used in a helper role to the other J2EE APIs for locating remote objects. For example, a developer who instantiates an EJB within a client application might only know the name of the EJB's remote interface and nothing about the actual class which will handle the transport between the client application and the EJB container. JNDI is used to look up the actual class given an interface name.

JNDI supports LDAP (Lightweight Directory Access Protocol), an industry directory standard. This allows Java clients to connect to LDAP-compliant directory servers (e.g., Netscape Directory Server), and other LDAP clients to connect to Java enterprise applications. JNDI directories can issue events when changes are made to directory bindings. Other objects can register listeners to receive these events.

Java Message Service (JMS)

JMS is an asynchronous messaging service for connecting different Java applications, or a distributed application that runs on more than one virtual machine. Asynchronous messaging differs from the synchronous messaging used in RMI and EJB, and has different applications. The JMS API supports transactional message queues, which are implemented by various J2EE applications servers.

JavaMail

JavaMail is an object-oriented API for parsing, constructing, and sending MIME e-mail over the Internet. It consists of abstract classes for sending e-mail messages, representing MIME multipart messages, and representing e-mail folders. JavaMail would be useful in the discussion-forum example for sending out e-mail alerts to subscribing users when new messages are posted.

XML

XML (see http://www.xml.org) is not new, nor is it officially part of J2EE, but its role in enterprise Java applications is significant enough that it merits discussion here.

XML's role in enterprise applications stems from its utility in B2B information exchange. Most collaborative commerce systems will probably make at least some use of XML as a format for interchanging structured data. Also, XML parsing is related to the JSP tag extension mechanism.

To facilitate the use of XML within Java applications, J2EE defines a standard interface for Java XML parsers. Interfaces are provided for both Simple API for XML (SAX) parsers and Document Object Model (DOM) parsers. SAX parsers are event-driven; they call methods in a specified document handler object when XML elements start or end, or when character data sections are encountered. DOM parsers create an in-memory tree of objects corresponding to the structure of the XML document.

Future directions

J2EE can be used for building community-based Web sites and collaborative Web applications. Java servlets, JSPs, and JDBC are the most important J2EE building blocks of a Web-based community, though the EJB API may occasionally be appropriate for interoperability with other systems where interaction over HTTP is cumbersome.

We showed an example of a database-backed web application that could be built with J2EE components, using only Java servlets, JSP, and JDBC. Other J2EE APIs like EJB and JavaMail would become important when we want to add specific features to the web application, or if we want to access the same set of business objects from server-side components in the same JVM, or programatically through remote procedure calls.

One of the greatest promises of the J2EE is the potential for client-server applications that are independent of their client type. By creating abstractions for business rules and data models in EJB classes, and using standard J2EE APIs for accessing them, it is possible to develop the same application with different client interfaces for Web browsers, handheld computers, and any future device with a JVM.


asj-editors@arsdigita.com

Reader's Comments

I would be keen to know what Philip's perspective is on J2EE, and most of the items discussed in this page. Has he read this brief article?

It seems Java, especially at the server level has advanced quite a bit since Philip wrote his book. Are software sellers just trying to convince us to use the latest and greatest so they can sell it, or is designing an application around objects a good methodology for application development, maintenance, and extensibility.

-- Philip Jensen, October 7, 2000

Indeed taking SQL queries out of JSP pages and putting them into compiled Java classes robs the page authors of the full expressive power of the SQL language. But isn't that a necessary (and desirable) consequence of building a structured system where the various functions (presentation, database access, ...) are layered and kept cleanly separate from each other? JSP as I understand it is meant to take part of the presentational side of things; it seems therefore quite natural to me that SQL subtleties should not be an issue to the JSP programmer. In other words, putting structure in a system has to be done at the expense of removing some degrees of freedom somewhere.

Of the two alternatives to the problem of retrieving information from a message bean, the first one (having a getXXX method for each attribute) seems perfectly acceptable to me. The fact that two queries are needed instead of one is beside the point. It is an efficiency issue croping in through the back door. If relational databases were really smart, it wouldn't have to be the case. But even if we want to compensate for our database weakness, a hypothetical message bean is the perfect place to do so. We want the bean to be easy to use with individual getXXX methods for each of the attributes and we want it to be efficient. One way to do it is to make sure that when the bean retrieves one (or many) rows from the messages table through a getXXX method call, it also gets all the columns which are likely to be needed and caches them. After a certain amount of time (or when memory becomes scarce), the bean drops the cached results. Hence the bean can hide these gruesome details from the bean consumer.



-- Guillaume Barreau, October 18, 2000

Embedding sql in jsp is simply insane. It makes schema evolution virtually impossible, and performance analysis extremely difficult (since you're reduced to browsing through a bunch of jsp's with slightly different variants of the same query looking for the exact one thats hammering your poor database). Also, it implies that either your database engineers are also UI experts, or vice versa. Neither of these assumptions scale well in the real world.

As for the performance issues, discussed in both the comments and the article - they both overlook the most important benefit of having an object wrapping around the sql - caching. Not only do you get code reuse, but you can also get actual object reuse. The bboard example is an excellent candidate since the objects are largely read only. Note that its important to distinguish between caching objects in the application, vs. the use of the RDBMS cache. While you will seem some benefits from cache hits in the database, it turns out that this will quickly be swamped by networking overhead if you make multiple distinct requests for different columns in the same row. With the exception of message bodies, where the cost of getting the column is relatively high, you're probably better off doing fewer queries that return multiple rows and caching the results locally than fetching just the row you need just when you need it. Minimizing round trips to the database is an important performance issue ...

-- Lee Schumacher, November 10, 2000

I agree that having SQL in presentation layer code (JSP) is a bad idea for anything except small, simple, quick'n'dirty hack projects.

Normally you would want presentation-layer objects to talk to application-layer objects which manage database access and any complex processing logic. That allows you to have much better control over what database access your system is doing, which is better for reliability and maintainability. ├Źn hig-traffic systems this also lets you make design deicsions about whether you want to allow objects to manage their own persistence by accessing the database at will, or whether you want to implement some kind of application cacheing scheme.

(Caching or not depends on things like whether you have performance issues accessing the db, which would argue for lots of cacheing, or whether your db is getting heavy update traffic from multiple soruces, which would argue against it. There are obvious dangers in trying to get too clever with application-level cacheing if you are operating in environments with a lot of concurrent read and update traffic, and if it matters to you that your read users get to see the most current updates. At this point you start having objects telling each other when to refresh cache, and will drift towards reimplementing a half-baked version of the DBMS's cacheing system - except that Oracle (or IBM or Sybase or whoever) have put tens of man-years of work into designing way more efficient and reliable algorithms than you are ever likely to.

The SQL-in-JSP examples aside, though, I found this a useful and clear overview of a topic that is surrounded with a lot of buzz and confusion if you're not intimately familiar with the technology.

-- Alan Little, December 13, 2000

We are presently dealing with the SQL-in-JSP UI-vs-DB seperation issue by having two seperate JSP pages for each URL (different file extensions); one sets up the database queries (it's generally just Java code) and one defines the visual display (using our ATS templating system to deal with displaying the results of the database query setup page).

My personal experience with this is that it is much simpler to code the queries because you can reload the page to see an update, rather than having to recompile a class, shutdown the webserver, and restart the webserver. You can still put queries into Java classes if they are truly general-purpose, but the "full expressive power" argument and desire to use as few DB queries as possible generally results in this not being the appropriate thing to do (i.e. you could write a one "getItem" query and reuse it on another "show all items" page by calling it a hundred times to get a hundred items; but then you've just done a join in your programming language rather than in the database, robbing your code of efficiency via huge database overhead. Always do the joins in the database + don't ask for more information than you need = unfortunately less chance to reuse queries than you might wish for)

End result: UI authors learn a few new tags and they never have to know anything about SQL. SQL/Java authors write a "page contract" for the UI authors and then their SQL+logic is isolated from the presentation. Nobody has to recompile and shutdown the webserver to see changes, although they can go that route if it's appropriate for the task at hand.

The ACS has had the database queries mostly in the pages to be served for several years now and it's worked out quite well. I don't think anyone could argue that the ACS is a small simple hack.

-- David Eison, December 16, 2000

Related Links

spacer