I am involved in several projects that require integration with business partners webservices. By adopting JAX-WS 2.1 stack supported by NetBeans/Galssfish our applications easily benefit from Java representations of operations and data structures with which we must interact. JAX-WS has also allowed speed to expose functionality implemented in Java, for internal applications developed on other platforms.
All this ease of integration can cheer us up at first, so we extensively use these benefits. The pitfalls lie in:
- to ignore the coupling with external data models upon consuming webservices
- to allow the transitivity of the internal data model upon providing webservices
The fact is that a webservice contract of today may become obsolete in a few months. Of course there are patterns of service-oriented architectures, adopted on the provider of webservices that minimize the impact of such developments. An interesting practice I have observed is the versioning of services. When a new version of service is available the old version is still functioning, for one or two developments.
However, the raise of a new service version reflects new business needs, and webservice consumers will be forced to migrate soon or late. From this point of view the older versions maintenance just delays the impact of evolution.
If the consumer established indirect dependency with the representations generated by Java tools such as JAX-WS, it will be protected from the impact of development of consumed services. The idea is not new, and is well discussed in a Jens Coldewey paper, particularly in the topic Subsystem-Façade (a reinterpretation of the GoF Facade pattern).
Considering the service to be consumed and its data structure as a subsystem, we avoid the direct use of classes generated by JAX-WS. In addition to using a Facade component to convert the data structures of the service consumed for the internal structures of a consumer application, we've find room for another integration practice , which I have named 'wrapper', and I want to comment in a future post.
The same principle of subsystem separation is applied when we assume the role of services provider via JAX-WS. Whereas our internal data model can evolve, it is not used directly in the interface of the offered services. We oppose the transitivity of our internal data model, according to the Value Object design pattern: create a custom data model, that intends to remain stable for services consumers, along internal changes.
I believe that these practices can be taken when creating web services in Java using other mechanisms such as JAX-RS for REST, or even with the precursors JAX-RPC and Apache Axis.
To expose webservices without transitivity there is also the Contact-First approach, used by Spring Web Services. Such approach can also be used in JAX-WS. In this case we define the schema of data and operations exposed in the first place, placing the generation of Java artifacts as a secondary activity.