All IT Courses 50% Off
JAVA Tutorials

WSDL/SOAP and HTTP Exposing

What is WSDL?

WSDL (Web Services Description Language) is an XML file that tells the client application what to do. The WSDL file contains all the information required to connect to the web service and use all the information provided by the web service.

The extension of the WSDL file is .wsdl. It contains the machine-readable description of how the service is called, what parameter it expects, and what data structure it returns.

The WSDL file comprises of the location of the web service and the methods that are exposed by the web service.

The general structure of a WSDL file consists of:

  • Definition
  • TargetNamespace
  • DataTypes
  • Messages
  • Porttype
  • Bindings
  • Service

Sample WSDL File looks like:

<!-- WSDL definition structure -->
<definitions     
name="WebService"
        targetNamespace=https://example.org/math/
        xmlns=https://schemas.xmlsoap.org/wsdl/>   
<!-- abstract definitions -->   
<types> ...    
<message> ...   
<portType> ...

   <!-- concrete definitions -->  
<binding> ...   
<service> ...
</definition>

Elements of WSDL:

  1. The <types> tag defines all the complex datatypes, which is used to exchange the message between the client application and the web service. It is important because if the web service works with a complex data type, then the client application must know how to process the complex data type. Data types like float, numbers, and strings are all simple data types, but there are structured data types also which may be provided by the web service. For example, there is a data type called EmployeeDataType that have two elements called EmployeeName of type string and the EmployeeID of type number or integer. Together they create a data structure that becomes a complex data type.
  2. The <messages> tag defines the message that is exchanged between the client application and the webserver. These messages explain the input and output operations that will be performed by the web service. 
  3. The <portType> tag encapsulates every input and output message into one logical operation. Therefore, there could be an operation called GetEmployee that accepts the EmployeeID from a client application, and send the EmployeeName as the output message.
  4. The <binding> tag binds the operation to the particular port type. When the client application calls the appropriate port type, it accesses the operations that are bound to this port type. Port types are similar to interfaces. Therefore, if a client application needs to use a web service, they use the binding information to ensure that they are being connected to the interface provided by the web service.
  5. The <service> tag is the name given to the web service. When a client application invoke the web service, it calls the name of the web service. 

What is SOAP?

SOAP (Simple Object Access Protocol) is an XML-based protocol for accessing web services over HTTP. It defines how web services talk to each other or talk to client applications that invoke them. It was configured as an intermediate language so that applications can be built on various programming languages that could easily communicate with each other and avoid the development effort.

A simple SOAP Message consists of the following elements:

  • The Envelope element
  • The header element and
  • The body element
  • The Fault element (Optional)

The SOAP Envelope encapsulates all the necessary details of the SOAP messages, which are exchanged between the web service and the client application.

The SOAP envelope element indicates the beginning and the ending of a SOAP message. It enables the client application that calls the web service to know when the SOAP message ends.

When a request is made to the SOAP web service, the response is returned in either two forms that is a successful response or an error response. When a successful response is generated, the response from the server will always be a SOAP message. If SOAP faults are generated, they returned HTTP 500 errors.

The SOAP Fault message comprises the following elements.

  • <faultCode>: This is the code that denotes the code of the error. The fault code can be of any given values:

SOAP-ENV:VersionMismatch: It is when an invalid namespace for the SOAP Envelope element is encountered.

SOAP-ENV:MustUnderstand: It is an immediate child element of the Header element, with the mustUnderstand attribute set to 1, was not understood.

SOAP-ENV:Client: The message is incorrectly formed or contained an incorrect information.

SOAP-ENV:Server: There is a problem with the server, and so the message could not proceed.

  • <faultString>: This is the text message which gives a detailed description of the error.
  • <faultActor> (Optional): This is a text string that indicates who caused the fault.
  • <detail>(Optional): This is the element for application-specific error messages. Therefore, the application could have a specific error message for different business logic scenarios.

Advantages of SOAP:

  • WS Security: SOAP defines its own security known as WS Security.
  • Language and Platform independent: SOAP web services can be easily written in any programming language and can be executed in any platform.

Disadvantages of SOAP:

  • Slow: SOAP uses XML format that needs to be parsed to read. It defines many standards that need to be followed while developing SOAP applications. Therefore, it is slow and consumes more bandwidth and resources.
  • WSDL dependent: SOAP uses WSDL and does not have any other mechanism to discover the service.

HTTP Exposing:

The GET operations are handled by an HTTP inbound gateway, while the rest (PUT, POST, and DELETE) are handled by HTTP inbound channel adapters since no response body is sent back to the client.

WSDL/SOAP and HTTP Exposing

Step 1: web.xml

<servlet>
    <servlet-name>springServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:xpadro/spring/integration/configuration/http-inbound-config.xml</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>springServlet</servlet-name>
    <url-pattern>/spring/*</url-pattern>
</servlet-mapping>

Step 2: pom.xml

<properties>
    <spring-version>4.1.3.RELEASE</spring-version>
    <spring-integration-version>4.1.0.RELEASE</spring-integration-version>
    <slf4j-version>1.7.5</slf4j-version>
    <junit-version>4.9</junit-version>
    <jackson-version>2.3.0</jackson-version>
</properties>
 
<dependencies>
    <!-- Spring Framework - Core -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring-version}</version>
    </dependency>
     
    <!-- Spring Framework - Integration -->
    <dependency>
        <groupId>org.springframework.integration</groupId>
        <artifactId>spring-integration-core</artifactId>
        <version>${spring-integration-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.integration</groupId>
        <artifactId>spring-integration-http</artifactId>
        <version>${spring-integration-version}</version>
    </dependency>
     
    <!-- JSON -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>${jackson-version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson-version}</version>
    </dependency>
     
    <!-- Testing -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit-version}</version>
        <scope>test</scope>
    </dependency>
     
    <!-- Logging -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j-version}</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>${slf4j-version}</version>
    </dependency>
</dependencies>

Step 3: http-inbound-config.xml

<int-http:inbound-gateway request-channel="httpGetChannel" reply-channel="responseChannel" supported-methods="GET" path="/persons/{personId}" payload-expression="#pathVariables.personId">     
    <int-http:request-mapping consumes="application/json" produces="application/json">
</int-http:request-mapping></int-http:inbound-gateway> 
<int:service-activator ref="personEndpoint" method="get" input-channel="httpGetChannel" output-channel="responseChannel"></int:service-activator>

Step 4: Define a simple bean.

@Component
public class PersonEndpoint {
    private static final String STATUSCODE_HEADER = "http_statusCode";     
    @Autowired
    private PersonService service;     
    public Message<?> get(Message<String> msg) {
        long id = Long.valueOf(msg.getPayload());
        ServerPerson person = service.getPerson(id);         
        if (person == null) {
            return MessageBuilder.fromMessage(msg)
                .copyHeadersIfAbsent(msg.getHeaders())
                .setHeader(STATUSCODE_HEADER, HttpStatus.NOT_FOUND)
                .build(); 
        }
           return MessageBuilder.withPayload(person)
            .copyHeadersIfAbsent(msg.getHeaders())
            .setHeader(STATUSCODE_HEADER, HttpStatus.OK)
            .build();
    }
         //Other operations
}

Step 5: Define a class.

@JsonIgnoreProperties(ignoreUnknown = true)
public class ClientPerson implements Serializable {
    private static final long serialVersionUID = 1L;     
    @JsonProperty("id")
    private int myId;
    private String name;     
    public ClientPerson() {}     
    public ClientPerson(int id, String name) {
        this.myId = id;
        this.name = name;
    }     
    //Getters and setters
}

Step 6: Add POST and PUT operations in http-inbound-config.xml

<int-http:inbound-channel-adapter channel="routeRequest"
    status-code-expression="T(org.springframework.http.HttpStatus).NO_CONTENT"
    supported-methods="POST, PUT"
    path="/persons, /persons/{personId}"
    request-payload-type="xpadro.spring.integration.server.model.ServerPerson">     
    <int-http:request-mapping consumes="application/json"/>
</int-http:inbound-channel-adapter>
 
<int:router input-channel="routeRequest" expression="headers.http_requestMethod">
    <int:mapping value="PUT" channel="httpPutChannel"/>
    <int:mapping value="POST" channel="httpPostChannel"/>
</int:router> 
<int:service-activator ref="personEndpoint" method="put" input-channel="httpPutChannel"/>
<int:service-activator ref="personEndpoint" method="post" input-channel="httpPostChannel"/>

Step 7: PutOperationsTest

@RunWith(BlockJUnit4ClassRunner.class)
public class PutOperationsTest {
    private static final String URL = "http://localhost:8081/int-http-xml/spring/persons/{personId}";
    private final RestTemplate restTemplate = new RestTemplate();
     
    //build headers method
     
    @Test
    public void updateResource_noContentStatusCodeReturned() {
        HttpEntity<Integer> getEntity = new HttpEntity<>(buildHeaders());
        ResponseEntity<ClientPerson> response = restTemplate.exchange(URL, HttpMethod.GET, getEntity, ClientPerson.class, 4);
        ClientPerson person = response.getBody();
        person.setName("Sandra");
        HttpEntity<ClientPerson> putEntity = new HttpEntity<ClientPerson>(person, buildHeaders());
         
        response = restTemplate.exchange(URL, HttpMethod.PUT, putEntity, ClientPerson.class, 4);
        assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());
         
        response = restTemplate.exchange(URL, HttpMethod.GET, getEntity, ClientPerson.class, 4);
        person = response.getBody();
        assertEquals("Sandra", person.getName());
    }
}

Step 8: PostOperationsTest

@RunWith(BlockJUnit4ClassRunner.class)
public class PostOperationsTest {
    private static final String POST_URL = "http://localhost:8081/int-http-xml/spring/persons";
    private static final String GET_URL = "http://localhost:8081/int-http-xml/spring/persons/{personId}";
    private final RestTemplate restTemplate = new RestTemplate();
     
    //build headers method
     
    @Test
    public void addResource_noContentStatusCodeReturned() {
        ClientPerson person = new ClientPerson(9, "Jana");
        HttpEntity<ClientPerson> entity = new HttpEntity<ClientPerson>(person, buildHeaders());
         
        ResponseEntity<ClientPerson> response = restTemplate.exchange(POST_URL, HttpMethod.POST, entity, ClientPerson.class);
        assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());
         
        HttpEntity<Integer> getEntity = new HttpEntity<>(buildHeaders());
        response = restTemplate.exchange(GET_URL, HttpMethod.GET, getEntity, ClientPerson.class, 9);
        person = response.getBody();
        assertEquals("Jana", person.getName());
    }
}

Facebook Comments
Tags

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Related Articles

Back to top button
Close
Close