|< BACK  NEXT >|
COM+ extends COM s run-time environment to provide infrastructure for developing enterprise-level applications. It specifically addresses the problems of the business tier in the three-tier model. This is an integral part of the Windows 2000 operating system. As many of the tedious, grungy details of run-time services are moved into the operating system, the developers are free to focus on higher-level problems and their solutions.
Let s quickly examine the services provided by COM+. In the later chapters, we will cover these services in detail.
Traditionally, a lot of configuration details of an application are embedded in the application itself. As an example, an application can explicitly check to ensure that its caller belongs to the administrative group. Such a control should really belong to the actual administrator of the application, and not the application itself.
COM+ provides a distinction between the main logic of the program and its configuration. It defines a standard location, called the COM+ Catalog, to store configuration information for each application. A developer can use declarative programming attributes, outside the scope of the application, to define the default configuration settings. However, an administrator can change these settings either programmatically or by using a COM+ provided tool called the Component Services Snap-in.
Currently, many commercially available database servers meet the requirements of a transaction. Such a server typically buffers the changes made to a specific database until the client tells it to commit the changes. At this point, all the changes are applied to the database in question.
Although the database server takes care of each database individually, there is no standardized technique to coordinate operations among distributed databases, and among distributed components. Developing such a code is extremely hard, as well as resource-consuming.
COM+ provides an easy way to treat operations across distributed databases and components as a single transaction. It simplifies the way an individual operation votes towards the outcome of a transaction.
A transaction, however, need not always deal with a database. It may involve a non-database-related operation such as sending an e-mail. In case the transaction fails, sending the e-mail should be aborted.
COM+ provides a mechanism to let the developers define one or more operations that can participate in a transaction. Using this mechanism, for example, you can develop code to access a legacy database as part of a distributed transaction.
As mentioned earlier, an enterprise system requires many security primitives such as authenticating a user, ensuring that the user is authorized to access the specific part of the system, providing encryption when data is transmitted over the wire, etc. COM+ provides all these services.
Enterprise applications often go beyond the basic security primitives. They require that the access to a specific part of the system be based on logical groupings of users, called roles. COM+ lets a developer define user roles for an application. Note that these user roles are not the same as the user groups that one can create using Windows User Manager. A Windows user group defines the resources that the group-users can access at the operating system level. A user role under COM+ is defined at the application level. It defines the specific parts of the application the users (under the role) have access to.
COM+ provides an easy way for administrators to associate existing user accounts (or user groups) with a particular role. For situations that are too complex to be handled administratively, COM+ provides a way for developers to programmatically define the security logic.
Under distributed systems, it is sometimes required that component B act on behalf of its caller component A when accessing another component C, where all three components reside on different machines. Such a requirement is called user delegation. Implementing user delegation is not an easy task and requires some low-level support from the operating system. Here, once again, COM+ (and Windows 2000) comes to the rescue.
Under distributed systems, certain critical portions of the components need protection against the possibility of concurrent access from multiple threads. Writing code to do this is not only expensive in terms of time and money, but it is also extremely difficult to get it right.
COM+ offers various levels of synchronization primitives to protect resources from concurrent access. Depending on the level of desired scalability, and the quality of the code, either the developer or the administrator can choose an appropriate synchronization level for the application. For situations that are too complex to handle administratively, COM+ defines programmatic ways to define synchronization logic.
For serializing calls to an object, classic COM required the Windows message queue. However, because of the way the architecture was implemented, any time a client made a call to such an object, it required a thread-switch, which tends to be expensive. COM+ defines a new synchronization paradigm which controls concurrent access and doesn t require a thread switch or the Windows message queue.
The development model under classic COM is based on procedural interaction. A client connects to a component, queries the appropriate interface, and makes synchronous method calls on the returned interface. The following code example illustrates this behavior. The code fragment credits a user account with 100 dollars. It uses a remote component for updating the account balance.
// Get the account manager object from the machine "PVTEST00" COSERVERINFO serverInfo; serverInfo.pwszName = OLESTR("PVTEST00"); ... MULTI_QI mqiEntry; mqiEntry.pIID = &IID_IUnknown; ... HRESULT hr = CoCreateInstanceEx( __uuidof(AccountMgr), ..., &serverInfo, 1, &mqiEntry), ... IAccountMgrPtr spAccountMgr = mqiEntry.pItf; mqiEntry.pItf->Release(); spAccountMgr->Credit(CComBSTR("Pradeep"), 100); spAccountMgr = NULL; // release the object
Under such a model, the life cycle of the client is tightly coupled with the component. An RPC connection is maintained between the client and the account manager. This model is easy to program. The client assumes that the component is loaded and running throughout the interaction.
The program fails, however, if the remote object is not reachable. Perhaps the network was down at the time the call was made.
An alternative to such a synchronous programming technique is to use another technique called message-based programming.
In a message-based application, the client and the component are separated by time. Therefore, their life cycles are decoupled. This gives the appli-cation developer flexibility in the area of scalability and availability. If the component is not available, the client application can still execute.
Of course, developing a message-based distributed application requires a lot of plumbing. Microsoft provides this plumbing in the form of a technology called Microsoft s Message Queue Server (MSMQ).
COM+ simplifies message-based programming further by hiding the details of messaging with a service called Queued Components. The developers continue to develop the components in the same way they always did, with a couple of exceptions that we will cover later.
Here s how the process works. When the client instantiates a queued component, the run-time service actually creates a local proxy object called a recorder. As the client makes method calls, the recorder simply records them (into a MSMQ message). When the client releases the last reference to the object, the message is passed to the actual server via MSMQ. A special service running on the server then de-queues the message and instantiates the component using another proxy called the player. The player interacts with the component, as if it was the actual client, and plays the stored method calls. If a call fails during the operation, the message is placed back into the queue, at which point the developer has several options to deal with the message, based on the services provided by MSMQ.
Traditionally, events or callbacks between a component and any associated clients are handled as follows:
The component defines an interface that it will use for callbacks.
The client implements an object supporting this interface. Such an object is referred to as a sink.
The client registers the sink with the component.
The component invokes an appropriate method on the sink.
When no longer needed, the client can unregister the sink.
Note that the conventional sense of client and component reverses their roles when talking about events. As the component is making the method call, it becomes the client and the actual client becomes the server. In this regard, COM+ uses the term publisher for the component that will publish or provide information, and the term subscriber for the module that intends to receive such information.
A major drawback with the traditional publisher/subscriber model is that their life cycles are tightly coupled (because of COM s RPC-based implementation). Another drawback is that to multicast information, that is, to inform all the subscribers simultaneously, requires a lot of low-level code.
The COM+ events model significantly upgrades the traditional event model. It decouples the tight binding between the client and the server by providing an intermediary object called the event class. The actual event interface is implemented by this event class, making it look like a subscriber to the publisher. When a publisher wants to fire an event, it creates an instance of the event class, calls the appropriate method, and releases the interface. The runtime service then determines how and when to notify the subscribers.
As in the case of queued components, the lifetime of the publisher and the subscriber have been decoupled. If a subscriber is not active when an event occurs, the run-time event service can activate the subscriber and pass the information along.
Under classic COM, a client instantiates a component, uses it, and releases it when done. Under some cases, object instantiation may take a considerable amount of time. To handle such situations, it may be a good idea to maintain a set of component instances loaded in memory so that they are immediately available for use by the client application.
Recall from Chapter 3 that a client instantiates an object using CoCreateInstance API. Therefore, just creating a pool of objects is not enough. The COM+ run-time service has to intercept the object creation call and ensure that the object is fetched from the pool. Similarly, when the client releases the object, the COM+ run-time service has to ensure that the object is returned back to the pool.
An object needs a way to know when it is being activated or deactivated so that it can initialize its state or release the resources that it has been holding. COM+ specifies a standard interface, IObjectControl, that a class can implement to receive these notifications.
Object pooling support is needed for building large, scalable applications. However, some of the most precious resources in an enterprise application are its database connections. COM+ (along with ODBC and OLE DB) supports connection pooling (more precisely, pooling of database connections), which allows applications to create and destroy database connections on an as-needed basis without significant performance penalty.
In classic COM applications, objects are often created at startup and maintained (via reference counting) throughout the lifetime of the application. This practice tends to improve performance, as the application has a ready reference to all the objects whenever it needs to use them. However, it makes inefficient use of server resources.
JIT activation is another service provided by COM+ whereby the actual instances of an object are activated just prior to the first call made on them and are deactivated immediately after they finish their work.
Under JIT activation, when the client creates an object, the COM+ service creates a standard proxy and returns it to the client. The actual object is activated (a new instance created or an instance fetched from the pool of objects) only when the client makes the first call on the object.
When the actual object informs COM+ that it is done with the job it was supposed to do, COM+ releases the reference to this actual server-side object. If object pooling is enabled and the object agrees to go back to the object pool, COM+ puts it back into the pool.
The base client, however, is still holding a reference to the object (via its proxy). When the client makes another call, a server side object once again gets activated.
Together with object pooling, JIT activation can provide a high degree of scalability. More importantly, as we will see later, JIT can enforce transactional correctness with the greatest possible speed.
Prior to COM+, there was no easy way to install and register a COM server from the local machine to one or more remote machines. To install an application, administrators either walked up to each machine or used tools such as the Microsoft System Management Server (SMS).
COM+ provides an easy way for administrators to group one or more COM servers as one application and create an installable package file for the application. This package file can then be placed on a network shared drive, and from the local machine, an administrator can instruct each remote machine to install the application contained within the package. Once installed, an administrator can also uninstall an application remotely.
|< BACK  NEXT >|