35,99 €
Remoting offers developers many ways to customize the communications process, for efficiency, security, performance and power, and allows seamless integration of components running on several computers into a single application. This book exposes the full power of remoting to developers working in mixed platform environments in a way that will ensure they have a deep understanding of what remoting is capable of, and how they can make it work the way they want.
Sie lesen das E-Book in den Legimi-Apps auf:
Seitenzahl: 485
Veröffentlichungsjahr: 2013
Contents
Cover
Half Title page
Title page
Copyright page
Foreword
Series Foreword
Preface
How to read this book
Goals of the book
About the authors
Acknowledgments
Patterns and Pattern Languages
Our Pattern form
Key to the illustrations
Chapter 1: Introduction To Distributed Systems
Distributed Systems: reasons and challenges
Communication middleware
Remoting styles
Chapter 2: Pattern Language Overview
Broker
Overview of the Pattern chapters
Chapter 3: Basic Remoting Patterns
Requestor
Client Proxy
Invoker
Client Request Handler
Server Request Handler
Marshaller
Interface Description
Remoting Error
Interactions among the patterns
Chapter 4: Identification Patterns
Object ID
Absolute Object Reference
Lookup
Interactions among the patterns
Chapter 5: Lifecycle Management Patterns
Basic lifecycle patterns
Static Instance
Per-Request Instance
Client-Dependent Instance
General resource management patterns
Lazy Acquisition
Pooling
Leasing
Passivation
Interactions among the patterns
Chapter 6: Extension Patterns
Invocation Interceptor
Invocation Context
Protocol Plug-In
Interactions among the patterns
Chapter 7: Extended Infrastructure Patterns
Lifecycle Manager
Configuration Group
Local Object
QoS Observer
Location Forwarder
Interactions among the patterns
Chapter 8: Invocation Asynchrony Patterns
Fire and Forget
Sync with Server
Poll Object
Result Callback
Interactions among the patterns
Chapter 9: Technology Projections
Chapter 10: .NET Remoting Technology Projection
A brief history of .NET Remoting
.NET concepts – a brief introduction
.NET Remoting pattern map
A simple .NET Remoting example
Remoting boundaries
Basic internals of .NET Remoting
Error handling in .NET
Server-activated instances
Client-dependent instances and Leasing
More advanced lifecycle management
Internals of .NET Remoting
Extensibility of .NET Remoting
Asynchronous communication
Outlook for the next generation
Chapter 11: Web Services Technology Projection
A brief history of Web Services
Web Services pattern map
SOAP messages
Message processing in Axis
Protocol integration in Web Services
Marshaling using SOAP XML encoding
Lifecycle management in Web Services
Client-Side asynchrony
Web Services and QoS
Web Services security
Lookup of Web Services: UDDI
Other Web Services frameworks
Consequences of the pattern variants used in Web Services
Chapter 12: CORBA Technology Projection
A brief history of CORBA
CORBA pattern map
An initial example with CORBA
CORBA basics
Messaging in CORBA
Real-Time CORBA
Chapter 13: Related Concepts, Technologies, and Patterns
Related patterns
Distribution infrastructures
Quality attributes
Aspect-orientation and Remoting
Appendix A: Extending AOP Frameworks for Remoting
References
Index
Remoting Patterns
Copyright © 2005 John Wiley & Sons Ltd, The Atrium, Southern Gate, Chichester, West Sussex PO19 8SQ, England
Telephone (+44) 1243 779777
Email (for orders and customer service enquiries): [email protected]
Visit our Home Page on www.wileyeurope.com or www.wiley.com
All Rights Reserved. No part of this publication may be reproduced, stored in a retrieval system or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, scanning or otherwise, except under the terms of the Copyright, Designs and Patents Act 1988 or under the terms of a licence issued by the Copyright Licensing Agency Ltd, 90 Tottenham Court Road, London W1T 4LP, UK, without the permission in writing of the Publisher, with the exception of any material supplied specifically for the purpose of being entered and executed on a computer system for exclusive use by the purchaser of the publication. Requests to the Publisher should be addressed to the Permissions Department, John Wiley & Sons Ltd, The Atrium, Southern Gate, Chichester, West Sussex PO19 8SQ, England, or emailed to [email protected], or faxed to (+44) 1243 770620.
This publication is designed to provide accurate and authoritative information in regard to the subject matter covered. It is sold on the understanding that the Publisher is not engaged in rendering professional services. If professional advice or other expert assistance is required, the services of a competent professional should be sought.
Other Wiley Editorial Offices John Wiley & Sons Inc., 111 River Street, Hoboken, NJ 07030, USA Jossey-Bass, 989 Market Street, San Francisco, CA 94103-1741, USA Wiley-VCH Verlag GmbH, Boschstr. 12, D-69469 Weinheim, Germany John Wiley & Sons Australia Ltd, 33 Park Road, Milton, Queensland 4064, Australia John Wiley & Sons (Asia) Pte Ltd, 2 Clementi Loop #02-01, Jin Xing Distripark, Singapore 129809 John Wiley & Sons Canada Ltd, 22 Worcester Road, Etobicoke, Ontario, Canada M9W 1L1 Wiley also publishes its books in a variety of electronic formats. Some content that appears in print may not be available in electronic books.
Library of Congress Cataloging-in-Publication Data
Völter, Markus. Remoting patterns: foundations of enterprise, internet and realtime distributed object middleware / Markus Völter, Michael Kircher, Uwe Zdun. p. cm. Includes bibliographical references and index. ISBN 0-470-85662-9 (cloth : alk. paper) 1. Computer software—Development. 2. Software patterns. 3. Electronic data processing— Distributed processing. 4. Middleware. I. Kircher, Michael. II. Zdun, Uwe. III. Title. QA76.76.D47V65 2004 005.1—dc22
2004018713
British Library Cataloguing in Publication Data
A catalogue record for this book is available from the British Library
ISBN 0-470-85662-9
Foreword
Many of today’s enterprise computing systems are powered by distributed object middleware. Such systems, which are common in industries such as telecommunications, finance, manufacturing, and government, often support applications that are critical to particular business operations. Because of this, distributed object middleware is often held to stringent performance, reliability, and availability requirements. Fortunately, modern approaches have no problem meeting or exceeding these requirements. Today, successful distributed object systems are essentially taken for granted.
There was a time, however, when making such claims about the possibilities of distributed objects would have met with disbelief and derision. In their early days, distributed object approaches were often viewed as mere academic fluff with no practical utility. Fortunately, the creators of visionary distributed objects systems such as Eden, Argus, Emerald, COMANDOS, and others were undeterred by such opinion. Despite the fact that the experimental distributed object systems of the 1980s were generally impractical – too big, too slow, or based on features available only from particular specialized platforms or programming languages – the exploration and experimentation required to put them together collectively paved the way for the practical distributed objects systems that followed.
The 1990s saw the rise of several commercially successful and popular distributed object approaches, notably the Common Object Request Broker Architecture (CORBA) promoted by the Object Management Group (OMG) and Microsoft’s Common Object Model (COM). CORBA was specifically designed to address the inherent heterogeneity of business computing networks, where mixtures of machine types, operating systems, programming languages, and application styles are the norm and must co-exist and cooperate. COM, on the other hand, was built specifically to support component-oriented applications running on the Microsoft Windows operating system.
Today, COM has been largely subsumed by its successor, .NET, while CORBA remains in wide use as a well-proven architecture for building and deploying significant enterprise-scale heterogeneous systems, as well as real-time and embedded systems.
As this book so lucidly explains, despite the fact that CORBA and COM were designed for fundamentally different purposes, they share a number of similarities. These similarities range from basic notions, including remote objects, client and server applications, proxies, marshalers, synchronous and asynchronous communications, and interface descriptions, to more advanced areas, including object identification and lookup, infrastructure extension, and lifecycle management. Not surprisingly, though, these similarities do not end at CORBA and COM. They can also be found in newer technologies and approaches, including .NET, the Java 2 Enterprise Edition (J2EE), and even in Web Services (which, strictly speaking, is not a pure distributed object technology, but nevertheless has inherited many of its characteristics).
Such similarities are of course better known as ‘patterns’. Patterns are generally not so much created as discovered, much as a miner finds a diamond or a gold nugget buried in the earth. Successful patterns result from the study of successful systems, and the remoting patterns presented here are no exception. Our authors, Markus, Michael, and Uwe, who are each well versed in both the theory and practice of distributed objects, have worked extensively with each of the technologies I’ve mentioned. Applying their pattern-mining talents and efforts, they have captured for the rest of us the critical essence of a number of successful solutions and approaches found in a number of similar distributed objects technologies.
Given my own long history with CORBA, I am not surprised to find that several of the patterns that Markus, Michael, and Uwe document here are among my personal favorites. For example, topping my list is the Invocation Interceptor pattern, which I have found to be critical for creating distributed objects middleware that provides extensibility and modularity without sacrificing performance. Another favorite of mine is the Leasing pattern, which can be extremely effective for managing object lifecycles.
This book does not just describe a few remoting patterns, however. While many patterns books comprise only a loose collection of patterns, this book also provides a series of technology projections that tie the patterns directly back to the technologies that employ them. These projections clearly show how the patterns are used within .NET, CORBA, and Web Services, effectively recreating these architectures from the patterns mined from within them. With technology projections like these, it has never been easier to see the relationships and roles of different patterns with respect to each other within an entire architecture. These technology projections clearly link the patterns, which are already invaluable by themselves, into a comprehensive, harmonious, and rich distributed objects pattern language. In doing so, they conspicuously reveal the similarities among these different distributed object technologies. Indeed, we might have avoided the overzealous and tiresome ‘CORBA vs. COM’ arguments of the mid-1990s had we had these technology projections and patterns at the time.
Distributed objects technologies continue to evolve and grow. These patterns have essentially provided the building blocks for the experimental systems of the 1980s, for the continued commercial success and wide deployment of distributed objects that began in the 1990s, and for today’s Web Services integration approaches. Due to the never-ending march of technology, you can be sure that before too long new technologies will appear to displace Web Services. You can also be sure that the remoting patterns that Markus, Michael, and Uwe have so expertly provided for us here will be at the heart of those new technologies as well.
Steve VinoskiChief Engineer, Product Innovation IONA Technologies
March 2004
Series Foreword
At first glance writing and publishing a remoting pattern language book might appear surprising. Who is its audience? From a naïve perspective, it could only be distributed object middleware developers – a rather small community. Application developers merely use such middleware – why should they bother with the details of how it is designed? We see confirmation of this view from the sales personnel and product ‘blurbs’ of middleware vendors: remote communication should be transparent to application developers, and it is the job of the middleware to deal with it. So why spend so much time on writing – and reading – a pattern language that only a few software developers actually need?
From a realistic perspective, however, the world looks rather different. Despite all advances in distributed object middleware, building distributed systems and applications is still a challenging, non-trivial task. This applies not only to application-specific concerns, such as how to split and distribute an application’s functionality across a computer network. Surprisingly, many challenges in building distributed software relate to an appropriate use of the underlying middleware. I do not mean issues such as using APIs correctly, but fundamental concerns. For example, the type of communication between remote objects has a direct impact on the performance of the system, its scalability, its reliability, and so on and so forth. It has an even stronger impact on how remote objects must be designed, and how their functionality must be decomposed, to really benefit from a specific communication style.
It is therefore a myth to believe that remote communication is transparent to a distributed application. The many failures and problems of software development projects that did so speak very clearly! Failures occur due to the misconception that ‘fire and forget’ invocations are reliable, that remote objects are always readily available at their clients’ fingertips, or problems due to a lack of awareness that message-based remote communication decouples operation invocation from operation execution not only in space, but also in time, and so on.
But how do I know what is ‘right’ for my distributed system? How do I know what the critical issues are in remote communication and what options exist to deal with them? How do I know what design guidelines I must follow in my application to be able to use a specific middleware or remote communication style correctly and effectively? The answer is simple: understanding both how it works, and why it works the way it works. Speaking pictorially, we must open the black box called ‘middleware’, sweeping the ‘shade’ of communication-transparency aside, and take a look inside. Fundamental concepts of remoting and modern distributed object middleware must be known to, and understood by, application developers if they are to build distributed systems that work! There is no way around this.
But how can we gain this important knowledge and understanding? Correct: by reading and digesting a pattern language that describes remoting, and mapping its concepts onto the middleware used in our own distributed systems! So in reality the audience for a remoting pattern language is quite large, as it comprises every developer of distributed software.
This book contributes to the understanding of distributed object middleware in two ways. First it presents a comprehensive pattern language that addresses all the important aspects in distributed object middleware – from remoting fundamentals, through object identification and lifecycle management, to advanced aspects such as application-specific extensions and asynchronous communication. Second, and of immense value for practical work, this book provides three technology projections that illustrate how the patterns that make up the language are applied in popular object-oriented middleware technologies: .NET, Web Services, and CORBA. Together, these two parts form a powerful package that provides you with all the conceptual knowledge and various viewpoints necessary to understand and use modern communication environments correctly and effectively. This book thus complements and completes books that describe the ‘nuts and bolts’ – such as the APIs – of specific distributed object middlewares by adding the ‘big picture’ and architectural framework in which they live.
Accept what this book offers and explore the secrets of distributed object middleware. I am sure you will enjoy the journey as much as I did.
Frank BuschmannSiemens AG, Corporate Technology
Preface
Today distributed object middleware belongs among the basic elements in the toolbox of software developer, designers, and architects who are developing distributed systems. Popular examples of such distributed object middleware systems are CORBA, Web Services, DCOM, Java RMI, and .NET Remoting. There are many other books that explain how a particular distributed object middleware works. If you just want to use one specific distributed object middleware, many of these books are highly valuable. However, as a professional software developer, designer, or architect working with distributed systems, you will also experience situations in which just understanding how to use one particular middleware is not enough. You are required to gain a deeper understanding of the inner workings of the middleware, so that you can customize or extend it to meet your needs. Or you might be forced to migrate your system to a new kind of middleware as a consequence of business requirements, or to integrate systems that use different middleware products.
This book is intended to help you in these and similar situations: it explains the inner workings of successful approaches and technologies in the field of distributed object middleware in a practical manner. To achieve this we use a pattern language that describes the essential building blocks of distributed object middleware, based on a number of compact, Alexandrian-style [AIS+77] patterns. We supplement the pattern language with three technology projections that explain how the patterns are realized in different real-world examples of distributed object middleware systems: .NET Remoting, Web Services, and CORBA.
This book is aimed primarily at software developers, designers, and architects who have at least a basic understanding of software development and design concepts.
For readers who are new to patterns, we introduce patterns and pattern languages to some extend in this section. Readers familiar with patterns might want to skip this. We also briefly explain the pattern form and the diagrams used in this book. You might find it useful to scan this information and use it as a reference when reading the later chapters of the book.
In the pattern chapters and the technology projections we assume some knowledge of distributed system development. In Chapter 1, Introduction To Distributed Systems, we introduce the basic terminology and concepts used in this book. Readers who are familiar with the terminology and concepts may skip that chapter. If you are completely new to this field, you might want to read a more detailed introduction such as Tanenbaum and van Steen’s Distributed Systems: Principles and Paradigms [TS02].
For all readers, we recommend reading the pattern language chapters as a whole. This should give you a fairly good picture of how distributed object middleware systems work. When working with the pattern language, you can usually go directly to particular patterns of interest, and use the pattern relationships described in the pattern descriptions to find related patterns.
Details of the interactions between the patterns can be found at the end of each pattern chapter, depicted in a number of sequence diagrams. We have not included these interactions in the individual pattern descriptions for two reasons. First, it would make the pattern chapters less readable. Second, the patterns in each chapter have strong interactions, so it makes sense to illustrate them with integrated examples, instead of scattering the examples across the individual pattern descriptions.
We recommend that you look closely at the sequence diagram examples, especially if you want to implement your own distributed object middleware system or extend an existing one. This will give you further insight into how the pattern language can be implemented. As the next step, you might want to read the technology projections to see a couple of well-established real-world examples of how the pattern language is implemented by vendors.
If you want to understand the commonalities and differences between some of the mainstream distributed object middleware systems, you should read the technology projections. You can do this in any order you prefer. They are completely independent of each other.
Numerous projects use, extend, integrate, customize, and build distributed object middleware. The major goal of the pattern language in this book is to provide knowledge about the general, recurring architecture of successful distributed object middleware, as well as more concrete design and implementation strategies. You can benefit from reading and understanding this pattern language in several ways:
If you want to
use
distributed object middleware, you will benefit from better understanding the concepts of your middleware implementation. This in turn helps you to make better use of the middleware. If you know how to use one middleware system and need to switch to another, understanding the patterns of distributed object middleware helps you to see the commonalities, in spite of different remoting abstractions, terminologies, implementation language concepts, and so forth.
Sometimes you need to
extend
the middleware with additional functionality. For example, suppose you are developing a Web Services application. Because Web Services are relatively new, your chosen Web Services framework might not implement specific security or transaction features that you need for your application. You must then implement these features on your own. Our patterns help you to find the best hooks for extending the Web Services framework. The patterns show you several alternative successful implementations of such extensions. The book also helps you to you find similar solutions in other middleware implementations, so that you avoid reinventing the wheel. Another typical extension is the introduction of ‘new’ remoting styles, implemented on top of existing middleware. Consider server-side component architectures, such as CORBA Components, COM+, or Enterprise Java Beans (EJB). These use distributed object middleware implementations as a foundation for remote communication [VSW02]. They extend the middleware with new concepts. Again, as a developer of a component architecture, you have to understand the patterns of the distributed object middleware, for example to integrate the lifecycle models of the components and remote objects.
While distributed object middleware is used to integrate heterogeneous systems, you might encounter situations in which you need to
integrate
the various middleware systems themselves. Consider a situation in which your employer takes over another company that uses a different middleware product from that used in your company. You need to integrate the two middleware solutions to let the information systems of the two companies work in concert. Our patterns can help you find integration points and identify promising solutions.
In rarer cases you might need to
customize
distributed object middleware, or even
build
it from scratch. Consider for example an embedded system with tight constraints on memory consumption, performance, and real-time communication [Aut04]. If no suitable middleware product exists, or all available products turn out to be inappropriate and/or have a footprint that is to large, the developers must develop their own solution. As an alternative, you could look at existing open-source solutions and try to customize them for your needs. Here our patterns can help you to identify critical components of the middleware and assess the effort required in customizing them. If customizing an existing middleware does not seem to be feasible, you can use the patterns to build a new distributed object middleware for your application.
The list above consists of only a few examples. We hope they illustrate the broad variety of situations in which you might want to get a deeper understanding of distributed object middleware. As these situations occur repeatedly, we hope these examples illustrate why we think the time is ready for a book that explains such issues in a way that is accessible to practitioners.
Markus Völter works as an independent consultant on software technology and engineering based in Heidenheim, Germany. His primary focus is software architecture and patterns, middleware and model-driven software development. Markus has consulted and coached in many different domains, such as banking, health care, e-business, telematics, astronomy, and automotive embedded systems, in projects ranging from 5 to 150 developers.
Markus is also a regular speaker at international conferences on software technology and object orientation. Among others, he has given talks and tutorials at ECOOP, OOPSLA, OOP, OT, JAOO and GPCE. Markus has published patterns at various PLoP conferences and writes articles for various magazines on topics that he finds interesting. He is also co-author of the book Server Component Patterns, which is - just like the book you are currently reading - part of the Wiley series in Software Design Patterns.
When not dealing with software, Markus enjoys cross-country flying in the skies over southern Germany in his glider.
Markus can be reached at [email protected] or via www.voelter.de
Michael Kircher is working currently as Senior Software Engineer at Siemens AG Corporate Technology in Munich, Germany. His main fields of interest include distributed object computing, software architecture, patterns, agile methodologies, and management of knowledge workers in innovative environments. He has been involved in many projects as a consultant and developer within various Siemens business areas, building software for distributed systems. Among these were the development of software for UMTS base stations, toll systems, postal automation systems, and operation and maintenance software for industry and telecommunication systems.
In recent years Michael has published papers at numerous conferences on topics such as patterns, software architecture for distributed systems, and eXtreme Programming, and has organized several workshops at conferences such as OOPSLA and EuroPLoP. He is also co-author of the book Pattern-Oriented Software Architecture, Volume 3: Patterns for Resource Management.
In his spare time Michael likes to combine family life with enjoying nature, engaging in sports, or just watching wildlife.
Michael can be reached at [email protected] or via www.kircher-schwanninger.de
Uwe Zdun is working currently as an assistant professor in the Department of Information Systems at the Vienna University of Economics and Business Administration. He received his Doctoral degree from the University of Essen in 2002, where he worked from 1999 to 2002 as research assistant in the software specification group. His research interests include software patterns, scripting, object-orientation, software architecture, and Web engineering. Uwe has been involved as a consultant and developer in many software projects. He is author of a number of open-source software systems, including Extended Object Tcl (XOTcl), ActiWeb, Frag, and Leela, as well as many other open-source and industrial software systems.
In recent years he has published in numerous conferences and journals, and co-organized a number of workshops at conferences such as EuroPLoP, CHI, and OOPSLA.
He enjoys hiking, biking, pool, and guitar playing.
Uwe can be reached at [email protected] or via wi.wu-wien.ac.at/~uzdun
A book such as this would be impossible without the support of many other people. For their support in discussing the contents of the book and for providing their feedback, we express our gratitude.
First of all, we want to thank our shepherd, Steve Vinoski, and the pattern series editor, Frank Buschmann. They have read the book several times and provided in-depth comments on technical content, as well as on the structure and coherence of the pattern language.
We also want to thank the following people who have provided comments on various versions of the manuscript, as well as on extracted papers that have been workshopped at VikingPLoP 2002 and EuroPLoP 2003: Mikio Aoyama, Steve Berczuk, Valter Cazzalo, Anniruddha Gokhale, Lars Grunske, Klaus Jank, Kevlin Henney, Wolfgang Herzner, Don Hinton, Klaus Marquardt, Jan Mendling, Roy Oberhauser, Joe Oberleitner, Juha Pärsinen, Michael Pont, Alexander Schmid, Kristijan Elof Sorenson (thanks for playing shepherd and proxy), Michael Stal, Mark Strembeck, Oliver Vogel, Johnny Willemsen, and Eberhard Wolff.
Finally we thank those that have been involved with the production of the book: our copy-editor Steve Rickaby and editors Gaynor Redvers-Mutton and Juliet Booker. It is a pleasure working with such proficient people.
Over the past couple of years patterns have become part of the mainstream of software development. They appear in different types and forms.
The most popular patterns are those for software design, pioneered by the Gang-of-Four (GoF) book [GHJV95] and continued by many other pattern authors. Design patterns can be applied very broadly, because they focus on everyday design problems. In addition to design patterns, the patterns community has created patterns for software architecture [BMR+96, SSRB00], analysis [Fow96], and even non-IT topics such as organizational or pedagogical patterns [Ped04, FV00]. There are many other kinds of patterns, and some are specific for a particular domain.
A pattern, according to the original definition of Alexander1 [AIS+77], is:
… a three-part rule, which expresses a relation between a certain context, a problem, and a solution.
This is a very general definition of a pattern. It is probably a bad idea to cite Alexander in this way, because he explains this definition extensively. In particular, how can we distinguish a pattern from a simple recipe? Consider the following example:
Is this a pattern? Certainly not. It is just a simple, plain if-then rule. So, again, what is a pattern? Jim Coplien, on the Hillside Web site [Cop04], proposes another, slightly longer definition that summarizes the discussion in Alexander’s book:
Each pattern is a three-part rule, which expresses a relation between a certain context, a certain system of forces which occurs repeatedly in that context, and a certain software configuration which allows these forces to resolve themselves.
Coplien mentions forces. Forces are considerations that somehow constrain or influence the solution proposed by the pattern. The set of forces builds up tension, usually formulated concisely as a problem statement. A solution for the given problem has to balance the forces somehow, because the forces cannot usually all be resolved optimally – a compromise has to be found.
To be understandable by the reader, a pattern should describe how the forces are balanced in the proposed solution, and why they have been balanced in the proposed way. In addition, the advantages and disadvantages of such a solution should be explained, to allow the reader to understand the consequences of using the pattern.
Patterns are solutions to recurring problems. They therefore need to be quite general, so that they can be applied to more than one concrete problem. However, the solution should be sufficiently concrete to be practically useful, and it should include a description of a specific software configuration. Such a configuration consists of the participants of the pattern, their responsibilities, and their interactions. The level of detail of this description can vary, but after reading the pattern, the reader should know what he has to do to implement the pattern’s solution. As the above discussion highlights, a pattern is not merely a set of UML diagrams or code fragments.
Patterns are never ‘new ideas’. Patterns are proven solutions to recurring problems. So known uses for a pattern must always exist. A good rule of thumb is that something that does not have at least three known uses is not a pattern. In software patterns, this means that systems must exist that are implemented according to the pattern. The usual approach to writing patterns is not to invent them from scratch – instead they are discovered in, and then extracted from, real-life systems. These systems then serve as known uses for the pattern. To find patterns in software systems, the pattern author has to abstract the problem/solution pair from the concrete instances found in the systems at hand. Abstracting the pattern while preserving comprehensibility and practicality is the major challenge of pattern writing.
There is another aspect to what makes a good pattern, the quality without a name (QWAN) [AIS+77]. The quality without a name cannot easily be described: the best approximation is universally-recognizable aesthetic beauty and order. So a pattern’s solution must somehow appeal to the aesthetic sense of the pattern reader – in our case, to the software developer, designer, or architect. While there is no universal definition of beauty, there certainly are some guidelines as to what is a good solution and what is not. For example, a software system, while addressing a complex problem, should be efficient, flexible and easily understandable. The principle of beauty is an important – and often underestimated – guide for judging whether a technological design is good or bad. David Gelernter details this in his book Machine Beauty [Gel99].
The patterns in this book are software patterns. They can further be seen as architectural patterns or design patterns. It is not easy to draw the line between architecture and design, and often the distinction depends on your situation and viewpoint. For a rough distinction, let’s refer to the definition of software architecture from Bass, Clements, and Kazman [BCK03]:
The software architecture of a program or computing system is the structure or structures of the system, which comprise software components, the externally-visible properties of those components and the relationships among them.
What we can see here is that whether a specific pattern is categorized as an architectural pattern or a design pattern depends heavily on the viewpoint of the designer or architect. Consider for example the Interpreter pattern [GHJV95]. The description in the Gang-of-Four book describes it as a concrete design guideline. Yet according to the software architecture definition above, instances of the pattern are often seen as a central elements in the architecture of software systems, because an Interpreter is a central component of the system that is externally visible.
Most of the patterns in this book can be seen as falling into both categories – design patterns and architectural patterns. From the viewpoint of the designer, they provide concrete guidelines for the design of a part of the distributed object middleware. Yet they also comprise larger, visible structures of the distributed object middleware and focus on the most important components and their relationships. Thus, according to the above definition, they are architectural foundations of the distributed object middleware as well.
A single pattern describes one solution to a particular, recurring problem. However, ‘really big problems’ usually cannot be described in one pattern without compromising readability.
The pattern community has therefore come up with several ways to combine patterns to solve a more complex problem or a set of related problems:
Compound patterns
are patterns that are assembled from other, smaller patterns. These smaller patterns are usually already well known in the community. Often, for a number of related smaller patterns, known uses exist in which these patterns are always used together in the same software configuration. Such situations are good candidates for description as a compound pattern. It is essential that the compound pattern actually solves a distinct problem, and not just a combination of the problems of its contained patterns. A compound pattern also resolves its own set of forces. An example of a compound pattern is
Bureaucracy
by Dirk Riehle [Rie97], which combines
Composite, Mediator, Chain of Responsibility
, and
Observer
(all from the GoF book, [GHJV95]).
A
family of patterns
is a collection of patterns that solves the same general problem. Each pattern either defines the problem more specifically, or resolves the common forces in a different way. For example, different solutions could focus on flexibility, performance or simplicity. Usually each of the patterns has different consequences. A family therefore describes a problem and
several
proven solutions. It is up to the reader to select the appropriate solution, taking into account how he wants to resolve the common forces in his particular context. A good example is James Noble’s
Basic Relationship Patterns
[Nob97], which describes several alternatives ways in which logical relationships between objects can be realized in software.
A
collection
, or
system of patterns
comprises several patterns from the same domain or problem area. Each pattern stands on its own, sometimes referring to other patterns in the collection in its implementation. The patterns form a system because they can be used by a developer working in a specific domain, each pattern resolving a distinct problem the developer might come across during his work. A good example is
Pattern Oriented Software Architecture
by Buschmann, Meunier, Rohnert, Sommerlad, and Stal (also known as POSA 1 [BMR+96]).
The most powerful way of combining patterns is a pattern language. Pattern languages have several characteristics:
A pattern language has a language-wide goal. The purpose of the language is to guide the user step by step to reach this goal. The patterns in a pattern language are not necessarily useful in isolation. The patterns in this book, for example, form a pattern language in the domain of distributed object middleware.
A pattern language is
generative
in nature. Applying the pattern language generates a
whole
. This generated whole should be ‘beautiful’ in the sense of QWAN. The whole is ‘generated’ by applying the patterns in the pattern language one after another in an incremental process of refinement. The basic idea is that each refinement step makes the whole successively more coherent.
To generate the whole, the pattern language has to be applied in a specific order. This order is defined by one or more sequences. Depending on the context in which the pattern language is applied, or which aspects of the whole are actually required, there can be several sequences through a pattern language.
Because the patterns must be applied in a specific sequence, each pattern must define its place in the sequence. To achieve this, each pattern has a section called its
context
, which mentions earlier patterns that must be implemented before the current pattern can be implemented successfully. Each pattern can also feature a
resulting context
that describes how to continue. This contains references to the patterns that can be used to help in the implementation of the current pattern, or explains how to proceed in the incremental refinement process of the whole.
Pattern languages – in contrast to the other forms of combining patterns discussed above – not only specify solutions to specific problems, but also describe a way to create the whole, the overall goal of the pattern language. Note that a particular pattern can play a role in more than one pattern language. For example, we integrate some patterns from other sources in our pattern language, such as the Broker pattern [BMR+96], which we use to motivate the overall problem and context of the pattern language in this book.
In this section we provide a brief introduction to the pattern form used in this book. The form of our patterns is similar to the Alexandrian [AIS+77] format, but omits examples in the pattern description and photographs used to visualize the pattern. This book contains many example applications of the patterns, but instead of presenting an example for each individual pattern, the example applications appear separately in the form of UML sequence diagrams at the end of each pattern chapter, and as Technology Projections.
The individual pattern descriptions are structured as follows: each pattern starts with a name. The name is an important part of a pattern in a pattern language, because it is used throughout the language to refer to the particular pattern. When referencing pattern names from our pattern language, we always write them in SMALLCAPS font. External patterns from the literature are highlighted in Italics.
The next section is the context of the pattern in the pattern language. The context is separated by three stars from the main body of the pattern. The main body starts with a problem section written in bold face font. The problem, addressed by the pattern, is then illustrated in more detail in the problem detail section plain font. The system of forces leading to the pattern’s solution is discussed here. The section is written in two different styles:
In structural patterns this section contains problem details and a short discussion of forces.
In behavioral patterns, found in Chapter 5,
Lifecycle Management Patterns
and Chapter 8,
Invocation Asynchrony Patterns
, this section contains an example application scenario that motivates the need for the pattern’s solution. We feel that such an example illustrates the forces for those patterns much better than an abstract discussion.
Following the problem discussion, the solution of the pattern is provided using bold face, illustrated by a figure. Three stars separate the main body of the pattern from the solution details that follow. The solution details discuss variants of the pattern, related patterns (in the pattern language and from literature), as well as the consequences of applying the pattern.
Examples and known uses are provided in the Technology Projections chapter, which projects the patterns onto a specific technology. We present technology projections for .NET Remoting, Web Services, and CORBA. Other known uses of the patterns are discussed in Chapter 13, Related Concepts, Technologies, and Patterns. Below, the pattern format layout is illustrated by an example, with some side-headings for explanation.
Pattern Name
Invocation Interceptor
Context
Applications need to transparently integrate add-on services.
Problem
In addition to hosting remote objects, the server application often has to provide a number of add-on services, such as transactions, logging, or security. The clients and remote objects themselves should be independent of those services.
Problem Detail and Forces - or - Motivating Example
Consider the typical concern of security in distributed object middleware: remote objects need to be protected from unauthorized access. The remote objects themselves should not have to worry about authorization – they should be accessible with or without authorization enabled. When the server application needs to enforce security, the client must add the relevant credentials, such as user name and password, to the request.
Therefore:
Solution
Provide hooks in the invocation path, for example in the INVOKER and REQUESTOR, to plug in INVOCATION INTERCEPTORS. INVOCATION INTERCEPTORS are invoked before and after request and reply messages pass the hook. Provide the interceptor with all the necessary information to allow it to provide meaningful add-on services, such as operation name, parameters, OBJECT ID, and, if used, the INVOCATION CONTEXT.
Scenario Illustration and Explanation
Solution Details and Related Patterns
INVOCATION INTERCEPTORS allow for the transparent integration of additional orthogonal services. These additional services are independent of the individual clients and remote objects.
Consequences
If more than one INVOCATION INTERCEPTOR is applicable to an invocation, the interceptors are often interdependent. In most cases, therefore, they are arranged in a chain of interceptors. Each INVOCATION INTERCEPTOR forwards the invocation to the next interceptor in the chain. Alternatively, the components that provide the hooks, such as REQUESTOR and INVOKER, can manage the passing of information between elements of the chain.
References to Patterns from the Literature
The INVOCATION INTERCEPTOR is a specialization of
Interceptor
[SSRB00] for distributed object middleware.
The pattern chapters have a specific structure. Some of the chapters provide additional sections, but the following three sections are common to each chapter:
Each chapter starts with an introduction to the general topic of the chapter. Each pattern in the chapter is introduced with one or two sentences. An overview diagram that shows the relationship between the different patterns is provided. This diagram also connects the patterns to patterns in other chapters – the patterns from other chapters are rendered in gray in these figures.
The second part of each pattern chapter introduces the patterns themselves. Each pattern – using the structure shown above – covers a couple of pages.
A third section, called
Interactions among the Patterns
, shows how the patterns interact. The interactions show example usage scenarios only, and are therefore incomplete. The scenarios are illustrated with UML sequence diagrams and described in the associated text. The
Technology Projection
chapters provide more detailed example applications that focus on the pattern language as a whole.
Most of the illustrations in this book use UML, with some slight variations. We explain the UML subset we use in the following sections. The collaboration diagrams used in the pattern descriptions are not true UML.
Each pattern is illustrated with a ‘collaboration diagram’. In addition to the dynamic collaboration semantics known from the respective UML diagrams, we also display containment structures in these diagrams, so they are not formal UML diagrams. The following figure provides an example illustration, annotated with comments to serve as a key.
Here are some more details of our notation:
Although remoting is used typically to communicate between one machine and another, that’s not necessarily always the case - it can also be used for communication between two processes on the same machine. This is the reason why the
Machine Boundary
is optional.
An
apparent method invocation
means that the denoted operation is logically executed directly by the invoking entity but in reality other intermediate steps might be involved, such as a proxy.
The
«stereotype»
notation used in some methods denotes the fact that we don’t actually invoke an operation, but influence the target conceptually. For example,
«create»
does not mean that the create operation is called, but instead that the client
creates
the target object.
The double-arrow does not mean that there are exactly two operations invoked, but instead, that a sequence of operations – those mentioned in the attached box – are executed directly after one another.
Class diagrams are standard UML, except for the dependency arrow, which we draw as a solid arrow instead of a lined arrow. This is purely for aesthetic reasons.
At the end of each pattern chapter we illustrate the patterns, their use, and their collaborations with a set of sequence diagrams. These are mostly standard UML and thus require no specific explanation. However, we use some non-standard but intuitive notations, which the following example illustrates. For example, a multi-threaded object has two lifelines, and we use a stereotype «create» to denote the creation of other objects.
1. In his book, A Pattern Language – Towns • Buildings • Construction [AIS+77] Christopher Alexander presents a pattern language consisting of 253 patterns about architecture. He describes patterns that guide the creation of space for people to live, including cities, houses, rooms, and so on. The notion of patterns in software builds on this early work by Alexander.
In this chapter we introduce distributed systems briefly. In particular, we describe the fundamental challenges addressed by the patterns in this book, and introduce important terminologies and concepts. This chapter, however, cannot provide a complete introduction to the broad field of distributed systems. More extensive introductions to these topics can be found in other books, such as Tanenbaum and van Steen’s Distributed Systems: Principles and Paradigms [TS02].
This section provides an introduction to distributed systems, the reasons why they exist, and the challenges in their design.
The application areas for distributed systems are diverse and broad. Many major large and complex systems in use today are distributed systems. Below we provide examples to illustrate this.
The Internet can be seen as a large distributed system with a huge number of servers, providing services via a set of communication protocols such as HTTP, FTP, Telnet, and SMTP, to an even larger number of clients. The protocols used in the Internet are simple, rugged, and proven.
Telecommunication networks use digital switches that run software to provide communication facilities. That is, telecommunications networks depend heavily on distributed communication. As development cycles in this domain become shorter, the use of low-level programming and communication is replaced by object-oriented programming languages and corresponding distributed object middleware technologies. Those allow for higher programming efficiency, though often at the cost of memory overhead and somewhat reduced execution performance.
Business-to-business (B2B) collaboration systems, conducting electronic commerce among businesses, are an important application area for distributed systems. Today Electronic Data Interchange (EDI) [Ans04] is heavily used for electronic commerce, but Web-based technologies such as XML-based Web Services will probably be used in the future in this area (see for example [CFH+02]).
International financial transactions are executed via a distributed system provided by SWIFT (Society of Worldwide Interbank Financial Telecommunication). SWIFT is an industry-owned cooperative supplying secure, standardized messaging services and interface software to financial institutions. In 2002 more than 7,500 financial institutions in 200 countries were connected to SWIFT, processing about 7 million messages daily [Swi02]. The system was originally established to simplify the execution of international payments. Several financial and infrastructure services have been added to its portfolio recently.
Embedded systems, such as in-vehicle software, elevator control systems, household appliances, mobile devices, and many others, have crucial requirements for distributed communication. For example, modern cars contain a complex network of electronic control units (ECU). These ECUs run software that controls a particular aspect of the car. The features of a car typically are interrelated: for example, you should not be able to switch critical ECUs into diagnostic mode while the car is in use. The ECUs must therefore communicate with each other. As for other embedded systems, strict timing requirements have to be obeyed. More and more embedded systems are becoming network-aware, and therefore require efficient programmability of distributed communication. The upcoming AUTOSAR middleware standard [Aut04] addresses these concerns in the context of in-vehicle software.
Many scientific applications, such as DNA analysis, extraterrestrial signal interpretation, or cancer research, need massive amounts of computational power and thus cannot easily be run on a single machine. Clusters, Grids, or distributed peer-to-peer systems are commonly used to solve these types of problem collaboratively.
These are only a few examples of distributed systems – many other fields use distributed systems as well. We hope this incomplete list of examples nevertheless gives you an idea of the diversity and complexity of distributed systems.
Why do we use distributed systems? There are many reasons why distributed systems are used today. In general, we can distinguish problem-related reasons and property-related reasons, which often occur together.
Problem-related reasons for distributed systems occur when we face problems that are inherently distributed. For instance, if a computer user in Europe wants to read a Web page that is located on a server in the USA, the Web page has to be transported to the remote user – there is no way around that, it is simply the purpose of the system.
There are also property-related reasons for using distributed systems – that is, reasons that are motivated by a particular system property that should be improved by distributing the system. Examples of such system properties are:
Performance and Scalability
. If a system has to cope with sufficiently heavy loads that a single machine cannot cost-effectively solve the problem, the problem is divided and assigned to several machines to share the load. To allow these to efficiently handle the computing load, the machines have to be coordinated in some way. This process is called ‘load balancing’, and results in a distributed system. For example, most Web sites with very high hit rates are served by more than one machine. Another example is the area of super-computing: Grids of smaller machines are assembled to provide a performance unattainable by any single machine. We discuss availability and scalability patterns in Chapter 13,
Related Concepts, Technologies, and Patterns
.
Fault Tolerance
. Another reason for using distributed systems is fault tolerance. All hardware devices have some Mean Time Between Failure (MTBF) that is smaller than infinity. Software can also fail: a program might have a bug or some non-deterministic behavior that results in a failure, or in strange behavior that may happen only occasionally. As a consequence, every machine, or a part of it, will fail at some time. If the overall system should continue working in such an event, it must be designed so that the system does not fail completely when a partial failure occurs. One approach to this is to distribute the software system over many machines, and ensure that its clients do not notice when a specific machine fails. The coordination between different software components running on individual machines results in a distributed system Note that there are ways to provide fault tolerance other than hardware redundancy. For more details, refer to Chapter 13,
Related Concepts, Technologies, and Patterns
.
Service and Client Location Independence
. In many systems the location of clients and services is not known in advance. In contrast to classical mainframe or client/server systems, services can be transparently executed on remote hosts equipped with more storage or computing power. For example, in a peer-to-peer system, new distributed or local peers providing additional services might join and leave the system at any time.
Maintainability and Deployment
. Deployment of software to a large number of machines is a maintenance nightmare that increases the total cost of ownership (TCO) of a system. An alternative solution is to provide
thin clients
that only accept user input and present output, and locate the business logic remotely on central servers. Changes to the business logic thus do not affect clients. Enterprise systems use this thin client approach, keeping the system functionality and the data on one or more central machines.
Security
. Another reason for using a distributed system is security. Security information, such as user credentials, might be consistently kept at a central site and accessed from many remote locations. Alternatively, for security reasons, some information or functionality might not be kept at a single site only, but instead distributed over a number of nodes, perhaps administered by different people and organizations. Some machines that store critical data might be located in specially secured computing centers, for example a restricted area that requires a special key for access and is monitored with security cameras. Such secured machines often need to be accessed by other nodes of the system. To coordinate the nodes, remote communication is again necessary.
Business Integration
. In the past business was mainly achieved by people interacting with each other, either directly, by surface mail, or by phone. When e-mail started to appear, some business was carried out via e-mail, but orders were still entered by people using personal computers. In recent years the term
Enterprise Application Integration
(EAI) has been introduced. EAI is about integrating the different systems in enterprises into one coherent, collaborating ‘system of systems’. This integration involves communication between the various systems using different remoting styles, as well as data mapping and conversions, without human intervention.
Compared to traditional, non-distributed systems, additional challenges arise when engineering distributed systems, such as:
Network Latency
. A remote invocation in a distributed system takes considerably more time than an invocation in a non-distributed system. If a certain performance level is required from the distributed system, or when strict deadlines have to be met, this additional time delay must be taken into account.
Predictability
. The time it takes to invoke an operation differs from invocation to invocation, because it depends on the network load and other parameters, such as the location of the remote process, how fast the invocation travels across the network, and how fast it is processed by the remote process. The network can even fail. Lacking end-to-end predictability of remote invocations is especially problematic for systems with hard real-time requirements that mandate specified deadlines that must not be missed, which would constitute a system failure. Guaranteeing real-time requirements is a major challenge in many distributed real-time embedded systems, such as aircraft flight control. Note that predictability cannot be assumed in non-distributed systems either. An operation’s invocation time is influenced by many factors, such as processor load or the status of a garbage collector. However for many systems these times can be assumed to be very small and constant, and thus can be neglected in practice. Such assumptions cannot be made in a distributed system. Though, predictable transmission times in distributed systems can be provided by using time-triggered communication [Kop97], which is increasingly used in safety-critical real-time applications.
Concurrency
. Other problems arise from the fact that there is real concurrency in a distributed system. In contrast to multi-threaded or multi-process systems running on a single-processor machine, in distributed systems several processing steps can happen at the same time. Coordinating such systems is far from simple. Even basic coordination, such as providing a common time reference, requires sophisticated protocols. Concurrency can cause a number of problems, such as non-determinism, deadlocks, and race conditions.
Scalability
. Since different parts of a system, such as clients and servers, are distributed and therefore more or less independent systems themselves, it is not always possible to know in advance how many of these different systems are actually available, and how high the communication load is going to be at a certain time. For example, it is hard to determine the number of clients for a Web server: at certain peak times, many more clients than expected might want to access a Web site. The software, the hardware, and the network must be able to scale up to handle this additional load at any time – or at least fail gracefully.
Partial Failure
. In systems that run on a single machine, ideally in a single process, a failure such as a hardware problem or a fatal software bug usually has a simple consequence: the program stops running completely. It is not possible for only parts of the program to stop, which is what partial failure is all about. In distributed systems, this is different: it is quite possible for only a part of the overall system to fail. However, in many systems it can become very difficult to determine which part of the system has actually failed, and how to recover. For example, if a client communicates with a server and does not receive a reply, this can have many reasons: the server process may have crashed, or the server hardware may have gone down. Or maybe the process has not crashed, but is only overloaded, and may merely take longer to respond to the request. Finally, there might be no problem with the server at all, but the network itself might be broken, overloaded, or unreliable. Depending on how the system fails, different ways of recovery are necessary. Therefore the real problem is to determine the real cause of the failure. But it is sometimes impossible for clients to detect the causes of failures. There are many algorithms for detecting such problems [TS02], but none of them is simple, and all imply an additional performance overhead.
The ‘bottom line’ is that you should only distribute your system if distribution is really needed. Distribution adds complexity concurrency inefficiency and other potential problems to your application that would not occur in a non-distributed context. We do not advocate avoiding the use of distributed systems, it’s just important to carefully evaluate when and what to distribute. Check Fowler’s First law of distributed object design in [Fow03], Don’t distribute your objects!
Distributed systems can be built directly on top of low-level network protocols. For example, communication can be based on TCP/IP sockets, which allow distributed processes to pass each other messages using send and receive operations directly [Ste98]. But this raises a number of problems, because developers have to deal with low-level networking details. In particular, such systems:
Are usually not easy to
scale
Are typically rather
cumbersome
and
error prone
to use for developers
Are hard to
maintain
and
change
Do not provide
transparency
of distributed communication
A common solution to these problems is to add an additional software layer, called communication middleware, or simply middleware, that hides the heterogeneity of the underlying platforms, and provides transparency of distributed communication for application developers. In this context, transparency aims to make remote invocations as similar as possible to local invocations. However, since remote invocations introduce new kinds of errors, latency, and so forth, complete transparency is not possible. This aspect will be addressed in more detail later in this book.
The figure below shows how the middleware hides the network services and other details of remote communication from clients and server applications.
