diff --git a/src/site/apt/why-contract-first.apt b/src/site/apt/why-contract-first.apt new file mode 100644 index 00000000..bf144bf3 --- /dev/null +++ b/src/site/apt/why-contract-first.apt @@ -0,0 +1,183 @@ + ------------------- + Why Contract-First? + ------------------- + +Why Contract-First? + + When creating Web services, there are two development styles: and . When using a +contract-last approach, you start with the Java code, and let the Web service contract (WSDL, see sidebar) be generated +from that. When using contract-first, you start with the WSDL contract, and use Java to implement said contract. + + Spring-WS only supports the contract-first development style. This page explains why. + +* Object/XML Impedance Mismatch + + Similar to the field of ORM, where we have an +{{{http://en.wikipedia.org/wiki/Object-Relational_impedance_mismatch}Object/Relational impedance mismatch}}, there is a +similar problem when converting Java objects to XML. At first glance, the O/X mapping problem appears simple: create an +XML element for each Java object, converting all Java properties and fields to sub-elements or attributes. However, +things are not so simple as they appear: there is a fundamental difference between hierarchical languages such as XML +(especially XSD) and the graph model of Java. Note that most of the contents in this section was inspired by +{{{http://www.hpl.hp.com/techreports/2005/HPL-2005-83.pdf}Rethinking the Java SOAP Stack}} and +{{{http://safari.awprofessional.com/0321130006}Effective Enterprise Java}}. + +** XSD extensions + + In Java, the only way to change the behavior of a class is to subclass it, adding the new behavior to that subclass. +In XSD, you can extend a data type by restricting it: i.e. constraining the valid values for the elements and +attributes. For instance, consider the following example: + ++-------------------------------------- + + + + + ++-------------------------------------- + + This type restricts a XSD string by ways of a regular expression, allowing only three upper case letters. If this +type is converted to Java, we will end up with an ordinary <<>>; the regular expression is lost in the +conversion process, because Java does not allow for these sorts of extensions. + +** Unportable types + + One of the most important goals of a Web service is to be interoperable: to support multiple platforms such as Java, +.NET, Python, etc. Because all of these languages have different class libraries, you must use some common, interlingual +format to communicate between them. That format is XML, which is supported by all of these languages. + + Because of this conversion, you must make sure that you use portable types in your service implementation. Consider, +for example, a service that returns a <<>>, like so: + ++-------------------------------------- +public Map getFlights() { + // use a tree map, to make sure it's sorted + TreeMap map = new TreeMap(); + map.put("KL1117", "Stockholm"); + ... + return map; +} ++-------------------------------------- + + Undoubtedly, the contents of this map can be converted into some sort of XML, but since there is no way +to describe a map in XML, it will be proprietary. Also, even if it can be converted to XML, many platforms do not have a +data structure similar to the <<>>. So when a .NET client accesses your Web service, it will +probably end up with a <<>>, which has different semantics. + + This problem is also present when working on the client side. Consider the following XSD snippet, which describes a +service contract: + ++-------------------------------------- + + + + + + + + + ++-------------------------------------- + + This contract defines a request that takes an <<>>, which is a XSD datatype representing a year, month, and +day. If we call this service from Java, we will probably use a <<>> or +<<>>. However, both of these classes actually describe times, rather than dates. So, we will +actually send data that represents the fourth of April 2007 at midnight (<<<2007-04-04T00:00:00>>>), which is not +the same as the fourth of April 2007 (<<<2007-04-04>>>). + +** Cyclic graphs + + Imagine we have the following simple class structure: + ++-------------------------------------- +public class Flight { + private String number; + private List passengers; + + // getters and setters omitted +} + +public class Passenger { + private String name; + private Flight flight; + + // getters and setters omitted +} ++-------------------------------------- + + This is a cyclic graph: the <<>> refers to the <<>>, which refers to the <<>> again. +Cyclic graphs like these are quite common in Java. If we took a naive approach to converting this to XML, we will end up +with something like: + ++-------------------------------------- + + + + Arjen Poutsma + + + + Arjen Poutsma + + + + Arjen Poutsma + ... ++-------------------------------------- + + which will take a pretty long time to finish, because there is no stop condition for this loop. + + One way to solve this problem is to use references to objects that were already marshalled, like so: + ++-------------------------------------- + + + + Arjen Poutsma + + + ... + + ++-------------------------------------- + + This solves the recursiveness problem, but introduces new ones. For one, you cannot use an XML validator to validate +this structure. Another issue is that the standard way to use these references in the SOAP (RPC/encoded) has been +deprecated in favor of document/literal. + + These are just a few of the problems when dealing with O/X mapping. It is important to respect these issues when +writing Web services. The best way to respect them is to focus on the XML completely, while using Java as an +implementation language. This is what contract-first is all about. + +* Contract-first versus Contract-last + + Besides the Object/XML Mapping issues mentioned in the previous section, there are other reasons for preferring a +contract-first development style. + +** Fragility + + If you use a contract-last development style, you will have no guarantee that the contract stays constant over time. +Each redeployment of the service can possibly result in a different contract. Additionally, an upgrade of the SOAP stack +used, or a migration to a different SOAP stack can also change said contract. + + In order for a contract to be useful, it must remain constant for as long as possible. If a contract changes, you +will have to contact all of the users of your service, and instruct them to get the new version of the contract. + +** Performance + + When Java is automatically transformed into XML, there is no way to be sure as to what is sent across the wire. +An object might reference another object, which refers to another, etc. In the end, half of your virtual machine +might be converted into XML, which will result in a slow service. + + When using contract-first, you explicitly describe what XML is sent where, thus making sure that it is exactly what +you want. + +** Versioning + + Even though a contract must remain constant for as long as possible, they need to be changed sometimes. +In Java, this typically result in a new Java interface, such as <<>>, and a (new) implementation of +that interface. Of course, the old service must be kept around, because there might be clients who have not migrated +yet. + + If using contract-first, we can have a looser coupling between contract and implementation. Such a looser coupling +allows us to implement both versions of the contract in one class. We could, for instance, use an XSLT to convert any +"old-style" messages to the "new-style" messages. \ No newline at end of file diff --git a/src/site/fml/faq.fml b/src/site/fml/faq.fml index 22825f09..3ec4f2fa 100644 --- a/src/site/fml/faq.fml +++ b/src/site/fml/faq.fml @@ -36,8 +36,7 @@ /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/.compatibility/14compatibility.jar - . - You can safely remove or rename it, and the tests will run again. + . You can safely remove or rename it, and the tests will run again.

@@ -47,14 +46,23 @@ What is SAAJ? - SAAJ is the SOAP with Attachments API for Java. Previously, it has been part of JAXM, but it has been - released as a seperate API as part of the - Java Web Service - Developer Pack - - , and also as part of J2EE 1.4. SAAJ is generally known as the package - javax.xml.soap - . +

+ SAAJ is the SOAP with Attachments API for Java. Previously, it has been part of JAXM, but it has + been + released as a seperate API as part of the + Java Web Service + Developer Pack + + , and also as part of J2EE 1.4. SAAJ is generally known as the package + javax.xml.soap + . +

+

+ Spring-WS uses this standard SAAJ library to create representations of SOAP messages. Alternatively, + it can use + Apache AXIOM + . +

@@ -94,16 +102,17 @@

If you get the following stack trace:

-
-org.springframework.beans.factory.BeanCreationException:
-  Error creating bean with name 'org.springframework.ws.soap.saaj.SaajSoapMessageContextFactory'
-  defined in ServletContext resource [/WEB-INF/springws-servlet.xml]:
-  Invocation of init method failed;
-nested exception is java.lang.NoSuchMethodError: 
-  javax.xml.soap.MessageFactory.newInstance(Ljava/lang/String;)Ljavax/xml/soap/MessageFactory;
-Caused by:
-  java.lang.NoSuchMethodError: javax.xml.soap.MessageFactory.newInstance(Ljava/lang/String;)Ljavax/xml/soap/MessageFactory;
-
+
+                    org.springframework.beans.factory.BeanCreationException:
+                    Error creating bean with name 'org.springframework.ws.soap.saaj.SaajSoapMessageContextFactory'
+                    defined in ServletContext resource [/WEB-INF/springws-servlet.xml]:
+                    Invocation of init method failed;
+                    nested exception is java.lang.NoSuchMethodError:
+                    javax.xml.soap.MessageFactory.newInstance(Ljava/lang/String;)Ljavax/xml/soap/MessageFactory;
+                    Caused by:
+                    java.lang.NoSuchMethodError:
+                    javax.xml.soap.MessageFactory.newInstance(Ljava/lang/String;)Ljavax/xml/soap/MessageFactory;
+                

Like most J2EE libraries, SAAJ consists of two parts: the API that consists of interfaces ( saaj-api.jar @@ -124,6 +133,22 @@ Caused by: WSDL + + Why does Spring-WS only support contract-first? + +

+ You can find the answer to this question on + a separate page + + . +

+

+ Note that Spring-WS only requires you to write the XSD; the WSDL can be generated from that. + The tutorial + illustrates how. +

+
+
How do I retrieve the WSDL from a Service? The &WSDL query parameter does not work. diff --git a/src/site/site.xml b/src/site/site.xml index d4f5a2fc..e2084400 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -28,6 +28,7 @@ +