Business Tier Components
The J2EE specification describes an end-to-end environment for the development of enterprise applicationsfrom client GUI libraries, to Web browsers, to Web servers running JSPs and servlets, to the business tier, to the resource tier.
Business tier components run on the middle tier and thus have historically been referred to as middleware. These components run within an application server, which provides the container for the components. As with applets, this container provides various services for the component: lifecycle management, pooling, security, and automatic failover.
Prior to the EJB specification, developers creating middleware components needed to write code to specifically manage the infrastructure and provide services for the component. The EJB specification provides for the services in a consistent manner, thus providing the developer with a certain degree of portability in being able to move a component or set of components from one application server to another. In order to understand the creation and development of a J2EE application, it is important to understand the middleware technology provided with J2EE. For this reason, the next section discusses EJBs in more detail.
EJBs lie at the core of the J2EE architecture. They represent the middleware component specification for Java. The pure object-oriented nature and platform- independence, and security and network I/O features of Java made it a natural for the development of distributed components.
Following the release of the first EJB specification, the specification was quickly embraced and implemented by a number of application server vendors, and at last count, there were over 30 J2EE application servers available with varying costs and compliance levels (not all 30 are J2EE-certified by Sun Microsystems). Among these vendors, many try to distinguish themselves by offering specialized services. Not all vendors implement the complete J2EE specification, and many may implement a version of J2EE but not the current version.
As stated previously, EJBs operate within a logical container that provides a number of services; it is these services, in combination with the advantages of an object-oriented development, that make J2EE such an attractive development environment.
The following sections introduce some of the basic concepts of EJBs. But this nontrivial topic will not be dealt with in detail at this point; chapters 24 26 discuss EJBs in detail.
Client Interaction with EJBs
The EJB is a remote object used by clients. The exact nature of the client can vary. The client can be another EJB, a Web component such as a servlet or JSP, a standalone Java application, or an application or component written in another language. These clients are referred to as rich clients.
An EJB client accesses the services provided by the EJB in a two-step process. First, the object is looked up using a naming service, which returns a reference to the home interface for the EJB. Next, the home interface is used to create a remote reference for the EJB. This remote reference is then used to access the services (the methods) of the EJB (see Figure 1-2: EJB Access).
Figure 1-2 EJB Access
The remote reference is effectively used as any other object would be used. Parameters may be passed to the remote object, and values may be returned from the object. Method parameters are passed by value, not by reference, as they are done with objects in the local Java Virtual Machine (JVM). Parameters passed must be serializable.
Communication with the EJB is by proxy. The client never holds a reference directly to the EJB, but instead holds an indirect reference to a remote interface (the remote object in the server). The remote interface communicates with its counterpart in the application server, which in turn communicates with the EJB. This allows the container of the application server to intervene and manage communication with the EJB. It is this indirection that allows the container to implement the various services identified below.
The EJB Container
With EJBs, the container is implemented by what is commonly called an application server. Application server vendors and open source development groups may add additional services above and beyond the EJB specification and have some discretion on how services are implemented, but in order to be compliant, they must provide a core set of services, as follows:
J2EE emphasizes the use of declarative programming for many of these services. Rather than use complicated, error-prone method calls to implement a particular service, a declarative scheme under the control of the container is used to manage the service. The developer makes entries in a configuration file (known as the deployment descriptor), which describes specifically how the service should be implemented. These services and some background information on how they may be implemented are discussed in the following sections.
Security. EJB application servers must implement a specific role-based security model and must provide a role reference facility that allows a role reference name to be established for the role. Role permissions are then associated with methods and can be assigned to all methods within a component.
EJB security does not deal with authenticationthe expectation is that this is managed in the presentation tier or the client tier. EJB security is concerned with the user's role and whether or not the user (in his or her role) has permission to perform the action he or she is attempting to perform (executing a method or accessing a resource).
Transactions. The EJB specification provides for transactions related to components and for transaction managers that transparently manage transactions with a single data source or with multiple data sources combined. Transactions can be managed either by the container using container-managed transactions or programmatically through specific method calls using bean-managed transactions.
Components may run within a transaction and may propagate transactions down the call chain. This means that a method may have one transaction mode and call another method. That method being called may elect to use or not use the transaction of the method that called it, depending on the configuration of the component. This provides an easy mechanism to manage transactions based on component boundaries.
Naming. The naming services provided by the EJB application server allow the component to use a JNDI naming service to access J2EE resources. A JNDI naming service allows an arbitrary name to be associated with a resource. The resource is represented by a Java object reference that provides access to the services of the resource.
The J2EE resources accessed through the naming service could be an EJB component, a JDBC data source, or an environment entry that provides configuration information for the component. The naming service allows entries to be retrieved as object references that may be cast or narrowed to their specific Java type.
Scalability. The EJB server should provide scalability features, which should be enjoyed by the components transparently. The EJB specification does not provide details on what these scalability features should be or how they should be implemented (though it does specify that pooling of EJB components may be done and provides callback methods to allow some control over the process). Virtually all EJB application servers provide some type of scalability feature, though the type and sophistication varies.
Lifecycle Management. The EJB server should provide lifecycle management services for the component. This means that the application server should find the bean when it is requested and should be able to return a home object reference for the bean. When the home object attempts to create or locate the bean, the application server should create or access the remote object reference and return it to the client that requested the component.
Lifecycle management also includes the passivation of EJBs. If an EJB component has not been accessed for some time, the application server can elect to passivate the bean. When the EJB component is later requested, the application server must be able to find the bean and restore its state.
EJBs can be instantiated before use and kept in a pool. Then, when an EJB is requested by a client, it is simply retrieved from the pool and made available to the client, thus avoiding the overhead of object instantiation (for the EJB) at runtime. See Figure 13.
Figure 1-3 EJB component pooling.
Scalability and Failover
The scalability of an application represents the application's ability to handle an increase in usage without a significant drop in performance. For a Web site, usage is generally represented by the number of concurrent users or the number of page hits for the site for some increment of time (day, hour, minute, second).
Scalability is not addressed directly in the J2EE specification, but is addressed indirectly in the design of the components and how they interact with the container. Scalability is usually provided using a feature known as load balancing, where a dispatcher component can dispatch service requests over one or more servers. This load balancing depends on another feature known as application server clustering, where multiple application servers are attached to a cluster or group of servers. These servers usually work together to provide both scalability and failover capabilities for the distributed application.
Load balancing can be done using various algorithms, from a simple round-robin algorithm where requests are distributed evenly among all available servers, to a weighted average form of load balancing where requests are distributed among servers based on some statistical weight (see Figure 14).
Figure 1-4 Scalability with multiple servers.
Application servers may also provide some form of failover capabilities. The failover capabilities of a server represent the server's ability to survive a failure of some sort caused by either the server hardware or the operating system. Specifically, failover generally applies to the ability of session activity to survive the failure of one of the servers in the cluster. This failover may be transparent, meaning that if the server on which the session is running fails, the other servers in the cluster will manage its workload transparently to the client application.
Flavors of EJBs
EJBs come in three flavors as of the EJB 2.0 specification: session beans, entity beans, and message-driven beans. These variations are for a purpose. Each bean has specific functionality that makes it amenable for providing certain services, as detailed in the following sections.
Session beans represent a session between a client and an EJB, a client conversational state. Using the service model, a client will request a service from the bean through some conversation and the bean will respond with a result. This communication between the client process and the bean may or may not require the EJB to retain state information between invocations. If a session bean retains state between invocations, then it is considered a stateful session bean. If a session bean does not retain state between invocations, then it is considered a stateless session bean.
Any stateless session bean, since it does not retain state between invocations, should not use instance members or class members, because they will not be guaranteed to have sensible valuesvalues specific to a client sessionbetween invocations. In this vein, stateless session beans should receive a request, perform all work necessary to complete the request, and then return results for the request all within the space of the invocation (the method call).
Entity beans represent a unique element in a persistent data store. They represent persistent data, and in relational database terms, they are said to represent a row in a database table (or potentially, a unique record composed of a join across multiple tables).
Since they represent a unique relation in a persistent data store, an entity bean is represented by a primary key, a unique representation for the entity bean. A primary key can be represented by one or more columns in the underlying table.
An entity bean does not need to be mapped into a relational database. An entity bean could be mapped into a legacy database system or even into a set of files, though the most common implementation is that of object-relational mapping, using the entity bean to represent some portion of a relational database.
Entity beans must remain synchronized with the persistent data store. This is accomplished using a set of callback methods called by the container for certain lifecycle events. These methods must be implemented by the entity bean. Specifically, the ejbLoad method is used to load the bean from the database, and the ejbStore method is used to synchronize the bean with the database.
An entity bean developer can write the code for the ejbLoad and ejbStore methods (and a few others), or the application server vendor can provide a tool that will write the code for these methods. If the developer provides the code for the entity beans database synchronization, then the bean is using bean-managed persistence (BMP). If the developer allows the application server tool to create the code for the Entity Bean persistence, then the entity bean is using container-managed persistence (CMP).
As part of the EJB 2.0 specification, additional features have been added to entity beans to improve performance, address some of the limitations of the previous specification, and enhance the implementation of CMP. A query language (EJB-QL) has also been added, which allows internal selects and the navigation of related beans, values, and dependent objects.
MDBs have been added as part of the EJB 2.0 specification. These beans represent a useful integration of the JMS and the EJB. Am MDB allows asynchronous invocation of an EJB component. The MDB is stateless and is invoked by the container upon the arrival of a message.
Declarative Authorization and Security with EJBs
As indicated previously, the EJB container provides a number services for the distributed component including security and transactions. Part of the design for the EJBs stresses the use of declarative syntax versus traditional programming for certain properties. Using declarative syntax, entries in an XML file, an individual can define the security and transaction properties of an enterprise Java bean. This allows for easier integration of existing components from a variety of sources.
The alternative is to programmatically define the security of an application. This is a common approach with other applications, where the specific security of an application is defined in a series of Java language statements. Though common, this approach is prone to error. Using EJB declarative security provides a cleaner approach.
Deploying the EJB
Once the interfaces and classes for the EJB have been declared, they must be deployed into the application server. This deployment process reads a deployment descriptor, an XML-encoded document that describes various properties of the EJB (see Figure 15). These properties include but are not limited to transactional behavior, whether a session bean is stateful or stateless, and whether an entity bean is using CMP or BMP.
Figure 1-5 EJB deployment.
The application vendor is expected to provide a tool that will perform the deployment process. The process includes reading the deployment descriptor, finding the classes and interfaces required, possibly generating implementation code for the interfaces, and making entries into the name server.