A web container hosts websites and web services, both of which are deployed as WAR files. Tomcat Catalina is the RI for a web container. A website in Java is a mix of static HTML pages; servlets; higher level servlet generators and HTML-templating constructs such as JSP and JSF (Java Server Faces) scripts; backend JavaBeans dedicated specifically to servlets and the equivalent; utility classes of all kinds; and, of course, JavaScript embedded in the HTML pages. There are many JVM-centric frameworks for web development, including Netty, Seam, Sitemesh, Tapestry, Wicket, Struts, Spring MVC, VRaptor, Grails, and even Rails on JRuby.
Tomcat, like other web containers such as Jetty, can be embedded in an application server as the JAS web container. JBoss, for example, once bundled Tomcat into one JAR file (with a .sar extension for service archive) and Jetty into another, leaving it up to the JAS administrator about which of these to use as the JBoss web container. Some JASes still use embedded Tomcat for the community edition but roll their own for the production edition. Whatever the implementation choice, a JAS has a web container for deploying websites and, increasingly, web services. The deployed WAR files typically contain the standard configuration document web.xml and may contain vendor-specific configuration documents as well. To host web services, a web container usually relies upon a servlet interceptor that mediates between the client and the web service.
In contemporary websites, the model-view-controller (MVC)
pattern has become popular, even dominant. A model maintains state information about the site and is responsible for
persistence through a data store such as a database system; a view provides an appropriate representation of a model; and
a controller is a request endpoint that
implements the business logic that coordinates interaction between models on the one side and views on the other side.
Java EE has the @Entity
annotation
to signal that instances of the annotated class are to be persisted, typically in a relational database system. An @Entity
class is thus a natural way to build a model with persistence. (The section below on the EJB container goes into more
detail on the @Entity
annotation.)
In interactive web applications, JSP, JSF, or even
higher level templating constructs
can generate an HTML view of a model; either a servlet or a servlet coordinated with a Session EJB, discussed shortly, is a natural way to
implement a controller.
For Java-based web services deployed in an application server such as GlassFish, @Entity
instances are likewise a
natural way to implement models. The web service itself is the controller that exposes business logic in @WebMethod
or
RESTful code
and interacts, as appropriate, with models. Views in web services are basically response documents, with XML and JSON as
the usual formats.
The message-oriented middleware in a JAS requires a JMS (Java Message Service) provider, which furnishes the store-and-forward technologies lumped together under the term messaging. JMS supports synchronous and asynchronous messaging styles and two types of message repository: topics, which are akin to bulletin boards in that a read operation does not automatically remove a posted message; and queues, which are FIFO (First In, First Out) lists in which a read operation, by default, removes the read item from a queue. Under JMS, a publisher publishes messages to a topic and a sender sends messages to a queue. A subscriber to a topic or a receiver on a queue receives such messages either synchronously through a blocking read operation or asynchronously through either a nonblocking read or the JMS event-driven notification mechanism. JMS topics implement the publisher/subscriber model of messaging, whereas JMS queues implement the point-to-point model.
The EJB container holds EJB instances, which are of three types: Session, Entity, and
Message-Driven. Session and traditional Entity EJBs are built on a Java RMI foundation, whereas Message-Driven EJBs are built on a JMS foundation.
A Message-Driven EJB is a JMS MessageListener
implemented as an EJB. A listener receives an event notification
whenever a new message arrives at a topic or a queue at which the listener has registered interest.
A Session EJB typically implements an enterprise application’s business logic and interacts as needed with
other application components, either local (for instance, other EJBs in the same container) or remote
(for instance, clients on a different host). As the name suggests, a Session EJB is designed to maintain a client session.
A Session EJB is either stateless or stateful. A stateless Session EJB is, in effect, a collection of mutually independent
instance methods that should operate only on data passed in as arguments. The EJB container assumes that a stateless
Session EJB instance does not maintain state information in instance fields. Suppose, for example, that a Session
EJB encapsulates two instance methods, m1 and m2. If this EJB were deployed as stateless, then the EJB container
would assume that a particular client, C, could invoke m1 in one EJB instance and m2 in another EJB instance because
the two methods do not share state. If the same Session EJB were deployed as stateful, then the EJB container would have to
ensure that the C invocation of m1 and m2 involved the same EJB instance because the two methods presumably share state.
As this summary implies, an EJB container automatically manages a pool of EJB instances for all types of EJB.
A @Stateless
Session EJB automatically becomes a SOAP-based web service by adding the @WebService
annotation;
hence, legacy stateless session EJBs become SOAP-based web services through a single additional annotation.
In J2EE, the precursor to Java EE 5, EJBs in general and Entity EJBs in particular were tricky to code and even trickier to configure,
as the configuration required a complicated XML document, the notorious ejb-jar.xml document—the DD (Deployment Descriptor).
A case could be made that J2EE is too much work for too little reward. Things are much better with Java EE.
For example, Java EE 5 and greater allow the programmer to configure an EJB with in-code
annotations such as @Stateless
instead of with a separate XML document; hence, the DD is now optional.
Prior to Java EE 5, an Entity EJB instance was the preferred way to provide an enterprise application with an in-memory cache
of a database object such as a table row. The Entity EJB was the persistence construct that brought ORM capabilities to the application. A traditional Entity EJB could be deployed with either BMP (Bean Managed Persistence) or
CMP (Container Managed Persistence). At issue was whether the programmer or the EJB container maintained coherence between the
data source (for instance, a table row) and the EJB instance. In the early days of EJB containers, the case could be made that
BMP was more efficient. Yet the EJB containers quickly improved to the point that CMP became the obvious choice. Indeed,
CMP emerged as a major inducement for and benefit of using traditional Entity EJBs. An EJB deployed with CMP also had
to deploy with CMT (Container Managed Transactions). All of this changed with Java EE 5, which extended the capabilities of the
original Entity EJB to POJO classes annotated with @Entity
.
In effect, the @Entity
annotation let Java programmers enjoy many benefits of the traditional Entity EJB without enduring
the pain of
configuring and programming this kind of EJB.
Although the legacy Entity EJB remains a powerful programming construct,
it has given way to the @Entity
annotation at the center of the JPA. JPA
integrates features from related technologies such as Hibernate, Oracle’s TopLink, Java Data Objects, and traditional Entity EJBs.
The @Entity
is now the preferred way to handle persistence. This chapter has two examples that illustrate JPA.
EJBs, unlike servlets, are thread-safe: the EJB container assumes responsibility for thread synchronization.
As in the case of requests against servlets, each request against an EJB executes as a separate thread.
Even in a traditional browser-based web application, EJBs are thus well suited as backend support for servlets.
For instance, a servlet might pass a request along to a Session EJB, which in turn might use instances of various
classes, annotated with @Entity
, as persisted data sources (see Figure 7-1).
The web container, message-oriented-middleware provider, and the EJB container expose different APIs, and components in each container may require security and persistence services (e.g., with a relational database management system handling the persistence). A challenge is for components in one container or service to find those in another. The JNDI provider in a JAS handles the registering-by-name and finding-by-name of components across containers and services. In a JAS, the JNDI provider maintains, at the least, a naming service in which names (for instance, the deployed name of an EJB or a message queue) are bound to entities (in this case, the deployed EJB or the queue). If the JNDI provider supports directory services as well, then the name of an entity binds to the entity and its attributes. In the simple case, a JNDI provider maintains a hierarchical database of name/entity pairs. Any component dropped into a JAS container is automatically registered with the naming service and thereafter available for lookup. In Java EE 5 and later, the JNDI provider is largely unseen infrastructure; the naming conventions are simpler than they once were.
The security provider brings to the JAS high-level security services for components deployed in any of the containers. Among these services are, of course, authentication and authorization. The security provider has to be JAAS compliant. Nowadays a security provider typically has plug-ins for providers such as an LDAP provider. The security in an application server is usually integrated. For instance, the container-managed security that the web container provides is integrated into the default JAAS-based security that the EJB container provides. It is common, moreover, for a JAS such as GlassFish to deploy, by default, a web service with both an HTTP and an HTTPS endpoint.
The client container consists of the software libraries that a client requires to interact with
deployed components such as message topics or EJBs and to use services such as JNDI and security. In the case of web service
clients, however, there is essentially no change if the service is deployed under the lightweight Endpoint
publisher,
a web server such as Tomcat or Jetty, or a JAS. Even in the JAS environment, web services represent a simplified approach
to distributed systems.
A JAS typically comes with a RDBMS, which serves as the persistence store. In a modern JAS, the
JPA provider manages connections between in-memory objects such as @Entity
instances and database entities such as
table rows or join views. A
modern JAS also allows an RDBMS to be plugged in so that the administrator has a range of choices. GlassFish, for example, comes with
Apache Derby but it is uncomplicated to use a different system such as MySQL or PostgreSQL. This chapter has examples that involve
Derby and HSQLDB, both of which are implemented in Java. HSQLDB supports in-memory as well as disk-based tables, and both
database systems support transactions.