Developing Web services with Apache CXF + Maven (Part 2)

Introduction

In this lab, we will look at two more aspects in Web service development with Apache CXF.

  1. Handling (custom) SOAP Faults
  2. Writing a service client program using CXF libraries (i.e., consumer of the service)

Before we start, I am assuming that you have done Lab01 already. This means in this lab, I can skip providing detailed instructions when similar instructions were shown/given in Lab01.

Activity 1: Testing the Web Service using SoapUI

In Lab01, we have used a tool in Eclipse's (Web Service Explorer) to test the service you have deployed. From Lab02 and onwards, we will use a tool that is purposely built for testing Web services.

One of the popular (and free) options is SoapUI. We can develop automated test projects in SoapUI to make sure web services which we develop work as excpected. These test cases are called integration testing. Integration testing is different from unit testing. Unit testing only validates part of business logics within a service but integration testing might involve multiple services. in this section we only create a simple SoupUI test case for HelloWorld service which we developed earlier.

First, open Eclipse and locate your project from Lab01. Deploy the HelloWorldCXF service locally or onto your Docker host.

Now, download SoapUI from the SourceForge site. A version later than 5.2 should be OK. After downloading, install it according to their instructions. Run SoapUI, then try the following for quick testing.

  1. Go to 'File -> New SOAP Project'. On the pop-up window, name the new project (e.g., Lab01 Test), enter the URL of the WSDL. Of course, this URL is different depending on where your service is running. If it is running from your docker host, it should be: http://your-own-comp9322srv-ip:8888/HelloWorldCXF/HelloWorld?wsdl)

  2. On the navigation pane of the tool on the left, you should see the new project created. Expand the project to see the service and its operations. When you click on the name of the operation, it should expand to see 'Request 1'. Double click 'Request 1'. Fill in test values (in SOAP request). Press the green arrow button (at the top left corner). You should see the SOAP response. Some relevant screenshots of SoapUI below (the Initial WSDL address should be your own).

  3. In the next step, we create a SoapUI Test Suit. Right click on the Request1 and choose 'Add to TestCase' option.

  4. Type 'Lab01 TestSuite 1' and click OK. In the new window, enter 'HelloWorld TestCase' and click OK on the next dialog.

  5. On the navigation pane right click on the 'Test Steps' and from Add Step menue select Properties. Enter initProperties as value and click OK. Make sure initProperties step is located before 'sayHi - Request 1'. Add hello-request property with Lab01 value.

  6. On the navigation pane double click on 'sayHi - Request 1'. In the bottom left corner of newly opened window, click on Assertions and add new Contains assertion from 'Property Content' menue .

  7. Open up the new assertion and enter Hello ${initProperties#hello-request}

  8. Double click on 'HelloWorld TestCase' and run it. It should finish all the steps successfully

Activity 2: Developing Onboarding Validation Service

In this activity, we will develop another Web service, but this time, will consider creating custom faults to communicate errors.

This service is used as part of Onboadrding process which validates the employee's address and driver license.

Move to your workspace $9322_PRAC$/workspace

Let us start by getting a fresh Maven template by following the steps through the maven template generation process.

   $ mvn archetype:generate -Dfilter=org.apache.cxf.archetype:

Choose Option 2 (i.e., cxf-jaxws-...). Then choose Package version number 99. (Note: a student reported that he could complete the exercise with the latest version 108 as well.)

Use au.edu.unsw.soacourse as the groupId, onboarding-validation-service as the artefactId, leave the version as 1.0-SNAPSHOT, and the package name au.edu.unsw.soacourse.onboardingservice.

Import the created project template into Eclipse. Then continue with the rest of the lab exercise.

We are going to start from taking this WSDL (similar to what we used in the previous lab). Put it under 'src/main/resources/wsdl'.

There are two operations: ValidateAddress() and ValidateDriverLicense(). It is noted that a mock implementation of these operations would involve, roughly, (i) If address is not "455 George St, Sydney NSW 2000" return a SOAPFault otherwise return Sydney , (ii) Check if driver license number is 8 digit then return true otherwise return a SOAPFault.

Now, let us assume that we want to create one custom exception for each operation.

Of course, these exceptions are going to be sent over to the requester as SOAP faults.

In the contract-first design fashion we saw in Lab01, we are going to declare these custom faults in the WSDL file. Open the WSDL file and edit it as follows:

  1. In wsdl:portType, wsdl:operation, for each operation add a fault message as a possible option. It should look like this:

  2. Now in wsdl:message sections, declare the fault messages: ValidateAddressFaultMsg and ValidateDriverLicenseFaultMsg. In each of the fault messages, we declare that it has an element called ValidateAddressFault and ValidateDriverLicenseFault respectively. The types of these new elements will be defined in the next step. The new message sections should look like this:

  3. Now in wsdl:types -> xsd:schema section, let's add type definitions for the two fault messages and their elements. We'd like to have the errors to have a custom error code and some text. So, for each fault message, declare one common type - called serviceFaultType which has a sequence of two elements: errorcode and errortext. After that, we will finally declare elements ValidateAddressFault, ValidateDriverLicenseFault as of serviceFaultType. The type declaration for these should look like this:

  4. Now in wsdl:binding section, add a message binding for the faults each operation so that the faults messages are also recognised here. Note - in soap:fault, the name attribute (which refers to the name of the fault message defined) is compulsory. The new binding section should looke liks this. Note the addition of wsdl:fault and soap:fault in each operation.

  5. The above step completes all the information required to declare SOAP faults in WSDL. Now based on this new contract, you want to generate the code - and complete the service logic.

  6. To generate the code, add the code-gen plugin configuration into pom.xml (copy from the previous lab). While you are there, make sure that the maven-compiler-plugin part is referencing JDK 1.7. Update Maven project and make sure that you are seeing no errors.

  7. Run 'mvn generate-sources'. Refresh the project content and examine the src/main/java-generated directory. In addition to the usual Request/Response beans, you should notice new SOAP fault related beans like ServiceFaultType, ValidateAddressFaultMsg, ValidateDriverLicenseFaultMsg.

  8. Also, in the SEI OnboadrdingValidationService, you should see validateAddress() throwing ValidateAddressFaultMsg, validateDriverLicense() throwing ValidateDriverLicenseFaultMsg.

  9. Now let's implement the SEI OnboadrdingValidationService. This time, with SOAP faults.

  10. Create a new class OnboadrdingValidationServiceImpl. To start with, it should look something like this:

    That is, the class OnboadrdingValidationServiceImpl implements the SEI interface. It should also have the @WebService ananotation (with the matching endpointInterface property defined correctly). The skeleton of the methods in questions are ready to be filled in.

  11. You may have a look at a sample implementation of OnboadrdingValidationServiceImpl.java. It includes the rough code for generating SOAP faults for each operation. Complete the necessary sections - but also modify the code as you see fit.

  12. Once you are happy that the code is complete, configure the project for compilation and deployment. Go to src/main/webapp, and open beans.xml. Configure the

  13. endpoint.

  14. Now save everything, compile and deploy the code to Tomcat container.

Deploy the service to your docker host

Run the service on your docker host to compete the following activities. Note that the IP address of the server shown in the following activities should correspond to your own address.

Seeing the SOAP faults

Once the service is deployed, you may use the Web Service Explorer in Eclipse to quickly check if the SOAP faults are thrown as expected, but the Web Service Explorer may not display the actual SOAP message in XML clearly.

You can use SoapUI. We assume that you have completed the activity with SOAP-UI at the start of this lab. Run SoapUI, then try the following.

  1. Go to 'File -> New SOAP Project'. On the pop-up window, name the new project (e.g., Lab02 Test), enter the URL of the WSDL. In this lab, it should be: http://comp9322srv-ip:8888/OnboardingValidationCXF/OnboadrdingValidationService?wsdl)

  2. On the navigation pane of the tool on the left, you should see the new project created. Expand the project to see the service and its operations. When you click on the name of the operation, it should expand to see 'Request 1'. Double click 'Request 1'. Fill in test values (in SOAP request). Press the green arrow button (at the top left corner). You should see the SOAP response. Send a request that will generate a fault and see the structure of the returned SOAP fault. Some relevant screenshots of SoapUI below. The fault message element we have defined appears in the detail part of the SOAP fault.

Activity 3: Developing a Web Service Client Application

Leave your OnboadrdingValidationService running on the host. In this activity, we will create a Java-based client application that 'talks' to it.

In this part of the lab, we will learn how to develop a consumer application of a Web service. It is likely that your client application is also a Web application. So, let's look at the option where a Web service is consumed as part of some other Web application. In this exercise, we will use the Servlet API to build a simple Web page.

Let first get a Web app template from Maven and do some simple configuration to start using Servlet.

Project template creation using Maven, setting up the basic structure for Apache CXF and Servlet API

Let's create a Web application template using Maven archetype first. Run the following (all in one line).

mvn archetype:generate -DgroupId=au.edu.unsw.soacourse -DartifactId=onboarding-validation-client -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

If running this for the first time, it may take a while to complete the command. At the end of running it successfully, you should get a new directory named 'onboarding-validation-client'.

Import the template into Eclipse as 'Existing Maven Project'. Examine the template directory. It is quite bare at the moment. Note some generic stuff here, such as the pom.xml file, src/main/webapp and src/main/webapp/WEB-INF.

We need to add some stuff to make it more relevant to our task. First, create 'java' directory under /src/main. We will create Java files for the project there. Second , create 'jsp' directory under /src/main/webapp/WEB-INF. We are not going to use JSP files in this exercise, but you may want to still create this directory, if you want to use this project template later for a more complete servlet/jsp-based Web App.

Note: creating new projects in Maven. At this point, let's think about creating these new templates in Maven. Obviously, you do not want to run Maven archetype:generate everytime. Also, the archetypes do not give you the precise structure of the project and artefacts. For example, you may want /src/main/java directory all the time, or you'd like pom.xml to already have the necessary plugins declared. Obviously, one easy way to solve this is to have your own Maven project directory structure and artefacts. Save it as your own template (in any archive file format will do such as zip or tar). Whenever you want to create a new project based on the template, you could import the template as an existing Maven project.

Another way to do this is to create your own custom Maven archetype using the template. It may take a bit of effort at the start, but if you are going to use the template often, it probably is worth the time spent. More information about how to create your own custom Maven archetype can be found here.

Now let's start adding/configuring the project to work with Apache CXF and Servlet API.

  1. Take this pom.xml file. Replace the existing pom.xml with it. Let us examine the file to see what kind of configuration has been added.

  2. Note the cxf-codegen-plugin part in pom.xml. Like the Apache CXF dependencies, we need this codegen plugin to run wsdl2java tool. Pay particular attention to the address of the WSDL file. It is referring to the already deployed service's location now. This means, for the codegen to work, you need to have the service running. However, it is also possible to download the WSDL from the address and copy it into your local file system to reference it. Here, we will just use the 'live' service address (i.e., the one running on your Docker host).

    <configuration>
       <sourceRoot>src/main/java-generated</sourceRoot>
          <wsdlOptions>
             <wsdlOption>
                <wsdl>http://your-own-comp9322srv-ip:8888/OnboardingValidationCXF/OnboadrdingValidationService?wsdl</wsdl>
             </wsdlOption>
          </wsdlOptions>
      </configuration>
      <goals>
          <goal>wsdl2java</goal>
      </goals>
    ...
       
  3. Generate the stub code first by running 'Run-As, Maven generate-source'. BUT make sure you have updated the project by running 'Maven, Update Project'.
  4. You should see the stub classes generated in the new folder src/main/java-generated/
  5. Now, Take this Java file and import into /src/main/java and adjust so that you have the proper package structure recognised. Let's look inside the code for a moment:

  6. Make sure that you configure web.xml correctly. You should probably change the <URL-Mapping> part of the servlet-mapping configuration. Set the URL pattern to validateaddress.

  7. Update the project. Then, run 'Maven install' on the project. Let us depoy this client to your local Tomcat only. Do 'Run As', 'Run on Server' to deploy the application to your local:8080 server. You should fix any errors - the console should not show any ERROR.

  8. If everything is fine, test the client app by running:

Exercises for you: