3.2 Transactional component middleware
Transactional component middleware (TCM) covers two technologies: Microsoft Transaction Server (MTS), which became part of COM+ and is now incorporated in .NET, from Microsoft; and Enterprise JavaBeans (EJB) from the anti-Microsoft camp. OMG did release a CORBA-based standard for transactional component middleware, which was meant to be compatible with EJB, but extended the ideas into other languages. We will not describe this standard further since it has not attracted any significant market interest.
Transactional component middleware (TCM) is our term. TCM is about taking components and running them in a distributed transaction processing environment. (We discuss distributed transaction processing and transaction monitors in Chapter 2.) Other terms have been used, such as COMWare and Object Transaction Manager (OTM). We don't like COMWare because components could be used in a nontransactional environment in a manner that is very different from a transactional form of use, so having something about transactions in the title is important. We don't like OTM because components are too important and distinctive not to be included in the name; they are not the same as objects.
Transactional Component Middleware fits the same niche in object middleware systems that transaction monitors fit in traditional systems. It is there to make transaction processing systems easier to implement and more scalable.
The magic that does this is known as a container. The container provides many useful features, the most notable of which are transaction support and resource pooling. The general idea is that standard facilities can be implemented by the container rather than by forcing the component implementer to write lots of ugly system calls.
One of the advantages of Transactional Component Middleware is that the components can be deployed with different settings to behave in different ways. Changing the security environment is a case in point, where it is clearly beneficial to be able to change the configuration at deployment time. But there is some information that must be passed from developer to deployer, in particular the transactional requirements. For instance, in COM+ the developer must define that the component supports one of four transactional environments, namely:
Requires a transaction: Either the client is in transaction state (i.e., within the scope of a transaction) or COM+ will start a new transaction when the component's object is created.
Requires a new transaction: COM+ will always start a new transaction when the component's object is created, even if the caller is in transaction state.
Supports transactions: The client may or may not be in transaction state; the component's object does not care.
Does not support transactions: The object will not run in transaction state, even if the client is in transaction state.
In general, the first and third of these are commonly used. Note that the client can be an external program (perhaps on another system) or another component working within COM+. EJB has a similar set of features. Because the container delineates the transaction start and end points, the program code needs to do no more than commit or abort the transaction.
Figure 3-2 Transactional components in Microsoft COM+
Figure 3-3 Transactional components in Enterprise JavaBeans
When a component is placed in a container (i.e., moved to a file directory where the container can access it and registered with the container), the administrator provides additional information to tell the container how to run the component. This additional information tells the system about the component's transactional and security requirements. How the information is provided depends on the product. In Microsoft COM+, it is provided by a graphical user interface (GUI), the COM+ Explorer. In the EJB standard, the information is supplied in eXtensible Markup Language (XML). For more information about XML, see the box about XML in Chapter 4.
A client uses the server by calling an operation in the IClassFactory (COM+) or MyHomeInterface (EJB) interface to create a new object. The object's interface is then used directly, just as if it were a local object. In Figures 3-2 and 3-3 you see that the client reference does not point at the user written component but at an object wrapper. The structure provided by the container provides a barrier between the client and the component. One use of this barrier is security checking. Because every operation call is intercepted, it is possible to define security to a low level of granularity.
The other reason for the object wrapper is performance. The object wrapper makes it possible to deactivate the component objects without the client's knowledge. The next time the client tries to use an object, the wrapper activates the object again, behind the client's back, so to speak. The purpose of this is to save resources. Suppose there are thousands of clients, as you would expect if the application supports thousands of end users. Without the ability to deactivate objects, there would be thousands of objects, probably many thousands of objects because objects invoke other objects. Each object takes memory, so deactivating unused objects makes an enormous difference to memory utilization.
Given that objects come and go with great rapidity, all the savings from the efficient utilization of memory would be lost by creating and breaking database connections, because building and breaking down database connections is a heavy user of system resources. The solution is connection pooling. There is a pool of database connections, and when the object is deactivated the connection is returned to the pool. When a new object is activated, it reuses an inactive connection from the pool. Connection pooling is also managed by the container.
The next obvious question is, when are objects deactivated? Simply deleting objects at any time (i.e., when the resources are a bit stretched) could be dangerous because the client might be relying on the component to store some information. This is where COM+ and EJB differ.
In COM+, you can declare that the object can be deactivated after every operation or at the end of a transaction. Deactivation in COM+ means elimination; the next time the client uses the object, it is recreated from scratch.
Deactivating after every operation brings the system back to the level of a traditional transaction monitor, because at the beginning of every operation the code will find that all the data attributes in the object are reset to their initial state.
Deactivating at the end of every transaction allows the client to make several calls to the same object, for instance, searching for a record in the database in one call and updating the database in another call. After the transaction has finished, the object is deactivated.
A traditional feature of transaction monitors is the ability to store data on a session basis, and you may have noticed that there is no equivalent feature in COM+. Most transaction monitors have a data area where the transaction code can stash data. The next time the same terminal runs a transaction, the (possibly different) transaction code can read the stash. This feature is typically used for storing temporary data, like remembering the account number this user is working on. Its omission in COM+ has been a cause of much argument in the industry.
Enterprise JavaBeans is a standard, not a product. There are EJB implementations from BEA, IBM, Oracle, and others. The network connection to EJB is the Java-only Remote Method Invocation (RMI) and the CORBA interface IIOP. IIOP makes it possible to call an EJB server from a CORBA client.
EJB components come in two flavors, session beans and entity beans. Each has two subflavors. Session beans are logically private beans; that is, it is as if they are not shared across clients. (They correspond roughly to what we describe as agent objects in the previous box entitled "Patterns for OO middleware.") The two subflavors are:
Stateless session beans: All object state is eliminated after every operation invocation.
Stateful session beans: These hold state for their entire life.
Exactly when a stateful session bean is "passivated" (the EJB term for deactivated) is entirely up to the container. The container reads the object attributes and writes them to disk so that the object can be reconstituted fully when it is activated. The stateful bean implementer can add code, which is called by the passivate and activate operations. This might be needed to attach or release some external resource.
The EJB container must be cautious about when it passivates a bean because if a transaction aborts, the client will want the state to be like it was before the transaction started rather than what it came to look like in the middle of the aborted transaction. That in turn means that the object state must be saved during the transaction commit. In fact, to be really safe, the EJB container has to do a two-phase commit to synchronize the EJB commit with the database commit. (In theory it would be possible to implement the EJB container as part of the database software and manage the EJB save as part of the database commit.)
Entity beans were designed to be beans that represent rows in a database. Normally the client does not explicitly create an entity bean but finds it by using a primary key data value. Entity beans can be shared.
The EJB specification allows implementers to cache the database data values in the entity bean to improve performance. If this is done, and it is done in many major implementations, it is possible for another application to update the database directly, behind the entity bean's back so to speak, leaving the entity bean cache holding out-of-date information. This would destroy transaction integrity. One answer is to allow updates only through the EJBs, but this is unlikely to be acceptable in any large-scale enterprise application. A better solution is for the entity bean not to do caching, but you must ensure that your EJB vendor supports this solution.
The two subflavors of entity beans are:
Bean-managed persistence: The user writes the bean code.
Container-managed persistence: The EJB automatically maps the database row to the entity bean.
Container-managed persistence can be viewed as a kind of 4GL since it saves a great deal of coding.
3.2.3 Final comments on TCM
When EJBs and COM+ first appeared, there was a massive amount of debate about which was the better solution. The controversy rumbles on. An example is the famous Pet Store benchmark, the results of which were published in 2002. The benchmark compared functionally identical applications implemented in J2EE (two different application servers) and .NET. The results suggested that .NET performed better and required fewer resources to develop the application. This unleashed a storm of discussion and cries of "foul!" from the J2EE supporters.
In our opinion, the controversy is a waste of time, for a number of reasons. A lot of it arose for nontechnical reasons. The advocatesdisciples might be a better wordof each technology would not hear of anything good about the other or bad about their own. The debate took on the flavor of a theological discussion, with the protagonists showing all the fervor and certainty of Savonarola or Calvin. This is ultimately destructive, wasting everyone's time and not promoting rational discussion. Today there are two standards, so we have to live with them. Neither is likely to go away for lack of interest, although the next great idea could replace both of them. And is it bad to have alternatives? Many factors contribute to a choice of technology for developing applications (e.g., functional requirements, performance, etc.). The two technologies we have been discussing are roughly equivalent, so either could be the right choice for an enterprise. The final decision then comes down to other factors, one of which is the skill level in the organization concerned. If you have a lot of Java expertise, EJB is the better choice. Similarly, if you have a lot of Microsoft expertise, choose COM+.
There are, of course, legitimate technical issues to consider. For example, if you really do want operating system independence, then EJB is the correct choice; the Microsoft technology works only with Windows. If you want language independence, you cannot choose EJBs because it supports Java only. There may also be technical issues about interworking with existing applications, for which a gateway of some form is required. It could be that one technology rather than the other has a better set of choices, although there are now many options for both.
Both technologies have, of course, matured since their introduction, removing some reasonable criticisms; the holes have been plugged, in other words. And a final point we would like to make is that it is possible to produce a good application, or a very bad one, in either of these technologiesor any other, for that matter. Producing an application with poor performance is not necessarily a result of a wrong choice of technology. In our opinion, bad design and implementation are likely to be much greater problems, reflecting a general lack of understanding both of the platform technologies concerned and the key requirements of large-scale systems. Addressing these issues is at the heart of this book.
Transaction component middleware is likely to remain a key technology for some time. COM+ has disappeared as a marketing name but the technology largely remains. It is now called Enterprise Services and is part of Microsoft .NET. More recent developments, which have come very much to the fore, are service orientation and service-oriented architectures in general, and Web services in particular, which we discuss in the next chapter.