[TransWarp] Peer service discovery in PEAK

Phillip J. Eby pje at telecommunity.com
Wed Jul 23 17:56:19 EDT 2003

There is an interesting commonality between 1) the problem of mapping pure 
domain components to absolute URLs in a web application, and 2) the problem 
of finding a DM for a class, or finding a particular kind of DM in relation 
to another DM.

In both cases we can view this as an issue of "service discovery".  In 
existing PEAK architecture, services are registered as providers within a 
certain hierarchy of components, using interfaces or property names as 
keys.  This registration is generally done either through configuration 
files, or by classes defining bindings with 'offerAs' settings.

This approach works well for services that need to be "broadcast" to an 
"area" of components, the component doing the offering knows that its 
children need it, and there is a "natural" key shared by the offering 
component and the client components.  For services like 
storage.ITransactionService, the interface itself is such a natural key, 
because transaction services are implicitly singletons within their 
offering scope.  (IOW, no component reasonably needs to "acquire" more than 
one transaction service.)

For other services, such as DMs, there is no "natural" key available, 
forcing one to create various "artificial" keys, either by using component 
paths (and thus forcing a particular shape on the component hierarchy) or 
creating new interfaces and/or property names.  These artificial keys are 
awkward, because they are a convention that must be understood and used by 
both the supplier and client.

In very early versions of PEAK and TransWarp, there was a mechanism whereby 
components automatically offered themselves as a provider of any interface 
they implemented.  This wasn't a good idea, because in effect, the keys 
used were too generic.  Interfaces by themselves aren't that useful in the 
general case of service discovery.  For example, knowing that you have a 
storage.IEntityDM doesn't tell you much.  What class(es) does it serve?

In essence, the issue is one of service "parameters".  We need to be able 
to identify a service in terms of (for example) an interface and a class, 
or an interface and a class and a flag, or who knows what else, 
exactly.  We also probably need to be able to search for a service without 
necessarily having an exact key match.  For example, maybe searching for a 
I_DM for class Foo, should be able to return an IWritableDM for class Bar, 
if IWritableDM subclasses I_DM and Foo subclasses Bar.  (It's not 
immediately clear to me if this is literally the case.)

Another issue with the current mechanism is that it's strictly a 
centralized mechanism.  That is, peer components can't find each other 
unless mediated by one of their parents.  And components don't offer 
services to their parents, unless the parent specifically commissioned them 
for a particular task.

But if we did allow components to broadcast suitably parameterized 
"offerings", how far should they be broadcast?  Does a component register 
with all its parents?  What if more than one component exists for the 
function within the same "scope"?

Some forces in play:

* Laziness: we don't want components to have to exist from the start of an 
application; this could potentially be expensive.  But, for DMs this may 
not be *too* expensive, since mere instantiation of a DM isn't that 
expensive.  We also don't want to have to import all an application's 
domain classes at startup, since importing a module is even more 
expensive.  We can probably work around this latter issue using 
'whenImported()' to do registrations once the domain-class modules are 

* Composability: we want to be able to build new applications from pieces 
of the old.  Thus, even when determining "absolute" locations of things, we 
don't want this hardcoded in the components.  Also, if we have things like 
a peer service location system, we need to avoid "pollution" between 
contexts.  So how high up do you send a notification of service availability?

After talking this over with Ty a bit, it seems to us that what we should 
do for now is implement specific "discovery" services for specific tasks, 
and not try to create a general mechanism yet.  We need to implement a few 
of these before we'll know the general scope of them.

The two specific discovery services we need at present are discovery of 
certain kinds of DM by the class(es) they serve, and the discovery of 
specialists, also by a class served.  A third kind we've tentatively 
identified is peer DOMlet discovery, to allow DOMlets in a page to 
advertise services to each other.  But we don't have enough specific 
details yet, just some vague scenarios we thought of while going through 
our existing apps with interesting forms.  (E.g. forms that let you move 
items between two lists, that let you edit an outline, etc.)

None of these services is critical right now; they are just 
ease-of-development issues.  This e-mail is just to keep a record of the 
concepts for when we get to implementing them.

More information about the PEAK mailing list