4

Apache CXF - Contract First Web Services - briansdevblog

 3 years ago
source link: https://www.briansdevblog.com/2016/10/apache-cxf-contract-first-web-services/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Source Code

The full source code for this post is available on GitHub so feel free to have a look. You may find it useful to have the code locally as you work through this post.

Domain Model Definition

We’ll begin by defining the service domain model as an XML Schema Definition (XSD). The schema will define the entities that our Account service will use. We’ll begin by defining the core Account entity – the diagram below shows the XSD snippet that defines the Account as well as a visual representation taken from XML Spy.

Account Complex Type

Next we’ll define the AccountDetailsRequest type that will be used as a parameter to the Account service.

AccountDetailsRequest

Finally we’ll define the AccountDetailsResponse type that will be used as the return type from the Account service.

AccountDetailsResponse

The full schema definition is shown below.

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://com/blog/samples/webservices/accountservice" xmlns:account="http://webservices.samples.blog.com" targetNamespace="http://com/blog/samples/webservices/accountservice" elementFormDefault="qualified">
 <xsd:complexType name="Account">
  <xsd:sequence>
   <xsd:element name="AccountNumber" type="xsd:string"/>
   <xsd:element name="AccountName" type="xsd:string"/>
   <xsd:element name="AccountBalance" type="xsd:double"/>
   <xsd:element name="AccountStatus" type="EnumAccountStatus"/>
  </xsd:sequence>
 </xsd:complexType> 
 <xsd:simpleType name="EnumAccountStatus">
  <xsd:restriction base="xsd:string">
   <xsd:enumeration value="Active"/>
   <xsd:enumeration value="Inactive"/>
  </xsd:restriction>
 </xsd:simpleType>
 <xsd:element name="AccountDetailsRequest">
  <xsd:complexType>
   <xsd:sequence>
    <xsd:element name="accountNumber" type="xsd:string"/>
   </xsd:sequence>
  </xsd:complexType>
 </xsd:element>
 <xsd:element name="AccountDetailsResponse">
  <xsd:complexType>
   <xsd:sequence>
    <xsd:element name="AccountDetails" type="Account"/>
   </xsd:sequence>
  </xsd:complexType>
 </xsd:element>
</xsd:schema>
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://com/blog/samples/webservices/accountservice" xmlns:account="http://webservices.samples.blog.com" targetNamespace="http://com/blog/samples/webservices/accountservice" elementFormDefault="qualified">
  3. <xsd:complexType name="Account">
  4. <xsd:sequence>
  5. <xsd:element name="AccountNumber" type="xsd:string"/>
  6. <xsd:element name="AccountName" type="xsd:string"/>
  7. <xsd:element name="AccountBalance" type="xsd:double"/>
  8. <xsd:element name="AccountStatus" type="EnumAccountStatus"/>
  9. </xsd:sequence>
  10. </xsd:complexType>
  11. <xsd:simpleType name="EnumAccountStatus">
  12. <xsd:restriction base="xsd:string">
  13. <xsd:enumeration value="Active"/>
  14. <xsd:enumeration value="Inactive"/>
  15. </xsd:restriction>
  16. </xsd:simpleType>
  17. <xsd:element name="AccountDetailsRequest">
  18. <xsd:complexType>
  19. <xsd:sequence>
  20. <xsd:element name="accountNumber" type="xsd:string"/>
  21. </xsd:sequence>
  22. </xsd:complexType>
  23. </xsd:element>
  24. <xsd:element name="AccountDetailsResponse">
  25. <xsd:complexType>
  26. <xsd:sequence>
  27. <xsd:element name="AccountDetails" type="Account"/>
  28. </xsd:sequence>
  29. </xsd:complexType>
  30. </xsd:element>
  31. </xsd:schema>
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://com/blog/samples/webservices/accountservice" xmlns:account="http://webservices.samples.blog.com" targetNamespace="http://com/blog/samples/webservices/accountservice" elementFormDefault="qualified">
 <xsd:complexType name="Account">
  <xsd:sequence>
   <xsd:element name="AccountNumber" type="xsd:string"/>
   <xsd:element name="AccountName" type="xsd:string"/>
   <xsd:element name="AccountBalance" type="xsd:double"/>
   <xsd:element name="AccountStatus" type="EnumAccountStatus"/>
  </xsd:sequence>
 </xsd:complexType> 
 <xsd:simpleType name="EnumAccountStatus">
  <xsd:restriction base="xsd:string">
   <xsd:enumeration value="Active"/>
   <xsd:enumeration value="Inactive"/>
  </xsd:restriction>
 </xsd:simpleType>
 <xsd:element name="AccountDetailsRequest">
  <xsd:complexType>
   <xsd:sequence>
    <xsd:element name="accountNumber" type="xsd:string"/>
   </xsd:sequence>
  </xsd:complexType>
 </xsd:element>
 <xsd:element name="AccountDetailsResponse">
  <xsd:complexType>
   <xsd:sequence>
    <xsd:element name="AccountDetails" type="Account"/>
   </xsd:sequence>
  </xsd:complexType>
 </xsd:element>
</xsd:schema>

Service Contract Definition

Next we’ll define the public facing service contract using a WSDL. A WSDL is an XML document that describes a SOAP Web Service and how clients can interact with it. WSDLs are a great way to describe service contracts because they are easy to interpret by developers and can be used by tooling to generate many useful artefacts, some of which we’ll look at later.  The Account Service WSDL is defined as follows.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap12/"
 xmlns:tns="http://www.briansjavablog.com/Accounts/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="Accounts"
 targetNamespace="http://www.briansjavablog.com/Accounts/"
 xmlns:accounts="http://com/blog/samples/webservices/accountservice">
 <wsdl:types>
  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <xsd:import namespace="http://com/blog/samples/webservices/accountservice"
    schemaLocation="../schema/AccountsService.xsd">
   </xsd:import>
  </xsd:schema>
 </wsdl:types>
 <wsdl:message name="AccountDetailsRequest">
  <wsdl:part element="accounts:AccountDetailsRequest" name="parameters" />
 </wsdl:message>
 <wsdl:message name="AccountDetailsResponse">
  <wsdl:part element="accounts:AccountDetailsResponse" name="parameters" />
 </wsdl:message>
 <wsdl:portType name="Accounts">
  <wsdl:operation name="GetAccountDetails">
   <wsdl:input message="tns:AccountDetailsRequest" />
   <wsdl:output message="tns:AccountDetailsResponse" />
  </wsdl:operation>
 </wsdl:portType>
 <wsdl:binding name="AccountsServiceSoapBinding" type="tns:Accounts">
  <soap:binding style="document"
   transport="http://schemas.xmlsoap.org/soap/http" />
  <wsdl:operation name="GetAccountDetails">
   <soap:operation
    soapAction="http://www.briansjavablog.com/Accounts/GetAccountDetails" />
   <wsdl:input>
    <soap:body use="literal" />
   </wsdl:input>
   <wsdl:output>
    <soap:body use="literal" />
   </wsdl:output>
  </wsdl:operation>
 </wsdl:binding>
 <wsdl:service name="AccountsService">
  <wsdl:port binding="tns:AccountsServiceSoapBinding" name="AccountsPort">
   <soap:address
    location="http://localhost:8080/apache-cfx-demo/services/accounts" />
  </wsdl:port>
 </wsdl:service>
</wsdl:definitions>
  1. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2. <wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap12/"
  3. xmlns:tns="http://www.briansjavablog.com/Accounts/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  4. xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="Accounts"
  5. targetNamespace="http://www.briansjavablog.com/Accounts/"
  6. xmlns:accounts="http://com/blog/samples/webservices/accountservice">
  7. <wsdl:types>
  8. <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  9. <xsd:import namespace="http://com/blog/samples/webservices/accountservice"
  10. schemaLocation="../schema/AccountsService.xsd">
  11. </xsd:import>
  12. </xsd:schema>
  13. </wsdl:types>
  14. <wsdl:message name="AccountDetailsRequest">
  15. <wsdl:part element="accounts:AccountDetailsRequest" name="parameters" />
  16. </wsdl:message>
  17. <wsdl:message name="AccountDetailsResponse">
  18. <wsdl:part element="accounts:AccountDetailsResponse" name="parameters" />
  19. </wsdl:message>
  20. <wsdl:portType name="Accounts">
  21. <wsdl:operation name="GetAccountDetails">
  22. <wsdl:input message="tns:AccountDetailsRequest" />
  23. <wsdl:output message="tns:AccountDetailsResponse" />
  24. </wsdl:operation>
  25. </wsdl:portType>
  26. <wsdl:binding name="AccountsServiceSoapBinding" type="tns:Accounts">
  27. <soap:binding style="document"
  28. transport="http://schemas.xmlsoap.org/soap/http" />
  29. <wsdl:operation name="GetAccountDetails">
  30. <soap:operation
  31. soapAction="http://www.briansjavablog.com/Accounts/GetAccountDetails" />
  32. <wsdl:input>
  33. <soap:body use="literal" />
  34. </wsdl:input>
  35. <wsdl:output>
  36. <soap:body use="literal" />
  37. </wsdl:output>
  38. </wsdl:operation>
  39. </wsdl:binding>
  40. <wsdl:service name="AccountsService">
  41. <wsdl:port binding="tns:AccountsServiceSoapBinding" name="AccountsPort">
  42. <soap:address
  43. location="http://localhost:8080/apache-cfx-demo/services/accounts" />
  44. </wsdl:port>
  45. </wsdl:service>
  46. </wsdl:definitions>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap12/"
 xmlns:tns="http://www.briansjavablog.com/Accounts/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="Accounts"
 targetNamespace="http://www.briansjavablog.com/Accounts/"
 xmlns:accounts="http://com/blog/samples/webservices/accountservice">
 <wsdl:types>
  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <xsd:import namespace="http://com/blog/samples/webservices/accountservice"
    schemaLocation="../schema/AccountsService.xsd">
   </xsd:import>
  </xsd:schema>
 </wsdl:types>
 <wsdl:message name="AccountDetailsRequest">
  <wsdl:part element="accounts:AccountDetailsRequest" name="parameters" />
 </wsdl:message>
 <wsdl:message name="AccountDetailsResponse">
  <wsdl:part element="accounts:AccountDetailsResponse" name="parameters" />
 </wsdl:message>
 <wsdl:portType name="Accounts">
  <wsdl:operation name="GetAccountDetails">
   <wsdl:input message="tns:AccountDetailsRequest" />
   <wsdl:output message="tns:AccountDetailsResponse" />
  </wsdl:operation>
 </wsdl:portType>
 <wsdl:binding name="AccountsServiceSoapBinding" type="tns:Accounts">
  <soap:binding style="document"
   transport="http://schemas.xmlsoap.org/soap/http" />
  <wsdl:operation name="GetAccountDetails">
   <soap:operation
    soapAction="http://www.briansjavablog.com/Accounts/GetAccountDetails" />
   <wsdl:input>
    <soap:body use="literal" />
   </wsdl:input>
   <wsdl:output>
    <soap:body use="literal" />
   </wsdl:output>
  </wsdl:operation>
 </wsdl:binding>
 <wsdl:service name="AccountsService">
  <wsdl:port binding="tns:AccountsServiceSoapBinding" name="AccountsPort">
   <soap:address
    location="http://localhost:8080/apache-cfx-demo/services/accounts" />
  </wsdl:port>
 </wsdl:service>
</wsdl:definitions>

The WSDL is composed of 5 main parts

  • Types – the <wsdl:types> section defines the domain model associated with the service. The types are defined using XSD and can be defined in the WSDL itself or imported from a separate XSD. On line 9 above we import the schema definition file we created earlier.
  • Message – the <wsdl:message> is used to define the request and response messages handled by the service. The nested <wsdl:part> section defines the domain type that will be used to form the messages.
  • PortType – the <wsdl:portType> defines the service operations that are exposed to clients, parameters required to invoke the operations and response types returned.
  • Binding – the <wsdl:binding> section defines the protocol and data format.
    • The binding type attribute refers to the portType defined earlier in the WSDL.
    • The soap binding style can be either RPC or document. In this instance we’ve chosen document.
    • The transport attribute indicates that the service will be exposed over HTTP. Other less common options include JMS and SMTP.
    • The operation element defines each operation that we exposed through the portType.
    • Binding – the <wsdl:binding> section defines the protocol and data format.
  • Service – the <wsd;:service> defines the exposed service using the portType and binding we defined above.

POM Configuration

Now that we’ve defined the WSDL its time to configure the POM to use the Apache CXF code generation plugin. The plugin invokes a WSDL2Java process which parses the WSDL and generates a service endpoint interface and associated domain objects. The plugin configuration is shown below. Note that I’ve omitted the rest of the POM definition for brevity. To see the full definition pull the sample code from github.

        <plugins>
    <plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>3.1.7</version>
<executions>
   <execution>
      <id>generate-sources</id>
 <phase>generate-sources</phase>
 <configuration>
    <sourceRoot>src/generated/java</sourceRoot>
    <wsdlOptions>
       <wsdlOption>
          <wsdl>${basedir}/src/main/resources/wsdl/Accounts.wsdl</wsdl>
       </wsdlOption>
    </wsdlOptions>
 </configuration>
 <goals>
    <goal>wsdl2java</goal>
 </goals>
   </execution>
</executions>
    </plugin>
        </plugins>
  1. <plugins>
  2. <plugin>
  3. <groupId>org.apache.cxf</groupId>
  4. <artifactId>cxf-codegen-plugin</artifactId>
  5. <version>3.1.7</version>
  6. <executions>
  7. <execution>
  8. <id>generate-sources</id>
  9. <phase>generate-sources</phase>
  10. <configuration>
  11. <sourceRoot>src/generated/java</sourceRoot>
  12. <wsdlOptions>
  13. <wsdlOption>
  14. <wsdl>${basedir}/src/main/resources/wsdl/Accounts.wsdl</wsdl>
  15. </wsdlOption>
  16. </wsdlOptions>
  17. </configuration>
  18. <goals>
  19. <goal>wsdl2java</goal>
  20. </goals>
  21. </execution>
  22. </executions>
  23. </plugin>
  24. </plugins>
        <plugins>
    <plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>3.1.7</version>
<executions>
   <execution>
      <id>generate-sources</id>
 <phase>generate-sources</phase>
 <configuration>
    <sourceRoot>src/generated/java</sourceRoot>
    <wsdlOptions>
       <wsdlOption>
          <wsdl>${basedir}/src/main/resources/wsdl/Accounts.wsdl</wsdl>
       </wsdlOption>
    </wsdlOptions>
 </configuration>
 <goals>
    <goal>wsdl2java</goal>
 </goals>
   </execution>
</executions>
    </plugin>
        </plugins>

The WSDL path on line 14 tells CXF what WSDL to run WSDL2Java with. The sourceRoot configuration on line 11 is the fully qualified package name that the generated class will be copied to. Its a good idea to put these in src/generated/java so that its obvious to other developers that the package contains generated code.

Code Generation

We’re now ready to generate the Service Endpoint Interface and domain objects from the WSDL. To run the code generation simply open a command window and run mvn generate-sources.

Generated Domain and Service Interface

Refresh the IDE workspace and you will see 2 new packages. The package names are based on the namespaces specified in the WSDL. The contents of both packages is described below.

  • com.blog.samples.webservices.accountservice – contains 4 service domain objects, Account, AccountDetailsRequest, AccountDetailsResponse and EnumAccountStatus. These 4 types represent the service request and response. ObjectFactory is a helper class for creating new instances of the domain types and package-info.java applies XML namespace metadata to all domain classes in the package.
  • com.briansjavablog.accounts – contains the Service Endpoint Interface Accounts.java. This interface is a Java representation of the service operation we defined in the WSDL. The contents of this class are covered in detail below. AccountsService.java is a web service client and can be used to invoke the service.

Service Endpoint Interface

The Service endpoint interface that was generated in the previous step is defined below.

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK