Google

Feb 21, 2012

Java Web Services Interview Questions and Answers: SOAP clients

Q. How would you go about generating a SOAP Web service client in Java?
A. There are number of IDE based and other tools to achive this. The steps involved include

1. Get hold of the WSDL file for the service.
2. Generate the client Java code using the relevant IDE or maven plugin like jaxws-maven-plugin.
3. Use the generated code within your client Java file to invoke the service. Read the server details like host name and port-number from an environment based configuration file. The URL specified in the WSDL is hard-coded just for the contract sake.
The WSDL file can be drawn as shown below.




The sample WSDL file is OrderServices.WS_getOrdersForAccount.wsdl. This WSDL file could come from a Web service written in any language like C#, Java, etc or an enterprise Service bus like Tibco, Oracle Service Bus, web Methods, etc.


<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="getOrdersForAccountWS" targetNamespace="http://server123/OrderExecutionServices.OrderServices.PublicServices:getOrdersForAccountWS" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:soapjms="http://www.w3.org/2010/soapjms/" xmlns:tns="http://server123/OrderExecutionServices.OrderServices.PublicServices:getOrdersForAccountWS" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/">
  <wsdl:types>
    <xsd:schema targetNamespace="http://server123/OrderExecutionServices.OrderServices.PublicServices:getOrdersForAccountWS" xmlns:tns="http://server123/OrderExecutionServices.OrderServices.PublicServices:getOrdersForAccountWS" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
          <xsd:element name="getOrdersForAccount" type="tns:getOrdersForAccount"/>
          <xsd:element name="getOrdersForAccountResponse" type="tns:getOrdersForAccountResponse"/>
          <xsd:complexType name="getOrdersForAccount">
            <xsd:sequence>
              <xsd:element name="accountNo" type="xsd:string"/>
              <xsd:element name="fromDate" type="xsd:string"/>
              <xsd:element name="toDate" type="xsd:string"/>
              <xsd:element name="minRow" type="xsd:string"/>
              <xsd:element name="maxRow" type="xsd:string"/>
            </xsd:sequence>
          </xsd:complexType>
          <xsd:complexType name="getOrdersForAccountResponse">
            <xsd:sequence>
              <xsd:element maxOccurs="unbounded" name="OrderSummaries" nillable="true" type="tns:OrderSummary"/>
            </xsd:sequence>

          </xsd:complexType>
          <xsd:complexType name="OrderSummary">
            <xsd:sequence>
              <xsd:element name="orderNo" nillable="true" type="xsd:string"/>
              <xsd:element name="description" nillable="true" type="xsd:string"/>
              <xsd:element name="orderDate" nillable="true" type="xsd:string"/>
              <xsd:element name="orderStatus" nillable="true" type="xsd:string"/>
              <xsd:element name="unitsValue" nillable="true" type="xsd:string"/>
              <xsd:element name="nettValue" nillable="true" type="xsd:string"/>
            </xsd:sequence>
          </xsd:complexType>
     </xsd:schema>
  </wsdl:types>
  <wsdl:message name="getOrdersForAccountWS_PortType_getOrdersForAccountResponse">

    <wsdl:part name="parameters" element="tns:getOrdersForAccountResponse">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="getOrdersForAccountWS_PortType_getOrdersForAccount">
    <wsdl:part name="parameters" element="tns:getOrdersForAccount">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="getOrdersForAccountWS_PortType">
    <wsdl:operation name="getOrdersForAccount">

      <wsdl:input message="tns:getOrdersForAccountWS_PortType_getOrdersForAccount">
    </wsdl:input>
      <wsdl:output message="tns:getOrdersForAccountWS_PortType_getOrdersForAccountResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="OrderExecutionServices_OrderServices_PublicServices_getOrdersForAccountWS_Binder" type="tns:getOrdersForAccountWS_PortType">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="getOrdersForAccount">

      <soap:operation soapAction="OrderExecutionServices_OrderServices_PublicServices_getOrdersForAccountWS_Binder_getOrdersForAccount" style="document"/>
      <wsdl:input>
        <soap:body parts="parameters" use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body parts="parameters" use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>

  <wsdl:service name="OrderExecutionServices.OrderServices.PublicServices.getOrdersForAccountWS">
    <wsdl:port name="OrderExecutionServices_OrderServices_PublicServices_getOrdersForAccountWS_Port" binding="tns:OrderExecutionServices_OrderServices_PublicServices_getOrdersForAccountWS_Binder">
      <soap:address location="http://server123:7555/ws/OrderExecutionServices.OrderServices.PublicServices.getOrdersForAccountWS/OrderExecutionServices_OrderServices_PublicServices_getOrdersForAccountWS_Port"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>




Ensure that you have required jar files required for jaxws-rt and jaxws-tools. It depends on the version of Java and Maven you are using.


The jaxws-rt.jar is required if you are using Java version 5. In Maven pom.xml, you will require the following dependnecy if using Java 5. The Java 6 comes with the relevant libraries within rt.jar under javax.xml.ws package.

<dependencies>
 <dependency>
  <groupId>com.sun.xml.ws</groupId>
  <artifactId>jaxws-rt</artifactId>
  <version>2.2</version>
 </dependency>
</dependencies>


If your Maven does not have the jaxws-tools included, then you will require the following dependency jar for the jaxws-maven-plugin.


<dependencies>
 <groupId>com.sun.xml.ws</groupId>
 <artifactId>jaxws-tools</artifactId>
 <version>2.2.1</version>
</dependencies>



Configure the Maven pom.xml file to generate the relevant code to invoke the Web service with the "jaxws-maven-plugin".

<build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxws-maven-plugin</artifactId>
                <version>1.10</version>
                <executions>
                    <execution>
                        <id>compile-orderservice-wsdl</id>
                        <goals>
                          <goal>wsimport</goal>
                        </goals>
                        <configuration>
                            <sourceDestDir>${basedir}/src/main/java</sourceDestDir>
                            <wsdlUrls>
                                <wsdlUrl>${basedir}/src/main/resources/wsdl/OrderServices.WS_getOrdersForAccount.wsdl</wsdlUrl>
                            </wsdlUrls>
                            <packageName>com.myapp.service.ws</packageName>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            
   
   ....
   
</build>


Finally the client class that makes use of the generated classes and the JAXWS classes like QName and BindingProvider.


package com.myapp.ws.client;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;

import org.apache.log4j.Logger;

//...other imports

public class OrderServiceImpl implements OrderService {

    private static final Logger LOG = Logger.getLogger(OrderServiceImpl.class);
 
    private static final String PACKAGE_NAME = "OrderExecutionServices.OrderServices.PublicServices";
 private static final String SERVICE_NAME = PACKAGE_NAME + ".getOrdersForAccountWS";
 private static final String NAMESPACE_URI = "http://server123/OrderExecutionServices.OrderServices.PublicServices:getOrdersForAccountWS"
  
   
    @Override
    public List<order> getOrder(OrderQuery query) throws OrderServiceException {
        LOG.trace("getOrdersForAccount accountNumber=" + query.getAccountNumber());
  //The WSDL service element has the sample endpoint location. Here provide the actual location
  //by reading the <hostname>:<portno> from a config file
        URL url = toUrl("http://myserver:5555/" + "ws/" + SERVICE_NAME +  + "?WSDL");
  // it takes namespaceURI and the localPart as the arguments
        QName qName = new QName(NAMESPACE_URI, SERVICE_NAME);
  //OrderExecutionServicesOrderServicesPublicServicesGetOrderForAccountWS is a generated class from the WSDL using wsimport
        OrderExecutionServicesOrderServicesPublicServicesGetOrderForAccountWS service =
            new  OrderExecutionServicesOrderServicesPublicServicesGetOrderForAccountWS(url, qName);
  //GetOrderForAccountWSPortType is a generated class from the WSDL using wsimport
        GetOrdersForAccountWSPortType port = service.getOrderExecutionServicesOrderServicesPublicServicesGetOrderForAccountWSPort();
        configurePort(port);

   // The binding element in the WSDL defines the operation name as "getOrdersForAccount" 
        List<order> listOfOrders = port.getOrderForAccount(
                query.getAccountNumber(),
                query.getFromDate(),
                queryl.getToDate(),
                query.getStartRow(),
                query.getStartRow() + query.getPageSize());
       
        return listOfOrders;
    }

   

    private void configurePort(Object port) {
        if (port instanceof BindingProvider) {
            BindingProvider bindingProvider = BindingProvider.class.cast(port);
            Map<string, Object> requestContext = bindingProvider.getRequestContext();
            requestContext.put(BindingProvider.USERNAME_PROPERTY, "john"); //should be read from a properties file
            requestContext.put(BindingProvider.PASSWORD_PROPERTY, "");     //should be read from a properties file
            requestContext.put("com.sun.xml.ws.connect.timeout", 1000L);   //should be read from a properties file 
            requestContext.put("com.sun.xml.ws.request.timeout", 20L);     //should be read from a properties file in encrypted format and then decrypted
        } else {
            throw new RuntimeException("Expected " + port + " to be of " + BindingProvider.class);
        }
    }

    private static URL toUrl(String url) {
        try {
            return new URL(url);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
    }

}



Q. How would you generate a sample SOAP payload from the WSDL
A.

1. Open the soapUI tool. If not already installed, download the free version and install it.
2. Create a new soapUI project by clicking File --> New soapUI Project.
3. In the pop-up enter a project name and where it says initial WSDL/WADL point your WSDL file. It could be a local file or a URL pointing to your WSDL.For example, OrderServices.WS_getOrdersForAccount.wsdl.

http://server123:7555/ws/OrderExecutionServices.OrderServices.PublicServices.getOrdersForAccountWS/OrderExecutionServices_OrderServices_PublicServices_getOrdersForAccountWS_Port?wsdl


4. Say okay and yiu will have a soapUI project created with a sample request contang the SOAP payload under the operation "getOrdersForAccount" subfolder. The payload will look like

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ord="http://server123/OrderExecutionServices.OrderServices.PublicServices:getOrdersForAccountWS">
   <soapenv:Header/>
   <soapenv:Body>
      <ord:getOrdersForAccount>
         <accountNo>?</accountNo>
         <fromDate>?</fromDate>
         <toDate>?</toDate>
         <minRow>?</minRow>
         <maxRow>?</maxRow>
      </ord:getOrdersForAccount>
   </soapenv:Body>
</soapenv:Envelope>


Fill in the "?"s and configure the actual endpoint details, etc you will be able to test the actual service from the soapUI tool.

Labels:

8 Comments:

Anonymous Javin said...

Good questions but REST is getting popular day by day and replacing SOAP web services which was standard earlier . By the way I have also blogged about some RESTFul Web service Interview Questions Answers you may like.

5:28 PM, February 26, 2012  
Blogger jaylen watkins said...

EXCELLENT STUFF ABOUT JAVA INTERVIEW QUESTIONS. THANKS.

Interview Questions

9:27 PM, March 12, 2012  
Blogger rupesh said...

wonderful explanation...
clean and clear

2:19 PM, June 07, 2012  
Blogger Unknown said...

Glad you liked it.

2:33 PM, June 07, 2012  
Blogger Ronit said...

It's a nice blog to provide a good information. I bookmarked this blog further more useful information. Thanks for sharing this.... Web Services Company

6:06 PM, September 18, 2012  
Anonymous Anonymous said...

Very good precise coverage

5:19 PM, December 16, 2012  
Anonymous Anonymous said...

Thank you very much for sharing your knowledge

5:46 PM, June 13, 2013  
Blogger Debashish Sahu said...

I am now a Fan of you. It's like reading 5 times from any book is same as reading once the Articles published in this blog. Thank you very much for sharing your knowledge.

8:46 PM, March 12, 2014  

Post a Comment

Subscribe to Post Comments [Atom]

<< Home