Web Service Versioning and Deprecation
Web Service Versioning and Deprecation
By: Jeffrey Kenyon
Jan. 21, 2003 12:00 AM
Current standards for SOAP, WSDL, and UDDI have no explicit support for the versioning and deprecation of Web services. This article introduces a means for Web service versioning and deprecation that is lightweight and flexible, and requires minimal development effort.
This approach is intended primarily for use within a corporation using one or more internal UDDI registries. It may be applied in the UDDI public registry "cloud," but only for controlling versioning and deprecation for Web services controlled by a single provider.
1. The ability for a consuming application to automatically determine and consume the most recent version of the Web service that supports the required functionality
Scenario: Web Service Developer
As part of the Web service development or deployment, the developer creates a WSDL (Web Service Description Language) file, describing the interface of the Web service. The developer registers this WSDL file as a TModel in an appropriate UDDI registry, with the Overview URL field in the TModel data structure pointing to the URL of the WSDL file.
If the deployed service is a new version of an existing service, it is registered as a new binding on the existing service, and that binding is linked to all the tModels it supports.
Scenario: Application Developer
The developer incorporates code to find a service binding dynamically, at application startup time (in lieu of looking up the access point from a configuration file, or hard-coding the value), at predetermined intervals, and/or in exception handling (i.e., when a Web service call fails). This code, taking as its argument a tModel key corresponding to the expected interface, searches for all services supporting the specified interface.
Should an application developer require a Web service binding, he or she searches by tModel key for the service bindings supporting that tModel (while it is possible to search by name, there is nothing preventing multiple tModels from all having the same name). For each service implementing that interface, the application retrieves the version information (using getVersion()) and selects the highest (i.e., most up-to-date) version of the Web service.
For example, take the following UDDI entry shown in Table 1.
An application programmed to use the interface described in Service 1 Interface would be able to use Service 1 v1.01 initially; when Service 1 v1.5.0 was released, the application would automatically begin using it (since it is the highest version supported by the required interface). When Service 1 v2.0 is released, the application will ignore it; even though it is the same service, it does not support the required interface.
Public Registry Applications
One issue is that of trust. In the world of public Web services, trust should be established prior to using a service:
Another issue that could arise when applying this strategy blindly within the public registry is that of multiple distinct services, from one or more providers, supporting the same interface. As a simple example, take an interface for retrieving stock quotations. On January 1, 2003, CompanyA releases version 1.0 of a service implementing the interface, and in April of the same year, follows up with version 1.5. In July, CompanyB releases version 1.0 of their service implementing the interface. Under the versioning strategy described, applications would continue to use CompanyA's version 1.5 service, despite the fact that CompanyB's service is actually the most recent version of the service implementing the interface. Version numbers are, and always have been, meaningless between software providers.
Versioning Code Walkthrough
First, assume the existence of a Web service supporting a getVersion message (see Listing 1). The values populated for major, minor, and patch are under the control of the Web service. Thus, the ability to allow the source code control system to supply the values returned by getVersion is totally under the control of the developer, and is dependent upon the programming language and source code control system chosen.
The code required to locate the binding(s) corresponding to the most recent version of the service is, unfortunately, rather complex when implemented directly in UDDI API v1.0 calls. The complexity is due to the API not supporting searches for services, across all businesses that support a given tModel. As a result, the code is somewhat clunky: we must retrieve a list of all businesses, then for each business, look at each service to discover whether there is a binding supporting the given tModel (represented below by the String tModelKey, containing a valid TModel key with the prefix "uuid:"). This complexity goes away with the UDDI API v2.0 (release version, not draft).
If the application developer is quite sure that he or she is interested only in services from a specific provider, he or she may optionally limit the search for bindings to that single provider (or to a pool of potential providers). While this would make the code considerably faster, the disadvantage is that if the service is shifted to a different provider, the service bindings would no longer be found. This particular disadvantage may be overcome by performing the wider search across all businesses only if the limited search fails (see Listing 2).
The BindingObj class holds the UDDI BindingTemplate instance, as well as storing the results of the getVersion() call on the access point named in the BindingTemplate (by storing the BindingObj in a Java TreeSet with a custom comparator used to sort based on version numbers, we avoid the need to do an explicit sort later).
The call to the Web service's getVersion() message is handled in the same way as a call to any other message in the service to be consumed. The developer should keep in mind that getVersion() returns a complex data structure of three integer values. As an example, when handling the response from a .NET service in Apache SOAP, it is necessary to explicitly deserialize the structure (see Listing 3).
The reference implementation provided with this article contains the full code examples (source code for this article can be found online at www.sys-con.com/webservices/sourcec.cfm).
When a specific tModel is to be taken out of service, its UDDI registry entry is modified to add the identifier DEPRECATED, with a value of the date (in YYYY/MM/DD format) after which the tModel is no longer supported. Optional identifiers are DEPRECATED_MSG, containing additional details on the deprecation, and DEPRECATED_ LINK, a URL to which users may refer for information that is more detailed.
To support deprecation, the application developer inserts a check into the service binding code; prior to looking for services that support the tModel, the tModel "identifierBag" data structure is checked for the DEPRECATED flag and value. There are three possible outcomes to this check:
To implement this deprecation method, developers only need to insert their own code when encountering the aforementioned conditions, and direct the information appropriately within their application (e.g., to the console, to an alarming system, e-mail to the administrator, etc.).
The Web service should be kept in service for some locally defined minimum period of time following the deprecation date of its last tModel(s), and its access logs checked on a daily basis. Continued access implies that an application has bound directly to the Web service (or that deprecation warnings have been ignored), and it will be necessary to immediately follow up with the application developers to directly notify them of the Web service's impending demise. The application architect should also be contacted, to provide remedial education on the recommended method of binding to a Web service.
After this period, the Web service may be removed from service. The owner of the tModel should then delete the registry entry for the tModel from any UDDI registries to prevent any inadvertent future use of that TModel.
Deprecation Code Walkthrough
Now that we have a tModel object (tm), we can examine the identifierBag in the deprecation-related tags (see Listing 5).
If the DEPRECATED identifier is not present, the deprecation check is complete. If it is present, we must compare the deprecation date to the current date to see whether the error produced should be nonfatal (deprecation has not yet occurred) or fatal (deprecation has occurred).
In either case, when we generate the message explaining the deprecation, we should include the content of DEPRECATED_MSG (a brief explanation of the deprecation) and DEPRECATED_LINK (a link to a more complete explanation of the deprecation; see Listing 6).
Development Roadmap and Final Notes
1. Web service developer builds support for getVersion message into his or her service.
The process outlined in this document is reasonably lightweight. By limiting the requirements to placing versioning and deprecation data in standard locations, the developers are free to determine the best approach for implementation within their own application context. For an application that carries out a startup procedure at regular intervals, it may mean retrieving the appropriate binding upon startup and performing a deprecation check as a maintenance process once a month. For an application intended to run continuously, it may mean checking for more recent versions and deprecations once a week.
To be successful, Web service and application developers must follow the processes outlined here. While I believe that this strategy is logical and sound in its own right, it is further supported by the design of the UDDI businessService and bindingTemplate data structures. The absence of identifiers on these structures requires that versioning and deprecation information be stored either in the free-text description fields, or in some other data structure as dictated by some internal process.
One very important principle that Web service developers must follow is that any time they modify the WSDL interface, they must create a new tModel. A given tModel represents a version of a specification (in this case, an interface and implementation specification). Just as you cannot go back and modify an existing specification and keep the original version number, you cannot modify a tModel (or the underlying versions of the documents it refers to) once released. Developers will code their applications to the interface described in the WSDL file attached to the tModel but if the Web service developer changes that interface without issuing a new tModel, application Web service calls will suddenly start breaking.
This approach to versioning takes advantage of the features of UDDI, but relies upon the participation of both application and Web service developers in equal measure (sort of the Web services version of Mutual Assured Destruction). Application developers rely on Web service developers to implement the getVersion message, to maintain proper UDDI registry entries, and to continue supporting specific interfaces until they are officially deprecated. Web service developers rely on application developers to bind to a service based on the tModel required, and to use UDDI to find the binding for the latest version of a service supporting that tModel.
Programming to interfaces, rather than to specific implementations of Web services, ensures that application developers will always use the most up-to-date Web service, and will be notified in a timely manner of all (and only) relevant interface deprecations.
Reader Feedback: Page 1 of 1
SOA World Latest Stories
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
SYS-CON Featured Whitepapers
Most Read This Week