Difference between revisions of "Common-gcore-stubs"

From Gcube Wiki
Jump to: navigation, search
(Quick Tour)
Line 10: Line 10:
 
== Quick Tour==
 
== Quick Tour==
  
At the time of writing, most gCube services are JAX-RPC services implemented and running on the gCore stack inside a gCube Hosting Node. <code>common-gcore-stubs</code> allows us to invoke such services without dependencies on that stack, hence from within arbitrary client environments. It does so by interacting on our behalf with the JAX-WS runtime, which is part of the Java platform since version 1.6.
+
At the time of writing, most gCube services are [http://jcp.org/aboutJava/communityprocess/final/jsr101/ JSR101] (JAX-RPC) services implemented and running on the gCore stack inside a gCube Hosting Node. <code>common-gcore-stubs</code> allows us to invoke such services without dependencies on that stack, hence from within arbitrary client environments. It does so by interacting on our behalf with the [http://jcp.org/aboutJava/communityprocess/final/jsr224 JSR224] (JAX-WS) runtime, which is part of the Java platform since version 1.6 as the standard for SOAP-based Web Services and Web Service clients. With <code>common-gcore-stubs</code>, we use a modern standard to call services that align with a legacy standard.
  
 
We provide the library with:
 
We provide the library with:
Line 16: Line 16:
 
* information about the target service, such as its gCube coordinates (service class, service name) and its WSDL coordinates (namespace, porttype name);
 
* information about the target service, such as its gCube coordinates (service class, service name) and its WSDL coordinates (namespace, porttype name);
 
* the address of a target endpoint of the services;
 
* the address of a target endpoint of the services;
* the Service Endpoint Interface (SEI) of the service, i.e. the local Java interface that models the remote API of the service and provides additional information about its endpoint through JSR-181 annotations.  
+
* the Service Endpoint Interface (SEI) of the service, i.e. the local Java interface that models the remote API of the service and provides additional information about its endpoint through [http://jcp.org/aboutJava/communityprocess/final/jsr181/ JSR-181] annotations.  
  
The library gives us back a dynamically generated proxy implementation of the SEI, synthesised by the JAX-WS runtime and then appropriately configured to issue gCube calls to the target endpoint (i.e. propagate the call scope, target service coordinates, client identity, etc.).  
+
The library gives us back a dynamically generated proxy implementation of the SEI, which is first synthesised by the JAX-WS runtime and then appropriately configured by the library to issue gCube calls to the target endpoint (i.e. propagate the call scope, target service coordinates, client identity, etc.). This proxy can serve as a local stub for Acme endpoints.
  
In the following, we illustrate the process and relevant APIs through a simple example.
+
In the following, we run through a simple example to illustrate the process and relevant APIs.
  
===A Dummy Service===
+
===A Sample Service===
  
 
For the sake of simplicity, let us illustrate how to use <code>common-gcore-stubs</code> to call a fictional gCore '''Acme''' service. Let us assume that the remote API of <code>Acme</code> is defined by the following WSDL:
 
For the sake of simplicity, let us illustrate how to use <code>common-gcore-stubs</code> to call a fictional gCore '''Acme''' service. Let us assume that the remote API of <code>Acme</code> is defined by the following WSDL:
Line 57: Line 57:
 
</portType>
 
</portType>
  
       <binding name="AcmePortTypeSOAPBinding" type="tns:AcmePortType">
+
       <binding name="binding:AcmePortTypeSOAPBinding" type="tns:AcmePortType" xlmns:binding=""http://acme.org/bindings"">
 
           <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
 
           <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
 
           <operation name="foo">
 
           <operation name="foo">
Line 70: Line 70:
 
       </binding>
 
       </binding>
  
       <service name="AcmeService">
+
       <service name="service:AcmeService" xlmns:service="http://acme.org/service">
         <port name="AcmePortTypePort" binding="tns:StatelessPortTypeSOAPBinding">
+
         <port name="AcmePortTypePort" binding="binding:StatelessPortTypeSOAPBinding">
 
             <soap:address location="...some address..."/>
 
             <soap:address location="...some address..."/>
 
         </port>
 
         </port>
Line 80: Line 80:
 
</source>
 
</source>
  
Like all gCore services, Acme defines a single porttype, <code>AcmePortType</code>, with a single operation, <code>foo()</code> that takes and returns a string. Like for most gCore services, <code>foo()</code> can be invoked via SOAP/HTTP in a [http://www.w3.org/TR/wsdl#_how-s document/literal] style (essentially request and response types appear in the SOAP <body> as they are defined in <types> section).
+
Like all gCore services, Acme defines a single porttype, <code>AcmePortType</code>, with a single operation, <code>foo()</code> that takes and returns a string. Like in most gCore services, <code>foo()</code> can be invoked via SOAP/HTTP in a [http://www.w3.org/TR/wsdl#_how-s document/literal] style (request and response message parts appear in the SOAP body as the corresponding elements in the <code><types></code> section of the WSDL).
  
'''Note:''' While gCore services are WSDL-first, they use tooling to derive a WSDL complete with binding information from a partial WSDL that includes only logical definitions. The derived WSDL spreads over a number of files that follow a chain of imports. In this scheme, the namespaces used in the different files differ from those used before, which is however of no consequence for our example.
+
'''Note:''' gCore services are normally developed WSDL-first and use tooling to derive a WSDL complete with binding information from a partial WSDL that includes only logical definitions (types, port-types, operations). By design, the tooling spreads the derived WSDL across a number of files that follow a chain of imports. It also defines ad-hoc namespaces for the information it derives (e.g. <code>http://acme.org/service</code> for the <code><service></code> definitions, or <code>http://acme.org/bindings</code> for <code><binding></code> definitions). Here, we present the WSDL as a whole but keep using different namespaces for port-types, bindings, and service definitions so as to facilitate mapping the example to the WSDLs of real gCube services.
 +
 
 +
The WSDL provides the following coordinates about Acme, which we capture in a class of constants to use later with <code>common-gcore-stubs</code>:
 +
 
 +
<source lang="java5">
 +
 
 +
import ....
 +
 
 +
public class AcmeConstants {
 +
 
 +
        public static final String serviceNS = "http://acme.org/service";
 +
public static final String serviceLocalName = "AcmeService";
 +
 +
public static final QName serviceName = new QName(namespace,localname);
 +
 +
public static final String porttypeNS = "http://acme.org";
 +
static final String porttypeLocalName = "AcmePortType";
 +
}
 +
 
 +
 
 +
 
 +
</source>
 +
 
 +
===The Service Endpoint Interface ===
 +
 
 +
In JAX-WS terminology, the SEI is a local Java interface that mirrors the remote API of the Acme service. Its declaration includes annotations that provide the JAX-WS runtime with (some of the) information required to generate an implementation of the interface which can correctly call an Acme endpoint.
 +
 
 +
One way to obtain a SEI is to derive it from the WSDL with tooling, such as the [http://docs.oracle.com/javase/6/docs/technotes/tools/share/wsimport.html wsimport] utility which ships with the JDK. For this example, however, we produce the SEI manually, which gives us more control and makes for cleaner code.
 +
 
 +
<source lang="java5">
 +
 
 +
@WebService(name=porttypeLocalName,targetNamespace=porttypeNS)
 +
public interface AcmeStub {
 +
 
 +
  @SOAPBinding(parameterStyle=BARE)
 +
  String foo(String s);
 +
 +
}
 +
 
 +
</source>
 +
 
 +
We name the SEI to reflect that it acts as a stub of the Acme service. As required by JAX-WS, we annotate the SEI with <code>@WebService</code>, providing the coordinates of the Acme's porttype.
 +
We then declare the method <code>foo</code> with the expected signature. We also annotate the method with <code>@SOAPBinding</code>, to indicate that the the WSDL declaration for <code>foo</code> operation does ''not'' follow the so-called [http://www.ibm.com/developerworks/webservices/library/ws-usagewsdl wrapped pattern], which is otherwise assumed by default.
 +
 
 +
'''Note''': in essence, "bare" means that the elements that carry the input and output strings will not be found in turn inside a holder element, but will appear top-level in the SOAP body. For operations that take and return a single primitive type, such as <code>foo</code> the bare pattern is the natural choice, provided that we name the elements in such a way that the service runtime can easily dispatch requests (here <code>foo</code> does the job).
 +
 
 +
===The Service Descriptor ===
 +
 
 +
 
 +
=== Stubbed Calls ===

Revision as of 12:15, 27 November 2012

common-gcore-stubs is a client-library that interacts with the JAX-WS runtime of the Java platform to generate dynamic JAX-WS proxies of remote gCore services. Architecturally, it operates at the lowest layer of the Featherweight Stack for gCube clients.

common-gcore-stubs is available through our Maven repositories with the following coordinates:

<artifactId>common-gcore-stubs</artifactId>
<groupId>org.gcube.core</groupId>

Quick Tour

At the time of writing, most gCube services are JSR101 (JAX-RPC) services implemented and running on the gCore stack inside a gCube Hosting Node. common-gcore-stubs allows us to invoke such services without dependencies on that stack, hence from within arbitrary client environments. It does so by interacting on our behalf with the JSR224 (JAX-WS) runtime, which is part of the Java platform since version 1.6 as the standard for SOAP-based Web Services and Web Service clients. With common-gcore-stubs, we use a modern standard to call services that align with a legacy standard.

We provide the library with:

  • information about the target service, such as its gCube coordinates (service class, service name) and its WSDL coordinates (namespace, porttype name);
  • the address of a target endpoint of the services;
  • the Service Endpoint Interface (SEI) of the service, i.e. the local Java interface that models the remote API of the service and provides additional information about its endpoint through JSR-181 annotations.

The library gives us back a dynamically generated proxy implementation of the SEI, which is first synthesised by the JAX-WS runtime and then appropriately configured by the library to issue gCube calls to the target endpoint (i.e. propagate the call scope, target service coordinates, client identity, etc.). This proxy can serve as a local stub for Acme endpoints.

In the following, we run through a simple example to illustrate the process and relevant APIs.

A Sample Service

For the sake of simplicity, let us illustrate how to use common-gcore-stubs to call a fictional gCore Acme service. Let us assume that the remote API of Acme is defined by the following WSDL:

<definitions name="Acme"
    targetNamespace="http://acme.org" xmlns:tns="http://acme.org" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 
 	<types>
	<xsd:schema targetNamespace="http://acme.org">
 
               <xsd:element name="foo" type="xsd:string" />
	       <xsd:element name="fooResponse" type="xsd:string" />
 
	</xsd:schema>
	</types>
 
	<message name="fooInputMessage">
		<part name="request" element="tns:foo"/>
	</message>
	<message name="fooOutputMessage">
		<part name="response" element="tns:fooResponse"/>
	</message>
 
	<portType name="AcmePortType">
 
		<operation name="foo">
			<input message="tns:fooInputMessage"/>
			<output message="tns:fooOutputMessage"/>
		</operation>
 
	</portType>
 
      <binding name="binding:AcmePortTypeSOAPBinding" type="tns:AcmePortType" xlmns:binding=""http://acme.org/bindings"">
           <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
           <operation name="foo">
             <soap:operation soapAction="http://acme.org/StatelessPortType/fooRequest"/>
             <input>
                 <soap:body use="literal"/>
            </input>
           <output>
              <soap:body use="literal"/>
           </output>
         </operation>
       </binding>
 
       <service name="service:AcmeService" xlmns:service="http://acme.org/service">
         <port name="AcmePortTypePort" binding="binding:StatelessPortTypeSOAPBinding">
             <soap:address location="...some address..."/>
         </port>
       </service>
 
</definitions>

Like all gCore services, Acme defines a single porttype, AcmePortType, with a single operation, foo() that takes and returns a string. Like in most gCore services, foo() can be invoked via SOAP/HTTP in a document/literal style (request and response message parts appear in the SOAP body as the corresponding elements in the <types> section of the WSDL).

Note: gCore services are normally developed WSDL-first and use tooling to derive a WSDL complete with binding information from a partial WSDL that includes only logical definitions (types, port-types, operations). By design, the tooling spreads the derived WSDL across a number of files that follow a chain of imports. It also defines ad-hoc namespaces for the information it derives (e.g. http://acme.org/service for the <service> definitions, or http://acme.org/bindings for <binding> definitions). Here, we present the WSDL as a whole but keep using different namespaces for port-types, bindings, and service definitions so as to facilitate mapping the example to the WSDLs of real gCube services.

The WSDL provides the following coordinates about Acme, which we capture in a class of constants to use later with common-gcore-stubs:

import ....
 
public class AcmeConstants {
 
        public static final String serviceNS = "http://acme.org/service";
	public static final String serviceLocalName = "AcmeService";
 
public static final QName serviceName = new QName(namespace,localname);
 
	public static final String porttypeNS = "http://acme.org";
	static final String porttypeLocalName = "AcmePortType";
}

The Service Endpoint Interface

In JAX-WS terminology, the SEI is a local Java interface that mirrors the remote API of the Acme service. Its declaration includes annotations that provide the JAX-WS runtime with (some of the) information required to generate an implementation of the interface which can correctly call an Acme endpoint.

One way to obtain a SEI is to derive it from the WSDL with tooling, such as the wsimport utility which ships with the JDK. For this example, however, we produce the SEI manually, which gives us more control and makes for cleaner code.

@WebService(name=porttypeLocalName,targetNamespace=porttypeNS)
public interface AcmeStub {
 
  @SOAPBinding(parameterStyle=BARE)
  String foo(String s);
 
}

We name the SEI to reflect that it acts as a stub of the Acme service. As required by JAX-WS, we annotate the SEI with @WebService, providing the coordinates of the Acme's porttype. We then declare the method foo with the expected signature. We also annotate the method with @SOAPBinding, to indicate that the the WSDL declaration for foo operation does not follow the so-called wrapped pattern, which is otherwise assumed by default.

Note: in essence, "bare" means that the elements that carry the input and output strings will not be found in turn inside a holder element, but will appear top-level in the SOAP body. For operations that take and return a single primitive type, such as foo the bare pattern is the natural choice, provided that we name the elements in such a way that the service runtime can easily dispatch requests (here foo does the job).

The Service Descriptor

Stubbed Calls