PA165/Lab session Webservices SOAP

Z FI WIKI
Přejít na: navigace, hledání


Developing webservices with SOAP

In this lab session, we will see how we can deploy webservices with SOAP and JAX-WS. What is needed for the current lab:

What is needed for the current lab:


Configuring Marshaling/Unmarshaling in Netbeans

We will see how you can configure JAXB to Marshal and unmarshal data from and to XML. We can use the schemagen (generate XML schema from Java class) and xjc (Generate Java class from XML Schema) tools.

How to configure JAXB and use it from Netbeans: https://netbeans.org/kb/docs/websvc/jaxb.html


Creating a SOAP webservice published from the JVM

We will show how we can create a SOAP webservice by just using command line tools. Move to a directory in which you want to create the project.

mkdir soap.project
mkdir -p cz/muni/fi/pa165/soap
cd cz/muni/fi/pa165/soap
vi Hello.java

Copy the following content for the service interface:

 
package cz.muni.fi.pa165.soap;
 
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
@WebService
@SOAPBinding(style=SOAPBinding.Style.RPC)
public interface Hello {
	String sayHello(String name);
}
vi HelloWS.java

Copy the content for the implementation of the webservice:

 
package cz.muni.fi.pa165.soap;
 
import javax.jws.WebService;
@WebService(endpointInterface="cz.muni.fi.pa165.soap.Hello")
public class HelloWS implements Hello {
	public String sayHello(String name) {
		return "Hello " + name;
	}
}

At this point, we need to publish our webservice. Create a new class called HelloPublisher.java and add the following content:

 
package cz.muni.fi.pa165.soap;
 
import javax.xml.ws.Endpoint;
public class HelloPublisher {
public static final String URI = "http://localhost:9999/hello";
public static void main(String[] args) {
	HelloWS impl = new HelloWS();
	Endpoint endpoint = Endpoint.publish(URI, impl);
	boolean status = endpoint.isPublished();
	System.out.println("Web service running = " + status);
  }
}


From the root directory compile the three java files (one interface, the implementation and the publisher):

javac -cp . cz/muni/fi/pa165/soap/HelloWS.java cz/muni/fi/pa165/soap/HelloWS.java  cz/muni/fi/pa165/soap/HelloPublisher.java

Let's then run the publisher directly from one terminal:

java  cz/muni/fi/pa165/soap/HelloPublisher 

This will run the main class that will publish the webservice. If you open the webpage at the address http://localhost:9999/hello you will get access to the webservice data:

Service Name:	{http://soap.pa165.fi.muni.cz/}HelloWSService
Port Name:	{http://soap.pa165.fi.muni.cz/}HelloWSPort
	
Address:	http://localhost:9999/hello
WSDL:	http://localhost:9999/hello?wsdl
Implementation class:	cz.muni.fi.pa165.soap.HelloWS

As well, you can access the wsdl definition of the webservice at the address http://localhost:9999/hello?wsdl

This should look like:

<definitions targetNamespace="http://soap.pa165.fi.muni.cz/" name="HelloWSService">
    <types/>
    <message name="sayHello">
        <part name="arg0" type="xsd:string"/>
    </message>
    <message name="sayHelloResponse">
        <part name="return" type="xsd:string"/>
    </message>
    <portType name="Hello">
        <operation name="sayHello">
            <input wsam:Action="http://soap.pa165.fi.muni.cz/Hello/sayHelloRequest" message="tns:sayHello"/>
            <output wsam:Action="http://soap.pa165.fi.muni.cz/Hello/sayHelloResponse" message="tns:sayHelloResponse"/>
        </operation>
    </portType>
    <binding name="HelloWSPortBinding" type="tns:Hello">
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
        <operation name="sayHello">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal" namespace="http://soap.pa165.fi.muni.cz/"/>
            </input>
            <output>
                <soap:body use="literal" namespace="http://soap.pa165.fi.muni.cz/"/>
            </output>
        </operation>
    </binding>
    <service name="HelloWSService">
        <port name="HelloWSPort" binding="tns:HelloWSPortBinding">
            <soap:address location="http://localhost:9999/hello"/>
        </port>
    </service>
</definitions>

In case you need, you can generate a wsdl file automatically by using the wsgen command. By using wsgen -verbose -keep -cp . cz.muni.fi.pa165.soap.HelloWS -wsdl you can generate the wsdl file you need to call it by targeting the implementation class. Try to generate the wsdl file and compare it with the one that has been deployed.

Let's write a consumer for the webservice: given the WSDL file, we can generate a stub for us. We can use the wsimport tool based on the wsdl definition.

First, let's create a new directory for the client project:

mkdir soap.project.client
cd  soap.project.client
mkdir bin
mkdir src

Then we can generate the client code:

wsimport -d bin -s src http://localhost:9999/hello?wsdl

You should have two classes in the folder soap.project.client/src/cz/muni/fi/pa165/soap:

Hello.java → interface to the WS HelloWSService.java → the implementation of the client for connection to the ws

The Hello.java interface will be as follows:

 
package cz.muni.fi.pa165.soap;
 
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.ws.Action;
 
 
/**
 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.2.4-b01
 * Generated source version: 2.2
 * 
 */
@WebService(name = "Hello", targetNamespace = "http://soap.pa165.fi.muni.cz/")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface Hello {
 
    /**
     * 
     * @param arg0
     * @return
     *     returns java.lang.String
     */
    @WebMethod
    @WebResult(partName = "return")
    @Action(input = "http://soap.pa165.fi.muni.cz/Hello/sayHelloRequest", output = "http://soap.pa165.fi.muni.cz/Hello/sayHelloResponse")
    public String sayHello(
        @WebParam(name = "arg0", partName = "arg0")
        String arg0);
 
}
 

The HelloWSService class:

 
package cz.muni.fi.pa165.soap;
 
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;
 
 
/**
 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.2.4-b01
 * Generated source version: 2.2
 * 
 */
@WebServiceClient(name = "HelloWSService", targetNamespace = "http://soap.pa165.fi.muni.cz/", wsdlLocation = "http://localhost:9999/hello?wsdl")
public class HelloWSService
    extends Service
{
 
    private final static URL HELLOWSSERVICE_WSDL_LOCATION;
    private final static WebServiceException HELLOWSSERVICE_EXCEPTION;
    private final static QName HELLOWSSERVICE_QNAME = new QName("http://soap.pa165.fi.muni.cz/", "HelloWSService");
 
    static {
        URL url = null;
        WebServiceException e = null;
        try {
            url = new URL("http://localhost:9999/hello?wsdl");
        } catch (MalformedURLException ex) {
            e = new WebServiceException(ex);
        }
        HELLOWSSERVICE_WSDL_LOCATION = url;
        HELLOWSSERVICE_EXCEPTION = e;
    }
 
    public HelloWSService() {
        super(__getWsdlLocation(), HELLOWSSERVICE_QNAME);
    }
 
    public HelloWSService(WebServiceFeature... features) {
        super(__getWsdlLocation(), HELLOWSSERVICE_QNAME, features);
    }
 
    public HelloWSService(URL wsdlLocation) {
        super(wsdlLocation, HELLOWSSERVICE_QNAME);
    }
 
    public HelloWSService(URL wsdlLocation, WebServiceFeature... features) {
        super(wsdlLocation, HELLOWSSERVICE_QNAME, features);
    }
 
    public HelloWSService(URL wsdlLocation, QName serviceName) {
        super(wsdlLocation, serviceName);
    }
 
    public HelloWSService(URL wsdlLocation, QName serviceName, WebServiceFeature... features) {
        super(wsdlLocation, serviceName, features);
    }
 
    /**
     * 
     * @return
     *     returns Hello
     */
    @WebEndpoint(name = "HelloWSPort")
    public Hello getHelloWSPort() {
        return super.getPort(new QName("http://soap.pa165.fi.muni.cz/", "HelloWSPort"), Hello.class);
    }
 
    /**
     * 
     * @param features
     *     A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.  Supported features not in the <code>features</code> parameter will have their default values.
     * @return
     *     returns Hello
     */
    @WebEndpoint(name = "HelloWSPort")
    public Hello getHelloWSPort(WebServiceFeature... features) {
        return super.getPort(new QName("http://soap.pa165.fi.muni.cz/", "HelloWSPort"), Hello.class, features);
    }
 
    private static URL __getWsdlLocation() {
        if (HELLOWSSERVICE_EXCEPTION!= null) {
            throw HELLOWSSERVICE_EXCEPTION;
        }
        return HELLOWSSERVICE_WSDL_LOCATION;
    }
 
}

We need to just add the class that will use the client implementation we can call it HelloWSClient.

vi  src/cz/muni/fi/pa165/soap/HelloWSClient.java

and use content similar to:

 
package cz.muni.fi.pa165.soap;
 
public class HelloWSClient {
    public static void main(String[] args){
    HelloWSService serviceImpl = new HelloWSService();
    Hello service = serviceImpl.getHelloWSPort(); 
    System.out.println(service.sayHello("World"));
    }
}

Let's compile the class from the root directory:

javac -cp .:bin/ -d bin/ src/cz/muni/fi/pa165/soap/HelloWSClient.java 

then let's run the class:

java -cp .:bin/ cz.muni.fi.pa165.soap.HelloWSClient 

This will call the webservice and print out the message that we set.


Creating a webservice with JAX-WS in Netbeans

Let's see how you can create a webservice with Netbeans support (this is similar to what you can do with REST webservices, if you use Netbeans interface to manage them): https://netbeans.org/kb/docs/websvc/jax-ws.html