Web services in Java SE, Part 2: Creating SOAP web services

Learn how to create SOAP-based Web services

JAX-WS supports SOAP-based Web services. Part 2 of this four-part series on Java SE Web services defines a SOAP-based units-conversion Web service, builds and then verifies this Web service locally via the default lightweight HTTP server (discussed in Part 1), interprets the service's WSDL document, and accesses the service from a simple client.

Defining a units-conversion web service

The units-conversion Web service, which I've named UC, consists of four functions for converting between centimeters and inches and between degrees Fahrenheit and degrees Celsius. Although this example could be architected as a single Java class, I've chosen to follow best practices by architecting it as a Java interface and a Java class. Listing 1 presents the Web service's UC interface.

Listing 1. The UC Web service's Service Endpoint Interface

package ca.javajeff.uc;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public interface UC
{
   @WebMethod double c2f(double degrees);
   @WebMethod double cm2in(double cm);
   @WebMethod double f2c(double degrees);
   @WebMethod double in2cm(double in);
}

UC describes a Service Endpoint Interface (SEI), which is a Java interface that exposes a Web service interface's operations in terms of abstract Java methods. Clients communicate with SOAP-based Web services via their SEIs.

UC is declared to be an SEI via the @WebService annotation. When a Java interface or class is annotated @WebService, all public methods whose parameters, return values, and declared exceptions follow the rules defined in Section 5 of the JAX-RPC 1.1 specification describe Web service operations. Because only public methods can be declared in interfaces, the public reserved word isn't necessary when declaring c2f(), cm2in(), f2c(), and in2cm(). These methods are implicitly public.

Each method is also annotated @WebMethod. Although @WebMethod isn't essential in this example, its presence reinforces the fact that the annotated method exposes a Web service operation.

Listing 2 presents the Web service's UCImpl class.

Listing 2. The UC Web service's Service Implementation Bean

package ca.javajeff.uc;

import javax.jws.WebService;

@WebService(endpointInterface = "ca.javajeff.uc.UC")
public class UCImpl implements UC
{
   @Override
   public double c2f(double degrees)
   {
      return degrees * 9.0 / 5.0 + 32;
   }

   @Override
   public double cm2in(double cm)
   {
      return cm / 2.54;
   }

   @Override
   public double f2c(double degrees)
   {
      return (degrees - 32) * 5.0 / 9.0;
   }

   @Override
   public double in2cm(double in)
   {
      return in * 2.54;
   }
}

UCImpl describes a Service Implementation Bean (SIB), which provides an implementation of the SEI. This class is declared to be a SIB via the @WebService(endpointInterface = "ca.javajeff.uc.UC") annotation. The endpointInterface element connects this SIB to its SEI, and is necessary to avoid undefined port type errors when running the client application presented later.

The implements UC clause isn't absolutely necessary. If this clause isn't present, the UC interface is ignored (and is redundant). However, it's a good idea to keep implements UC so the compiler can verify that the SEI's methods have been implemented in the SIB.

The SIB's method headers aren't annotated @WebMethod because this annotation is typically used in the context of the SEI. However, if you were to add a public method (which conforms to the rules in Section 5 of the JAX-RPC 1.1 specification) to the SIB, and if this method doesn't expose a Web service operation, you would annotate the method header @WebMethod(exclude = true). By assigning true to @WebMethod's exclude element, you prevent that method from being associated with an operation.

This Web service is ready to be published so that it can be accessed from clients. Listing 3 presents a UCPublisher application that accomplishes this task in the context of the default lightweight HTTP server.

Listing 3. Publishing UC

import javax.xml.ws.Endpoint;

import ca.javajeff.uc.UCImpl;

public class UCPublisher
{
   public static void main(String[] args)
   {
      Endpoint.publish("http://localhost:9901/UC", new UCImpl());
   }
}

Publishing the Web service involves making a single call to the EndPoint class's Endpoint publish(String address, Object implementor) class method. The address parameter identifies the URI assigned to the Web service. I've chosen to publish this Web service on the local host by specifying localhost (equivalent to IP address 127.0.0.1) and port number 9901 (which is most likely available). Also, I've arbitrarily choosen /UC as the publication path. The implementor parameter identifies an instance of UC's SIB.

The publish() method creates and publishes an endpoint for the specified implementor object at the given address, and uses the implementor's annotations to create Web Services Definition Language (WSDL) and XML Schema documents. It causes the necessary server infrastructure to be created and configured by the JAX-WS implementation based on some default configuration. Furthermore, this method causes the application to run indefinitely. (On Windows machines, press the Ctrl and C keys simultaneously to terminate the application.)

Building and verifying the web service

It's not difficult to build the previously-defined UC Web service. First, you need to create a suitable directory structure containing the appropriate files. Accomplish this task by performing the following steps:

  1. Within the current directory, create a ca directory. Within ca, create a javajeff directory. Finally, within javajeff, create a uc directory.
  2. Copy Listing 1 to a UC.java source file and store this file in ca/javajeff/uc.
  3. Copy Listing 2 to a UCImpl.java source file and store this file in ca/javajeff/uc.
  4. Copy Listing 3 to a UCPublisher.java source file and store this file in the current directory, which contains the ca directory.

The next task is to compile these source files. Assuming that you haven't changed directories, execute the following command to compile these source files in Java SE 9 (omit --add-modules java.xml.ws in Java SE 6, 7, or 8):

javac --add-modules java.xml.ws UCPublisher.java

If these source files compile successfully, execute the following command to run this application in Java 9 (omit --add-modules java.xml.ws in Java SE 6, 7, or 8):

java --add-modules java.xml.ws UCPublisher

While the application runs, use a Web browser to verify that this Web service is running correctly and to access its WSDL document. Start your favorite Web browser and enter the following line in the address bar:

http://localhost:9901/UC

Figure 1 shows the resulting Web page in the Google Chrome Web browser.

Figure 1. UC's Web page provides detailed information on the published Web service

UC's Web page provides detailed information on the published Web service

Figure 1 presents the Web service endpoint's qualified service and port names. (Notice that the package name has been inverted -- uc.javajeff.ca instead of ca.javajeff.uc). A client uses these names to access the service.

Figure 1 also presents the address URI of the Web service, the location of the Web service's WSDL document (the Web service URI suffixed by the ?wsdl query string), and the package-qualified name of the Web service implementation class.

Interpreting the web service's WSDL document

The location of the UC Web service's WSDL document is presented as a link. Click this link to view the WSDL document, whose contents are presented in Listing 4.

Listing 4. UC's WSDL document

<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
             xmlns:wsp="http://www.w3.org/ns/ws-policy" 
             xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" 
             xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" 
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
             xmlns:tns="http://uc.javajeff.ca/" 
             xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
             xmlns="http://schemas.xmlsoap.org/wsdl/" 
             targetNamespace="http://uc.javajeff.ca/" name="UCImplService">
  <types>
    <xsd:schema>
      <xsd:import namespace="http://uc.javajeff.ca/" schemaLocation="http://localhost:9901/UC?xsd=1"/>
    </xsd:schema>
  </types>
  <message name="c2f">
    <part name="parameters" element="tns:c2f"/>
  </message>
  <message name="c2fResponse">
    <part name="parameters" element="tns:c2fResponse"/>
  </message>
  <message name="in2cm">
    <part name="parameters" element="tns:in2cm"/>
  </message>
  <message name="in2cmResponse">
    <part name="parameters" element="tns:in2cmResponse"/>
  </message>
  <message name="cm2in">
    <part name="parameters" element="tns:cm2in"/>
  </message>
  <message name="cm2inResponse">
    <part name="parameters" element="tns:cm2inResponse"/>
  </message>
  <message name="f2c">
    <part name="parameters" element="tns:f2c"/>
  </message>
  <message name="f2cResponse">
    <part name="parameters" element="tns:f2cResponse"/>
  </message>
  <portType name="UC">
    <operation name="c2f">
      <input wsam:Action="http://uc.javajeff.ca/UC/c2fRequest" message="tns:c2f"/>
      <output wsam:Action="http://uc.javajeff.ca/UC/c2fResponse" message="tns:c2fResponse"/>
    </operation>
    <operation name="in2cm">
      <input wsam:Action="http://uc.javajeff.ca/UC/in2cmRequest" message="tns:in2cm"/>
      <output wsam:Action="http://uc.javajeff.ca/UC/in2cmResponse" message="tns:in2cmResponse"/>
    </operation>
    <operation name="cm2in">
      <input wsam:Action="http://uc.javajeff.ca/UC/cm2inRequest" message="tns:cm2in"/>
      <output wsam:Action="http://uc.javajeff.ca/UC/cm2inResponse" message="tns:cm2inResponse"/>
    </operation>
    <operation name="f2c">
      <input wsam:Action="http://uc.javajeff.ca/UC/f2cRequest" message="tns:f2c"/>
      <output wsam:Action="http://uc.javajeff.ca/UC/f2cResponse" message="tns:f2cResponse"/>
    </operation>
  </portType>
  <binding name="UCImplPortBinding" type="tns:UC">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="c2f">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
    <operation name="in2cm">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
    <operation name="cm2in">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
    <operation name="f2c">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>
  <service name="UCImplService">
    <port name="UCImplPort" binding="tns:UCImplPortBinding">
      <soap:address location="http://localhost:9901/UC"/>
    </port>
  </service>
</definitions>

A WSDL document is an XML document with a definitions root element, which makes a WSDL document nothing more than a set of definitions. This element includes various xmlns attributes for identifying various standard namespaces, along with targetNameSpace and name attributes:

  • The targetNamespace attribute creates a namespace for all user-defined elements in the WSDL document (such as the c2f element defined via the message element with this name). This namespace is used to distinguish between the user-defined elements of the current WSDL document and user-defined elements of imported WSDL documents, which are identified via WSDL's import element. In a similar fashion, the targetNamespace attribute that appears on an XML Schema-based file's schema element creates a namespace for its user-defined simple type elements, attribute elements, and complex type elements.
  • The name attribute identifies the Web service and is used only to document the service.

Nested within definitions are types, message, portType, binding, and service elements:

1 2 3 Page 1
Page 1 of 3