Proposal for LC73/LC75n (multiple interfaces for a service)

After giving more consideration to LC73 [1] and LC75n [2], following
conversations with some of our folks and stimulated by Rich Salz's article
and comments [3], we'd like to propose to (re-)introduce the ability for
a service to implement multiple interfaces.



A first motivation is to allow the definition of management endpoints on a service.

With the present state of the spec, WSDL authors would either be forced to define
a completely separate service and express (currently in a non-standard way) its
relationship to the original one, or define an interface that extends the normal
interface of the service plus the management one.

Here's an example of the former approach:

  <wsdl:service name="FooService"
                interface="myns:foo">

      <!-- a SOAP endpoint -->
      <wsdl:endpoint name="SoapEndpoint"
                     binding="myns:MyGenericSoapBinding"
                     address="..."/>

      <!-- an alternate endpoint, this time using XML/HTTP -->
      <wsdl:endpoint name="XmlHttpEndpoint"
                     binding="myns:MySpecializedXmlHttpBinding"
                     address="..."/>
  </wsdl:service>

  <wsdl:service name="FooManagementService"
                interface="wsmg:ServiceManager"
                somens:relatesTo="myns:FooService">

      <!-- a management endpoint -->
      <wsdl:endpoint name="ManagementEndpoint"
                     binding="wsmg:SoapManagementBinding"
                     address="..."/>
  </wsdl:service>

Although it would be possible to define a new component in WSDL with the desired
semantics (a "service group" maybe?), we believe that the common case is one
where a service is exposing different interfaces to different classes of users.
Consequently, it is desirable to use the term "service" to denote such an entity.

The other approach, i.e. interface inheritance, is not the right solution in this case.

WSDL authors shouldn't be forced to bind all the operations in a giant "Foo+ServiceManager"
interface for every endpoint that they expose, especially considering that
management operations are likely to require different protocols/features/modules
than ordinary ones. Also, this complexity might well leak onto the client,
affecting client developers even if they are not in the least interested in
using the management functionality.

As mentioned in [1], other WS-specifications define a number of additional
interfaces that a service might want to implement (e.g. WS-MetadataExchange,
WSRP). They raise issues similar to those described above wrt to Web services
management, and none of them is more amenable to the use of interface inheritance.



A different motivation is given by versioning.

Although it is theoretically possible to create a new version an interface by
extending an old one, such an approach turns out to be severely impractical.

First of all, it's impossible to redefine an operation in a derived interface,
e.g. to expand the set of allowed incoming messages. Thus, fine-grained,
schema-based approaches to provide versioning are killed right from the start.

Furthermore, interfaces are not the only consideration. Existing clients of
a web service will be using one or more endpoints and their bindings.

Extending an old endpoint E implementing base interface I1 to support a new
operation defined in a derived interface I2 requires extending the binding
for I1 used by E so as to cover all of I2. In turn, this may require some
serious tinkering to the binding itself. E.g. the WSDL author would like
to use different SOAP modules, or features, for the new operations but
not the old ones

But clearly forcing a WSDL document to be heavily modified even in relatively
simple versioning scenarios is unnecessarily complicated and even dangerous,
as it may expose latent bugs in the WSDL processing library used by the clients.



Our argument then is that there are at least two important scenarios which
are pretty poorly served by the current WSDL 2.0 specification. We claim
then that (re-)introducing the ability for a service to implement multiple
interfaces would go a long way in addressing them.

Additionally, motivations based on toolability and backward compatibility
with WSDL 1.1 are hinted at in [2]. We won't elaborate on them further
here, but we believe that indeed they do provide additional arguments
for supporting multiple interfaces on a service.

We should also point out that, unlike [3], we are not proposing to remove
interface inheritance. Inheritance has its uses and it's the correct approach
in many cases. Furthermore, removing inheritance and replacing it with
copy-and-paste of faults and/or operations would obliterate the "extends"
relationship between interfaces, resulting in a net loss to WSDL users.



After this lengthy introduction, here is the detailed proposal.

Service changes:

  (1) remove the {interface} property from the Service component;

  (2) remove the @interface attribute from the wsdl:service element;

  (3) remove the constraint that all endpoint components in the {endpoints}
      property of a service component contain only bindings with an unspecified
      interface or bindings with the same interface as the service; ((note:
      for some reason, this constraint appears in section 2.14.1 instead of
       2.13.1 where it belongs))

  (4) change the first paragraph of 2.13.1 to say that "endpoints that
      implement the same interface are in effect alternate places at which
      the service provides the functionality described by that interface";
      ((note: I haven't found any stronger statements in the spec of the fact
      that different endpoints in a service are "equivalent". Is this a bug?))

Endpoint changes:

  (5) add a REQUIRED {interface} property to the Endpoint component;

  (6) introduce an optional @interface attribute on the wsdl:endpoint element;

  (7) change the definition of the {address} property of the Endpoint component
      to refer to the {interface} property on the same component (introduced in (5));

  (8) add the following XML mapping rules:

       - if the @interface AII is present, then either the binding doesn't
         specify an interface or it specifies the same one; in either case, the
         value of the {interface} property of the endpoint component is the
         Interface component referenced to by the (value of the) @interface AII;

       - if no @interface AII is present, then the binding must specify an
         interface; that interface becomes the value of the {interface} property
         of the endpoint component;

Here's the updated pseudo-schema for the wsdl:service element:

  <service name="xs:NCName">
    <documentation />?

    <endpoint name="xs:NCName" binding="xs:QName" interface="xs:QName"? address="xs:anyURI"? >
      <documentation />?

      <feature ... />*

      <property ... />*
    </endpoint>*

    <feature ... />*

    <property ... />*
  </service>*



As an example, here's a WSDL snippet using the new syntax:

  <wsdl:service name="FooService">

      <!-- a SOAP endpoint for the Foo interface -->
      <wsdl:endpoint name="SoapEndpoint"
                     interface="myns:Foo"
                     binding="myns:MyGenericSoapBinding"
                     address="..."/>

      <!-- an alternate endpoint for the Foo interface, this time using XML/HTTP -->
      <wsdl:endpoint name="XmlHttpEndpoint"
                     binding="myns:MySpecializedXmlHttpBinding"
                     address="..."/>

      <!-- a management endpoint for the service -->
      <wsdl:endpoint name="ManagementEndpoint"
                     interface="wsmg:ServiceManager"
                     binding="wsmg:SoapManagementBinding"
                     address="..."/>

      <!-- a new version of the Foo interface, labeled "Foo2" -->
      <wsdl:endpoint name="SoapEndpoint"
                     interface="myns:Foo2"
                     binding="myns:MyGenericSoapBinding"
                     address="..."/>

  </wsdl:service>

where the "myns:MySpecializedXmlHttpBinding" binding is defined as follows:

  <wsdl:binding name="MySpecializedXmlHttpBinding"
                interface="myns:Foo"
                type="...">
      ...
  </wsdl:binding>

The "FooService" above exposes two endpoints supporting the "Foo" interface.
It also offers a "ServiceManager" interface for management purposes. Finally,
it offers an endpoint for a new interface, "Foo2", which extends "Foo".

Although "Foo2" is a new version of "Foo", it's valuable to be able to keep
it separate so as to minimize the impact on clients. It's worth noting that,
although in this example we use the "myns:myGenericSoapBinding" for the endpoints
for both versions, the only requirement is that the binding for the endpoint
corresponding to the new version be compatible with the one used by the old one.
In more advanced versioning scenarios, "Foo2" could differ more substantially
from "Foo", even in ways that would prevent using interface inheritance altogether.
Still, we claim that "Foo2" has every right to be seen as an interface offered
by "FooService" as "Foo" itself, and it shouldn't be relegated to a separate
service.



The changes listed above are pretty much the  minimal set of changes that
would provide the desired result, i.e. allowing a service to implement multiple
interfaces all while making it clear that endpoints that implement the same
interface are simply different access paths to the same service.

If this proposal is accepted, then we'd like the working group to entertain the
possibility of changing the syntax to be more readable.

In particular, consider that a service would be offering a number of interfaces
in parallel ("I expose Interface1 AND Interface2 AND Interface3"), and for
each interface it'd offer a number of equivalent endpoints ("You can reach me
at EndpointA OR EndpointB OR EndpointC").

The following syntax might be more appropriate then:

  <wsdl:service name="FooService">

      <wsdl:interface ref="myns:Foo">
        <wsdl:endpoint name="SoapEndpoint"
                       binding="myns:MyGenericSoapBinding"/>
        <wsdl:endpoint name="XmlHttpEndpoint"
                       binding="myns:MySpecializedXmlHttpBinding"/>
      </wsdl:interface>

      <wsdl:interface ref="wsmg:ServiceManager">
        <wsdl:endpoint name="ManagementEndpoint"
                       binding="wsmg:SoapManagementBinding"/>
      </wsdl:interface>

      <wsdl:interface ref="myns:Foo2">
        <wsdl:endpoint name="SoapEndpoint"
                       binding="myns:MyGenericSoapBinding"/>
      </wsdl:interface>

  </wsdl:service>

This syntax would make it easier to figure out at a glance if a service
implements a given interface and which endpoints it offers, but it has
the drawback of requiring more extensive changes to the specification.

In the interest of not bogging down the discussion with syntactic issues,
we'd like to defer syntax enhancements to a later time, and focus for
the time being on the proposal as detailed above in points (1)-(8).

[1] http://www.w3.org/2002/ws/desc/4/lc-issues/#LC73
[2] http://www.w3.org/2002/ws/desc/4/lc-issues/#LC75n
[3] http://lists.w3.org/Archives/Public/public-ws-desc-comments/2004Nov/0018.html

Thanks,
Roberto

-- 
Roberto Chinnici
Java Web Services
Sun Microsystems, Inc.
roberto.chinnici@sun.com

Received on Tuesday, 23 November 2004 23:29:05 UTC