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 APIsFor 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 ClientThe RetailerDynamicProxyClient program constructs the dynamic proxy as follows:
Dynamic Invocation Interface ClientThe RetailerDIIClient program performs these steps:
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 APIsMicrosoft 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:
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]. |