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 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: Web services