|
21.2. Expanding to EJBsAll right, we'll admit it. It is a bit of a stretch to expand our sample application to the J2EE Enterprise JavaBean component model. The truth is, given the small data requirements and simplicity of our application, the Web front end that we put on our application in the previous chapters is probably sufficient to scale our application to even very large organizations. That confessed, we still think our example is the best way to address our topic. Why? Because EJBs are a large topic, worthy of several books (and we encourage you to read some of them, such as Enterprise JavaBeans Component Architecture by Gail Anderson and Paul Anderson (ISBN 0-13-035571-2). We simply cannot teach you all about EJBs in our book. Our goal here is to introduce the concepts, provide a working example, and explain how to deploy and maintain an EJB system on Linux using JBoss. Believe us, we'll have enough to cover to achieve that modest goal. 21.2.1. EJB ConceptsIn a way, the use of the term Enterprise JavaBean, with its echo of the older term JavaBean, is unfortunate. Apart from the similar intention of creating reusable components, the two technologies have little in common. 21.2.1.1 The Life Cycle of an Enterprise JavaBeanMost of the books on EJBs that we have seen start with the simplest type of bean and work their way up in complexity. We're going to dare to be different, because the most complex case isn't that hard, and once you understand it, the functions of all the other types of EJBs become obvious. They simply don't implement what they do not need. For the moment, assume that an EJB is a simple class that provides a set of methods to clients. The methods represent business functions that clients want the server to carry out. Implementing an Enterprise JavaBean requires implementing three Java source files:
We'll get into the details of these interfaces (and the sometimes obtuse reasons behind) a little later on. For now, we will concentrate on the implementation. The implementation class contains methods that are there only to allow the container to control the bean and to inform the bean of impending changes to its status. Those methods are defined in the bean class that the implementation class extends. The classes one extends to implement a bean are:
Please forgive us right now for admitting that we will not cover message beans in this book beyond a brief description in the next section. For details on message beans, take a look at Chapter 8 of Enterprise JavaBeans Component Architecture by Gail Anderson and Paul Anderson (ISBN 0-13-035571-2). Not all of the control methods need to be implemented in all cases, but the full set is not that large or difficult to understand. They correspond to important "life events" in lifetime of the bean. The primary events are: creation, destruction, passivation, activation, persist to DB, restore from DB, and context switching. CreationA bean is created when its constructor is called. As we shall learn, the calling of the constructor has absolutely no connection with a client request. For session beans, the container maintains a pool of instances to handle client requests. For entity beans, a bean (most commonly) represents a database table, and the setEntityContext() method is used to move that bean from row (instance) to row as needed. In practice, this usually means that a number of instances of the bean are created when the application server is started. Additional instances are created as the demand for this bean (number of clients, number of calls per unit time) increases. DestructionAs you know, Java objects do not have explicit destructors, but when a bean instance is destroyed, an explicit method in the Bean class is called to permit shutdown operations to take place. This is quite distinct from activation and passivation. Activation and passivation are operations carried out when the application server needs to shove aside some Bean instances that may still be needed by clients in order to make room for an active request that requires more than the available system resources. Passivation and activationAs we said above, passivation involves the container asking the beans that are still potentially needed to step aside to allow more urgent tasks (probably beans that are being actively called) to use resources tied up by otherwise idle beans. Think of this as like memory swap in an operating system. The bean will save any data and context information into some sort of persistent storage, which may be a database, flat files, XML files, whatever, when it is passivated. Context switchingSince both session and entity beans may be called upon to service requests from multiple clients, it is necessary to provide a method whereby the container can notify the bean which "context" (which may be loosely said to be a client) is active at the moment. In stateless session beans this is not necessarily implemented, but in stateful session beans and in entity beans this activity must be supported. How is this distinct from passivation and activation? Passivation is the temporary "swapping out" of a bean to make room for something else. Context switching is the move of a Bean instance from client to client. Or, to put it another way, passivation makes room for some other bean to become active and serve a client.[1] Context switching switches a given bean from client to client.[2]
21.2.1.2 The EJB ContainerA J2EE application server has two containers: a Web container and an EJB container. You can also think of these as "servers" in the more classic sense. J2EE calls them containers because it emphasizes the idea that you place Java objects (applets, servlets, and Enterprise JavaBeans) into the container that can run them (a browser, a Web container, an EJB container). The J2EE specification specifies the exact relationship between these application objects and their container. For EJB's, the container provides lifecycle control, network management, load management, perhaps clustering services, CMP (container-managed persistence) services, and so on. We'll talk a lot more about container services as we go along. For now, be aware that the container will start, stop, instantiate, destroy, and provide network services to the EJBs it contains. 21.2.2. Bean TypesEnterprise JavaBeans come in more than one variety. Let's take a look at those. 21.2.2.1 Session BeansA session bean is a reusable component that represents a collection of server methods. The intention is that each such method represents some business process, such as addCustomer(), createShoppingCart(), and so on. Session beans are thus organized around business processes. Actually, a session bean is not much more than a facade that collects a business process API into a single class. But remember what EJBs give younetworked server-based functionality, load balancing, clustering features, reliability, failover, and the ability to handle increased demand by merely adding more Bean instances and server hardware. The power comes not from how EJBs extend the language, but from how they automate and hide infrastructure. Session beans come in two major varieties: stateless and stateful. Let's take a look at what they offer and the differences between the two. Stateless Session BeansWhat they areA stateless session bean is one where each method call is completely independent of any other method call, whether by one or many clients. An EJB application designed this way has certain advantages. Since a single Bean instance can be switched from client to client on demand (because no state information is kept between method invocations), a small number of Bean instances can handle a large number of clients. Compare this with stateful session beans described below. Why you would use themIn a sense, this is the optimum bean. If you can design your application to use nothing but stateless session beans (perhaps backed by entity beans), then you have a maximally flexible, extensible, and adaptable enterprise applicationone that can be easily scaled from a single application server to a very large cluster. Why? Because the lack of state information means that any single Bean instance can serve any given client at any time that it is free without requiring any distribution of client information between Bean instances. From the client's perspective, the client can connect to any instance of the Bean on any server at any time to get the same work done. Stateful Session BeansWhat they areA stateful session bean is one that remembers its client between method invocations. It maintains some information between calls from a client. Because of this, a given Bean instance can only handle one client at a time, and if an instance is to be switched between clients, the information about the previous client must be saved so that the client's session may be restored later. An application that is designed around stateful session beans will generally require more resources than one designed around stateless session beans (described above) because each active client requires a dedicated instance of the Bean. Why you would use themWe think we've beaten the issue of the advantages of stateless beans into the ground. But what are the advantages of a stateful bean? Many types of client interaction require the bean to "remember" something about the client. The classic (and, by now, almost cliché) example is a Web-based shopping cart application. The remote interface for a stateful ShoppingCart EJB might look something like this: createCart Creates a new shopping cart for the customer. addItem Adds an item to the shopping cart. delItem Removes an item from the shopping cart. purchaseCart Processes the cart; charges the credit card; generates pick list, shipping list, and invoice; discards cart. abandonCart Discards the cart. Here, items like the identity of the customer and the list of items in the cart must be preserved between method invocations. Obviously, it is possible to present such an interface through a stateless bean by creating some sort of a session identifier token and passing that in to every method, thus allowing the stateless session bean to save this data to a database and then load it back, but the primary advantage of a stateful session bean is that this work is done for you through the setting of the bean's context. So, the primary advantage of stateful session beans is that the server side can keep track of client data for you. The primary disadvantage is that the container will try its best to keep an instance of the Bean around for every client, so it must sometimes swap an idle instance out to make room for an active instance, which is an expensive operation. Butand this is important to keep in mindit is much less expensive than reading and writing this data on every call to a stateless bean! You have to understand what is happening under the hood if you want to produce an optimal design. If you need state between method calls, a stateful bean is likely to be the most effective way to go. 21.2.2.2 Entity BeansWhat they areAn entity bean is often described as an object that represents a row in a database table. This is the most typical case, but it isn't always so. We have worked on a J2EE application where the entity bean represented an XML document in the filesystem. The general idea is that enterprise applications tend to work on lists of similar things: customers, employees, locations, accounts, servers, inventory items, and so on. An entity bean is an object that represents a single item in such a list. In other words, it is an interface to a data item. And, yes, in practice there is one entity bean class for a table and one instance of the class for each row. Obviously, a J2EE container doesn't maintain an in-memory instance for every row of every table. In fact, you can think of both entity beans and session beans as ways to automate keeping the optimal balance between in-memory instances for speed and data storage for memory utilization. Entity beans can be written to manage the persistent storage itself, using code added to the bean implementation by the bean author (this is known as bean-managed persistence, or BMP), or they may be written to allow the container to automatically manage the data in the underlying database for you (this is known as container-managed persistence, or CMP). Which you use may depend many factors, including the databases your container supports, the complexity of your database, the quantity of non-Java clients, or the amount of legacy code. Entity beans can be a hard sell in many development environments. We can see three strong reasons to resist the use of entity beans.
So, where is it suitable? Entity beans are particularly well suited to environments that are homogenous by being based either mostly on Java or on CORBA/IIOP. Further, they are well suited to environments where the bulk of the work is the editing and manipulation of small numbers of entities per session, as opposed to large reports or statistical queries where a session might want to use many or all rows in a table. Please note that using entity beans in such appropriate cases in no way precludes other types of use! You just won't likely use entity beans for them. In other words, you don't have to use it just because it is there. One further word. This is by no means an established doctrine, but it seems to be common practice to keep entity beans hidden behind session beans. In other words, it seems to be commonplace to not allow clients (Web applications, Java applications) to communicate directly with entity beans, but rather to have session beans perform all entity bean operations. This is probably because the idea of session beans is to decouple business process from implementation details, and entity beans, no matter how much they hide the underlying database, are still rather tightly coupled to the implementation of the data storage. Why you would use themEssentially, they allow you to write your data access layer exactly once, and then reuse it any number times without worrying about capacity and management. Also, by trying to keep the most often used data in fast memory, they can, when running on a powerful container or cluster of containers, keep many client operations running much faster than a strict write-read update back end. 21.2.2.3 Message BeansWhat they areWe're going to gloss over message beans in our book, but you should know what they are. A message bean represents an interface to a message queue. An entity bean represents a transaction where completion of the call tells you the operation has fully completed. A message queue, on the other hand, is an interface where you are given the firm promise that system will get to this when it can. The client doesn't know where or when the message will be handled. It doesn't know if it was successful or not. But it does know that it is the problem of the queue reader. There are many such operations in large enterprises. And there are many products that implement such functionality. Microsoft offers Message Queue Server (MSMQ). IBM has MQSeries. Message queues are common with operations that take time, or need to be batched, or require human intervention. Why you would use themLet's go back to our shopping cart idea. Management might want a daily sales report. You could send each and every item purchased to a message bean. Then a process to read that queue might be kicked off once a day and the report produced without hitting the database that supports all the current Web users. That's a good example of how a message queue (and thus a message bean) might be used. Again, we're not going to work with message beans here. 21.2.3. Under the HoodWe're not going to take apart the source code for JBoss here, but we do want to spend some time talking about what is going on in an EJB container. It isn't magic. The whole system is built on some familiar technologies that you can learn all about if you want to. First of all, the default protocol for EJB session and entity beans is RMI. That's right. A major part of an EJB container is the code to set up RMI connections between beans and clients. RMI is an application protocol that defines how to encode the state of a Java class, transfer it over a network (using TCP/IP sockets), and restore the coded data to a local implementation of the class (the encoding/decoding process is called marshaling/unmarshaling). That's part one. Knowing where to find the appropriate bean is the next part. |
|