From 2961697cab65d4873c07b2286624c41a14b14e61 Mon Sep 17 00:00:00 2001 From: Rick Evans Date: Wed, 23 May 2007 21:52:03 +0000 Subject: [PATCH] First pass through the tutorial, linking things up, correcting typos, etc. Will add some actual content later ;) --- src/docbkx/tutorial.xml | 273 +++++++++++++++++++++------------------- 1 file changed, 145 insertions(+), 128 deletions(-) diff --git a/src/docbkx/tutorial.xml b/src/docbkx/tutorial.xml index b1bbe7c5..8d994e4e 100644 --- a/src/docbkx/tutorial.xml +++ b/src/docbkx/tutorial.xml @@ -6,34 +6,39 @@
Introduction - This tutorial shows you how to write contract-first Web services, i.e. starting with the XML Schema/WSDL - contract instead of Java code. Spring Web Services focuses on this development style, and this tutorial - helps you get started. Note that the first part of this tutorial contains almost no Spring-WS specific - information: it is mostly about XML, XSD, and WSDL. The second part focusses on implementing this contract - using Spring-WS. + This tutorial shows you how to write + contract-first Web services, that is, + developing web services that start with the XML Schema/WSDL contract first + followed by the Java code second. Spring-WS focuses on this development style, + and this tutorial will help you get started. Note that the first part of this + tutorial contains almost no Spring-WS specific information: it is mostly about + XML, XSD, and WSDL. The second part + focusses on implementing this contract using Spring-WS . - In this tutorial, we will define a Web service that is created by a Human Resources department. Clients can - send holiday request forms to this service to book a holiday. + The most important thing when doing contract-first Web service development is + to try and think in terms of XML. This means that Java-language concepts are + of lesser importance. It is the XML that is sent across the wire, and you + should focus on that. The fact that Java is used to implement the Web service + is an implementation detail. An important detail, but a detail nonetheless. - The most important thing when doing contract-first Web service development is to try and think in terms of - XML. This means that Java-language concepts are of lesser importance. It is the XML that is sent across the - wire, and you should focus on that. The fact that Java is used to implement the Web service is an - implementation detail. An important detail, but a detail nonetheless. + In this tutorial, we will define a Web service that is created by a Human Resources + department. Clients can send holiday request forms to this service to book a holiday.
Messages - In this section, we will focus on the actual XML messages that are sent to and from the service. We will - start out by determining what these messages look like. + In this section, we will focus on the actual XML messages that are sent to + and from the Web service. We will start out by determining what these messages + look like.
Holiday - In the scenario, we have to deal with holiday requests, so it makes sense to determine what a holiday - looks like: + In the scenario, we have to deal with holiday requests, so it makes sense + to determine what a holiday looks like in XML: @@ -41,16 +46,19 @@ 2006-07-07 ]]> - A holiday consists of a start date and an end date. We decided to use the standard - ISO 8601 date format for the dates, - because that will save a lot of parsing hassle. We also added a namespace to the element, to make sure - our elements can used within other XML documents. + A holiday consists of a start date and an end date. We have also decided to + use the standard + ISO 8601 + date format for the dates, because that will save a lot of parsing hassle. + We have also added a namespace to the element, to make sure our elements + can used within other XML documents.
Employee - There is also the notion of an employee in the scenario. Here's what it looks like: + There is also the notion of an employee in the scenario. Here is what it + looks like in XML: @@ -59,15 +67,17 @@ Poutsma ]]> - We have used the same namespace as before. If this employee element could be used in other scenarios, it - might make sense to use a different namespace, such as + We have used the same namespace as before. If this + <Employee/> element could be used in other + scenarios, it might make sense to use a different namespace, such as http://mycompany.com/employees/schemas.
HolidayRequest - Both the holiday and employee element can be put in a HolidayRequest: + Both the holiday and employee element can be put in a + <HolidayRequest/>: @@ -82,18 +92,21 @@ ]]> - The order of the two elements does not matter: Employee could have been the first - element just as well. As long as all the data is there; that's what is important. In fact, the data - is the only thing that is important: we are taking a data-driven approach. + The order of the two elements does not matter: <Employee/> + could have been the first element just as well. What is important is + that all of the data is there. In fact, the data is the only thing + that is important: we are taking a data-driven + approach.
Data Contract - Now that we have seen some examples of the XML data that we will use, it makes sense to formalize this into - a schema. This data contract defines the message format we accept. - There are four different ways of defining such a contract for XML: + Now that we have seen some examples of the XML data that we will use, + it makes sense to formalize this into a schema. This data contract + defines the message format we accept. There are four different ways + of defining such a contract for XML: DTDs @@ -102,63 +115,67 @@ Schematron - DTDs have limited namespaces support, so they are not suitable for Web services. Relax NG and Schematron are - certainly easier than XSDs. Unfortunately, they are not so widely supported across platforms. We will use - XML Schema. + DTDs have limited namespace support, so they are not suitable for Web + services. Relax NG and Schematron certainly are easier than XML Schema. + Unfortunately, they are not so widely supported across platforms. We + will use XML Schema. - By far the easiest way to create a XSD is to infer it from sample documents. Any good XML editor or Java IDE - offers this functionality. Basically, these tools use some sample XML documents, and generate a schema from - it that validates them all. The end result certainly needs to be polished up, but it's a great starting - point. + By far the easiest way to create an XSD is to infer it from sample + documents. Any good XML editor or Java IDE offers this functionality. + Basically, these tools use some sample XML documents, and generate a + schema from it that validates them all. The end result certainly needs + to be polished up, but it's a great starting point. - Using the sample described above, we end up with the following generated schema: + Using the sample described above, we end up with the following + generated schema: - -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" - elementFormDefault="qualified" - targetNamespace="http://mycompany.com/hr/schemas" - xmlns:hr="http://mycompany.com/hr/schemas"> - <xs:element name="HolidayRequest"> - <xs:complexType> - <xs:sequence> - <xs:element ref="hr:Holiday"/> - <xs:element ref="hr:Employee"/> - </xs:sequence> - </xs:complexType> - </xs:element> - <xs:element name="Holiday"> - <xs:complexType> - <xs:sequence> - <xs:element ref="hr:StartDate"/> - <xs:element ref="hr:EndDate"/> - </xs:sequence> - </xs:complexType> - </xs:element> - <xs:element name="StartDate" type="xs:NMTOKEN"/> - <xs:element name="EndDate" type="xs:NMTOKEN"/> - <xs:element name="Employee"> - <xs:complexType> - <xs:sequence> - <xs:element ref="hr:Number"/> - <xs:element ref="hr:FirstName"/> - <xs:element ref="hr:LastName"/> - </xs:sequence> - </xs:complexType> - </xs:element> - <xs:element name="Number" type="xs:integer"/> - <xs:element name="FirstName" type="xs:NCName"/> - <xs:element name="LastName" type="xs:NCName"/> -</xs:schema> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> - This generated schema obviously can be improved. The first thing to notice is that every type has a root-level - element declaration. This means that the Web service should be able to accept all of these elements as data. This is not - desirable: we only want to accept a HolidayRequest. By removing the wrapping element tags - (thus keeping the types), and inlining the results, we can accomplish this. + This generated schema obviously can be improved. The first thing + to notice is that every type has a root-level element declaration. + This means that the Web service should be able to accept all of + these elements as data. This is not desirable: we only want to + accept a <HolidayRequest/>. By removing + the wrapping element tags (thus keeping the types), and inlining + the results, we can accomplish this. - - @@ -185,8 +202,8 @@ ]]> - The schema still has one problem: with a schema like this, you can expect the following messages to - validate: + The schema still has one problem: with a schema like this, you + can expect the following messages to validate: @@ -194,14 +211,18 @@ this is not a date neither is this - ... + ]]><!-- ... -->]]> - Clearly, we must make sure that the start and end date are really dates. XML Schema has an excellent built-in - date type which we can use. We also change the NCNames to + Clearly, we must make sure that the start and end date are really dates. + XML Schema has an excellent built-in date type which + we can use. We also change the NCNames to strings. Finally, we change the sequence in - HolidayRequest to all. This tells the XML parser that the order of - Holiday and Employee is not significant. Our final XSD looks like this: + <HolidayRequest/> to all. + This tells the XML parser that the order of + <Holiday/> and + <Employee/> is not significant. Our final + XSD now looks like this: @@ -215,8 +236,7 @@ - - @@ -245,19 +265,20 @@ - all tells the XML parser that the order of Holiday and - Employee is not significant. + all tells the XML parser that the order of + <Holiday/> and + <Employee/> is not significant. We use the xsd:date data type, which consist of a year, month, and day, for - StartDate and EndDate. + <StartDate/> and <EndDate/>. - xsd:string is used for first and last name. + xsd:string is used for the first and last name. @@ -271,7 +292,7 @@ A service contract is generally expressed as a WSDL file. Note that in Spring-WS, writing the WSDL by hand is not required. Based on the XSD and - some conventions, Spring-WS can create the WSDL for you, as explained in + some conventions, Spring-WS can create the WSDL for you, as explained in the section entitled . You can skip to the next section if you want to; the remainder of this section will show you how to write your own WSDL by hand. @@ -281,8 +302,7 @@ separate the schema from the definition, we will use a separate namespace for the WSDL definitions: http://mycompany.com/hr/definitions. - ]]> Next, we add our messages based on the written schema types. We only have one message: one with the - HolidayRequest we put in the schema: + <HolidayRequest/> we put in the schema: ]]> - We add the message to a port type as operation: + We add the message to a port type as an operation: @@ -486,12 +506,12 @@ ]]> - We could have made the servlet more restrictive by using the url pattern /humanresources, - but this will suffice for now. + (We could have made the servlet more restrictive by using the url pattern /humanresources, + but this will suffice for now.) - Additionally, there is WEB-INF/spring-ws-servlet.xml, which is a Spring application - context that will contain the Spring-WS bean definitions. + Additionally, there is WEB-INF/spring-ws-servlet.xml, which is the Spring application + context configuration file that will contain the Spring-WS bean definitions.
@@ -500,9 +520,9 @@ In Spring-WS, you will implement Endpoints to handle incoming XML messages. There are two flavors of endpoints: message endpoints and payload endpoints.. - Message endpoint gives access to the entire XML message, including SOAP headers, etc. Typically, the - endpoint will only be interested in the payload of the message, i.e. the contents - of the SOAP body. In that case, creating a payload endpoint makes more sense. + Message endpoints give access to the entire XML message, including SOAP headers. Typically, the + endpoint will only be interested in the payload of the message, that is the contents + of the SOAP body. In that case, creating a payload endpoint makes more sense.
Handling the XML Message @@ -539,7 +559,7 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint { private XPath nameExpression; - private HumanResourceService humanResourceService; + private final HumanResourceService humanResourceService; public HolidayEndpoint(HumanResourceService humanResourceService) { this.humanResourceService = humanResourceService; @@ -567,7 +587,7 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint { The HolidayEndpoint requires the HumanResourceService business service to operate, so we - use the constructor to inject it. Next, we set up XPath expressions + inject the dependency via the constructor. Next, we set up XPath expressions using the JDOM API. There are three expressions: //hr:StartDate for extracting the <StartDate> text value, //hr:EndDate for @@ -577,14 +597,14 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint { - The invokeInternal method is a template method, which gets passed - with the HolidayRequest element from the incoming XML message. We + The invokeInternal(..) method is a template method, which gets passed + with the <HolidayRequest/> element from the incoming XML message. We use the XPath expressions to extract the string values from the XML messages, and convert these values to Date objects using a SimpleDateFormat. With these values, we invoke a method on the - business service. Typically, this will result in result in a database transaction being + business service. Typically, this will result in a database transaction being started, and some records being altered in the database. Finally, we return - null, which indicates to Spring-WS that we don't want to send a + null, which indicates to Spring-WS that we do not want to send a response message. If we wanted a response message, we could have returned a JDOM Element that represents the payload of the response message. @@ -592,7 +612,7 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint { - Using JDOM is just one of the options to handle the XML, other options include DOM, dom4j, XOM, + Using JDOM is just one of the options to handle the XML: other options include DOM, dom4j, XOM, SAX, and StAX, but also marshalling techniques like JAXB, Castor, XMLBeans, JiBX, and XStream. We chose JDOM because it gives us access to the raw XML, and because it is based on classes (not interfaces and factory methods as with W3C DOM and dom4j), which makes the @@ -600,11 +620,10 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint { care for strict schema conformance, as long as we can find the dates and the name. - Because we use JDOM, we must add some dependencies to the pom.xml, which is in the + Because we use JDOM, we must add some dependencies to the Maven pom.xml, which is in the root of our project directory. Here is the relevant section of the POM: - + org.springframework.ws spring-ws-core @@ -632,14 +651,12 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint { 1.3 runtime - -]]> +]]> - Here is how we would wire up these classes in our spring-ws-servlet.xml - application context: + Here is how we would configure these classes in our spring-ws-servlet.xml + application context configuration file: - + @@ -655,8 +672,8 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint { Now that we have written an endpoint that handles the message, we must define how incoming messages are routed to that endpoint. In Spring-WS, this is the responsibility of an EndpointMapping. In this tutorial, we will route messages based on - their content, by using a PayloadRootQNameEndpointMapping. Here's how we - wire it up in spring-ws-servlet.xml: + their content, by using a PayloadRootQNameEndpointMapping. Here is how we + configure a PayloadRootQNameEndpointMapping in spring-ws-servlet.xml: @@ -670,12 +687,12 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint { ]]> - This means that whenever a XML message comes in with the namespace + This means that whenever an XML message is received with the namespace http://mycompany.com/hr/schemas and the HolidayRequest local name, it will be routed to the holidayEndpoint. - It also adds a PayloadLoggingInterceptor, - that dumps incoming and outgoing messages to the log. + (It also adds a PayloadLoggingInterceptor, + that dumps incoming and outgoing messages to the log.)
@@ -731,7 +748,7 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint { We set the location where the service can be reached: http://localhost:8080/holidayService. For development, this will suffice, but obviously we need to change this to http://mycompany.com/humanresources when going - live. One way to keep this to accomplish this would be to use Spring + live. A common way to to accomplish this is to use a Spring PropertyPlaceholderConfigurer. @@ -745,7 +762,7 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint { You can create a WAR file using mvn install. - If you deploy the application, and point your browser at + If you deploy the application (to Tomcat, Jetty, etc.), and point your browser at this location, you will see the generated WSDL. This WSDL is ready to be used by clients, such as soapUI, or other SOAP frameworks. @@ -753,7 +770,7 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint { That concludes this tutorial. The tutorial code can be found in the full distribution of Spring-WS. - The next step would be to look at the echo sample application, that is part + The next step would be to look at the echo sample application that is part of the distribution. After that, look at the airline sample, which is a bit more complicated, because it uses JAXB, WS-Security, Hibernate, and a transactional service layer. Finally, you can read the rest of the reference documentation.