The IObjectControl Interface

[Previous] [Next]

In Chapter 14, " Using Microsoft Transaction Server," we described the IObjectControl interface from an MTS perspective. We also described how MTS components could implement that interface and as a result get access to three event methods: Activate, Deactivate, and CanBePooled.

The IObjectControl Interface as Used in MTS

You'll recall that we recommended the following code for each of these three methods.

For the Activate method

 Private Sub ObjectControl_Activate() Set mobjCTX = GetObjectContext() mblnInMTS = Not (mobjCTX Is Nothing) End Sub 

For the Deactivate method

 Private Sub ObjectControl_Deactivate() End Sub 

For the CanBePooled method

 Private Function ObjectControl_CanBePooled() As Boolean ObjectControl_CanBePooled = False End Function 

The IObjectControl Interface as Used in COM+

To establish whether anything has changed in the IObjectControl interface as COM+ exposes it, we updated our Rational Rose model by reading the COM+ Services Type Library into it. We didn't modify the same model; we made a new copy of the model in order to keep the MTS version and the COM+ version of the model separate. Figure 161 shows one of the application's components implementing the IObjectControl interface.

As you can see from Figure 16-1, the set of events exposed by the IObjectControl interface is exactly the same as in the MTS version. The question that remains to be answered is whether any of these events have changed or if there's any reason we should change the way we react to them.

To make the IObjectControl interface and other COM+ Component Services available to your application, its Visual Basic project must have a reference to the COM+ Services Type Library. Figure 16-2 shows the References dialog box with that library selected.

click to view at full size.

Figure 16-1. HorseTrSrvcs objects implement the COM+ version of the IObjectControl interface.

click to view at full size.

Figure 16-2. Your Visual Basic project must have a reference to the COM+ Services Type Library.

The Activate method

Looking at the MTS code for the Activate method, you can see that it contains two lines of code. The first line saves the return value received when it calls the inherent MTS GetObjectContext method. This method either returns a reference to the calling object's context object or, if the calling object doesn't run in MTS, the method returns Nothing. The next line investigates the result of the GetObjectContext call, saving the result in the mblnInMTS variable. When the line is executed, the mblnInMTS variable is True if the calling object runs in MTS; otherwise, the value is False.

So what's the use of these two lines? Well, in MTS it's important for an object method to report to MTS that the job is done; sometimes also whether it was successfully done or it failed. An object can call either SetComplete to report success or SetAbort to report failure. The problem is that if the object isn't installed in MTS, the call to SetComplete or SetAbort ungracefully fails. This is the reason for code such as the following:

 If mblnInMTS Then mobjCTX.SetComplete 

Using such code, you avoid Visual Basic errors in situations in which an object is made to run in MTS and yet doesn't. With COM+, you don't have to protect yourself or your objects from these errors. You can just call the SetComplete or SetAbort method as follows:

 GetObjectContext.SetComplete 

This call is technically successful even if the object doesn't run in a COM+ application. So with COM+, there's no need to protect the code from failures when calling SetComplete or SetAbort, as you have to do in MTS. What's more, since you don't use the mblnInMTS and mobjCTX variables in COM+, you don't have to declare them as you did in the MTS version of the component, as follows:

 Option Explicit Implements MTxAS.ObjectControl Private mobjCTX As MTxAs.ObjectContext Private mblnInMTS As Boolean 

The COM+ version of such a component has to specify only the following:

 Option Explicit Implements COMSVCSLib.ObjectControl 

The Deactivate method

In Chapter 14, we left the Deactivate event method empty. We don't see any reason (apart from the issues mentioned in "Object Pooling" below) to add any code to this method for COM+.

The CanBePooled method

In Chapter 14, we recommended that you have the CanBePooled method return False, the reason being that MTS doesn't support object pooling. COM+ does support object pooling, but if you code your component in Visual Basic you should still have it return False. There's no way COM+ will put a Visual Basic component in an object pool, at least not as long as Visual Basic doesn't support aggregation and as long as Visual Basic supports the apartment threading model only. (We mentioned both aggregation and threading models in Chapter 15, "A COM+ Overview.") So whatever you make the CanBePooled method return, COM+ won't pool your Visual Basic 6.0 components. Just the same, you should still play it safe and have the CanBePooled method return False. Who knows what can happen in the next version of Visual Basic? And who knows what can happen to your component if you compile it in a later version of Visual Basic and then install it in a COM+ application? Playing it safe means having all CanBePooled events written in Visual Basic return False, at least for the time being.

Object Pooling

If you code your COM+ components in C++ or J++, you could consider using object pooling, but you shouldn't make such a decision lightly. We won't talk much about object pooling in this book, but the least we can do is give you a few hints:

First you should convince yourself that object pooling is worth it in the specific case for which you consider it. For a very simple component, it's probably not. Some people would claim that object pooling is worth doing only if it takes longer to create and activate an object than it does to use it. Only then, they say, is the extra effort of managing the pool worthwhile. Such a statement disqualifies stateful components from object pool considerations. The lifetime of a stateful object spans at least two calls; given that, a stateful object that takes more time to create than to use is hardly conceivable.

If you do decide to pool objects of a certain component, you must make absolutely sure that all objects look the same to its clients whether they come fresh from the object factory of the component or from the pool.

The places where you can make sure that all objects given to clients look the same are the Deactivate and Activate methods. You can use the Deactivate method to make sure the object forgets what a similar object, created fresh, won't know; you can use the Activate method to make sure the object owns every child object it's supposed to own.

The Context Object as Used in COM+

Let's take a look at a Rose diagram that features the context object in COM+. At the very least, this gives us an opportunity to see whether any of the methods we called in MTS have disappeared or changed. Figure 16-3 features such a diagram.

Figure 16-3 is quite interesting in several ways, especially since the COM+ elements of the diagram in the figure are automatically imported from Microsoft Windows 2000. Before we go into the most interesting parts of the diagram, just let us mention the relationship between the IObjectContext interface and the IUnknown interface. We allowed that relationship to stay in the diagram just to remind you of the absolute requirement that all COM interfaces must inherit from the IUnknown interface. Because every COM interface must inherit from the IUnknown interface, every COM interface must expose the QueryInterface, AddRef, and Release methods that are part of the IUnknown interface. The QueryInterface method allows clients of an object to ask the interface used for other interfaces implemented by the object; the AddRef method adds 1 to the object's reference count each time the object gets a new client; the Release method subtracts 1 from the object's reference count each time a client of the object lets it go. COM (and since COM+ is the new version of COM, also COM+) depends on objects destroying themselves. A COM object destroys itself when its reference count goes down to 0. This is why it's so important for every COM interface to inherit from the IUnknown interface.

click to view at full size.

Figure 16-3. Objects of the HorseTrSrvcs class get access to their context object through the IObjectContext interface.

The diagram in Figure 16-3 reveals that COM+ components in fact get access to their context object through a COM+ interface named IObjectContext. Another interesting point is that a class with a funny name implements this interface. This class is named Dummy30040732, and we're not kidding you. We didn't come up with that information by ourselves; our Rose model informed us when that information was imported from the type library. We're curious fellows, so we wanted to know more about this Dummy class. We created a new diagram, drew the Dummy class on it, and asked Rose to add all the closest neighbors of the class to the diagram. Figure 16-4 is what Rose came up with.

Looking at Figure 16-4, it's easy to see how this class with its understated name does quite a lot of the work of COM+ Component Services. It's also nice to know that we don't have to wrestle with the complexities of this class, only with the much simpler interfaces it implements. The same idea applies here as the one we put forward for our architecture in Chapter 9, "Using Separate COM Interfaces." Separate COM interfaces help achieve simplicity.

click to view at full size.

Figure 16-4. The Dummy30040732 class implements quite a few interfaces.

We won't go into the details of Figure 16-4; all we want to do is share this newfound knowledge with you. As COM+ developers, we work with simple interfaces. Behind the screen, objects with odd names perform all the services exposed by these interfaces. By the way, we're not going to ask to be excused for the funny (or not so funny) display of interface names in Figure 16-4—the way those names are spread over two lines without hyphens and without structure. If anyone should ask to be excused for that, Rational should. It's just not possible to influence the way names of classes, interfaces, and other objects are displayed in a Rose diagram such as Figure 16-4. The only way to have the names of such a diagram come out nicely is to expose all the methods of each interface (which would make the diagram completely unreadable and uninteresting) or to change the size of the icons (which in this diagram would mean making the interface icons into giant rings). Here's room for improvement!

Going back to Figure 16-3, you can easily see that nothing has changed since MTS. All the same methods are exposed in the context object of COM+ as in the context object of MTS. But there's one very important difference, not visible in the diagram; this difference concerns the CreateInstance method.

The CreateInstance method

In MTS, it was very important to use the CreateInstance method when creating other MTS objects. You might recall from Chapter 14, in the section "Creating Other MTS Objects," that one object installed in an MTS package must use the CreateInstance method to create other objects installed in an MTS package. Here's an example, taken directly from Chapter 14, of such code:

 If mblnInMTS Then Set objADOSrvcs = _ mobjCTX.CreateInstance("RaceDataAccess.RaceADOSrvcs") Else Set objADOSrvcs = CreateObject("RaceDataAccess.RaceADOSrvcs") End If 

The preceding code reveals that MTS objects use CreateInstance to create other objects. Ordinary COM objects, not installed in MTS, use CreateObject. In COM+, you don't have to deal with this complexity; the following code creates exactly the same result as the preceding code did in MTS:

 Set objADOSrvcs = CreateObject("RaceDataAccess.RaceADOSrvcs") 

The more complicated MTS code works in COM+ too, but in COM+ you don't need the extra complexity. In COM+, it's perfectly natural for an object to share the same context as the object creating it. In "old" COM, it isn't because object context isn't a natural thing for a COM object. If an MTS object needs to create another MTS object and also needs to share its context with that object, it must use the CreateInstance method. Otherwise, the newly created object will live in its own context.

In COM+, all this is changed. Every object in COM+ lives in a context. If no COM+ application is involved in the processing, every COM+ object created lives in the context of the thread on which the object is created. If one COM+ object installed in a COM+ application uses CreateObject to create another object, COM+ will create the new object in the same context as the one creating it. It's completely natural and completely automatic. It doesn't even matter if the object created has never been installed in a COM+ application; it's still created to run in the same context as the one creating it.

Mind you, your old MTS code, using the CreateInstance method, still works in COM+. There's no need to take it away from existing components. But there's also no need to use it in new components.

The SetComplete and SetAbort methods

We've already talked about the IObjectControl interface in this chapter, but we need to return to it here so that we can explain why you need to call SetComplete or SetAbort to make MTS or COM+ take back and recycle all the resources used by a certain object. In MTS, it's important to find out whether the object in question really runs in MTS before making the call. If the object doesn't run in MTS, the call fails and causes a Visual Basic error (if, as we assume, you write your components in Visual Basic). Hence code like the following:

 Public Sub Save(rs As Recordset) Dim objADOSrvcs As RaceADOSrvcs On Error GoTo SaveErr  If mblnInMTS Then mobjCTX.SetComplete Exit Sub SaveErr:  If mblnInMTS Then mobjCTX.SetAbort Err.Raise Number:=Err.Number, Source:=Err.Source, _ Description:=Err.Description End Sub 

In COM+, you can make this code simpler, as we showed you earlier in this chapter. You don't have to check to see whether the object runs in COM+ before calling SetComplete or SetAbort, so you don't need to use the mblnInMTS variable (or a corresponding COM+ variable). Here's an example of COM+ code, simplified as described:

 Public Sub Save(rs As Recordset) Dim objADOSrvcs As RaceADOSrvcs On Error GoTo SaveErr  GetObjectContext.SetComplete Exit Sub SaveErr:  GetObjectContext.SetAbort Err.Raise Number:=Err.Number, Source:=Err.Source, _ Description:=Err.Description End Sub 

The AutoCommit and AutoAbort methods

You can make the preceding code even simpler in COM+. As you might recall from Chapter 14, every method in an MTS component must make a call to MTS to report the outcome of the method's work. Four different messages could be sent to MTS: SetComplete, SetAbort, EnableCommit, and DisableCommit. Of these, EnableCommit was the default message. If your method doesn't call any of the methods just mentioned, MTS acts as if EnableCommit was called.

In COM+, objects can be made to call SetComplete or SetAbort by default rather than calling EnableCommit by default. All you have to do is set a property on the component, as shown in Figure 16-5. When you mark a method for automatic deactivation, as in the figure, the method automatically calls SetComplete after a successful operation and SetAbort after a failure. For example, if the method throws a Visual Basic error, it also calls SetAbort; otherwise, it calls SetComplete.

Figure 16-5. COM+ automatically calls the SetComplete or SetAbort method and deactivates this object when the Save method is done.

Security Roles at the Method Level

As we explained in Chapter 9, both MTS and COM+ support role-based security. Both let you define roles at the application level, which in MTS is the package level and in COM+ is the COM+ application level. At deployment time, you make existing user accounts and group accounts members of roles. Only users that are members of at least one of the security roles defined for a package or an application can access the components installed in that package or application. As a matter of fact, we shouldn't say users; we should say clients. Some clients, such as Sten and Per, would be normal users, people made of flesh and bone. Other clients, such as the impersonal user running the facade COM+ application under its own user account, would be applications. So for the rest of this section, we'll talk about clients rather than users.

For a component, you can select one or more of the roles already defined on the package or application level. This allows you to manage security differently for the different components installed in the same application. A specific client might be permitted to access component A but not component B in the same application. The setting of roles for applications and components and the setting of user account membership of roles are entirely declarative and administrative. You don't have to supply any code for this functionality.

A component such as component A, mentioned in the preceding paragraph, can expose more than one interface. MTS and COM+ both let you define roles at the interface level as well. This means that the client we talked about in the preceding paragraph, the one that was permitted to access the A component, might have permission to do so through one of that component's interfaces only. You can use this capability to set up a fine-grained permission filter for a component without having to create any code for it. For example, a HorseManager component might expose some of its functionality through an interface that the Customer Facades application is permitted to use, and other parts of its functionality through another interface that doesn't accept calls from the Customer Facades application. As with the roles defined on the component level, using this capability to control permission on the interface level doesn't require any special security code. But it does require a design effort. When designing the component and its interfaces, you must consider security. You must expose the functionality of the component through interfaces created primarily for the purpose of controlling security. Changes in security policy require changes in design. If it turns out to be improper to allow a certain class of clients access to a certain method and if this method already is in an interface this class of clients has access to, you must remove that class of clients from the access profile of that interface. You must also create a new interface containing only the methods these clients should still be able to access, and you must modify the component to implement that interface as well.

In COM+, you don't have to create that new interface or modify that component. This is because COM+ lets you set security roles at the method level too. Rather than having to create the new interface, modify the component, and redeploy it, all you have to do is change the role setting of the method you want to make inaccessible for that client. Role support at the method level might seem a small improvement, but in many installations, especially large installations, it might save quite a lot of work. Don't forget that the changes described in the preceding paragraph make it necessary to modify client programs as well; because the original interface is made inaccessible to the members of the role affected, client programs must be changed to access the still-available functionality through a different interface. Changing security at the method level doesn't have this consequence.



Designing for scalability with Microsoft Windows DNA
Designing for Scalability with Microsoft Windows DNA (DV-MPS Designing)
ISBN: 0735609683
EAN: 2147483647
Year: 2000
Pages: 133

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net