Advanced Web Services Technologies


As Web services standards are constantly evolving and improving, the major releases of development APIs such as .NET and the JDK are also being updated and improved with add-ons to keep them up to date with the latest specifications and profiles.

Java EE Web Service APIs

For example, the primary Web services API for Java, JAX-RPC, has been updated and improved to JAX-WS 2.0 (Java API for XML Web Services version 2.0) . This helps to limit confusion around JAX-RPC, which by name seems to suggest that it is an RPC API and not a Web services one. JAX-WS is up to date with conformance to the WS-I Basic Profile 1.1, the WS-I Attachments Profile 1.0, and the WS-I Simple SOAP Binding Profile 1.0. JAX-WS will also be the basis of Java-based interoperability with some of the newer Microsoft technologies such as the Windows Communication Framework (WCF, formerly known as Indigo) [SUNINTER]. New features introduced with JAX-WS include simplified development and deployment of a Web service, support for annotations such as listed in JSR 181 [JSR 181]. JAX-WS offers support for asynchronous client through traditional polling and callback mechanisms. Asynchronous Web services are further discussed in Chapter 8, "Asynchronous Web Services Integration," where JAX-RPC API is used to interoperate with .NET application using callback and polling-based strategies. Additionally, JAX-WS is aimed at the dynamic access of Web services via dynamic proxies. This helps to improve portability of an application.

As an example, with JAX-RPC, a traditional way to access a Web service is by creating an instance of a service and then obtaining a client stub:

// Obtain a copy of the Web service implementation class RetailerService service = new RetailerService_Impl(); // Obtain a client stub RetailerClient rc = (RetailerClient)service.getRetailerPort(); // Invoke the Web service rc.getCatalog(); 


Implementing a similar routine using JAX-WS would allow your code to be portable, as there are no static client stub components that have to be generated. Instead, the service class is loaded at runtime.

Assuming the Retailer Web service is implemented with .NET, you can build an interoperable client by first generating Java source code corresponding to the Web service. You can achieve this via <wsimport> task:

<wsimport    debug="${debug}"    verbose="${verbose}"    keep="${keep}"    extension="${extension}"    destdir="${build.classes.home}"    wsdl="${server.wsdl}">    <binding dir="${basedir}/etc" includes="${server.binding}"/> </wsimport> 


The <wsimport> Ant task is defined through the com.sun.toolsws.ant.WsImport class:

    <taskdef name="wsimport" classname="com.sun.tools.ws.ant.WsImport">        <classpath ref/>     </taskdef> 


You can then compile auto-generated source code and access the Web service in the following manner:

// Access the Web service port RetailerSoap port =  new Retailer().getRetailerSoap(); // Invoke Web service port.getCatalog(); 


With the JAX-RPC library, there is also a way to dynamically access a Web service. In the previous example of building the Java-based client to access a Web service, static client implementation was detailed out. There are two more types of clients that can be developed with JAX-RPCDynamic Proxy client and Dynamic Invocation Interface client. Figure 4-7 outlines all categories of clients that can be used with JAX-RPC.

Figure 4-7. JAX-RPC WS client types


The next two subsections demonstrate how to build the Dynamic Proxy Client and the Dynamic Invocation Interface (DII) client. You can learn more about building Web services with JAX-RPC and various client types at [JAX-RPC_Env].

Dynamic Proxy Client

The RetailerDynamicProxyClient program constructs the dynamic proxy as follows:

  1. Creates a service object named retailerService:

    Service retailerService =      serviceFactory.createService(retailerWsdlUrl,            new QName(nameSpaceUri, serviceName)); 

    A service object is a factory for proxies. To create the service object (retailerService), the program calls the createService method on another type of factory, a ServiceFactory object.

    The createService method has two parameters, the URL of the WSDL file and a QName object. At runtime, the client gets information about the service by looking up its WSDL. In this example, the URL of the WSDL file points to the WSDL that was deployed with the .NET-based Retailer service:

    http://localhost/retailerService/Retailer?WSDL 

    A QName object is a tuple that represents an XML qualified name. The tuple is composed of a namespace URI and the local part of the qualified name. In the QName parameter of the createService invocation, the local part is the service name, retailerService.

  2. The program creates a proxy (retailerProxy) with a type of the service endpoint interface RetailerSoap):

         RetailerSoap retailerProxy =      (RetailerSoap)retailerService.getPort(new QName(nameSpaceUri, portName),            RetailerSoap.class); 

    The retailerService object is a factory for dynamic proxies. To create retailerService, the program calls the getPort method of retailerService. This method has two parametersa QName object that specifies the port name and a java.lang.Class object for the service endpoint interface (RetailerSoap). The RetailerSoap class is generated by wscompile. The port name (RetailerSoap) is specified by the WSDL file.

Dynamic Invocation Interface Client

The RetailerDIIClient program performs these steps:

  1. Creates a Service object.

    Service service = factory.createService(new        QName(qnameService)); 

    To get a service object, the program invokes the createService method of a ServiceFactory object. The parameter of the createService method is a QName object that represents the name of the service, Retailer. The WSDL file specifies this name as follows:

    <service name="Retailer"> 

  2. From the service object, creates a Call object:

    QName port = new QName(qnamePort); Call call = service.createCall(port); 

    A Call object supports the dynamic invocation of the remote procedures of a service. To get a Call object, the program invokes the Service object's createCall method. The parameter of createCall is a QName object that represents the service endpoint interface. In the WSDL file, the name of this interface is designated by the portType element:

    <portType name="RetailerSoap"> 

  3. Sets the service endpoint address on the Call object: call.setTargetEndpointAddress(endpoint);

    In the WSDL file, this address is specified by the <soap:address> element.

  4. Sets these properties on the Call object:

    SOAPACTION_USE_PROPERTY SOAPACTION_URI_PROPERTY ENCODING_STYLE_PROPERTY 

    To learn more about these properties, refer to the SOAP and WSDL documents listed in the references section at the end of this chapter.

  5. Specifies the method's return type, name, and parameter:

    QName QNAME_TYPE_STRING = new QName(NS_XSD, "string"); call.setReturnType(QNAME_TYPE_STRING); call.setOperationName(new QName(BODY_NAMESPACE_VALUE,                     "getOrderStatus")); call.addParameter("OrderNumber", QNAME_TYPE_INT,                      ParameterMode.IN); 

    To specify the return type, the program invokes the setReturnType method on the Call object. The parameter of setReturnType is a QName object that represents an XML string type.

    The program designates the method name by invoking the setOperationName method with a QName object that represents getOrderStatus.

    To indicate the method parameter, the program invokes the addParameter method on the Call object. The addParameter method has three arguments: a String for the parameter name (String_1), a QName object for the XML type, and a ParameterMode object to indicate the passing mode of the parameter (IN).

  6. Invokes the remote method on the Call object:

    Object[] params = new Object[]{new Integer(1)}; String result = (String)call.invoke(params); System.out.println(result); 

    The program assigns the parameter value (order number) to an array (params) and then executes the invoke method with the object array as an argument.

Here is a complete listing of the source code for the Retailer DII client:

package j2eedotnet.chapter4.retailerservice.rpcstubs.client; import javax.xml.rpc.Call; import javax.xml.rpc.Service; import javax.xml.rpc.JAXRPCException; import javax.xml.namespace.QName; import javax.xml.rpc.ServiceFactory; import javax.xml.rpc.ParameterMode; import java.net.URL; /** *Dynamic Invocation Interface Client for Retailer Service */ public class RetailerDIIClient {      private static String qnameService = "Retailer";      private static String qnamePort = "RetailerSoap";      private static String BODY_NAMESPACE_VALUE =           "http://tempuri.org/";      private static String ENCODING_STYLE_PROPERTY =            "javax.xml.rpc.encodingstyle.namespace.uri";      private static String NS_XSD =           "http://www.w3.org/2001/XMLSchema";      private static String URI_ENCODING =            "http://schemas.xmlsoap.org/soap/encoding/";      public static void main(String[] args) {           System.out.println("Endpoint address = " + args[0]);           String UrlString = args[0] + "?WSDL";           try {                ServiceFactory factory =                     ServiceFactory.newInstance();                URL retailerWsdlUrl = new URL(UrlString);                Service service = factory.createService(new                     QName(BODY_NAMESPACE_VALUE,qnameService));                QName port =                     new Name(BODY_NAMESPACE_VALUE,qnamePort);                Call call = service.createCall(port);                call.setTargetEndpointAddress(args[0]);                call.setProperty(Call.SOAPACTION_USE_PROPERTY,                     new Boolean(true));                call.setProperty(Call.SOAPACTION_URI_PROPERTY,                      "http://tempuri.org/getOrderStatus");                call.setProperty(ENCODING_STYLE_PROPERTY, "");                QName QNAME_TYPE_STRING =                                new QName(NS_XSD, "string");                call.setReturnType(QNAME_TYPE_STRING);                QName QNAME_TYPE_INT =                    new QName(NS_XSD, int");                call.setOperationName(                  new Name(BODY_NAMESPACE_VALUE,"getOrderStatus"));                call.addParameter("OrderNumber", QNAME_TYPE_INT,                     ParameterMode.IN);                Object[] params = new Object[]{new Integer(1)};                String result = (String)call.invoke(params);                System.out.println(result);          } catch (Exception ex) {               ex.printStackTrace();          }     } } 


After having delved into a bit more detail on the JAX-RPC side, following is a closer look at .NET Web services APIs.

.NET Web Service APIs

Microsoft releases updates to the .NET Framework for Web services in the form of the Web Services Enhancements (WSE) packs. These are designed to simplify the development and deployment of Web services that comply with the published standards, particularly in the area of security. The latest version, WSE 3.0, an update to .NET 2.0, supports Kerberos tickets, X.509 certificates, and the most up-to-date WS-Security specifications. In addition to security, WSE 3.0 implements declarative behavior for security, where the security behavior of a service may be implemented using policy assertion files. These are then enforced in source code through use of attributes on the appropriate classes and methods [MSWSE3]. It also provides interoperability with the Windows Communication Foundation.

The Windows Communication Foundation, formerly known as Indigo, is the long-term strategy from Microsoft for connected systems, both synchronous and asynchronous. It is intended as a long term replacement for all technologies used for systems such as Web services, MSMQ, COM+, and .NET Remoting. It provides a single, consistent API for delivering software as a service that is secure, reliable, transactable, and conforms to the WSI Basic Profile. When developing for WCF, the developer mindset is to work with the ABC mnemonic:

  • A is for the Service Address Where is the service located?

  • B is for the Service Binding What methodology is used to communicate with it? Is it synchronous using SOAP or asynchronous using messaging?

  • C is for the Service Contract What does the service do? How do I invoke its methods? What do I pass in, and what do I get out?

To create a service, one has to first create the service contract, which is very similar to the initial step in creating a Java Web service as outlined previously, and then build an interface that is to be implemented later.

namespace IndigoRetailer {    using System;    using System.ServiceModel;    [ServiceContract()]    public interface IRetailer    {        [OperationContract]        string getProductCatalog();    } } 


For the WCF to recognize this as a service, the service level interface is attributed with the [ServiceContract()] declaration, and the individual methods that are to be exposed as Web methods are attributed with [OperationContract].

Next, the service class itself is implemented.

using System; using System.ServiceModel; namespace IndigoRetailer {       public class WCFRetailerService : IRetailer       {          public double getProductCatalog()          {             String dReturn = "Returned Values";             return dReturn;          }       }    } 


The Indigo classes are implemented in the ServiceModel namespace within ServiceModel.dll. To compile a WCF service, the following command is used:

Csc /r:System.ServiceModel.dll /out:WCFRetailerService.dll         /t:library WCFRetailerService.cs 


The service needs to be configured for the runtime to understand how to use it and how it should be conformed to any profiles, such as the WS-I Basic Profile.

This is achieved using web.config, where the <system.serviceModel> node configures how WCF uses this service.

<system.serviceModel>  <services>    <service behaviorConfiguration="RetailerBehavior"        type="IndigoRetailer" >        <endpoint address=""          binding="wsHttpBinding"          bindingConfiguration="Binding1"          contract="IndigorRetailer.IRetailer" />    </service>  </services>  <behaviors>    <behavior configurationName="RetailerBehavior"      returnUnknownExceptionsAsFaults="True">    </behavior>  </behaviors>  <bindings>     <wsHttpBinding>       <binding configurationName="Binding1" />     </wsHttpBinding>   </bindings> </system.serviceModel> 


Within this configuration, the bindings behavior is set up, as well as the address endpoint of the service. The last thing that is needed is a service mapperwhich is a simple text file (usually called service.svc). This file maps calls to the service to the appropriate class files and is placed within the IIS virtual directory in which the service resides and looks like this

<@Service language=c# Debug="true"     %> 


The WSDL for the service can now be accessed using the service mapper in this way:

http://localhost/servicedirectory/service.svc?wsdl 


The WCF toolkit provides a tool, svcutil, which can be used to create proxies to this service and the necessary configuration files for clients to access them. It is used like this

svcutil /language:C# /config:app.config http://localhost/servicedirectory/service.svd?wsdl 


Extensions to the JAX-WS API from Sun will allow for future interoperability between Java and WCF applications. At the time of writing, these are not yet available [SUNINTER].




Java EE and. Net Interoperability(c) Integration Strategies, Patterns, and Best Practices
Java EE and .NET Interoperability: Integration Strategies, Patterns, and Best Practices
ISBN: 0131472232
EAN: 2147483647
Year: N/A
Pages: 170

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net