Middleware is the set of services, protocols, and support utilities providing the `plumbing' that makes modern distributed systems and applications possible--the infrastructure that underlies web services, distributed objects, collaborative applications, e-commerce systems, and other important platforms. Not long ago, the term middleware was rarely heard, and middleware developers were rarer still. But over the past decade, the term, the research and practice, and its impact have become ubiquitous. Yet, until now, there has not been a book describing how to construct networked and concurrent object-oriented (OO) middleware, so its design has remained something of a black art. This book demystifies middleware construction, replacing the need to have an expert looking over your shoulder with well-reasoned, empirically-guided accounts of common design problems, forces, successful solutions, and consequences.
As is true for most concepts, nailing down the boundaries of middleware is hard. Conventionally, it consists of the software needed to build systems and applications, yet is not otherwise an intrinsic part of an operating system kernel. But it is not always possible to find middleware where you first look for it: middleware can appear in libraries and frameworks, operating systems and their add-ons, Java virtual machines and other run-time systems, large-grained software components, and in portions of end-products such as web services themselves.
This book is not a textbook surveying middleware or the types of applications and distributed system architectures you can devise using middleware. It instead presents a pattern language that captures the design steps leading to the construction of the OO communication support involved in most middleware. Many of the patterns described in this book also have utility in both higher-level and lower-level systems and applications that are not based directly upon middleware.
This book emphasizes practical solutions over theoretical formalisms. The basic ideas behind many presented patterns are well-known to experienced system developers--for example, dispatching, demultiplexing, callbacks, and configuration--and are sometimes variants of more general OO patterns--for example, proxies, adapters, and facades. This book's main contribution centers on in-depth engineering solutions based upon these ideas. Middleware developers must resolve a wide range of forces including throughput, responsiveness, dependability, interoperability, portability, extensibility, and accommodating legacy software. The diversity and severity of these forces accounts for the complexity of middleware patterns, as opposed to those seen in smaller-scale OO applications and concurrent programming.
The multitude of such forces, combined with years of engineering experience, often lead to a multitude of design considerations and engineering trade-offs separating an idea from its expression in middleware frameworks. The pattern description format used in this book helps to simplify this process by presenting solutions as series of concrete design steps. Many of these steps in turn invoke additional patterns. Together they form a pattern language, enabling developers to traverse from pattern to pattern while designing services and applications.
As mentioned by the authors, some of the ideas and techniques discussed in this book are complementary to those seen for example in W. Richard Stevens's pioneering books (e.g., See [Ste98]) on network programming. The main point of departure is the unrelenting focus on higher-level design issues. Rather than, for example, discussing the ins and outs of the Unix select() call, this book explains how to build a composable and flexible framework__a Reactor__based on select() and other operating system calls.
One of the implicit themes of this book is how to apply the bits and pieces of functionality dealing with I/O, threading, synchronization, and event demultiplexing offered by contemporary platforms as the foundation for constructing higher-level frameworks and components. The primary emphasis on C/C++ on Unix and Microsoft operating systems does not detract from this theme. For example, Java programmers will find a few minor disconnects in cases where Java already directly implements some of the patterns discussed in this book, for example, Scoped Locking, or provides frameworks structured in accord with particular implementations of patterns, such as the JavaBeans framework's support of configurable components, as well as a few where Java lacks access to underlying system mechanisms, such as synchronous event demultiplexing.
However, readers most familiar with Java, Smalltalk, and other OO programming languages will still profit from the central ideas conveyed by the patterns, can better appreciate how and why some became directly supported in language features and libraries, and will be able to construct useful components based upon other patterns. As an example, until the advent of java.nio , Java did not provide access to system constructs useful for asynchronous I/O. However, after referring to a description of the Proactor pattern described in this book, I once put together a Java version that simulated the demultiplexing step via a simple spin-loop thread that checked for I/O availability across multiple channels. This was less efficient, but was perfectly adequate within its intended usage context.
Over the years, some of the accounts in this book, such as Reactor, have evolved from descriptions of design inventions to design patterns. Everyone constructing portable OO middleware has written or used at least one Wrapper Facade. But early presentations of several other patterns now contained in this book also discussed novel contributions about their design. It was at first a bit uncertain whether such descriptions should be considered as patterns, which must be time-proven, independently (re)discovered solutions. However, over time, the authors and the OO middleware community have become more and more confident that the patterns in this book do indeed capture the essence of key forces and design issues, and have witnessed the described solutions being used over and over again across diverse usage contexts.
I invite you to share in this phenomenon. By reading--and especially, using--the material in this book, you'll see why pattern names such as Reactor and Proactor have become as common among OO middleware developers as have Decorator and Observer among OO GUI developers.