Bug 266723 - [Discovery] specify how clients can determine service uniqueness
Summary: [Discovery] specify how clients can determine service uniqueness
Status: RESOLVED FIXED
Alias: None
Product: ECF
Classification: RT
Component: ecf.discovery (show other bugs)
Version: 3.0.0   Edit
Hardware: All All
: P3 major (vote)
Target Milestone: 3.0.0M6   Edit
Assignee: Markus Kuppe CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 207089 266595
Blocks:
  Show dependency tree
 
Reported: 2009-03-02 12:43 EST by Scott Lewis CLA
Modified: 2015-07-24 18:43 EDT (History)
2 users (show)

See Also:


Attachments
v1 (126.36 KB, patch)
2009-03-09 13:35 EDT, Markus Kuppe CLA
no flags Details | Diff
mylyn/context/zip (27.69 KB, application/octet-stream)
2009-03-10 12:07 EDT, Markus Kuppe CLA
no flags Details
Added convenience methods to ServiceIDFactory.createServiceTypeID (5.13 KB, patch)
2009-03-10 17:06 EDT, Scott Lewis CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Scott Lewis CLA 2009-03-02 12:43:05 EST
Currently, the ECF discovery API does not specify how discovered services can be reliably determined to be unique.  In general, clients (i.e. those that are discovering services via ECF IDiscoveryLocator) need to be able to reliably determine from the information in the events whether a serviceDiscovered/undiscovered notification is in reference to an existing service, or a new service.
Comment 1 Scott Lewis CLA 2009-03-02 12:46:52 EST
One possible approach

1) Provider ContainerIDs are unique (as they already are/should be)
2) For clients using CompositeDiscoveryContainer, the IServiceEvent.getLocalContainerID() is specified to return the *originating* containerID (i.e. jmdns or jslp) rather than the CompositeDiscoveryContainer.getID().  This is a change from existing approach, I believe.
3) *Within* the context of a given containerID (i.e. the result of 2), IServiceIDs are considered/enforced to be unique.
Comment 2 Scott Lewis CLA 2009-03-03 12:53:37 EST
DNS-SD spec:

http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt

<quote>
In summary: The user-visible name is the primary identifier for a
   service. If the user-visible name is changed, then conceptually
   the service being offered is a different logical service -- even
   though the hardware offering the service stayed the same. If the
   user-visible name doesn't change, then conceptually the service being
   offered is the same logical service -- even if the hardware offering
   the service is new hardware brought in to replace some old equipment.
</quote>

So with zeroconf, the implication for us is that IServiceIDs uniquely identify the actual (remote) service.  This seems conceptually clean to me...discovery container ids restrict to a given discovery protocol (e.g. zeroconf, slp, etc), while the IServiceID uniquely identifies the service/service info published by that discovery mechanism.  I think it would make sense to define the JSLPID in a way that supports this basic approach (based upon what JSLP does/requires to uniquely identify a remote service...e.g. port on host).  Then clients (receivers of serviceDiscovered/undiscovered can depend upon a specific, clear semantics for uniqueness across all providers).  Just my thoughts about it.

The handling for the composite container has to be clarified, but I expect that the event.getLocalContainerID() could return the containerID of the *originating* mechanism/container.  If it's otherwise, we should probably specify that.

Then in the discovery view ui...I think it would be cool to have distinct service icons for slp/zeroconf...but even if we don't have these, I believe it should be possible to use the discovery container id in decisions about what to present (maybe this is already the case...I'm not sure).

My $0.03.
Comment 3 Markus Kuppe CLA 2009-03-09 13:35:11 EDT
Created attachment 128066 [details]
v1

Updated API, don't spare me with comments.
Comment 4 Markus Kuppe CLA 2009-03-09 13:38:15 EDT
Adding Christian, he might need to update Versant's providers.
Comment 5 Scott Lewis CLA 2009-03-09 13:55:43 EDT
(In reply to comment #3)
> Created an attachment (id=128066) [details]
> v1
> 
> Updated API, don't spare me with comments.
> 

Has this been committed to HEAD or just on the patch?
Comment 6 Markus Kuppe CLA 2009-03-09 14:16:15 EDT
No, it's not yet in HEAD. I'm waiting for (your) comments.
Comment 7 Scott Lewis CLA 2009-03-09 14:25:27 EDT
(In reply to comment #3)
> Created an attachment (id=128066) [details]
> v1
> 
> Updated API, don't spare me with comments.
> 

My comments.

1) Generally it looks good to me.  I think the simplification of the
ServiceInfo constructors (in particular) will make things much simpler.

2) I notice that you've left out the serviceName of the serviceid.  I was
thinking that the serviceid would consist (required) of URI and
IServiceTypeID...as you have it, but for those providers that actually *use*
the service name as the unique identifier (e.g. dns-sd) that the IServiceID
would include the service name... and so IServiceID would have both a
getLocation() (new) and a getServiceName() (deprecated in the patch). 
Providers of course implement the serviceid construction, so they can determine
at time of serviceID creation whether the data given (i.e. via the service info
constructor) is valid.

3) I guess if 2 were adopted the getServiceName() method on IServiceInfo would
be unnecessary, along with the getLocation() (i.e. both would be accessed via
the serviceid).

This seems to me pretty conceptually clean for a cross-provider API for unique
service id construction:  There are three things necessary for construction of
a serviceid...IServiceTypeID (unique service type), location/URI (opt),
serviceName (opt).  For those providers that use a non-human readable
identifier/URI for service uniqueness (slp), the service name is redundant, but
for those that use the service name as the unique identifier (dns-sd) the uri
is redundant...but across providers both types of info are required.  (and
providers can always throw an IDCreateException...I would also suggest having
ServiceInfo constructors declare throw IDCreateException (runtime exception so
clients don't have to catch, of course).

What do you think?

Comment 8 Markus Kuppe CLA 2009-03-09 15:51:13 EDT
(In reply to comment #7)

> 2) I notice that you've left out the serviceName of the serviceid.  I was
> thinking that the serviceid would consist (required) of URI and
> IServiceTypeID...as you have it, but for those providers that actually *use*
> the service name as the unique identifier (e.g. dns-sd) that the IServiceID
> would include the service name... and so IServiceID would have both a
> getLocation() (new) and a getServiceName() (deprecated in the patch). 
> Providers of course implement the serviceid construction, so they can determine
> at time of serviceID creation whether the data given (i.e. via the service info
> constructor) is valid.

What's the use case you want to solve by moving the serviceName into the serviceID? I see little gain and only woes with cross provider equality.
And even though Zeroconf mandates a service name to be unique, it buys us nothing by exposing this at the ECF discovery API level.

> 3) I guess if 2 were adopted the getServiceName() method on IServiceInfo would
> be unnecessary, along with the getLocation() (i.e. both would be accessed via
> the serviceid).

org.eclipse.ecf.discovery.ServiceInfo.getLocation() is a convenience method for consumers who don't care about service identity.

> This seems to me pretty conceptually clean for a cross-provider API for unique
> service id construction:  There are three things necessary for construction of
> a serviceid...IServiceTypeID (unique service type), location/URI (opt),
> serviceName (opt).  For those providers that use a non-human readable
> identifier/URI for service uniqueness (slp), the service name is redundant, but
> for those that use the service name as the unique identifier (dns-sd) the uri
> is redundant

It's not. You can't connect to a service name, but you can connect to an URI. On the other hand, the service name is great for UI. 

>...but across providers both types of info are required.  

Why? A service with address XYZ and type ABC will definitely be the same, independent of any service name.

> (and providers can always throw an IDCreateException...I would also suggest having
> ServiceInfo constructors declare throw IDCreateException (runtime exception so
> clients don't have to catch, of course).

The current implementation won't throw an IDCreateException. That is taken care of during IServiceTypeID creation already.
Comment 9 Scott Lewis CLA 2009-03-09 16:15:23 EDT
(In reply to comment #8)
> (In reply to comment #7)
<stuff deleted>
> 
> What's the use case you want to solve by moving the serviceName into the
> serviceID? 

Because some providers (e.g. dns-sd/zeroconf) *use* the serviceName as the service identifier.

>I see little gain and only woes with cross provider equality.

The provider has to implement IServiceID/create their own service ID type anyway...it doesn't seem to me much of an additional burden...and it certainly is/does become a burden for providers like dns-sd to implement IServiceID without serviceName.

> And even though Zeroconf mandates a service name to be unique, it buys us
> nothing by exposing this at the ECF discovery API level.

I disagree.  It makes things more consistent across providers...easing the burden of the clients that create URIs and service names.  In other words, it buys API usability...which will be important for adoption/usage (across providers).

> 
<stuff deleted>
> > a serviceid...IServiceTypeID (unique service type), location/URI (opt),
> > serviceName (opt).  For those providers that use a non-human readable
> > identifier/URI for service uniqueness (slp), the service name is redundant, but
> > for those that use the service name as the unique identifier (dns-sd) the uri
> > is redundant
> 
> It's not. You can't connect to a service name, but you can connect to an URI.
> On the other hand, the service name is great for UI. 

I think the main point here is that unique service identification (i.e. the semantics of IServiceID) should faithfully accomodate two different ways of identifying a service...i.e. with a user-provided 'service name' (ala dns-sd) and with a system-defined 'location' (ala slp).  I don't think it will improve usability of the API to favor one over the other (e.g. having a 'hidden' unique identifier rather/location rather than a user-visible name), so I think it makes sense to accomodate both...especially since it's not at all clear (to me) where/what approach will get the most adoption.  

Especially since the ServiceInfo constructors remain the same (which is now the main API for serviceID creation), I don't think this really creates any grief for clients...and only a very small amount of grief for the provider.

> 
> > (and providers can always throw an IDCreateException...I would also suggest having
> > ServiceInfo constructors declare throw IDCreateException (runtime exception so
> > clients don't have to catch, of course).
> 
> The current implementation won't throw an IDCreateException. That is taken care
> of during IServiceTypeID creation already.
> 

But it would be possible to have the service name be invalid (e.g. think of registering the name 'foo' with zeroconf twice)...and I would expect the provider to throw an IDCreationException in that case...inside the ServiceInfo constructor.  Again it might be helpful to use that API (those constructors) if the exception was explicitly declared.


Comment 10 Markus Kuppe CLA 2009-03-10 05:03:33 EDT
(In reply to comment #9)
> > What's the use case you want to solve by moving the serviceName into the
> > serviceID? 
> 
> Because some providers (e.g. dns-sd/zeroconf) *use* the serviceName as the
> service identifier.

This is no use case at the ECF discovery API level. Unless your intent is to expose provider specifics.

> and it certainly
> is/does become a burden for providers like dns-sd to implement IServiceID
> without serviceName.

There is a service name. It's just not part of ECF's definition of uniqueness. If the Zeroconf provider wants to use it, that's not a problem.

> > And even though Zeroconf mandates a service name to be unique, it buys us
> > nothing by exposing this at the ECF discovery API level.
> 
> I disagree.  It makes things more consistent across providers...easing the
> burden of the clients that create URIs and service names.

Do you have a code example? I don't get why this makes it easier (and more consistent) for a consumer.

> I think the main point here is that unique service identification (i.e. the
> semantics of IServiceID) should faithfully accomodate two different ways of
> identifying a service...i.e. with a user-provided 'service name' (ala dns-sd)
> and with a system-defined 'location' (ala slp).  I don't think it will improve
> usability of the API to favor one over the other (e.g. having a 'hidden' unique
> identifier rather/location rather than a user-visible name), so I think it
> makes sense to accomodate both...especially since it's not at all clear (to me)
> where/what approach will get the most adoption.  

In general IMO two different semantics for service uniqueness make things harder for consumers as well as providers. You have to check which semantics apply when and provide mapping to the other one.

On top of that it creates inconsistencies at the ECF discovery API layer. That is, with an URI (+ type) based ID, consumers are notified if services change locations (and can properly reconnect). With Zeroconf's definition this is not the case anymore. Because the ID does not change, the JmDNS container would not fire service undiscovery/discovery (rediscovery) events resulting in a stale service reference at the application layer. 
This is being dealt with in the Zeroconf spec by assigning a TTL of 2 minutes to SRV types. But ECF discovery does not define TTLs for IServiceInfo, thus this identity definition is incompatible.

That said, I even question if the semantics are that different anyway. In Zeroconf, services with different URIs will always have different service names too (but same type), otherwise you get a collision on the wire. A service name is nothing but a pretty printed version of an URI which is easier for a human to remember/work with [2]. Given, the underlying URI might change over time, but there will never be two URIs for one service at the same time.

Thus using the URI and service type is not favoring one over the other, but using the common denominator.

As a compromise, why not delegate provider specific uniqueness to the corresponding Namespace. Letting consumers use provider specifics if they need to. Meaning:

At the ECF discovery API level two services are the same if 
anURI1.equals(anURI2) && aIServiceTypeID1.equals(aIServiceTypeID2). 

But e.g. the JmDNS provider's Namespace redefines uniqueness to be aSericeInfo1.getServiceName().equals(aServiceInfo2.getServiceName()) && aServiceTypeID1.equals(aServiceTypeID2).

Scott, would you be able to provide a patch for this?

> But it would be possible to have the service name be invalid (e.g. think of
> registering the name 'foo' with zeroconf twice)...and I would expect the
> provider to throw an IDCreationException in that case...inside the ServiceInfo
> constructor.  Again it might be helpful to use that API (those constructors) if
> the exception was explicitly declared.

) The collision cannot be detected during ServiceInfo creation. I can only occur at registration.

b) If there is a collision on the Zeroconf layer, let the provider deal with it (e.g. transfer the service name as part of the service property/make it unique by adding random chars/throwing an Exception¹...). 

¹ An IDCreateException does not make sense when service name is not part of the ID. ;-)

[1] http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt section 4.4 page 8 
Comment 11 Scott Lewis CLA 2009-03-10 11:07:47 EDT
(In reply to comment #10)
> (In reply to comment #9)
> > > What's the use case you want to solve by moving the serviceName into the
> > > serviceID? 
> > 
> > Because some providers (e.g. dns-sd/zeroconf) *use* the serviceName as the
> > service identifier.
> 
> This is no use case at the ECF discovery API level. Unless your intent is to
> expose provider specifics.


I think it is a use case at the ECF discovery API level, because although I don't want to expose provider specifics, I also don't want service identity to be bound to single approach (opaque, non-user meaningful identifiers).  This seems to me a fairly fundamental aspect of a discovery mechanism...i.e. whether the service identity is defined by a human readable service name (or not).  I don't think we can come create a multi provider API that really 'decides' one way or another...as it's still a matter of adoption as to which will gain wider adoption (and, in fact, both approaches may get adoption for different reasons).

> 
> > and it certainly
> > is/does become a burden for providers like dns-sd to implement IServiceID
> > without serviceName.
> 
> There is a service name. It's just not part of ECF's definition of uniqueness.
> If the Zeroconf provider wants to use it, that's not a problem.

Yes, I know...but why the resistance to having IServiceID expose a service name and a URI rather than service info?  As you point out, the equals and hashcode impl can be based upon anything the provider defines (location, service name, both, etc).  I think it's conceptually simpler to have the IServiceID include this access rather than have it spread around.

<stuff deleted>
> 
> In general IMO two different semantics for service uniqueness make things
> harder for consumers as well as providers. You have to check which semantics
> apply when and provide mapping to the other one.

No you don't.  Since the IServiceID.equals and hashcode impls define the uniqueness of the associated service, all you do is call IServiceID.equals(other).

As you've defined it,to create a ServiceInfo requires a non-null URI, a non-null service name and a non-null IServiceTypeID, making the service id instance is now opaque to the client (which is good, I think).  The only thing in question is how the URI, service name, and type id are accessed by a) the holder of the serviceInfo; b) by clients.  I think it would be conceptually simpler to have consistent access to all three of these 'identity relevant' pieces of info.  Actually this makes me realize...perhaps the getServiceName() and getLocation could be on both the IServiceID and the IServiceInfo?  They return the same thing, after all.

<stuff deleted>

> As a compromise, why not delegate provider specific uniqueness to the
> corresponding Namespace. Letting consumers use provider specifics if they need
> to. Meaning:
> 
> At the ECF discovery API level two services are the same if 
> anURI1.equals(anURI2) && aIServiceTypeID1.equals(aIServiceTypeID2). 
> 
> But e.g. the JmDNS provider's Namespace redefines uniqueness to be
> aSericeInfo1.getServiceName().equals(aServiceInfo2.getServiceName()) &&
> aServiceTypeID1.equals(aServiceTypeID2).

Yes, I agree...it's been my intention throughout this discussion that the providers implement uniqueness (in terms of equals/hashcode) in their own 'preferred' way...but to do this, won't they need to have all three pieces of information (i.e. IServiceTypeID, service name, URI) passed in upon construction?

> 
> Scott, would you be able to provide a patch for this

Yes, but not right away.  I'm sort of strapped today (Tues).

> 
> > But it would be possible to have the service name be invalid (e.g. think of
> > registering the name 'foo' with zeroconf twice)...and I would expect the
> > provider to throw an IDCreationException in that case...inside the ServiceInfo
> > constructor.  Again it might be helpful to use that API (those constructors) if
> > the exception was explicitly declared.
> 
> ) The collision cannot be detected during ServiceInfo creation. I can only
> occur at registration.
> 
> b) If there is a collision on the Zeroconf layer, let the provider deal with it
> (e.g. transfer the service name as part of the service property/make it unique
> by adding random chars/throwing an Exception¹...). 
> 
> ¹ An IDCreateException does not make sense when service name is not part of the
> ID. ;-)


I'm don't think this is right.  In general, when any provider creates IServiceIDs it's possible to have a name conflict whether the service name is there or not (e.g. using the same URI to register two different services).  If the provider detects the name conflict and wishes to prevent registration of a conflicting name, how is it supposed to do it?   I suppose what we have now is that the registerService(serviceInfo) just silently fails.  



Comment 12 Markus Kuppe CLA 2009-03-10 11:19:05 EDT
(In reply to comment #11)
> it's been my intention throughout this discussion that the
> providers implement uniqueness (in terms of equals/hashcode) in their own
> 'preferred' way...but to do this, won't they need to have all three pieces of
> information (i.e. IServiceTypeID, service name, URI) passed in upon
> construction?

And that is the opposite of the design I have been working on for around the last year or so. At the ECF discovery API level there should only be one definition of uniqueness.

So where do we go from here with two mutual exclusive design directions?
Comment 13 Markus Kuppe CLA 2009-03-10 12:07:15 EDT
Released patch to HEAD
Comment 14 Markus Kuppe CLA 2009-03-10 12:07:19 EDT
Created attachment 128222 [details]
mylyn/context/zip
Comment 15 Markus Kuppe CLA 2009-03-10 12:08:25 EDT
Comment on attachment 128066 [details]
v1

Patch released to HEAD
Comment 16 Scott Lewis CLA 2009-03-10 13:36:19 EDT
(In reply to comment #12)
> (In reply to comment #11)
> > it's been my intention throughout this discussion that the
> > providers implement uniqueness (in terms of equals/hashcode) in their own
> > 'preferred' way...but to do this, won't they need to have all three pieces of
> > information (i.e. IServiceTypeID, service name, URI) passed in upon
> > construction?
> 
> And that is the opposite of the design I have been working on for around the
> last year or so. At the ECF discovery API level there should only be one
> definition of uniqueness.
> 
> So where do we go from here with two mutual exclusive design directions?
> 

I don't think they are mutually exclusive.  I think both can be accomodated by including both URI and serviceName in the construction of IServiceID instances and the accessors for same on IServiceID.  I think they both should be accomodated, as the model you've apparently been working from (opaque URI that uniquely identifies service...ala jslp) isn't sufficiently general IMHO...i.e. to accomodate the notion of a service name that defines uniqueness withing a given type.  Although this is what zeroconf/dns-sd does, I doubt it will be the last one.

I don't think this has to be a big deal.  I don't see the harm in accomodating both...as if ID construction is done via the ServiceInfo constructors (the usual case, right)?  And the ServiceInfo has all three pieces of info...what's really the conflict here?  We're completely in agreement that the serviceID implementer (provided by provider) will implement IServiceID.equals and hashCode in the way that the given provider actually determines uniqueness (i.e. via URI in case of jslp and service name for jmdns).

So I sort of fail to see what the design conflict is here Markus.  I think we're only actually discussing two things:

1) What accessor methods are on IServiceID and IServiceInfo.
2) Whether there are 3 args (in addition to 2) in the namespace.createInstance(args) call inside ServiceInfo constructor.

Do I misunderstand?





Comment 17 Scott Lewis CLA 2009-03-10 14:20:20 EDT
(In reply to comment #15)
> (From update of attachment 128066 [details])
> Patch released to HEAD
> 

I see that you released the changes without support for getServiceName() in IServiceID.  I disagree with leaving this support out, as I think it places an overly restrictive notion of IServiceID on providers, but since ServiceInfo is now primarily responsible for creating serviceID instances and IServiceInfo is exposed to all clients it's obviously not a huge deal.

For the record, I don't think this is a good choice at the API level...particularly given the relative ubiquity of providers like zeroconf relative to slp, but I consider it your (Markus') decision to make.  

I guess in summary I don't think it's every a great idea to try to impose a single model of how things should work (however conceptual clear to you/me) on a rather ugly/messy (but functional) world.  



Comment 18 Markus Kuppe CLA 2009-03-10 16:51:36 EDT
(In reply to comment #17)
> (In reply to comment #15)
> > (From update of attachment 128066 [details] [details])
> > Patch released to HEAD
> > 
> 
> I see that you released the changes without support for getServiceName() in
> IServiceID.  I disagree with leaving this support out, as I think it places an
> overly restrictive notion of IServiceID on providers, but since ServiceInfo is
> now primarily responsible for creating serviceID instances and IServiceInfo is
> exposed to all clients it's obviously not a huge deal.

I had to offload my patch somewhere as it became unmanageable because of other changes.

No reason to close this one prematurely.
Comment 19 Scott Lewis CLA 2009-03-10 17:06:22 EDT
Created attachment 128279 [details]
Added convenience methods to ServiceIDFactory.createServiceTypeID

Here are two suggested convenience methods on ServiceIDFactory.  Might make the usage simpler in the common cases.

Comments appreciated...or if not appropriate/desired that's fine too...I don't have a lot of investment in this code :).
Comment 20 Markus Kuppe CLA 2009-03-11 02:47:04 EDT
What kind of syntax does the createServiceTypeID(Namespace namespace, String serviceType) accept? Just the service type like "http", "osgiservices" and protocol, scope etc fall back to defaults?
Comment 21 Scott Lewis CLA 2009-03-11 11:11:57 EDT
(In reply to comment #20)
> What kind of syntax does the createServiceTypeID(Namespace namespace, String
> serviceType) accept? Just the service type like "http", "osgiservices" and
> protocol, scope etc fall back to defaults?
> 

Yes, that's the intention.
Comment 22 Markus Kuppe CLA 2009-03-11 11:25:25 EDT
patch released to HEAD
Comment 23 Scott Lewis CLA 2015-07-24 18:43:47 EDT
apparently fixed long ago.