Community
Participate
Working Groups
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.
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.
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.
Created attachment 128066 [details] v1 Updated API, don't spare me with comments.
Adding Christian, he might need to update Versant's providers.
(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?
No, it's not yet in HEAD. I'm waiting for (your) comments.
(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?
(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.
(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.
(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
(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.
(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?
Released patch to HEAD
Created attachment 128222 [details] mylyn/context/zip
Comment on attachment 128066 [details] v1 Patch released to HEAD
(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?
(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.
(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.
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 :).
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?
(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.
patch released to HEAD
apparently fixed long ago.