Web Server Programming
Chapter 10
Enterprise Java
A private individual, or small company, will typically find PHP (or ASP) an adequate technology for implementing a simple interactive web-site that has a few dynamically generated pages. Larger companies, that have a number of webapplications, will do better with a combination of servlets, JDBC, JSPs, and XML-XSLT (or the equivalent technologies as deployed in Microsoft's .NET). The deployable "webapp" structure facilitates management of multiple webapplications, each comprising processing that would require several PHP/ASP scripts, and all sharing databases. Code reuse is encouraged through the structure of servlets for control, JSPs (and XML technologies) for display, and application specific beans that embody business logic. Beans developed for one webapp can be reused in other webapps or may get used in ordinary Java applications that are not deployed via WWW. The fairly simple security model with servlets is sufficient for sites that have some webapps for general access, and others restricted to authenticated users who are permitted to operate in specified roles. The declarative web.xml deployment files allow a webapp to be reconfigured without recoding and recompilation.
It is only larger organizations that will need more sophisticated technical solutions. These will be organizations where Web delivered services must integrate with a much larger corporate IT infrastructure. Web initiated actions may need to integrate with message queuing systems, mailers, classical transactional database systems, and legacy applications (many implemented in languages other than Java, or C#; a lot of mission critical processing is still done by Cobol programs).
"Enterprise applications" comprise many different processes running on numerous machines; all needing to communicate in controlled ways. Various forms of middleware are used to "glue" the various parts together. One aspect of "enterpise Java" (and the .NET equivalents) is the provision of this middleware.
Another aspect, one that is emphasised in both Sun's and Microsoft's presentations, is the move towards "components" deployed in "containers". The component in container style has evolved from earlier architectures such as CORBA servants and "beans" in a servlet container. The "container" implements all the standard code for instantiating objects on demand, handling transactions and so forth. Components - smarter versions of the beans used in servlet containers - implement just application-specific business logic. The overall deployment system, that places components in containers, also handles some parts of the programming task - being capable of generating code for routine tasks such as transfers of data between memory and database tables.
The Enterprise Java and .NET technologies are intended to enhance the productivity of programmers who must implement multitier applications. As much as possible is automated. The architecture enforces separation of concerns. Development groups consist of different groups of specialists - most focus on application development, others specialize in the tasks related to deployment and configuration of applications. The applications developers ideally work on generic solutions to their company's business problems - developing components that can be deployed in many different applications and webapplications.
While this approach does have productivity advantages, it also has problems. The main problem is the level of sophistication and complexity. A full blown Enterprise Java application is an order of magnitude more complex that a simple servlet-bean-JSP webapplication. Several different technologies have to be understood and deployed in a consistent way (naming and directory services, EJB containers, servlet containers, message and mail systems, transaction systems, etc etc). Effective use of the primary programming model - distributed objects - requires a different approach from that used when developing ordinary OO programs for co-located objects (method invocations are costly when objects are distributed).
There is a substantial learning cost incurred when making the transition to Enterprise applications.
Really, you require a basic understanding of distributed objects prior to starting on Enterprise Java.
Java RMI is a rather limited form of distributed object technology - but it is probably the best starting point. Java RMI illustrates the basic principles, and RMI coding (if not deployment) is actually quite simple.
A typical Java RMI program has a server process that hosts either a single server object, or a factory object and a number of client-specific server objects. If there is a single server object, it handles requests from all clients and will typically do something like act as an intermediary in access to a database or filestore. A "factory object" solution is used when each client requires its own independent server object; these are created on demand by the factory.
The server objects are defined by their interfaces - the set of operations that they can perform on behalf of their clients. On the server side, there will be one or more instances of a class that implements this server interface. The client code works with instances of an automatically generated "proxy" (or "stub") class. This proxy class mimics the interface of the actual server. The client code uses an object model throughout - there is no apparent code related to network communications. When a server-side operation is required, the client code simply invokes the appropriate method in its proxy. It is the proxy that handles all the network communications, all the marshalling of data, the handling of responses and exceptions.
Java RMI consists of:
java.rmi package: this supplies the run time infrastructure and classes
used as base classes for implementation. On the client side, the infrastructure
takes responsibility for establishing communications with a server and for
transfer of requests. On the server side, the infrastructure helps route
requests to the appropriate server objects.rmic: this program generates the required client proxy class
from the definition of a server implementation class.rmiregistry: this program is a simple form of "naming and
directory" service. It allows a client to use a symbolic name for the
server with which it is to work. At run-time, the client will ask rmiregistry
to map the symbolic name into an actual object identifier (something that
includes host machine IP address, port number, object id).Sun offers a number of tutorials on RMI:
If you complete a tutorial exercise on RMI, and can understand the role of a "naming and directory service" like rmiregistry, then you have the minimal background knowledge of "distributed objects" needed to move on the EJBs.
However, it would be beneficial (though not essential) to explore a little of CORBA before starting EJBs. CORBA is the premier distributed object technology. CORBA has been harmed by a number of not quite compatible, incomplete implementations and by the lack of suitable introductory materials. These have contributed to a formidable reputation of being a difficult to learn technology. CORBA is not really difficult, it is just that the environment for the server side programming is feature rich and there are many support services - not just a naming service like Java RMI's rmiregitry. In a CORBA server, there are lots of diverse mechansisms for managing objects; these allow applications to scale up to situations where at least in principle you can have millions of server objects in a server process. CORBA services include name services, traders (analogy to "Yellow Pages" in a phone directory, you find servers not by name but by category and advertised properties), transaction services, event services (publish and subscribe computational model), security services and so forth. (Many CORBA implementations, e.g. Sun's 1.4 implementation, provide only a naming service, but you can always mix and match and make use of a service in a different CORBA implementation).
The distributed object model in CORBA is similar to that in Java RMI. Services are
defined by interfaces - the list of operations that a server object can perform
on behalf of a client. With CORBA, these interfaces are defined in Interface Definition
Language (IDL); they map down onto language specific versions. One of CORBA's strengths
is its support for multiple languages - you can have Java clients that access CORBA
servers implemented in C++, Cobol and ADA. A CORBA implementation will include IDL
compilers that fill the role of Java RMI's rmic; these IDL compilers
generate client proxy classes and server side classes from the IDL. Developers
must of course create the actual service implementation by defining a class that
extends one of those generated by the IDL compilers.
With Java 1.4, Sun upgraded its CORBA implementation to a version that is compatible with the CORBA standard. The current Sun 1.4 CORBA has an IDL to Java compiler, a proper implementation of the CORBA run time (ORB and Portable Adapter classes), a name server, and an activation daemon (starts CORBA servers as needed when clients appear). The implementation is adequate for simple experiments and can be used to generate Java clients for other CORBA implementations. You can instead use OpenOrb a Java CORBA implementation that supports a number of the CORBA services such as trading and events; or Mico a C++ CORBA (you can also pay real money and buy a commercial grade implementation from Iona or Borland).
Sun now provides a few introductory tutorials on CORBA - starting to fill a major gap. The tutorials include:
The tutorials "activators" and "locators" illustrate the controls on object life cycles that are available for CORBA developers. These mechanisms for controlling the existence of server objects do support many sophisticated application styles - but they add quite a lot to the work of a CORBA developer. One of the aims of EJB is to finesse all these object management activities; the management activities are standardized and incorporated in the EJB "container".
Once you have a background that includes some experience with JDBC and servlet technology, and a least an introduction to distributed objects using Java RMI, then you can begin to look at the Enterprise Java technologies. These include:
Some other Java packages are often included in this "Enterprise" group although also being available separately. These include CORBA-IDL and JDBC (both part of the Java Standard Edition), Java Servlets and JSPs.
The XML technologies include:
There are quite a number of naming and directory service implementations. Common ones include the CORBA CosNaming NameService available with all CORBA implementations, the Lightweight Directory Access Protocol (LDAP), Sun's NIS+ service, and even the Domain Name System. Each has some mechanism for defining a hierarchical name space; each allows data to be associated with a fully qualified name. (For example, a CosNaming name will map to data that represent a reference for a CORBA object - host IP, port, objectid.) Each implementation has a quite different syntax for names and a quite distinct mechanism for navigating and modifying a naming hierarchy.
JNDI is for these naming services what JDBC is for databases. Each database has a different low-level driver, but you never really notice this in Java programs using JDBC because the higher level JDBC interface is implementation neutral. It is much the same with JNDI. Your client program using JNDI to lookup a service will use the same API irrespective of whether the underlying implementation is a CORBA NameService or an LDAP server. (JNDI has a "service provider" interface that allows "drivers" to be provided for the different forms of naming and directory service that may be available.)
JNDI is growing in importance. The reason is that applications that use run-time lookup to discover services are easier to redeploy than applications that have server details embedded in their code.
If you look at a conventional JDBC program, you will see the name of the class of the required database driver and the URL for the database. If you want to change the database that is used, you must edit and recompile the code. Newer JDBC programs will use a JNDI service to obtain a "DataSource" object that corresponds to a given symbolic name. The symbolic name is looked up at run-time in the configured JNDI naming service. The data object associated with the name, the DataSource object, packages all necessary information required to obtain a driver and a connection to the appropriate database. The information in the JNDI service's data tables can be modified by a deployment tool, making it quite simple to change the database being used by an application.
JNDI style lookup is used consistently throughout EJB applications. Client programs
have symbolic names for the server objects that they wish to use - these are looked
up at run-time to obtain initial references for those objects. (It is a bit like
a Java RMI program getting an initial reference from rmiregistry.)
Session and Entity beans that use databases again have symbolic names for these databases;
the actual database details being defined at deployment time when the appropriate
data are inserted into the tables of a JNDI service associated with the EJB system.
Sun has general overviews and tutorials that clarify the role of JNDI and its use in client applications:
Sun's JNDI tutorialConventional client-server applications - like the Web or Java RMI - are synchronous. The client submits a request and then blocks waiting for a response. The remote call is similar to a local procedure call - you can't continue until the called procedure is exited.
Sometimes, asynchronous operations are more appropriate. There are various uses. One usage style has clients queuing work tasks; server processes can collect tasks from the queue when they have the time or other resources needed to process the tasks. If the client needs a response, the process that handled a task will queue up a reply in some other queue; the client polls this queue to check for the response. Another use is "publish and subscribe". An "event source" can publish data to an intermediary; clients can subscribe to particular event channels hosted by the intermediary process.
There are several message queue systems, such as IBM's MQ product, Talarian's SmartSockets, and Tibco's Rendezvous (Sun has a list of many message system vendors, although not on this list Microsoft also has a major messaging product). The Java Messaging Service is once again a standard API that allows Java programs to work with any of these varied implementations. Sun also has a tutorial available; and there is another tutorial illustrating integration of messaging services with an EJB solution.
The Java Mail Service is a package of classes that model a conventional mail system. The API allows Java applications to post mail. The JMS reference page has links to articles and examples illustrating the use of the mail services.
Databases will provide their own transaction management. You can set a database connection into user managed transaction mode, and mark the start and end of transactions that involve multiple database operations. The database will use locking or time stamping techniques and will provide some guarantee that transactions are acidic - atomic, consistent, isolated, and durable.
Things get a bit more difficult if there are multiple transactional resources. In an Enterprise level application, it is common for a program to work with more than one database (or other transactional resource such as a message queue). In these cases, you cannot rely on the transactional character of the individual resources because all aspects of a transaction must be handled consistently (it is unacceptable for one database to commit an action such as a debit, while a second database rolls back the corresponding credit action).
Distributed transactions generally involve a transaction manager component. This component coordinates the activities of the various transactional resources. There are a number of proprietary transaction managers; there are also managers and databases that work in compliance with the OMG's CORBA distributed transactional model (CosTransactions).
The Java Transaction elements of Enterprise Java include a low level JTS (Java Transaction Service) which is a Java interface to a CosTransactions server, and a higher level Java Transaction API.
While you may eventually have to work with JTA and JTS (for example, writing a Java client for a CORBA transaction system) your first encounter with Enterprise will be via EJBs where the transactions are all handled automatically by the EJB container. All that you will need to do is specify transactional requirements of different operations in the deployment descriptors created for your applications.
Enterprise Java Beans (EJBs) are the technology that you will encounter first. The J2EE download includes a reference implementation of all the technologies needed to create and deploy EJB solutions. The Tutorial provides a detailed step by step guide that builds up to the Java banking example that serves as a realistic illustration of the value of these technologies. (Remember: most of the early examples in the tutorial are intended to show how EJB components work - they do not illustrate appropriate uses. An application built along the lines illustrated in some of the Entity bean examples would have a very poor performance if actually deployed.)
The tutorial has a supplement that covers the new features in the 1.4 release. This has sections on Web Services, Message beans, changes to container managed persistence, and other extensions.
The Sun J2EE development kit contains the deploytool program
that is used to package applications. Unfortunately, deploytool has
been updated, but the documentation has not been updated. Despite numerous
complaints to Sun on the bug pages and forums of Java Developer Connection, Sun
has left the documentation incorrect for several months. Many would be EJB
developers have had their first exercises disrupted as they found the tutorial
examples could not be run.
Until Sun fixes the documentation, the following outline deployment (illustrated
for Sun's first Converter application) should be followed. (These
instructions are for Windows and were run on a Win-2000 machine; the
procedures for Linux/Unix will be very similar with appropriate
substitution of file names.)
j2ee
command; it will run if you have your environment variables set as detailed in
Sun's tutorial.)
deploytool in GUI mode.C:\whatever\j2eetutorial\examples\src\ejb\converter (fill
in the correct path name for wherever you have installed the j2eetutorial materials).
Savej2ee download that I got has an error
in one of the XML schema files used to define the structure of the XML files that must be
generated. It is a minor problem - one of the element closing tags, around line 170 in
the schema file, has been partially duplicated. If the verifier complains, find and
edit the faulty schema file.)deploy (from Tools menu). Unlike the
tutorial, there are now no pretty graphics showing progress of deplyment, just a report card;
should say Operation Completed Successfully
Directory of C:\j2sdkee1.4\j2eetutorial\examples\src\ejb\converter
26/04/2003 03:47p <DIR> .
26/04/2003 03:47p <DIR> ..
11/10/2001 02:50p 474 Converter.java
26/04/2003 03:47p 5,206 ConverterApp.ear
26/04/2003 03:45p 706 ConverterApp.ear.xml
11/10/2001 02:50p 1,031 ConverterBean.java
26/04/2003 03:54p 34,064 ConverterClient.jar
04/04/2002 03:43p 1,263 ConverterClient.java
11/10/2001 02:50p 432 ConverterHome.java
11/10/2001 02:50p 1,775 index.jsp
11/10/2001 02:50p 1,775 index.txt
9 File(s) 46,726 bytes
2 Dir(s) 17,757,114,368 bytes free
runclient -client ConverterApp.ear -name ConverterClient -textauth -stubs ConverterClient.jarThis should result in a prompt for username and password (as detailed in Sun's tutorial documentation), and should then run the application:
Initiating login ... Enter Username:guest Enter Password:123 Binding name:`java:comp/env/ejb/SimpleConverter` 12160.00 0.77
j2ee -stop