Friday, December 11, 2015

Java Web Services



Web services - in my simplistic view, these are the software components exposed over web (HTTP) as a service so various other programs or software modules can be able to interact. For easier understanding purpose, it is similar to how a web application deployed on an application server exposes its functions through a UI that a client program like internet browsers can access and display it. Web service even though communicate over HTTP, the exchange of information happens in an XML document with certain rules - called as SOAP (Simple Object Access Protocol)

Java provides an API to develop these components. This is called JAX-WS (Java API for XML Web Services).
And these can be implemented in 2 ways - RPC (remote procedure call) and in a message oriented i.e. in a document style

As this API makes it so simple, we just need below components to develop a simple webservice using JAX-WS

Lets see an RPC style implementation

1. Need a remote i.e. endpoint interface class
2. A remote implementation class
3. A remote publisher class
4. And a client

Below is the self explainable simple code logic

----------------
package com.myWSPackage;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

@WebService
@SOAPBinding(style = Style.RPC)
public interface IamJustAnInterface{
@WebMethod String implementMe(String name);
}
----------------
package com.myWSPackage;
import javax.jws.WebService;

@WebService(endpointInterface = "com.myWSPackage.IamJustAnInterface")
public class IamAnImplementer implements IamJustAnInterface{
@Override
public String implementMe(String name) {
try{Thread.sleep(10000);}catch(Exception e){}
return "Hi There - at your service : " + name;
}
}
-------------------
package com.myWSPackage;
import javax.xml.ws.Endpoint;

public class IamAPublisher{

public static void main(String[] args) {
  Endpoint.publish("http://localhost:7777/ws/hi", new IamAnImplementer());
    }
}
---------------
package com.myWSPackage;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;

public class WSClient{
  public static void main(String[] args) throws Exception {
  URL url = new URL("http://localhost:7777/ws/hi?wsdl");
    QName qname = new QName("http://myWSPackage.com/", "IamAnImplementerService");
    Service service = Service.create(url, qname);
    IamJustAnInterface ifi = service.getPort(IamJustAnInterface.class);
    System.out.println(ifi.implementMe("Buddy"));
    }
}
---------------------------------------------------

what happens on the client:
I have intentionally put a sleep in the service interface implementation class to capture the stacks

    SocketNativeIO.readBytesPinned(FileDescriptor, byte[], int, int, int)
    SocketNativeIO.socketRead(FileDescriptor, byte[], int, int, int) line: 32
    SocketInputStream.socketRead0(FileDescriptor, byte[], int, int, int)
    SocketInputStream.read(byte[], int, int) line: 129
    BufferedInputStream.fill() line: 218
    BufferedInputStream.read1(byte[], int, int) line: 258
    BufferedInputStream.read(byte[], int, int) line: 317
    HttpClient.parseHTTPHeader(MessageHeader, ProgressSource, HttpURLConnection) line: 690
    HttpClient.parseHTTP(MessageHeader, ProgressSource, HttpURLConnection) line: 633
    HttpURLConnection.getInputStream() line: 1195
    HttpURLConnection.getResponseCode() line: 379
    HttpClientTransport.readResponseCodeAndMessage() line: 198
    HttpTransportPipe.process(Packet) line: 151
    HttpTransportPipe.processRequest(Packet) line: 83
    DeferredTransportPipe.processRequest(Packet) line: 78
    Fiber.__doRun(Tube) line: 587
    Fiber._doRun(Tube) line: 546
    Fiber.doRun(Tube) line: 531
    Fiber.runSync(Tube, Packet) line: 428
    Stub.process(Packet, RequestContext, ResponseContextReceiver) line: 211
    SEIStub.doProcess(Packet, RequestContext, ResponseContextReceiver) line: 124
    SyncMethodHandler.invoke(Object, Object[], RequestContext, ResponseContextReceiver) line: 98
    SyncMethodHandler.invoke(Object, Object[]) line: 78
    SEIStub.invoke(Object, Method, Object[]) line: 107 ----> proxy and stub creation has been taken care by JDK
    $Proxy19.implementMe(String) ---------> is the remote call to the webservice's method
    WSClient.main(String[]) line: 15 ---------> is our client main method


what happens on the server side


    Thread.sleep(long) ------> just sleeps for 10 sec before it sends out the response
    IamAnImplementer.implementMe(String) line: 11 ---> call to the interface method which was exposed as a service
    NativeMethodAccessorImpl.invoke0(Method, Object, Object[])
    NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
    DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
    Method.invoke(Object, Object[]) line: 597
    InstanceResolver$1.invoke(Packet, Method, Object[]) line: 235
    InvokerTube$2.invoke(Packet, Method, Object[]) line: 135
    EndpointMethodHandler.invoke(Packet) line: 246
    SEIInvokerTube.processRequest(Packet) line: 82
    Fiber.__doRun(Tube) line: 587
    Fiber._doRun(Tube) line: 546
    Fiber.doRun(Tube) line: 531
    Fiber.runSync(Tube, Packet) line: 428
    WSEndpointImpl$2.process(Packet, WebServiceContextDelegate, TransportBackChannel) line: 232
    HttpAdapter$HttpToolkit.handle(WSHTTPConnection) line: 460
    HttpAdapter.handle(WSHTTPConnection) line: 233
    WSHttpHandler.handleExchange(HttpExchange) line: 95
    WSHttpHandler.handle(HttpExchange) line: 80
    Filter$Chain.doFilter(HttpExchange) line: 65
    AuthFilter.doFilter(HttpExchange, Filter$Chain) line: 65
    Filter$Chain.doFilter(HttpExchange) line: 68
    ServerImpl$Exchange$LinkHandler.handle(HttpExchange) line: 557
    Filter$Chain.doFilter(HttpExchange) line: 65
    ServerImpl$Exchange.run() line: 529
    ThreadPoolExecutor$Worker.runTask(Runnable) line: 886
    ThreadPoolExecutor$Worker.run() line: 908
    Thread.run() line: 662 ----> the publisher start a thread starts


The document style implementation is all the same way as above except the style declared in the remote
interface class will change to DOCUMENT.

The WSDL will be different for each of these implementations although there seems to be no change in the execution path i.e. stack traces shown above.

In Java EE7, there is support to implement RESTful webservices through the API called JAX-RS.
These are best suited when there is no need for state maintenance, can rely on underlying server caching mechanism and the content will not change dynamically and for light weight message exchanges like handsets, portable communication devices etc,. The RESTful services do not require XML messages or WSDL based API implementations.. They depend/implement the REST verbs like PUT/GET/POST/DELETE.. the implementation is very simple - a root reosource class annotated with the @PATH tells where the implemented java class is located and its methods annotated with the verbs like @GET, @Producer etc., tells which type of request handling will be done, what kind of text will be produced and the output etc., the servlet mapping defined the application's web.xml will tell the resource path and the mapped classes ro invoke.