BizTalk: Implement Design Patterns for Business Rules with Orchestration Designer
|Christian Thilmany and Todd McKinney|
|This article assumes you're familiar with COM+, MSMQ, and Visual Basic|
|Level of Difficulty 1 2 3 |
|Download the code for this article: BizTalk.exe (799KB) |
|Browse the code for this article at Code Center: BizTalk Patterns |
|SUMMARY Because the value of good software planning and design should never be underestimated, it can be beneficial to use one of the many existing design patterns as a foundation for solving some of your toughest architecture problems. This article describes several traditional design patterns including the Observer pattern and the Dispatcher pattern, elaborates on their structures, what they're used for, and how they can help you build a BizTalk-based solution. Following this is a discussion on using the BizTalk Orchestration Designer to build designs and integrate existing business processes. |
|hen it comes to software design, a good design is a good solution regardless of the technology. And no matter how good the technology may be, it is only as good as its design, and specifically the implementation of that design. In fact, a great design with older technology may still be good, but a bad design with new technology is usually just bad. Most great designs aren't developed on the first attempt; they must go through stages of change before they can be considered valuable. How do you learn to approach existing designs in a new way? And once you have a good design, how do you make it reusable? An even better question is how do you reuse what others have struggled to perfect? |
If you are thinking about Unified Modeling Language (UML), you are close, but not quite there. UML helps, but it really only contains the hieroglyphics (or language) you may need to convey your design. It is the standardized and fossilized assemblage of those UML symbols we need, and all of the historical toil that has gone along with those assemblies. Enter design patterns.
In this article, we will explain and implement the Observer and Chain of Responsibility patterns adapted from the book Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1995). We'll do the same with one of our own patterns, called the Dispatcher. We'll show you how to use these patterns in such a way that they can be applied to a loosely coupled architecture as one implemented with BizTalk™. This is not to say that these patterns only apply to BizTalk or any particular implementation. In fact, design patterns have traditionally been associated with purely object-oriented languages. In this article we will take some of the more traditional object-oriented design patterns, such as the Observer pattern, and use them in slightly different ways, while still keeping their behavioral benefits intact.
We hope to show how traditional design patterns can be seen and utilized in any design, or in any technology. Recognizing them not only helps improve your own custom design, but it also helps explain an existing implementation, whether this implementation is custom code you must now support or a commercial application such as BizTalk. We will also refer to other related patterns such as Interface, Factory Method, and Delegation. Finally, we will implement each pattern in the context of the BizTalk Orchestration Designer and put the patterns to work in a custom way. In addition, we'll even point out a few patterns that BizTalk itself uses.
Our sample implementation, available for download from the link at the top of this article, focuses on a product support department. (No, it is not another purchase order or reservations code sample!) The sample application will show how applying patterns to BizTalk can significantly ease the development and design for each subdepartment. It will provide the ability to answer and route online product support questions effectively and efficiently. But first we must explain the patterns themselves.
Learning about Design Patterns One of the better places to start learning about patterns is with the "Gang of Four"—Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, authors of Design Patterns. Like the "three amigos" of UML (Grady Booch, James Rumbaugh, and Ivar Jacobson), these four began the work of forming what is now thought of as the standard patterns. Besides Christopher Alexander, who first spoke of design patterns when referring to the actual architecture of buildings, the Gang of Four's work represents some of the original thoughts on object-oriented design patterns. In their book, they use C++ and Smalltalk; however, the book is geared to the patterns themselves, and not the language used to implement them. This general applicability to all languages is what makes patterns so powerful.
If you're looking for a true introduction to the world of object-oriented design, and to some of the more fundamental patterns, read Craig Larman's Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and the Unified Process (Prentice Hall, 2001). His General Responsibility Assignment Software Patterns (GRASP) provide some of the more basic object-oriented principles as applied to design patterns such as Low Coupling, High Cohesion, Expert, and so on. Traditionally, however, design patterns are geared to object-oriented languages.
For the developer using Visual Basic® 6.0 or earlier, this presents somewhat of a challenge. Using patterns with these versions of Visual Basic (which only support interface inheritance and don't support implementation inheritance) limits developers from using those patterns that do not make heavy use of implementation inheritance. Those patterns, such as the ones from the Gang of Four that use moderate levels of implementation inheritance, can be used with interface inheritance instead. This can still be done without damaging the intent of the pattern. This is exactly what we will demonstrate when we apply the Observer and Chain of Responsibility patterns later in our code. This does not apply to architectural patterns or to known design patterns that originally (or only) intended to use interface inheritance.
Design Patterns versus Architectural Patterns Besides being an outstanding communications tool, design patterns help make the design process faster. This allows solution providers to take the time to concentrate on the business implementation. More importantly, patterns help formalize the design to make it reusable. Reusability not only applies to the components themselves, but also to the stages the design must go through to morph itself into your final solution. The ability to apply a patterned repeatable solution is worth the little time spent learning formal patterns, or to even formalize your own.
When referring to design patterns in this article you will note that we usually leave out the word "design" since we are not only covering design patterns, but also what some refer to as architectural patterns. Most pattern books typically cover design patterns since more of the well-known patterns are at the design level. Rarely do they encroach upon the architectural level.
What is the difference? Some of this is subjective, but design patterns tend to be applied at lower levels of detail than architectural patterns. This means looking at how design applies to the structure of code within an architecture and the structure of the application as well.
In contrast, architectural patterns are usually focused on the reexecutable binary pieces of the system and not as much on the design within the system. Existing material covering architectural patterns is currently rather limited, but will hopefully become commonplace as time progresses. What we will be discussing in this article is a mixture of the two: combining known design patterns with a more architectural solution.
Pattern Descriptions To help explain what patterns are, the Gang of Four breaks a pattern's description into sections, which helps not only explain the pattern in detail, but also shows its context and its relationship with other design principles. These sections include: intent, motivation, applicability, structure (for example, UML notation), and consequences. In addition, areas such as the pattern's participants, its collaborations with other elements, and its implementation help provide elemental detail so that the pattern can be specifically applied to a design. A little sample code helps as well.
Some patterns can be self-explanatory. Others, however, are not. Some patterns may even overlap in meaning, thus it is recommended that all patterns follow certain classifications based on principles such as the pattern's purpose and scope. Design Patterns breaks this down into creational, structural, and behavioral categories. The point of all this sometimes convoluted classification is to give the pattern its context. Otherwise it is sometimes difficult to know when, or even how, to apply it.
Unlike the Gang of Four, we limit our pattern descriptions to a few consolidated descriptives. Hopefully this will give enough information about each pattern and how it can be implemented.
The Chain of Responsibility Pattern The intent of the Chain of Responsibility pattern is to provide a loosely coupled sender/receiver relationship by providing more than one component an opportunity to handle a request. This chains all receiving components and passes the request along the chain until the request is handled.
Motivation In an environment where business rules may be implemented in different components, or even in different applications, request senders should only have to maintain simple relationships. The sender or requester may only have enough information to send requests to one party. Also, to avoid unnecessary coupling of business logic among all requesters, only one receiver need be contacted in order to initiate a request. In cases where business rules may be distributed among separated applications or environments, it is prudent to hold requesters to a single relationship to avoid unnecessary coupling.
Context When a request is made that may require complex resolution, you might have to distribute the business rules used to fulfill that request. This may be due to system complexity, application architecture, or the request may be general enough to warrant a form routing to adequately respond with a reasonable answer.
As is the case for our product support sample, the request may not be fulfilled at one application site due to the distribution of the knowledge bases used to answer a request. The request must be routed until it can be handled. This also provides the benefit of not requiring the sender to have intimate knowledge of the appropriate receiver upon which to make the request. Finally, as in our sample, it provides enough flexibility to allow the routing order to change or even provide additional receivers in the system without the sender ever knowing.
Solution and Structure Here's where this pattern gets interesting. Traditionally when dealing with only object implementations of a class structure (for example, a system of just Visual Basic-based components and no BizTalk), the structure would look exactly like the Chain of Responsibility class model (see Figure 1).
Figure 1 Pattern Class Model
Any client could make a request to a member of the chain via a single interface, IHandler. Notice that this is where our UML model differs slightly from the original UML model from the Gang of Four: we substitute the base class for an interface so that this can be implemented using Visual Basic 6.0. When calling HandleRequest, the implementor of IHandler would then either handle the request or forward it on to the next member of the chain. Each handler, via the ConcreteHandler implementation, would have the ability to decide how to handle the request. The client doesn't know or care who handles it, as long as it is handled somewhere. In a loosely coupled system such as BizTalk, the choice for applying this pattern opens up several additional implementation possibilities, as we'll soon show later in this article.
Implementation In our example, the product support concrete handler can be a direct recipient of a method call, as we just described. However, with BizTalk you can now loosely couple the links between each concrete handler by using message queuing. This not only allows each concrete handler a loosely coupled way of receiving a request in a BizTalk-friendly manner, but it also provides a guaranteed form of delivering a request. This implementation can even be further expanded to span organizations by means of the BizTalk Messaging Manager. (Unfortunately, we don't have the space to cover this part of BizTalk here.) In our product support example we use Microsoft® Message Queuing (MSMQ) to do just that (see Figure 2).
The Observer Pattern The intent of the Observer pattern (see Figure 3) is to provide a mechanism to allow objects to subscribe dynamically to state change notifications from another object.
Figure 3 Observer Pattern Class Model
Motivation When client objects communicate with a server object of some kind, it's beneficial for those client objects to be made aware of server-side state changes in that object. This allows subscriber clients the opportunity to react to those state changes in a more dynamic fashion, thus adding robustness to the application.
Context Suppose a client communicates on a regular basis with a server object, but that communication is time-critical. As in the case with our observable component in the product support sample, each initial registration with the observable causes the publisher of information (Observable) to retain a copy of that reference for later notification. The server, or observable object in this case, just notifies all observers of the state change, not caring which objects (or schedules in our case) are actually observing it. Take heed, however. If there are hundreds of schedules all needing to be notified, this could be a significant performance hit. In this case, the notification mechanism would be better served running from a separate multicasting thread.
Solution and Structure As with the Chain of Responsibility pattern, this is where this pattern becomes interesting in the context of BizTalk. Traditionally, the Observer pattern is made up of an observer class which implements an interface containing a method that the Observable will call during notification. Notice that, like the Chain of Responsibility, our pattern model differs from the Gang of Four's by our use of interfaces. On the other side, the Observable class implements an interface that the observer calls in order to register with it. The observer calls Register whenever that client wants to begin receiving notifications. The Observable class then keeps a list of observers and, during state changes, calls the notification method on the interface passed to it by the observer during registration.
You may already be familiar with this publisher/subscriber-type relationship. If an observer wants to stop receiving notification, then that observer simply unregisters with the Observable object in similar fashion, or during notification unregistration may be automatic and immediate; this is a design decision. With BizTalk, the Observer and Observable boundaries usually will begin and end with exit and entry points of a compiled schedule, as you'll soon see.
Implementation In our example, we use the Observer pattern to receive notification of changes to the knowledge base. This notification takes the form of application-to-application communication. A component that wants to receive notification passes in a reference to itself, which is instantiated and called when the status change occurs. Note that this implementation also takes a loosely coupled, stateless form. We do not pass a live object reference, as with a callback, but rather a BizTalk-based schedule path that is composed as a moniker and used to instantiate the observer on notification.
The Dispatcher Pattern The intent of the Dispatcher pattern is to provide a single point of contact, or brokered handler, to all external requesters. In addition, it also provides a simple mechanism or entry/exit point into an existing system to decouple external systems from requesting internal components.
Motivation When trying to decouple synchronous or even asynchronous component-to-component communications, this pattern helps provide a single point upon which to communicate. This also isolates internally running components from having knowledge of which protocols will be used to communicate with external systems. This is especially important where existing orchestrations in BizTalk have already been implemented, thus preventing multiple changes from being made within the BizTalk-based schedule.
Context In our product support example, BizTalk will be used to orchestrate support question responses and route those question/responses appropriately. The dispatcher will be used to forward those questions not handled by anyone in the product support channel that we have set up. This external communication could be with external trading partners or within the organization. By providing a loosely coupled single point of communication to external resources from within each BizTalk-based schedule, we provide a proxy upon which to implement any change in that communication path. Changes could include protocol, message type, or process flow change as handled by other BizTalk-based schedules or directly with the external partner.
Solution and Structure The Dispatcher pattern (see Figure 4) is made up of a main broker-like Dispatcher component which is called by any client (an existing path within a BizTalk-based schedule in our case). The Dispatcher component then forwards that request in a uniform fashion to the external resource which can be identified by the message itself (an XML message in our case). Identifying the external component to call by message is only one option. The contract between the Dispatcher and the external resource, in this case a ConcreteDispatchable, must be established.
Figure 4 Dispatcher Pattern Class Model
For example, if direct component communication through COM is determined as the means of communication from the Dispatcher to the Dispatchable, then through the message that is passed to the Dispatcher, the Dispatcher may be able to instantiate the external components, and through its established contract call a predetermined interface on that method (IDispatchable). This is only one example of the many implementation forms of this pattern.
Implementation In our example, the Dispatcher pattern is used to provide a flexible integration point with external systems. This particular implementation uses a factory-method style of object creation based on the topic. Another viable option would be to pass the progid of the ConcreteDispatchable object in the XML message itself, or even use the BizTalk "openness" features to dynamically instantiate the appropriate external component (see the BizTalk documentation for details). The choice is yours but the same principles apply. The following code illustrates the creation of specific implementation component instances based on the topic found in the XML document.
sTopic = oDOM.selectSingleNode(".//topic").Text
If sTopic <> "" Then
'Dispatcher ACTS as a factory method pattern as well
If sTopic = "BizTalk" Then
Set oDispatchable =
ElseIf sTopic = "MSMQ" Then
'and so on...
'Set oDispatchable = CreateObject("...")
Other BizTalk-friendly Patterns Two other database-friendly patterns worth mentioning are the Interface pattern and the Factory Method pattern. Although the Interface pattern is a simple design pattern, using interfaces in an environment such as BizTalk is extremely useful. In keeping with using patterns that exhibit loosely coupled aspects, using an interface to all components abstracts the caller from changes to the implementation of the component implementing the interface. This increases the robustness of the architecture and may eliminate unnecessary recompilations in Visual Basic as well as provide a contract upon which to build further implementations using that same interface.
The Dispatcher pattern in our example demonstrated another well-known design pattern that uses a single method as the factory or creator of other objects. This Factory Method pattern isolates the caller from knowing the complexities of instantiating and initializing other worker components in the system. This comes in handy when dealing with external systems where coupling external components in each BizTalk Orchestration would violate its loosely coupled design.
But what does all this have to do with BizTalk? Well, let's see.
BizTalk and the Orchestration Designer BizTalk is made up of many elements, including the Orchestration Designer which we used to orchestrate the components in our sample. The Orchestration Designer is one of the most powerful and flexible features of BizTalk. Misusing it is also one of the easiest ways to turn a bad design into a bad solution.
Communicating to a BizTalk server implementation simply means using XML as the message format. As you may already know, BizTalk is completely structured around XML and uses a SOAP 1.1 XML message format. The BizTalk-friendly XML message is nothing more than a SOAP 1.1 XML message with additional biztags to comply with the BizTalk Framework specification.
BizTalk Server 2000 is the Microsoft implementation of the BizTalk framework specification. While BizTalk Server happens to run on a Windows® 2000 platform, the framework specification is implementation-agnostic. Any language could be used to implement a BizTalk server as long as it complies with the framework. This provides one of the most powerful features of BizTalk. A message could be sent to a BizTalk server (known as reliable messaging in BizTalk Server 2000) from anywhere as long as it's a well-formed and valid BizTalk message (see the BizTalk Framework 1.0 for details at http://www.biztalk.org). A BizTalk message can be received by an Active Server Page or message queue and forwarded to a running BizTalk server via BizTalk Messaging Manager. A message may even be sent directly to a compiled BizTalk Orchestration schedule. But where do you implement complex logic after a BizTalk server gets its hands on the message? This is where the Orchestration Designer comes in.
The BizTalk Orchestration Designer is a Microsoft Visio® 2000-based design tool that, when compiled, can run as an XLANG schedule. XLANG itself is described through XML (view a compiled schedule in Notepad and see for yourself). The designer provides a high-level means of orchestrating a middleware system's moving parts. Those moving parts can take the form of a message queue, COM component, BizTalk Channel, file, e-mail message, or HTTP-based service. Orchestration Designer provides a way to create loosely coupled business processes that may optionally be long-running in nature. With the Orchestration Designer, analysts not privy to the implementation complexities of COM or Web development can participate in the development of business rules by using the designer in Visio to lay out the business flow. The developer can then implement the moving parts that these designers orchestrate.
But what is the best way to implement BizTalk-friendly moving parts? This is where design patterns come in.
Using the BizTalk Orchestration Designer There are three key object categories in the business process page of the Orchestration Designer: flowchart shapes, ports, and implementation shapes. Conceptually, the way this works is that you, or your friendly neighborhood business analyst, use the flowchart shapes to create the process flow. The flowchart shapes support basic constructs such as if�then�else decisions, looping while a condition is true, branching execution, rejoining the branches together, and defining transactional boundaries. These relatively simple constructs can be used to create infinitely complex process logic. Implementation shapes come in a few varieties, most of which will be familiar to readers who have used MSMQ and COM+. You can implement application functionality in four basic ways: COM+ components, script components, MSMQ, or BizTalk Messaging. The glue that binds the business process to the implementation code is the third major object category in BizTalk process design—the port.
Ports are named locations where messages are sent and received. Ports can be defined initially as unbound or bound. To create an unbound port, on a design page in the BizTalk Orchestration Designer, right-click on the separator bar and select Add New Port from the popup menu. One primary use of the unbound port is to import an XML document and define the fields that will comprise the message to be passed. Note that unbound ports are less useful than bound ports for defining message flows, especially those that are bidirectional.
To create a bound port, drag an implementation shape onto the right side of the Orchestration Designer page and follow the wizard steps for that implementation. Binding a port provides the ability to define precisely what will travel through the port in each direction, since the target implementation is known when the binding is created. These steps are explained in greater detail in the BizTalk Server 2000 help file. The difference between these two means of port creation is illustrated in Figure 5. Ports are located on the separator bar, with the business process depicted to the left of the bar and the implementation displayed to the right.
BizTalk Orchestration shouldn't be used to design processes at too granular a level (see the Orchestration whitepapers at http://www.microsoft.com/biztalk). Its primary value is integration of existing business processes. To illustrate this idea, consider a traditional business application that uses COM+ components to control the process, and additional COM+ components to perform the work. System designers should strive to replace the controller functionality of such an application with BizTalk, and make use of the existing COM+ work components. As an analogy, you should do your choreography with BizTalk, and do the dancing with COM+, MSMQ, script components, and the BizTalk message tools.
Enough of the tool itself, how do we implement our patterns?
Implementing the Patterns To provide some context to the scenario that we are tackling, consider the following situation. A hypothetical software company that is small but growing fast has engaged us to consult on their internal systems. The problem is that their existing product support process is taking too much manpower to staff, and the company is having a difficult time gathering quality metrics on this function. The existing system is implemented in Microsoft Exchange, and uses the workflow capabilities of that product to route issues among support personnel.
What is needed is a comprehensive self-service solution to augment the existing application, and to answer questions without direct product support involvement. It would be a simple matter to expose the existing internal knowledge database to the Web as a solution to the problem (see Figure 6), but we want to illustrate that there are benefits to using BizTalk Server to accomplish this integration of existing and new functionality.
Figure 6 Default.asp Query Submission Form
One of our goals in creating the samples was to demonstrate the flexibility of using BizTalk Server Orchestration as the core application engine. Multiple integration points are possible using this architecture. Consider our first entry point into the system: an ASP page creates a COM+ component, then calls a method on that component that places the request message into an MSMQ queue. An XLANG schedule, which already has an instance running, picks up the request from the queue, launches a new schedule instance to monitor the queue, and proceeds to service the request by calling other COM+ components. Entry point number two illustrates a completely different scenario for achieving similar functionality. Here we take a request message from the browser and post it directly into the XLANG schedule from the ASP page.
The pattern implementations we have chosen also achieve a high degree of flexibility and extensibility. The Chain of Responsibility pattern is inherently flexible, functioning similarly to a linked list. The only knowledge required of a participant in the chain is where to forward the request if it can't be resolved. This is made even more flexible in our BizTalk implementation by allowing the component to directly forward the message via a call to Client.Execute. Client.Execute simply acts as a wrapper around the MSMQ APIs such that a message can be sent to a specified queue. The ConcreteHandler tells Client.Execute which queue to send to, which also happens to be the next queue in the chain. If, however, the component developer does not want to mess with the MSMQ APIs, the queue name can also be returned back to a running schedule where BizTalk is used to dynamically send the message to the appropriate queue in the chain. This is one of the niceties of BizTalk. The designer can now benefit by diverging from the traditional pattern implementation by doing it the "BizTalk way."
The code in Figure 7 shows the logic for arbitrarily passing a message to the next component using each of the methods just described. If the Boolean variable bSendDirect is true, the component is instantiated and called. If bSendDirect is false, the value is returned to the schedule and the orchestration invokes the component via MSMQ.
BizTalk Server also greatly simplifies the implementation of the Dispatcher pattern in our samples. We simply branch execution of unhandled requests to the Dispatcher implementation from within our orchestration schedule. By doing this, we have created a well-defined integration point with external systems that has built-in flexibility and extensibility to guard against major code rewrites when the operating environment changes.
Finally, the Observer pattern's functionality provides a simple and powerful mechanism for dynamically modifying system functionality, and responding to events that the application developer deems to be interesting. With a minimum of additional effort, we could use BizTalk Server's persistence mechanisms to create Observer/Observable relationships (or publish/subscribe if you prefer) that live beyond catastrophic events like system failures. In the following code, we illustrate the Observable object as it provides notification to all registered observers through XLANG. The XLANG scheduler allows us to access the schedule as an object.
While (nCount < m_iObserverCount)
sSchedule = m_saObservers(nCount)
strURL = "sked:///" & sSchedule
' This enables the XLANG Scheduler Engine to execute the XLANG
Set objExecute = GetObject(strURL)
Set oObserver = objExecute.Port("Observer")
| For related articles see:|
House of COM
"Make Your Legacy Apps Work on the Internet"
For background information see:
Design Patterns: Elements of Reusable Object-Oriented Software by Gamma, Helm, Johnson, and Vlissides (Addison-Wesley, 1995)
| Christian Thilmany is President of the eTier Group Inc. a consulting firm in Houston, TX. He specializes in distributed application architectures for Internet, Intranet, and client/server development. He can be reached at email@example.com.|
Todd McKinney is a Senior Consultant for Microsoft Services, specializing in middleware, enterprise development technologies, and system design. He can be reached at firstname.lastname@example.org.
From the October 2001 issue of MSDN Magazine.