Implementing .NET Manufacturing System


The Manufacturing System performs core business logic of asynchronously processing the purchase order request. The .NET Framework enables asynchronous communication out of the box by implementing the .NET Asynchronous Design Pattern. Although in the example Java and .NET services communicate asynchronously, the Java application won't be able to asynchronously invoke the .NET service using this pattern, given that Java doesn't support the .NET asynchronous model, and vice versa. There are a couple of ways to overcome this limitation. In the simplest scenario, the Web services call can be submitted to the Manufacturing system, which later sends POStatus by calling the WarehouseCallback service. On the other side it's important to show a user how to develop asynchronous calls using .NET for which one would perform a Web service call to a Manufacturing system that asynchronously processes this call. To demonstrate the .NET asynchronous programming the Façade pattern, GoF Façade Pattern, is introduced. For the .NET audience this is the Service Interface pattern, and for those who are familiar with Core J2EE Patterns, this component can be interpreted as the Web services Broker. This Façade intercepts an incoming Web services call and passes it further to the corresponding business component for asynchronous processing. The next section delves into various facets of the .NET Manufacturing system.

Manufacturing System Overview

The Manufacturing System needs to implement three main characteristics of the Replenish Stock use case. The first element of the Manufacturing system is processing the Java Warehouse client request. This component is implemented in the form of ManufacturerFaçade, which waits for a request and sends acknowledgement to the Java Warehousing system once the request has arrived. The ManufacturerFaçade follows a Façade GoF pattern and hides .NET semantics of processing the request. The façade invokes the next element of the Manufacturing system, POValidator, to actually perform asynchronous processing of the PO request. The POValidator class validates the purchase order, creates an invoice, and returns the POStatus. The third responsibility of the Manufacturing system is to submit the results of the asynchronous PO processing to the Java WarehouseCallback service, which is already deployed. Figure 8-6 highlights in gray the .NET Manufacturing system.

Figure 8-6. .NET Manufacturing system overview


As can be seen from the diagram, the validatePO method is invoked asynchronously. From the technical standpoint this call is implemented using the .NET Asynchronous Delegate strategy, as is described next.

The .NET Asynchronous Delegate

To implement asynchronous processing in .NET, this chooses to follow the Asynchronous Delegate strategy, for which there needs to be defined a Delegate component that has the same method signature as the method that will be invoked asynchronously. At runtime this Delegate will be extended by .NET CLR with BeginInvoke and EndInvoke methods. The BeginInvoke method is called first, while the EndInvoke method is automatically invoked upon request processing completion. While these wrapper methods are required for asynchronous processing, the actual method can be called synchronously. It is entirely up to the invoker to decide whether to call the method synchronously or asynchronously. In this case, the POValidator class contains the Delegate component:

public delegate void ManufacturerDelegate ( PurchaseOrder po, ref int invoiceNumber, ref String poStatus); 


Once again, the Delegate signature is identical to the method signature:

public void ValidatePO ( PurchaseOrder po,                           ref int invoiceNumber,                           ref String poStatus) 


Implementing .NET POValidator

As the name implies, the POValidator checks the content of the purchase order and reports if it's valid or not. If the PO is valid it creates and returns an invoice; otherwise it throws an exception. The core method of this class is the ValidatePO method, which after purchase order validation sets values for the POStatus. Refer to Listing 8-16.

Listing 8-16. POValidator

namespace J2eeDotNet.Chapter8.Manufacturer {  // Create an asynchronous delegate  public delegate void ManufacturerDelegate ( PurchaseOrder po,     ref int invoiceNumber, ref String poStatus);  // Create a class that processes the purchase order  public class POValidator {  public void ValidatePO ( PurchaseOrder po,     ref int invoiceNumber,ref String poStatus) {   int poNumber = po.PONumber;   if (( po != null || po.ProductQuantity.Length > 0 )){   // generate invoice number and the PO status     invoiceNumber = poNumber*10000;     poStatus = "PO_"+poNumber+"_Validated";   } else {     throw new ProcessPOException("Invalid PO: +poNumber);     }    }   }   public class ProcessPOException : Exception {     public ProcessPOException(string errorMsg): base(errorMsg){       // Extra code can be added here...     }   }//class } //namespace 

In Listing 8-16, aside from the Delegate and the method definition, the POValidator file also includes an exception class, ProcessPOException, which is invoked in case the Purchase Order is invalid.

In continuing to implement the Manufacturing system, the next job is to build the ManufacturerFaçade that accesses the POValidator component.

Implementing ManufacturerFaçade Web Service

The next main step in creating the manufacturing system is to develop the ManufacturerFaçade class, which represents the Web service endpoint and encapsulates logic necessary for asynchronous processing of the purchase order request. The .NET asynchronous model is somewhat complex, so it's important to look into each segment of making this asynchronous call.

The ManufacturerFaçade class contains a single Web method, SubmitPO, which starts with initializing various parameters passed to the BeginInvoke method of the asynchronous Delegate.

Initializing Parameters

As discussed earlier, the BeginInvoke method takes the same parameters as the method invoked asynchronously:

public void ValidatePO ( PurchaseOrder po,                     ref int invoiceNumber,                     ref String poStatus) 


Setting value for the PO status message is the next step in the process. Here the PO invoice value is also initialized.

int poNumber = order.PONumber; String poStatus="PO_"+poNumber+"_Submitted"; int invoice=-1; 


Next is to create an asynchronous Delegate, ManufacturerDelegate, by instantiating the POValidate class and passing the ValidatePO method to the delegate:

POValidator validator = new POValidator(); ManufacturerDelegate manufDelegate =   new ManufacturerDelegate(validator.ValidatePO); 


Prior to calling the BeginInvoke method of the ManufacturerDelegate, it is necessary to specify two more parametersthe asynchronous callback delegate class, AsyncCallback, and the state object. The AsyncCallback delegate class defines a callback method that is invoked once the PO validation is finished. As mentioned earlier, you cannot specify a Java class directly, instead implement a C# class called ProcessResponse that calls the WarehouseCallback to pass the PO status:

ProcessResponse resp = new ProcessResponse(poNumber); 


The semantics of the ProcessResponse class is discussed as follows.

The asynchronous callback delegate, AsyncCallback, is initialized next by passing the callback method, SetPOStatus, of the ProcessResponse class.

AsyncCallback cb = new AsyncCallback(resp.SetPOStatus); 


The .NET asynchronous model allows passing state, which is left empty for simplicity.

Object state = new Object(); 


This completes the initialization process.

Asynchronous Invocation

The next step is to call the BeginInvoke of the Asynchronous Delegate component. The BeginInvoke method initiates the asynchronous call and returns a value of type IAsyncResult interface. This interface links BeginInvoke and EndInvoke operations and provides the result of the ValidatePO method call. It is important to notice the order of arguments passed to the method as shown here. The method parameters are passed first, the callback delegate is always passed as the second to the last parameter, while state is passed last.

IAsyncResult ar = manufDelegate.BeginInvoke(                    order, ref invoice, ref poStatus,                    cb, state); 


When the BeginInvoke method is invoked, the CLR invokes the ValidatePO method using a background thread from an internal thread pool, which is to say the .NET Framework relies on a thread pool to facilitate asynchronous processing.

ManufacturerFaçade

Listing 8-17 shows a listing of the ManufacturerFaçade class returning the PO status.

Listing 8-17. ManufacturerFaçade

public class ManufacturerFaçade : System.Web.Services.WebService { [WebMethod(Description = "Manufacturer WebService Façade")] public string SubmitPO(PurchaseOrder order) {   int poNumber = order.PONumber;   String poStatus="PO_"+poNumber+"_Submitted";   int invoice=-1;   POValidator validator = new POValidator();   ManufacturerDelegate manufDelegate =      new  ManufacturerDelegate(validator.ValidatePO);   // Specifying the callback class   ProcessResponse resp = new ProcessResponse(poNumber);   // Define the asynchronous callback delegate.   AsyncCallback cb = new AsyncCallback(resp.SetPOStatus);   // Define a state object   Object state = new Object();   // Asynchronously invoke the SubmitPO method   IAsyncResult ar = manufDelegate.BeginInvoke(     order, ref invoice, ref poStatus,     cb, state);   return poStatus;   } } 

There are two classes referenced by the ManufacturerFaçade class that still need to be explored. They correspond to the ProcessResponse callback class and the PurchaseOrder class.

Implementing .NET Callback Class

Next up is implementing the .NET callback class that will be used to make a callback from the .NET Manufacturing system to the Java Warehouse system.

Once the PO processing is complete, the callback is invoked. This operation corresponds to the SetPOStatus method of the ProcessResponse class. This method is the OneWayAttribute method, which implies that it does not return any information.

[OneWayAttribute()] public void SetPOStatus(IAsyncResult ar) 


The SetPOStatus method is in control of invoking the WarehouseCallback Web service. Prior to calling the endpoint, the ManufacturerDelegate has to be obtained via the IAsyncResult interface. The way it works is somewhat convoluted. After the .NET Common Language Runtime completes the processing of the SetPOStatus method, the result is stored in the object of AsyncResult. The AsyncResult is used to retrieve its property called AsyncDelegate, which actually corresponds to the ManufacturerDelegate type. This is shown in the code below:

ManufacturerDelegate manufDelegate =      (ManufacturerDelegate)((AsyncResult)ar).AsyncDelegate; 


As already shown, the IAsyncResult interface connects the BeginInvoke call with the EndInvoke call, finishing the loop of executing by calling the EndInvoke method. By invoking EndInvoke, the output of asynchronous PO processing is retrieved.

manufDelegate.EndInvoke(ref invoiceNumber, ref poStatus, ar); 


There are couple output parameters that are receivedinvoiceNumber and POStatus, which will further be passed to the Retailer system via a Web services call:

WarehouseCallbackService server = new WarehouseCallbackService(); bool callbackResult = server.submitSN(invoiceNumber, poStatus); 


Listing 8-18 holds the content of the ProcessResponse class.

Listing 8-18. ProcessResponse Class

public class ProcessResponse {   int poNumber;   public ProcessResponse(int poNum)   {     poNumber=poNum;   }   // This is a CallBack method with the one-way qualifier   [OneWayAttribute()]   public void SetPOStatus(IAsyncResult ar)   {     int invoiceNumber = -1;     String poStatus   = "PO_Unknown";     // Extract the delegate from the AsyncResult     // (1) Need AsyncResult object to get delegate     // AsyncResult asyncObj = (AsyncResult)ar;     // (2) Get original delegate     ManufacturerDelegate manufDelegate =          (ManufacuturerDelegate)asyncObj.AsyncDelegate;     // Obtain the result of the asynchronous call     try     {         manufDelegate.EndInvoke(ref invoiceNumber, ref poStatus, ar);     } catch (ProcessPOException e)     {         throw new SoapException ("Invalid Purchase Order: "+ poNumber,             SoapException.ClientFaultCode);                  }     // Execute callback on the WarehouseCallback Web service     WarehouseCallbackService server = new WarehouseCallbackService();     bool callbackResult = server.submitSN(invoiceNumber, poStatus);     // Log callbackResult...       return;     } } 

This class finishes the loop of asynchronous request processing. One piece of data that has not yet been discussed, however, is how to pass around the PurchaseOrder object, which is presented next.

Creating the Purchase Order

The Purchase Order class acts as a .NET Data Transfer object that encapsulates data that have to be passed to the remote system. While it is fairly easy to pass around common data types such as strings or arrays, passing objects through Web services requires XML serialization. In this example the PurchaseOrder encapsulates three pieces of information: the purchase order number, an array of product name, and an array of product quantity. Each of these datum has corresponding getter and setter methods. The PurchaseOrder class is implemented in .NET as in Listing 8-19.

Listing 8-19. PurchaseOrder.class

namespace J2eeDotNet.Chapter8.Manufacturer {      public class PurchaseOrder      {           int _orderNumber;           string[] _productName;           int[] _productQuantity;           public int PONumber           {                get { return _orderNumber; }                set { _orderNumber=value; }           }           public String[] ProductName           {                get { return _productName; }                set { _productName=value; }           }           public int[] ProductQuantity           {                get { return _productQuantity; }                set { _productQuantity=value; }           }    } } 

The PurchaseOrder object is serialized on the .NET side as part of the ManufacturerFaçade WSDL. The object is deserialized then on the Java side into the Java Web services stub, which is referenced by the Warehouse class. The chapter gets into the semantics of this after the Warehouse class is built. Listing 8-20 is an auto-generated XML representation of the PurchaseOrder.

Listing 8-20. XML snippet for ManufacturerFaçade

  <s:complexType name="PurchaseOrder">   <s:sequence>   <s:element minOccurs="1" maxOccurs="1" name="PONumber" type="s:int" />   <s:element minOccurs="0" maxOccurs="1" name="ProductName" type="s0:ArrayOfString" />   <s:element minOccurs="0" maxOccurs="1" name="ProductQuantity" type="s0:ArrayOfInt" />   </s:sequence>   </s:complexType>   <s:complexType name="ArrayOfString">   <s:sequence>   <s:element minOccurs="0" maxOccurs="unbounded" name="string"   nillable="true" type="s:string" />   </s:sequence>   </s:complexType>   <s:complexType name="ArrayOfInt">   <s:sequence>   <s:element minOccurs="0" maxOccurs="unbounded" name="int" type="s:int" />   </s:sequence>   </s:complexType> 

This XML snippet is part of the ManufacturerFaçade WSDL.

Architect's Note

Ideally, the Purchase Order schema should be defined before the integration work starts. Defining a schema for any objects passed between Web services is a typical top-down approach, which is discussed later in the chapter. Examples of implementation of a top-down approach are provided later on in the book.


To summarize at this point, a number of classes and patterns have been implemented to comprise the .NET Manufacturing System. It may be useful now to go back to the original UML diagram in Figure 8-3, highlighting these components, to review relationships among them.

After implementing the .NET ManufacturerFaçade it is now time to deploy the Manufacturing system.

Deploying .NET Manufacturing System

The chapter continues building and deploying classes using an ant script. The build.xml file contains a single target to compile and deploy all .NET-related classes. This target is called deploy-dotnet-service. However, before starting to build these classes, it is important to ensure that the WarehouseCallback Web service is up and running. Check the http://localhost:8080/J2eeDotNet/Chapter8/Retailer/WarehouseCallback URL before starting the ant script. After validating that the WarehouseCallback is running, you can deploy the .NET Web service.

This command compiles and deploys all necessary constituents of the .NET Manufacturing system. You then can check for a running ManufacturerFaçade service by going to the URL, http://localhost/J2eeDotNet/Chapter8/Manufacturer/ManufacturerFaçade.asmx.

The following screen (Figure 8-7) is displayed in the browser window.

Figure 8-7. Output screen of ManufacturerFaçade


Following is a set of individual steps involved in the deployment process, so that you can build your own code in a similar manner.

Preparing Build Directories

The very first step involves creating build directories specified in the prepare-dotnet task. Refer to Listing 8-21.

Listing 8-21. prepare-dotnet task

  <target name="prepare-dotnet">     <mkdir dir="${iis.bin}"/>     <mkdir dir="${iis.deployroot}/J2eeDotNet"/>     <mkdir dir="${iis.deployroot}/J2eeDotNet/Chapter8"/>     <mkdir dir="${iis.deployroot}/J2eeDotNet/Chapter8/Eanufacturer"/>     <mkdir dir="${build.src}/retailer"/>   </target> 

The iis.bin property corresponds to the location of the Inetpub/wwwroot directory. The rest of the properties are relative to the iis.bin and are defined in the build.xml file.

Generating a WarehouseCallback Proxy Class

In the next step the WarehouseCallback Web service proxy class is prepared, by invoking the wsdl.exe and passing argument parametersthe name of an output class, .NET language, protocol, and location of the WSDL file corresponding to the WarehouseCallback endpoint. Refer to Listing 8-22.

Listing 8-22. WarehouseCallback.cs class

<!-- Creating the WarehouseCallback.cs class --> <exec dir="${build.src}/retailer" executable="${wsdl.home}/wsdl.exe" os="Windows XP"> <arg line="/out:WarehouseCallback.cs /language:CS /protocol:SOAP ${endpoint.warehousecallback}"/> </exec> 

This operation yields the auto-generated source code for the WarehouseCallback.cs class.

Generating WarehouseCallback Assembly

Now it is necessary to create an assembly DLL that will be referenced by the WarehouseCallback client application. This can be achieved by using the csc.exe compiler: csc.exe /target:library WarehouseCallback.cs or an equivalent ant operation, that looks like the following:

<!-- Creating the WarehouseCallback.dll library --> <exec dir="${build.src}/retailer" executable="${csc.home}/csc.exe" os="Windows XP"> <arg line="/target:library /out:${iis.bin}/WarehouseCallback.dll WarehouseCallback.cs"/> </exec> 


This command produces a WarehouseCallback.dll.

Developer's Note

At this point it is helpful to define a simple .NET client application to validate the deployment of the WarehouseCallback. This is a simple unit test, and yet it saves time and effort while troubleshooting distributed applications. Also remember to always display the SOAP message that you are sending over the wire. Previewing the SOAP call can typically help to reveal the details of the call, request, and response parameters.


Compiling .NET Classes

Having deployed the WarehouseCallback DLL, the next step is to compile the PurchaseOrder and POValidate classes that are accessed by the ManufacturerFaçade component. Once again the csc.exe compiler is used to create a single assembly, called PO.dll, as in Listing 8-23.

Listing 8-23. PO.dll

<!-- Compiling .NET classes --> <exec dir="${src.manufacturer}" executable="${csc.home}/csc.exe" os="Windows XP"> <arg line="/target:library /out:${iis.bin}/PO.dll PurchaseOrder.cs POValidator.cs"/> </exec> 

Deploying .NET Assembly

This operation deploys the PO.dll under the Inetpub\wwwroot directory and will be referenced at runtime by the ManufacturerFaçade:

<!-- Deploying the .NET Manufacturer Web service --> <copy file="${src.manufacturer}/ManufacturerFaçade.asmx" todir="${iis.deploy}"/> 


Developer's Note

While this is relying on ant to generate the directory structure and deploy corresponding components, there is more than one deployment option. Depending on your skill set and preferences, you may choose to deploy your .NET application using XCOPY, VS.NET installer, or the Copy Project option in .NET The Visual Studio/IDE.


As a recap, the deployed application encompasses two constituents. The first one corresponds to the ManufacturerFaçade.asmx Web service represented with ASP.NET. It is deployed in the virtual directory, wwwroot. This Web service references the core business logic of the manufacturing system. It represents the second deployment constituent encapsulated into the PO.dll assembly. The callback, ProcessResponse, class invokes the WarehouseCallback Web service represented with WarehouseCallback.dll. These assembly files are located in the bin directory underneath the virtual directory. Listing 8-24 shows a sample deployment hierarchy:

Listing 8-24. Sample Deployment Hierarchy

Inetpub/wwwroot/    |    --- bin            PO.dll            WarehouseCallback.dll   --- J2eeDotNet/Chapter8/Manufacturer           ManufacturerFaçade.asmx 

Previewing .NET ManufacturerFaçade

Once the Web service is deployed the deployed service and its WSDL can be explored. The same screen as was shown earlier is viewable at the corresponding URL, http://localhost/J2eeDotNet/Chapter8/Manufacturer/ManufacturerFaçade.asmx. Under the cover, the .asmx handler is automatically invoked to compile the application and deploy the assembly into the corresponding location. The .asmx handler also automatically creates WSDL. In this case, the client uses a GET request for the .asmx endpoint; therefore, the WSDL can be generated and previewed by appending "?WSDL" at the end of the URL, that is, http://localhost/J2eeDotNet/Chapter8/Manufacturer/ManufacturerFaçade.asmx?WSDL.

Before extending the code any further, look back and examine what has been built so far. The earliest component was WarehouseCallback that defined the SubmitSN method. This class is the last participant in the Replenish Stock flow and is invoked by the Manufacturing system, which was built next. The Manufacturing system embraces a number of components such as ManufacturerFaçade, PurchaseOrder, and POValidator that process the purchase order request. The POValidator class followed the Asynchronous Delegate .NET pattern, which is built into .NET but not into the Java programming language. In order to interoperate with the .NET Asynchronous Delegate model, a layer of abstraction has been created using the GoF Façade pattern. This abstraction is represented via the ManufacturerFaçade ASP.NET application. The ManufacturerFaçade is a Web service acting as a façade to the Retailer system.

By deploying the .NET Manufacturing system, most of the work required to develop the Replenish Stock use case has been accomplished. The only other class left to build is the Warehouse client that invokes the ManufacturerFaçade Web service endpoint. The Retailer system is implemented in Java, thus the Warehouse client is built in Java.

Implementing a Java Warehouse Client

The Warehouse client program is much simpler than any of the classes implemented so far. All the Warehouse client does is to create an instance of the purchase order and pass it to the Manufacturing system. Because the purchase order is processed asynchronously, keep in mind that the ManufacturerFaçade service only returns an acknowledgement.

Deploying a Java Warehouse Application

If you want to skip individual build steps and run the Warehouse client right away, you may do so by invoking the ant script with the run-client option. You will see a series of messages with the final few lines corresponding to the Warehouse output information. Refer to Listing 8-25.

Listing 8-25. ant Script to Deploy a Java Warehouse Application

$ ant run-client Buildfile: build.xml init:      [echo] --- Building j2eedotnet.chapter9 --- prepare: generate-client:      [echo] --- Generating Java stubs for the Manufacturer Web service --- [wscompile] Note: Some input files use unchecked or unsafe operations. [wscompile] Note: Recompile with -Xlint:unchecked for details. compile-client:      [echo] --- Compiling Warehouse application ---     [javac] Compiling 1 source file to C:\bookcd\build\classes run-client:      [echo] --- Running Warehouse application ---      [java] j2eedotnet.chapter8.retailer.Warehouse: In main...      [java] After Impl      [java] End point is: http://localhost/J2eeDotNet/Chapter8/Manufacturer/Manu facturerFaçade.asmx?WSDL      [java] j2eedotnet.chapter8.retailer.Warehouse: The Purchase Order Status is: PO_132_Submitted BUILD SUCCESSFUL Total time: 10 seconds 

The preceding message only corresponds to the initial request submission, whereas the actual processing of the request occurs asynchronously. The actual result of the PurchaseOrder processing, listed in the log file, warehouseCallback.log, contains the invoice number and the status information. This log record is submitted by the WarehouseCallback application. Refer to Listing 8-26.

Listing 8-26. Log record for WarehouseCallback

<record>   <date>2004-10-14T12:38:00</date>   <millis>1097743080865</millis>   <sequence>52</sequence>   <logger>j2eedotnet.chapter8.retailer</logger>   <level>FINE</level>   <class>j2eedotnet.chapter8.retailer.WarehouseCallbackImpl</class>   <method>submitSN</method>   <thread>11</thread>   <message>PurchaseOrder status </message>   <param>Invoice: 1320000</param>   <param>Status: PO_132_Validated</param> </record> 

As usual, the text examines each step of building the Warehouse application. Given that the Warehouse application has to access the .NET Manufacturing endpoint, the Warehouse application is started by generating corresponding client stubs.

Generating .NET ManufacturerFaçade Stubs and Other Components

The only operation performed by the Warehouse is accessing the .NET ManufacturerFaçade. For that, stubs, ties, WSDL, and other necessary components need to be prepared to interoperate between Java and .NET. These can be performed with the wscompile JAX-RPC command. The config.xml file is provided as an input to wscompile, specifying a Java package name for generated classes and the location of the ManufacturerFaçade WSDL file. The package name is used by wscompile when creating Java stubs. The config.xml file for the Warehouse is referenced in Listing 8-27.

Listing 8-27. config.xml for ManufacturerFaçade

<?xml version="1.0" encoding="UTF-8" ?>  <configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/con- fig"> <!--     Warehouse client accesses the WSDL of the ManufacturerFaçade.     The Warehouse client is part of the j2eedotnet.chapter8.retailer package --> <wsdl location="http://localhost/J2eeDotNet/Chapter8/Manufacturer/Manufact urerFaçade.asmx?WSDL" packageName="j2eedotnet.chapter8.retailer"/>  </configuration> 

The actual target invoking wscompile is called generate-client. Refer to Listing 8-28.

Listing 8-28. generate-client Task in the ant Script

  <target name="generate-client" depends="prepare">     <echo message="--- Generating Java stubs, WSDL,and other from the Manufacturer Web service ---"/>     <wscompile         keep="true"         client="true"         base="${build.classes}"         sourceBase="${build.src}"         xPrintStackTrace="true"         verbose="false"         classpath="${compile.classpath}"         config="${etc.client}/config.xml">         <classpath>            <path ref/>         </classpath>     </wscompile>  </target> 

The wscompile command generates stub and interface classes. For interoperability, it is important to access the generated source code. In this case check the PurchaseOrder.java class to be able to create an instance of it, given the Warehouse application passes a PurchaseOrder object to the .NET system. The Java code that follows looks somewhat different from the one originally created with C#. For example, an array was translated into a new object, ArrayOfString and ArrayOfInt, which needs to be created to pass the PurchaseOrder object around. Refer to Listing 8-29.

Listing 8-29. Purchase Order Program

// This class was generated by the JAXRPC SI, do not edit. // Contents subject to change without notice. // JAX-RPC Standard Implementation (1.1.2, build R23) // Generated source version: 1.1.2 package j2eedotnet.chapter8.retailer; public class PurchaseOrder {    protected int PONumber;    protected j2eedotnet.chapter8.retailer.ArrayOfString productName;    protected j2eedotnet.chapter8.retailer.ArrayOfInt productQuantity;    public PurchaseOrder() {    }    public PurchaseOrder(int PONumber,        j2eedotnet.chapter8.retailer.ArrayOfString productName,        j2eedotnet.chapter8.retailer.ArrayOfInt productQuantity) {        this.PONumber = PONumber;        this.productName = productName;        this.productQuantity = productQuantity;    }    public int getPONumber() {        return PONumber;    }    public void setPONumber(int PONumber) {        this.PONumber = PONumber;    }    public j2eedotnet.chapter8.retailer.ArrayOfString getProductName() {        return productName;    }    public voidsetProductName(      j2eedotnet.chapter8.retailer.ArrayOfString productName) {        this.productName = productName;    }    public j2eedotnet.chapter8.retailer.ArrayOfInt getProductQuantity()     {        return productQuantity;     }     public void setProductQuantity(       j2eedotnet.chapter8.retailer.ArrayOfInt productQuantity) {         this.productQuantity = productQuantity;     } } 

Writing the Warehouse Application

The Warehouse application obtains the ManufacturerFaçade Web service stub to access the .NET Web service.

ManufacturerFaçadeSoap_Stub stub = (ManufacturerFaçadeSoap_Stub) (new ManufacturerFaçade_Impl().getManufacturerFaçadeSoap()); 


It then sets the service endpoint value, based on settings specified in the build.xml file:

stub._setProperty(      javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY,      System.getProperty("endpoint")); 


The following step corresponds to initializing the PurchaseOrder object with all specifics of the generated ManufacturerFaçade stub classes:

int poNumber = 132; String [] products = {"Table", "Chair", "Monitor"}; int[] qty = {2,3,4}; PurchaseOrder po =     new PurchaseOrder(poNumber, new ArrayOfString(products), new ArrayOfInt(qty) ); 


As a final step, the Warehouse accesses the stub to submit the PurchaseOrder:

String poStatus = stub.submitPO(po); 


Listing 8-30 is the complete listing of the Warehouse.java class.

Listing 8-30. Warehouse.java Class

public class Warehouse {   public static void main(String[] args)   {   try   {     // Create service stub factory     ManufacturerFaçadeSoap_Stub stub = (ManufacturerFaçadeSoap_Stub)         (new ManufacturerFaçade_Impl().getManufacturerFaçadeSoap());     // Set the Web service Endpoint property,     stub._setProperty(     javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY,     System.getProperty("endpoint"));     // Preparing the PurchaseOrder     int poNumber = 132;     String [] products = {"Table", "Chair", "Monitor"};     int[] qty = {2,3,4};     PurchaseOrder po = new PurchaseOrder(poNumber,         new ArrayOfString(products), new ArrayOfInt(qty) );    System.out.println("j2eedotnet.chapter8.retailer.Warehouse.main():         Accessing endpoint "+System.getProperty("endpoint"));       String poStatus = stub.submitPO(po);    System.out.println("j2eedotnet.chapter8.retailer.Warehouse.main():         The Purchase Order Status is: " + poStatus);     }     catch (Exception ex)     {       ex.printStackTrace();     }   }// main } 

Compiling the Warehouse Java Application

Earlier the compilation of Java classes was described, and it is no different here. Refer to Listing 8-31.

Listing 8-31. compile-client Task in the ant Script

  <target name="compile-client" depends="generate-client">     <echo message="--- Compiling Warehouse application ---"/>      <javac srcdir="${src.retailer}"            includes="**/Warehouse.java"            destdir="${build.classes}">         <classpath ref/>      </javac>   </target> 

Executing the Warehouse Java Client Application

The Warehouse program is executed in Listing 8-32.

Listing 8-32. run-client Task in the ant Script

  <target name="run-client" depends="compile-client">     <echo message="--- Running Warehouse application ---"/>       <java classname="j2eedotnet.chapter8.retailer.Warehouse" fork="true">         <sysproperty key="endpoint" value="${endpoint.manufac- turer}"/>         <classpath ref/>       </java>   </target> 

Achieving Asynchronous Callback in Java

So far this chapter has explored how to embrace .NET solutions for the asynchronous callback strategy. Should one build the Manufacturing system in Java, it would require implementing asynchronous behavior in Java. From a Java EE .NET interoperability standpoint, nothing changes. Web services still remain the core technology for passing a PurchaseOrder request and sending the status callback between the Retailer and the Manufacturing system. What does change, though, is how requests are processed internally. While in the .NET Manufacturing system example, callback method was being passed to the asynchronous delegate; Java does not have a build in callback algorithm. The JDK1.5, also known as Java 5, introduces a new library, java.util.concurrent, to facilitate concurrency in Java applications as well as to address asynchronous processing. Primarily, the Executor framework of java.util.concurrent can be used to build asynchronous computations. Similar to the .NET example, the POValidator class is used to validate the PO and to return a status as a callback to WarehouseCallback. Instead, in this Java example a status class is created to encapsulate the PO id, invoice number, and status message. The status class implements the Serializable interface to be able to serialize the status into an XML document and send it via callback to the .NET Retailer system. Here is a prototype of the status class in Listing 8-33.

Listing 8-33. Implementation of the Status class

public class Status implements Serializble {     PurchaseOrder po;     String status;     int invoice;     public Status(PurchaseOrder po, int inv, String msg){         order = po;         invoice = inv;         status = msg;     }     // setter and getter methods for each attributes } 

The preceding status class is first instantiated by the POValidator upon successful validation of the purchase order. The POValidator in Java is very similar to the one implemented in .NET. The only difference is that in Java a Runnable interface has been implemented to be able to invoke the validatePO method asynchronously in a separate thread.

class POValidator implements Runnable 


The Runnable interfaces mandate implementation of the run() method, which in this case invokes the validatePO method. The validatePO() checks the PO, creates a Status, and invokes the ProcessResponse to make a Web service callback to the Retailer system, as in Listing 8-34.

Listing 8-34. validatePO

    private void validatePO () {        // validate order        // create an invoice or an error message        int invoice = order.getNumber()*1000;        // create status        String statusMsg = "PO_"+order.getNumber()+"_Validated";        Status status = new Status(order, invoice, statusMsg);        // For a callback invoke ProcessResopnse class        ProcessResponse response = new ProcessResponse();        response.setPOStatus(status);     } 

Listing 8-35 shows a snippet of the POValidator class.

Listing 8-35. POValidator

 class POValidator implements Runnable {    private PurchaseOrder order;    public POValidator(PurchaseOrder po) {        order =po;    }    public void run(){        validatePO();    }    private void validatePO () {       // validate order       // create an invoice or an error message       int invoice = order.getNumber()*1000;       // create status       String statusMsg = "PO_"+order.getNumber()+"_Validated";       Status status = new Status(order, invoice, statusMsg);       // For a callback invoke ProcessResopnse class       ProcessResponse response = new ProcessResponse();       response.setPOStatus(status);    }    } 

The next big component to implement comprises the ManufacturerFaçade, which is responsible for submitting the PO to the POValidator. This class uses the new java.util.concurrent library. The single important component of the ManufacturerFaçade corresponds to the Executor class. Although the Java threading is detailed out later in the chapter, here threads are used to achieve asynchronous invocation. The code sample that follows exploits the ThreadPerTaskExecutor class, which is in essence a flavor of an Executor that creates a new thread for each task, to make an asynchronous call to the POValidator:

class ThreadPerTaskExecutor implements Executor {     public void execute(Runnable r) {         new Thread(r).start();     }  } 


In the real world it's much better to recycle threads via the thread pool.

There are multiple options for enabling threading in an application including thread pool creation, thread per task execution or a background thread for all tasks that have to be processed.

The execute method takes a parameter representing a task to be executed. The task is represented via the Runnable interface. The Executor starts a thread that performs a specific Runnable task, to allow the task to be executed asynchronously. Now it's time to demonstrate how to make an asynchronous invocation to validate the purchase order.

Asynchronous Invocation

The ManufacturerFaçade class starts with the submitPO method that follows, which initializes a new Executor thread:

ThreadPerTaskExecutor executor = new ThreadPerTaskExecutor(); 


Then an instance of the POValidator class is created, and the PO request is passed to the constructor:

 POValidator validate = new POValidator(order); 


The POValidator is the task to be passed to the Executor:

executor.execute(validate); 


The POValidator implements the Runnable interface, whose run() method is invoked when the thread is started. This run() method calls validatePO() to validate the actual purchase order.

At the end of the submitPO method, it returns the corresponding Status to the Web service consumer:

String statusMsg = "PO_" order.getOrderNumber()+"_Submitted"; return statusMsg; 


Listing 8-36 is the ManufacturerFaçade class.

Listing 8-36. ManufacturerFaçade Class

Public class ManufacturerFaçade {    // A Web service method    void String submitPO(PurchaseOrder order) {    ThreadPerTaskExecutor executor = new ThreadPerTaskExecutor();    POValidator validate = new POValidator(order);    executor.execute(validate);    // Create a response status message    String statusMsg = "PO_" order.getOrderNumber()+"_Submitted";    return statusMsg;   } } 

Processing the purchase order asynchronously in Java is not the end of the exercise. After the status of the order is ready, a callback needs to be made to the .NET WarehouseCallback system. As a best practice it's best to restrict responsibility of each class and keep the callback invocation within the scope of the ProcessResponse class. Assuming the .NET WarehouseCallback Web service stubs have been generated, the actual invocation of the Web service in Java can be performed as follows (refer to Listing 8-37).

Listing 8-37. ProcessResponse

public class ProcessResopnse {    public void setPOStatus(Status status){        // Create service stub factory, WarehouseCallbackSoap_Stub        WarehouseCallbackSoap_Stub stub = (WarehouseCallbackSoap_Stub) (new WarehouseCallback_Impl().getWarehouseCallbackSoap());      // Set the Web service Endpoint property      stub._setProperty(            javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY,            System.getProperty("dotnetcallback.endpoint"));      // Make a Web service call to .NET WarehouseCallback      boolean ackn = stub.subnmitSN(status);      // Log callbackResult…      } catch (Exception ex) {                 ex.printStackTrace();      } 

All in all, implementing the Replenish Stock use case with the asynchronous callback strategy using an Executor is fairly simple. All that's needed is to create an Executor to execute a task and follow it up with a call to the .NET WarehouseCallback. As a matter of fact, a similar approach with .NET could have been used. More about asynchronous processing in .NET is to come when the chapter talks about the response polling strategy.

SOAP Tools for Java and .NET Developers

With asynchronous Web service development, it is useful to use SOAP tools to take a closer look at the SOAP message sent as a request or response. Once your application has been deployed, the content of the message being sent must be found valid. There are a number of free and commercial tools to perform tasks such as reviewing the content of SOAP request and SOAP response. The .NET WebService Studio is a free tool that lets the user explore the SOAP message. There is a simple GUI tool from Apache, Mindreef's SOAPScope, as well as other tools available on the market.

Automatic Callback via Asynchronous Java Proxy

Creating the .NET ManufacturerFaçade and leveraging the .NET asynchronous model is one way to build interoperability across Java and .NET. The other technique mentioned earlier is Asynchronous Java Proxy. The proxy is a layer of indirection implemented on the Java Warehouse side, which employs threads to make a Web service call. The actual call to the .NET system occurs synchronously. The diagram in Figure 8-8 outlines the details of this technique, highlighting Java code in gray.

Figure 8-8. Asynchronous Java Proxy overview


The Warehouse client makes a call on the ManufacturerProxy to submit the purchase order request. The proxy uses a thread, which submits a request to the .NET system. The actual implementation involves opening the URL connection of the Web service and passing the SoapRequest over that connection. The thread blocks wait for a response and, once the response is available, pass it to the WarehouseCallback.

The Java Proxy technique has been published for a while and is documented under the Sun Developer Network: http://developers.sun.com/sw/building/tech_articles/async_paper.html, where the actual code can be downloaded and previewed. The preceding Java Proxy will be used to build the Replenish Stock use case. Keep in mind that the utility classes rely on Apache's Web services toolkits, xalan.jar and xerces.jar. But if you want to use these utility classes with Sun's WSDP, you will need to change the utilities import statement and recompile them. When you are ready to test out the sample, archive all utility classes into asyncproxy.jar and place it under the lib directory. You can always modify the sample code to fit your application needs.

Implementation Details

The key component of this asynchronous proxy implementation is the wsdlCompiler tool, represented as a wsdlCompiler class. It parses the Web service WSDL and creates all necessary classes to perform asynchronous communication. To be more precise, the wsdlCompiler tool auto-generates the Java Proxy class corresponding to the Web service. The proxy class encapsulates an asynchronous version of the Web method and a synchronous version of it. It is up to the client to invoke the Web method asynchronously. In this case, a new thread is created to execute the executeWebMethod, which passes a SOAP request to the Web service endpoint.

In addition to the proxy class, the wsdlCompiler creates the IWebServiceCallback interface. To make an asynchronous call, the client has to implement this interface and pass the callback instance to the proxy. The purpose of this callback class is to return the response back to the client.

ManufacturerService Web Service

To use wsdlCompiler, it is necessary to deploy the actual Web service. The ManufacturerService that follows is a very simple .NET Web service similar to the ManufacturerFaçade built previously. Refer to Listing 8-38.

Listing 8-38. ManufacturerService .NET Web Service

namespace J2eeDotNet.Chapter8.Manufacturer { public class ManufacturerService : System.Web.Services.WebService { [WebMethod(Description = "Manufacturer WebService")]  // The following demonstrates the Asynchronous Pattern using call- back.  public string SubmitPO(int order) {   PurchaseOrder po = new PurchaseOrder();   po.PONumber = order;   int invoice=-1;   String poStatus = "PO_"+order+"_Submitted";   POValidator validator = new POValidator();   validator.ValidatePO(po, ref invoice, ref poStatus);   return poStatus;   }  } 

The preceding class invokes the POValidator component to validate the order, and the passing argument was simplified to take an integer rather than a complex type. The mapping between the XML schema and Java types can be extended to accommodate compound data types stored in the WsdlCompilerDataTypes.xml file that is accessed by the wsdlCompiler tool to generate the SOAP request and SOAPResponse XML documents.

To deploy the service, place the actual ASP.NET file under the same directory as the ManufacturerFaçade. Browse to the URL: http://localhost/J2eeDotNet/Chapter8/Manufacturer/ManufacturerService.asmx to ensure that the service is running correctly. Here is the WSDL of the Web service that is used next: http://localhost/J2eeDotNet/Chapter8/Manufacturer/ManufacturerService.asmx?WSDL.

Implementing WarehouseCallback Classes

After the Web service is deployed, it is possible to generate a Java Proxy. All that's needed then is to pass the WSDL location to the wsdlCompiler. The ant file can be previewed to see how to do that, but the focus right now are the artifacts of that operation. The wsdlCompiler created a ManufacturerFaçadeProxy and the IWebServiceCallback interface. The callback interface defines one method, done, that needs to be implemented. It is, however, up to the developer to modify the utility classes to generate a more sophisticated callback routine.

public interface IWebServiceCallback{  public void done(InputStream in) ; } 


What is returned is the InputStream that essentially contains an XML SOAPResponse message.

The WarehouseCallback implements the callback interface by simply printing out the content sent to the InputStream. Refer to Listing 8-39.

Listing 8-39. WarehouseCallback Implementation

public class WarehouseCallback implements IWebServiceCallback      {      public void done(InputStream in)      {           try           {                 int i= -1;                 System.out.println("Receiving the callback");           String msg="";                while((i = in.read()) > -1)                {                  System.out.print((char)i);                    }           }           catch(IOException e)           {                e.printStackTrace();           }      } } 

Implementing Warehouse Classes

The Warehouse class is also very simple. It creates a callback instance to pass to the proxy and invokes the proxy to pass it the order id and the callback:

proxy.SubmitPOAsync(orderNumber, callback); 


The proxy contains two methods for each Web service methodone corresponding to synchronous invocation and the other corresponding to asynchronous invocation. Invoking the SubmitPOAsync method implies asynchronous invocation of the SubmitPO Web method. Listing 8-40 is the entire Warehouse class.

Listing 8-40. Warehouse Class

public class Warehouse {   public static void main(String[] args) {       ManufacturerServiceProxy proxy = new ManufacturerServiceProxy();      IWebServiceCallback callback = new WarehouseCallback();      int orderNumber = 1244;      System.out.println("Warehouse.main(): In main... ");      proxy.SubmitPOAsync(orderNumber, callback);      System.out.println("Warehouse.main(): Submitted                PO,"+orderNumber+", to the Proxy...");  } } 

Deploying Asynchronous Proxy Example

To simply run the asynchronous Proxy example, create the run-asyncproxy. This command invokes wsdlCompile to generate the proxy, compiles the Warehouse and the WarehouseCallback classes, and executes the Warehouse client. In the following output, Listing 8-41, the build and compile output is skipped:

Listing 8-41. ant Build Result

$ ant run-asyncproxy Buildfile: build.xml build-asyncproxy: ... compile-asyncproxy: ... run-asyncproxy:     [echo] --- Running CallbackTest application ---     [java] Warehouse.main(): In main...     [java] Warehouse.main(): Submitted PO,1244, to the Proxy...     [java] Receiving the callback     [java] <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/ envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body>  <SubmitPOResponse xmlns="http://tempuri.org/">  <SubmitPOResult>PO_1244_Validated</SubmitPOResult>  </SubmitPOResponse>  </soap:Body> </soap:Envelope> BUILD SUCCESSFUL Total time: 15 seconds 

Build Asynchronous Proxy

There are ant tasks corresponding to the asynchronous Proxy example. To build the Java Proxy and auto generate the callback interface, the wsdlCompiler tool is used, as shown in Listing 8-42:

Listing 8-42. build-asyncproxy Task in the ant Script

   <target name="build-asyncproxy">       <echo message="--- Building async proxy ---"/>       <java classname="asyncproxy.WsdlCompiler" fork="true">           <arg line="${endpoint.manufService}           j2eedotnet.chapter9.asyncproxy"/>           <classpath ref/>        </java>        <move file ="ManufacturerServiceProxy.java"              todir="${src.asyncproxy}"/>        <move file ="IWebServiceCallback.java"              todir="${src.asyncproxy}"/>    </target> 

Compile Asynchronous Proxy Classes

The next step is to compile the classes. Refer to Listing 8-43.

Listing 8-43. compile-asyncproxy Task in the ant Script

   <target name="compile-asyncproxy" depends="build-asyncproxy">       <echo message="--- Compiling async proxy client ---"/>       <javac srcdir="${src.asyncproxy}"             destdir="${build.classes}">           <classpath ref/>       </javac>   </target> 

Run Asynchronous Proxy Example

To run the example, invoke the run-asyncproxy target, as shown in Listing 8-44.

Listing 8-44. run-asyncproxy Task in the ant Script

   <target name="run-asyncproxy" depends="compile-asyncproxy">       <echo message="--- Running CallbackTest application ---"/>       <java classname="j2eedotnet.chapter8.asyncproxy.Warehouse"              fork="true">         <classpath ref/>       </java>    </target> 

Benefits and Limitations

The Asynchronous Java Proxy technique offers Java developers a way to achieve asynchronous processing without getting into the details of the .NET world. However, the biggest limitation of this technique, at least with the provided implementation, pertains to the fact that individual Java threads are going to keep the underlying HTTP connection open until the remote processing of the request is complete. It is also important to leverage a thread pool rather then create a new thread per individual task. This technique does not leverage the .NET asynchrony.

It is worth noting that this technique, just like .NET Façade, can be modified to accommodate the response polling strategy in addition to automatic callback.

Using Java Proxy or .NET Façade?

Where you would use Java Proxy and where you would consider the .NET Façade depends on the developer's skill set and the status of the enterprise. For Java developers it may be much simpler to perform asynchronous Web services communication with Web services, while if the individual is a savvy .NET developer, the .NET Façade may be the way to go. By the status of the enterprise, the fact is that some of the systems are built in such a way that they are very difficult to extend or modify. Therefore, regardless of skill set, choice of options may be limited to accomplish asynchronous Web services across those systems.

You can learn additional techniques of developing a Java EE-based asynchronous callback strategy with JAX-RPC by referring to [AsyncProcJAXRPC].

Asynchronous Callback Summary

By now the semantics of building the asynchronous callback may seem overwhelming and may even shadow the original objective of this chapter. What has been accomplished so far is the asynchronous Java EE-.NET processing that followed the course of the SOA. Design-wise it has started with the asynchronous callback strategy. As part of this effort, it has been demonstrated how to perform asynchronous callback in .NET as well as Java. The next objective is to understand the response polling strategy that is also useful to facilitate asynchronous Java EE .NET communication.




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