Java And XML
Java, XML and the Command Patter
Java, XML and the Command Patter
Aug. 18, 2000 12:00 AM
This month's column shows the advantages of using Java and XML to implement the Command Pattern. It also provides a brief illustration of how this pattern can be used to implement transaction integrity via compensating actions.
Patterns provide developers with reproducible solutions to common problems. The format for describing a pattern consists of a description of the problem, a brief description of the solution, the solution to the problem, good and bad consequences to the solution, and a list of related patterns.
The Command Pattern is a behavioral pattern. Behavioral patterns are used to combine, organize and manage behavior. The Command Pattern encapsulates commands as objects so they can be manipulated by a controlling subsystem that plays the role of a command manager. The command manager is capable of controlling the selection and orderly execution of commands. Historical command logs can be kept to enable the rollback of commands.
In a complementary fashion, Java provides a heterogeneous framework for deploying applications while XML provides a cross-platform framework for representing objects. Together they provide a perfect framework for implementing the Command Pattern across heterogeneous applications.
The Java framework receives commands over the Web via servlets. XML enables objects to be represented, packaged and passed across the network. By taking the common user interface extension to the Command Pattern and substituting it with XML, we're able to disjoin the command generation subsystem from specific command class implementations. This allows any heterogeneous Web-enabled application to submit XML commands to a servlet-based system. The extension is achieved by passing the information and the name of the command inside the XML message. A command factory processes this information and is responsible for creating instances of command classes (see Figure 1). This level of abstraction allows the dynamic manipulation of command names to class-type mapping.
Once the command object has been created, it's executed by the command manager (see Figure 1). The command manager is responsible for updating the history command information, processing the command execution and managing the output associated with the execution. When calling undo or rollback, the Command Manager is responsible for reading the history log and executing a compensating command to undo the state changes associated with the execution of the first command.
To understand the advantages of XML and Java when implementing the Command Pattern, let's create a scenario of a furniture store that wants to expand their services, not only over the Web but also within the store.
Nacme, a local furniture store, has decided to extend their services to support over-the-Web purchases. They're interested in providing a system that enables them to deduct merchandise from their master inventory system in real time. The inventory system provides a maximum quantity of available furniture that we can deduct from in order to fulfill an order. It supports a socket-based ASCII protocol. In addition, they're interested in having a wireless system within their store to collect customers' shopping cart information. This information needs to be automatically processed against their master inventory system.
The Web-based system they like is Java Servlet-based and the wireless system is C-based. Neither system provides a native interface to their master inventory system. Is this a problem or an opportunity? Nacme's IT department wants to minimize the amount of integration they'll have to write between the three systems. The IT department would like to treat their inventory system as a black box and send it commands to decrement or increment the inventory.
It's no surprise that the Command Pattern can solve their problem. The four steps to formulating a solution are:
- Identify the types of commands we're interested in abstracting. In this case they're increase and decrease.
- Identify the various system boundaries. In this case both systems, the Web-based and the wireless-based, need to produce XML commands that will be fed to the inventory system (see Figure 2).
- Identify the XML command syntax. This includes the SKU and the quantity that needs to be manipulated (see Figure 3).
- Identify the Java classes that will hold the command information. The reason for migrating the information contained in XML objects to Java objects is efficiency. It's more efficient to access information and to manipulate Java objects inside a Java program than it is to manipulate XML hierarchies as objects (see Figure 4).
Another advantage to creating an XML command abstraction is that additional integrations need to support only the generation of XML commands. Additional system interfaces can range from Palm Pilots to cell phones. Java was selected as the implementation platform because it's capable of running on both UNIX and NT. As Nacme grows, they see themselves migrating hardware platforms to what's considered more mission-critical UNIX systems. Since their master inventory system software runs on NT and UNIX, they believe the Java platform will allow them to preserve their investment in their integration solution.
Another advantage of this architecture is that the interfaces, Web and wireless, complement each other and allow customers to enhance their shopping experience. They can order a product online, then cancel it by calling the store. In a similar fashion, customers can order a product at the store, then cancel online. The main complexity associated with this type of flexibility is keeping track of the order information. This can be done as part of the command manager functionality. As commands are processed by the application, they're logged into the system and associated with the submitter. This provides the security authorization required to cancel an order. In addition, the system can retrieve the previous action committed by the user and execute a compensating action on behalf of the user. Compensating actions are used to return the system to its original state. In some cases the system state can't be restored exactly; however, this isn't required as long as the system can be returned to a transaction integral state. For example, a user submitted an order to purchase five additional dining chairs. If the user wants to cancel the order, the system submits a command to increase inventory by five chairs, assuming the chairs weren't in the process of being delivered. If they were being delivered, the system won't allow the user to cancel the order. He or she has to receive the chairs and then manually submit an RMA process.
One consequence associated with the Command Pattern is that the object that triggers the execution of the command isn't the one that executes it. However, this consequence can be viewed as a positive side effect since it allows the Command Manager to collect command history and delegate command execution to other subsystems. The command history can be used by another system to replay command executions and, in some cases, replay command attacks. Perhaps a more important side effect of this pattern is that new commands can be added without affecting the dependencies and control flow of existing commands. This is critical if we want to design a system that can grow over time.
Taking this approach to the next level, imagine how it can be used and modified to provide transaction integrity on systems that support compensating transactions. The history log becomes the transaction log and is used to roll back transactions based on the types of manipulated resources and executed commands. The command manager plays the role of a transaction manager and is the one responsible for managing the life cycle of a transaction. Transactions in this case span multiple commands and their boundaries need to be defined. While this is feasible, potential complications arise when there are dependencies between commands. If one command is successful and the following one fails, can we blindly roll back all the commands associated with the transaction? In many situations the answer is no. However, in other situations where dependencies aren't a problem, this solution may work out fine.
For additional information on how to leverage the power of Java and XML across distributed transactions, attend my presentation, "Transaction Integrity Across Distributed Java Programs and the J2EE Framework," at JavaCon 2000.
For examples on how to use the Command Pattern and other patterns written in Java see Volume 1 of Patterns in Java by Mark Grand (Wiley). And the original patterns book is Design Patterns: Elements of Reusable Object-Oriented Software by Gamma et al. (Addison-Wesley).
About Israel HilerioIsrael Hilerio is a program manager at Microsoft in the Windows Workflow Foundation team. He has 15+ years of development experience doing business applications and has a PhD in Computer Science.