Let me confess to a glorious misconception early on in my career with MTS, to which I will own up, so that you don’t make the same mistake. The project on which I was working was a prototype implementation of a distributed object system. We decided to do the whole thing by the book, so we used an object-oriented design tool as the first step. We identified our data items, decided on some of the operations that we would carry out on them, fed them into the tool and turned the handle to generate the code stubs. The net result was a whole rat’s nest of object references inside object references, which we then went on to turn into COM objects. (To confuse matters further, we also isolated the COM layer from the underlying objects, so that we could put a CORBA wrapper round the objects as well — yep, it was one of those projects)
Of course, we knew that you could register any object with MTS and make it transactional, so we tried to do this with ours. You can guess what happened: we failed, miserably. Because our objects were so closely tied to their underlying data, they were all far too "stateful" for MTS to make any sense of them whatsoever. We had totally failed to understand the three-tier model. We had concentrated on the data, and we had completely ignored the processes.
What do I mean by stateful? A stateful object is one that maintains its state over a prolonged period of time. There's a spectrum of "statefulness" really. It stretches from objects that are just a collection of atomic methods that do a job and then return a result to the base client, and are then ready for the next call, to objects whose collective state is needed by the base client for some time (that is, over some method calls). If you want an example of a seriously stateful object, think back to our teleconferencing example in Chapter 2 — the conference objects can actually exist for quite a long period of time.
This is a good time to point out that, if you use stateful objects in MTS, you'll have to take some steps to ensure that the particular instances of the objects are retained for that base client. MTS doesn't guarantee that the business object instance it uses for a particular client won't change between two method calls. MTS is desperate to commit transactions wherever possible and get everything out of the way.
To put this in an example — imagine your MTS objects acquire their state from a persistent store when they are instantiated. Doing whatever validation it is that grown-up business objects do, they yield the relevant information to the base client that called them into existence. The base client information is updated (at typing and thinking speed) and then a different method of the client (behind the Submit button) calls the business objects with just those properties it's updated. Those objects then persist their state entire. But, by default, there's no reason that those business objects will be the same — cue potential embarrassment.
At the risk of running ahead of myself a little, let me tell you how you ensure MTS assumes nothing. You just call the
method of the context object, to set the objects' progress in the transaction to an indeterminate state while you make your various calls. The DisableCommit()
method re-enables the default.EnableCommit()
And to cap it all, the more state an object has, though, the greater the performance hit in MTS.
A better scenario under MTS is to use business objects that acquire data, analyze it, pass it on to the base client per their request, and then finish their job with a smile. When the base client wants to upload the modified data, the business objects are reinstantiated and do their updating stuff to the database.
I think we’re about ready to have a go at some MTS coding. Let’s have a look at the source of our
object.Negotiator