Harvard Business School researcher Clay Christiansen's classic, The Innovator's Dilemma, defines a key challenge facing organizations. The "dilemma" is that even a large organization's carefully developed planning might come to naught as a result of disruptive changes brought about by a suddenly appearing upstart or technology. For instance, disruptive change occurred as PCs became powerful enough to take on jobs previously reserved for mainframes and expensive servers, to the chagrin of mainframe and server manufacturers. More recently, as traditional desktop software is increasingly supplanted by software as a service delivered over the Internet, entrenched PC software houses must scramble to devise new plans to cope with nascent businesses built around that new delivery model.
Disruptive change is not the sole domain of business managers, however. Change can as easily disrupt technology as it can the course of business. That may at first sound trite, since technology is a near synonym of rapid change. But a more careful look reveals that technology evolution is often the result of incremental change rather than disruptive innovation. For instance, most enterprises using Java technology to develop internal systems follow the J2EE architecture, a model now almost ten years old. During that decade most J2EE progress occurred as stepwise change, not in sudden leaps. Similarly smooth evolution marked the path of the Java programming language, most operating systems, and even desktop and enterprise software.
Among the many reasons to favor progress in small doses is compatibility: Since today's fresh source files become tomorrow's legacy code, the need to allow old and new code to work together preserves investment and minimizes business interruptions. But that is just Christiansen's thesis: While most of us prefer incremental progress, sometimes disruptive change occurs as a result of a conditions beyond the control of a single organization. Then an organization - or technology - must rise to the challenge, or see its relevance fade. This occasional Leading Edge Java series on innovative architectures is about projects that successfully navigated disruptive change, and in doing so created novel solutions to problems that soon all of us might face.
A significant disruptive change is currently brought about by ubiquitous high-speed networking that enables computing to move away from the data center to the network's edges. While current enterprise software architectures are often labeled as "distributed," distribution is often between a fairly static client and a remote server containing all business and presentation logic.
A typical example of this client-server model is a web browser invoking a backend J2EE server: The browser is relegated to rendering a view already assembled on the server and to passing user input back to that server, hardly taking advantage of either the bandwidth of a broadband connection or the impressive computational fire power assembled on the user's PC.
Most important, however, is that this model relegates the user experience to interacting with static images rendered on the screen, and is absent of the high levels of interactivity users are increasing spoiled with not only in desktop software, but especially in video games and multimedia applications that do take advantage of locally available hardware resources.
This article presents an example of extending J2EE with Jini technology to enable computing to move to the network's edges, and to allow devices located on the network to fully participate in an enterprise Java environment. The architecture presented here was developed by Rubean, a German software firm, and came about by the requirement to enable thousands of banking devices - ATMs, teller machines, cash registers - to operate in a Java framework. The devices are distributed in hundreds of bank branch offices, and must be invoked from J2EE applications running in a centralized data center.
Substitute banking devices with any other type of device, or even with legacy software, and the architecture is generally useful in extending the enterprise Java platform to the new reality of increasingly distributed computing. While applicable outside its immediate context, it is helpful to understand how Rubean's distributed architecture came about.
The story takes us back to Germany in the late 1990s. German community banks have for long relied on centralized data centers for their computing needs: Instead of each bank running its independent IT department, as is common with U.S. banks, German banks have formed alliances, and alliance members receive their computing services from an uber-IT department operated on behalf of member banks. Such shared IT departments serve dozens of member banks and possibly tens of thousands of users. In essence, shared IT departments deliver computing resources as a service to member banks' branch offices.
A branch bank office, however, maintains a eclectic computing environment on its own. In addition to employees' desktop PCs, a branch office contains a myriad of special-purpose banking devices: ATM machines, cash dispensing machines used by tellers, and check printing machines, to mention just a few.
While banking devices offer special capabilities, they have surprisingly limited connectivity options. Connectivity is typically restricted to the RS-232 serial communication protocol, connecting to the COM1, COM2 or parallel ports of a PC via device-specific communication protocols. In spite of the limited connectivity, such devices must be shared between bank employees. For instance, a cash dispenser connected to one employee's PC must be accessible from another user's computer.
Banking devices are connected to PCs, and are commanded by driver software installed on those PCs. Maintaining driver installations for thousands of device types scattered around hundreds of bank branch offices meant a gargantuan effort from bank alliance IT departments: Device drivers that worked on an Ethernet-based LAN did not work on a TokenRing LAN, or on different OSs, such as Unix, OS/2, or Windows.
Changing a branch PC's operating system, network configuration, or attached devices demanded a new driver distribution, as well as configuration and testing efforts. Configuration databases containing device details, such as baud rate, x/on-x/off settings, parity, COM port configuration, had to be administered for thousands of different devices and configuration options. This proved very costly since update and configuration procedures required the effort of many staff members. And administrators often felt the angst instability and poor software quality brought about.
But the legacy driver software at least provided a communication link between the banking software and the banking devices. When a large IT operator decided in 1998 to move from a home-brewed legacy system to J2EE, it asked Rubean to help migrate device access to the Java environment. Rubean quickly realized that nothing comparable to device drivers existed in Java technology. Instead, communication with banking devices was limited to the Java Communication API (Java COMM) that allowed low-level commands to be passed between a Java program and a device's serial or parallel ports.
In addition, while the J2EE software resided in the IT operator's remote data centers, the banking devices had to be located inside the branches, and the J2EE software had not only to know about these devices, but also had to be able to invoke their various capabilities. For instance, a user interacting with the J2EE software via a Web browser might wish to dispense cash to a customer. The J2EE backend in the remote data center would then have to instruct a cash dispenser in the branch office to emit the cash. And users interacted with the banking software not only through a Web browser, but sometimes also via rich-client UIs installed on employees desktops.
Rubean wanted to take advantage of two Java features from the outset: JavaBeans and RMI. The benefit of JavaBeans arises from the realization that a banking device often combines a variety of capabilities. For instance, an ATM machine is a magnetic card reader (it reads the ATM card), a cash dispenser, a printer (it prints receipts), and can also accept and hold deposit envelops. Another device might combine these functional areas differently - for instance, a cash drawer may offer the cash dispenser and printer functions, but not a magnetic card reader function.
Representing device capabilities as JavaBeans abstracts out device capabilities into the bean interfaces, and then composes those beans into the specific set of functions offered by a device. For instance, an ATM machine may be composed of a
DepositHolder beans. An implementation of such interfaces for each kind of device can supply the tedious mechanics of shuffling device commands back and forth on the serial interface to affect the desired operation, such as changing device settings or printing a receipt, hiding device-specific complexity from clients.
JavaBeans, however, defines no means to invoke the functionality of a banking device over the network. Rubean considered RMI (Java Remote Method Invocation, or Java RMI) for that purpose. RMI communication is based on Java interfaces: An object declares a remote interface -- a Java interface that extends
java.rmi.Remote -- and then an administrator publishes an implementation of that interface into a registry on the network. Clients can locate the remote object in the registry, retrieve from the registry the remote implementation, and invoke methods on that remote object to facilitate procedure calls across the network. Because RMI relies on Java interfaces, it dovetails with the approach of composing complex devices from beans centered around functionality, since a bean interface can also extend the
A key aspect of RMI is that the code for the implementation of the remote object entered in the RMI registry downloads dynamically to the client. That allows the client to rely on the Java implementation classes to dispatch the remote method call, preserving the full Java semantics of the interface. Code downloading in RMI occurs automatically, and is arranged by the RMI runtime system, a part of every J2SE and J2EE system. An RMI client can count on an interface's full Java semantics, since no translation to an intermediate language such as XML takes place.
In Rubean's architecture, dynamic code downloading allows a client to know only that an ATM machine implements the
Printer interface, for instance, to print a receipt on that ATM. The intricacies of communicating with the remote ATM machine remain hidden from clients: Device-specific communication code can simply download under the covers by the RMI runtime when the client invokes the
print() method on the remote object.
RMI and JavaBeans, therefore, allowed Rubean to separate the concerns not only of what a device does from how a specific device performs that functionality, but also from communicating with that device.
However, RMI still requires remote objects to be registered into a centralized object registry. And because clients discover RMI objects based on a registry key, the management of such keys would still have presented a formidable configuration challenge. Instead of providing a solution to the pre-Java configuration nightmare, RMI might have just moved the problem to managing remote object registrations instead.
In addition, RMI defines a point-to-point communication pattern, where one object directly invokes another object across a network. In order for that object invocation to work, the remote object implementation (the service) must arrange to listen on a TCP socket for incoming method invocations. The client, in turn, must know the IP address of the remote service's host.
In RMI, the service exports itself on its host via RMI helper classes. In some cases, a remote object service may register with the host operating system as an operating system service, such as a Unix daemon or a Windows service, ensuring that it becomes available to service remote calls as soon as the host boots up.
Once such a remote service is exported, the service would register a proxy object in an RMI registry. That proxy object represents the remote service to RMI clients on the network. Among other data, the RMI proxy - or stub -- embeds the remote service host's IP address as well as a URL a client can download the proxy's classes from. Most of the exporting and the creation of a proxy object is automated by the RMI runtime.
That convenience, however, presents a problem in an environment where hosts receive dynamic IP addresses from a DHCP server. As a host with an exported service restarts, it may receive a new IP address, one different from the IP embedded in that service's proxy inside the RMI registry. A client that retrieved the proxy with the wrong IP address would receive network communication failures when attempting to invoke methods on the remote service's proxy. Equally important, a client has no way of learning when a remote service's host powers down, and thus has no chance to retrieve an alternate device's proxy.
Rubean concluded that they needed a service registration paradigm that would enable them to employ the power of interface-based design in their very dynamic deployment environment. For this, they turned to Jini technology.
In the late 1990s, RMI's designers at Sun were working on making RMI more dynamic, and defined a more comprehensive Java network communication infrastructure, Jini technology. Although first presented to developers as a way to enable devices to communicate, Rubean realized that Jini technology defined a general object-oriented network infrastructure and, more important, that it provided a framework for their branch banking architecture.
The Jini architecture extends RMI in two ways that were important to Rubean: First, it no longer mandates registry keys for service registration and lookup. Instead, it defines a discovery protocol based on IP multicast that enables clients to discover service registries. Once a client discovers a registry, that client can search for services based on a set of Java interfaces a service must implement, as well as any number of attribute values associated with a service's registration in Jini lookup services. For instance, a client looking to dispense cash would search for a service registration implementing the
CashDispenser interface. It might, in addition, search for a cash dispenser with appropriate currency. To do this, the client would add the
CurrencyCode class to the list of service attributes, with the
code property set to
USD. The client would then receive a list of zero of more service proxies matching the search criteria.
Another way the Jini architecture extends RMI is that Jini lookup service registrations are never permanent. When a service registers its proxy, a lookup service returns to that service an object representing the proxy's lease inside the lookup service. The service must periodically renew that lease. If the lease expires, the lookup service purges the proxy object, making the service unavailable for discovery.
The Jini dynamic service discovery and lease-based registration abilities provided a solution to Rubean's problem: When a PC with a connected device boots up, that PC starts and exports and remote object representing the device as a Jini service, and advertises that service's interfaces on the network. Since Jini service selection is based on Java interfaces, registry keys need not be managed. And lease-based registrations in Jini lookup services ensure that clients always receive service proxies of available services, since proxies of unavailable hosts are purged by the lookup service.
Rubean's architecture, therefore, presents banking devices not as RMI objects, but as Jini services. An implementation of such services is installed on bank branch PCs with the appropriate connected devices, and users can discover any device in the bank office via Jini discovery.
Rubean's remaining challenges were the installation and configuration of Jini services on PCs offering banking devices; and making the J2EE application running in a remote data center aware of the available devices in a bank branch.
Rubean's service installation is based on Java WebStart. A user with a banking device connected to his PC visits a Web page, and invokes on that page a WebStart application. The application commences an installation wizard that interrogates the local PCs serial and parallel ports and tries to determine the kind of device connected to those ports. If a device does not support automated querying, the user is given an opportunity to enter configuration data. Next, the installation program installs an operating system service suitable for running RMI-based remote object services. That RMI daemon - RMID -- is part of the J2SE distribution, and Rubean's installer sets RMID up as an OS service.
Next, the Rubean installer downloads the appropriate RMI service object for the device, and registers that remote object implementation with RMID. The result of these steps is that whenever the user's PC is booted, the remote object representing the device will instantiate and start listening for incoming method calls. As that object instantiates, it registers a proxy for itself in Jini lookup services, using the dynamic Jini service registration mechanism. Should the device's host power down, that service will cease to renew its lookup service leases, causing Jini lookup services to purge the stale service proxy.
For every supported device, Rubean provides such a Jini service. The remote object implementation contains the complicated code - a device delegate -- to communicate with each device type over the PC's serial or parallel communication ports. As clients discover such services on the network and make method calls on the service's Jini proxy, those method calls dispatch back to the service implementation, which then performs the device-specific logic.
A Jini network typically runs several Jini lookup services, and Rubean's service installer installs a Jini lookup service on each service host. Therefore, even if all but two computers are powered on in a bank branch, a user on one PC can still discover and use devices connected to the other computer.
Because the Jini approach abstracts out communication based on Java interfaces, the remote banking software's business logic needs to know only the available Java interfaces, not implementations of those interfaces. For instance, to dispense cash from an ATM, the remote banking software would invoke the
As a result, Rubean's architecture does not require a remote application server to be aware of specific devices in each branch office. Instead, a crucial aspect of Rubean's architecture is that device control is a presentation-layer responsibility: a banking device, for instance "presents" some business operations or its view, much as a display presents the view of an application's user interface. Thus discovery and use of the actual device service—an implementation of the Jini service interface—occurs in the application's presentation logic, and is performed entirely on the client.
Many traditional enterprise architectures center around the notion that centralizing resources reduces costs. For instance, having one user directory in an organization is more cost effective than managing numerous departmental directories. Or, having a large document repository in an enterprise data center is more economical than storing documents on a myriad of office servers. The logic behind this notion is that having one administrator for the centralized resource is not only cheaper than having to manage the multitude of resources, but also produces fewer errors, misunderstandings, and security risks.
But the assumption behind that logic is being questioned by novel and innovative architectures. The assumption is that the administrator is a human. Paying people costs a lot of money, but the situation might be different if administration of distributed resources is completely automated. Such high levels of administrative automation are behind architectures that have proven to scale to very large numbers of users with only marginal increase in costs. Google, for instance, is known to prefer many inexpensive servers to a few pricier and beefier ones, thanks to a server management system that allows for a ratio of one administrator for every few thousand servers.
Rubean's architecture has also proven that decentralizing device management can save money. Automated service installation and Jini discovery at the branch level allows for a completely decentralized device management environment. Rubean's customers no longer have to manage a large centralized database of devices and device settings. Instead, each device publishes its availability and settings though their Jini service proxies.
Since devices in a branch office are of use only inside that office, limiting their dynamic discovery and use to clients within the branch is preferred. This also enables the central application server to remain completely ignorant of the specific devices available in each bank branch. The J2EE application logic can, instead, focus on device types represented by Java interfaces and Rubean's device beans.
In addition, while traditional enterprise architectures consider centrally located resources -- such as an application server, a database server, or a file server -- as services, Rubean's architecture extends the service notion to devices on the network's edge. It enables an ATM machine, for instance, to offer services on the network, and even allows an application server to become a client of that service.
Rubean's distributed device management architecture has been in use in German and Swiss banks since 2002, with currently over 35,000 users. The decentralized Jini approach at first seemed counter to accepted wisdom, but at the end the system exceeded users' expectation in reliability and cost savings. In the words of Rubean's chief engineer, Anton Decker, Jini technology is not simply an architecture or an API, but forces a designer to adhere to realities of the network:
"You could build a conventional system that communicates with a socket or plain RMI... Jini is not so much an API ... but is really a philosophy that describes a model for distributed objects that you have to fulfill to achieve a robust and reliable system. There is no other approach that's really addresses issues such as partial failure, self healing and stuff like that."
Jini Community Web site
Frank Sommers is a Senior Editor with Artima Developer. He also serves as chief editor of ClusterComputing.org, the IEEE Technical Committee on Scalable Computing's newsletter, and is an elected member of the Jini Community's Technical Oversight Committee. Frank is also founder and president of Autospaces, a company dedicated to delivering rich-client Java enterprise solutions to small and medium-size businesses. Prior to joining Artima, Frank wrote the Jiniology and Web services columns for JavaWorld.