Testing Interoperability Between Metro and .NET

By Harold Carr

The March 2007 Tech Tip, Securing Web Services Using WSIT introduced Web Services Interoperability Technology (WSIT), an implementation of open web services technologies that enables interoperability between Java EE and .NET. WSIT along with Java API for XML-Based Services (JAX-WS) comprise the stack of web services technologies in GlassFish v2. The web services stack in GlassFish v2 is called Project Metro or Metro for short. Metro is built into Sun Java System Application Server 9.1. Metro also runs in other containers such as Tomcat.

WSIT, also called Project Tango, includes features that enable advanced web service interoperability with the .NET Windows Communication Foundation (WCF), a set of technologies for building and running connected systems. WSIT also addresses key aspects of web services interoperability such as reliable messaging, transaction handling, and security. What this means is that any combination of Metro-based and WCF-based clients and services can interoperate with support for reliable messaging, transaction handling, and security.

To ensure that the stack of WCF and Metro technologies interoperate properly and provide the proper support, Microsoft and Sun engineers run comprehensive interoperability tests called "plug-fests". You can find out more about the plug-fests, including the scenarios that are tested, by viewing the Web Services Interoperability Plug-Fest Home Page. All tests pass in the current levels of .NET and Metro: .NET 3.0 and Metro 1.0.

In this tip, you'll build and run an interoperability test in which a Metro-based client communicates with a WCF-based service. A package that contains the code for the interoperability test accompanies the tip. The code examples in the tip are taken from the source code of the sample (which is included in the package).

A Reliable One-Way Interoperability Test

The interoperability test you'll build and run in this tip is a "reliable one-way test." This type of test is described in "Scenario #1.1. One-Way Anonymous Client" in the document WCF (Indigo) Introperability Lab: Reliable Messaging. This is a typical enterprise use case where a client sends data to a service for processing but does not wait for a response -- that's why it's called "One-Way". However, the client wants assurances that the messages are received by the service.

The message flow in this test is as follows:

Reliable Messaging Operation
Reliable Messaging Operation
 
  • The client initiates the establishment of a reliable communication channel by sending a CreateSequence protocol message.

  • The service creates a sequence identifier to uniquely identify the reliable channel. The service returns this identifier in a CreateSequenceResponse protocol message.

  • The client sends three application messages. Each of these messages is accompanied with header information containing the sequence identifier for the channel and a message number identifying the message.

  • For each application message received, the service responds with a SequenceAcknowledgement identifying what messages have been received. The service does this without having to wait for the business logic to complete processing.

  • If the client sees that some of the messages it sent have not been received, it retransmits those messages. (This situation is not tested in this tip.)

  • The client closes the channel when the channel is no longer needed. This causes a LastMessage protocol messages to be sent.

  • The service responds with a SequenceAcknowledgement protocol message indicating which messages have been received.

  • Again, if the client sees that some of the messages it sent have not been received, it resends those messages. This is followed by another LastMessage. The LastMessage-resend sequence repeats until all messages have been received by the service. (That is not exercised in this tip.)

  • The client sends a TerminateSequence protocol message.

  • The service responds with an HTTP 202 response indicating that the request has been accepted for processing.

Metro-Based Client

Let's start by creating the Metro-based client. You can view the source code for the client in the file ReliableOneWay.java. Here is a snippet of the source code in that file:

   package reliableoneway.client;
   
   import org.tempuri.IPing;
   import org.tempuri.PingService;
   
   public class ReliableOneWay {
   
       public ReliableOneWay() {}
       
       public static void main(final String[] args) 
       {
        try {
        
            PingService service = new PingService();
            IPing port = service.getCustomBindingIPing();
            
            msg(null, "BEFORE FIRST MESSAGE");
            
            msg(port, "FIRST MESSAGE");
            msg(port, "SECOND MESSAGE");
            msg(port, "THIRD MESSAGE");
            
            msg(null, "TERMINATE");
            
            ((com.sun.xml.ws.Closeable)port).close(); 

Using a reliable messaging (RM)-based web service is no different than using any SOAP-based web service. First you create a proxy to the service (see the section Running wsimport). Here, the service is PingService, which is defined in the WSDL (see the section WSDL). Then you obtain a port defined in that service, in this case, CustomBindingIPing. Then you can send application messages to that service by calling the ping method on the port. Here the method msg calls port.ping(String) when port is not null. In this example, three messages are sent.

These steps are the same steps you would take to use any SOAP-based web service. The one additional step is calling close on the port. This signals Metro to terminate the RM channel if the service is using RM. In general, it's a good idea to close ports when they are no longer needed. This enables Metro to reclaim any resources used by that port.

WSDL

You generate the PingService proxy from the Web Service Definition Language (WSDL) file for the service. You can find the WSDL for the service by going to the Web Services Interoperability Plug-Fest Home Page. Click on the "RM Endpoints (WS-Addressing 1.0)" link. Then click on the "OneWay.svc" link. The address of the WSDL is http://131.107.72.15/ReliableMessaging_Service_WSAddressing10_Indigo/OneWay.svc?wsdl.

The WSDL file is quite large because it is used for other test scenarios besides scenario 1.1, that is, scenarios that involve security. The port that this tip uses is named CustomBinding_IPing. It references the following policy binding:

   <wsp:Policy wsu:Id="CustomBinding_IPing_policy">
     <wsp:ExactlyOne>
       <wsp:All>
         <wsrm:RMAssertion>
           <wsrm:InactivityTimeout Milliseconds="600000"/>
           <wsrm:AcknowledgementInterval Milliseconds="200"/>
         </wsrm:RMAssertion>
         <wsaw:UsingAddressing/>
       </wsp:All>
     </wsp:ExactlyOne>
   </wsp:Policy>  

The RMASssertion in the policy binding specifies an RM policy assertion for the service. Within the assertion, the InactivityTimeout parameter sets then interval of time that the service remains inactive before closing. The AcknowledgementInterval parameter sets the interval of time that a destination waits before sending an acknowledgment to the message source on reliable channels. You can find out more about RM policy assertions in the WS-ReliableMessaging Policy specification. The main point here is that including the RMAssertion in the WSDL and then referencing it in the CustomBinding_IPing binding that is used in the CustomBinding_IPing port causes operations on that port to use reliable messaging.

The Structure of the Test

In this tip, you'll use ant to create the proxy, compile the code, and run the client test. You can also use NetBeans -- for more details, see the WSIT Tutorial.

If you haven't already done so, download and install GlassFish v2. Then download the sample application for the tip and extract its contents. You should now see the newly extracted directory as <sample_install_dir>/interop, where <sample_install_dir> is the directory where you installed the sample application. For example, if you extracted the contents to C:\\ on a Windows machine, then your newly created directory should be at C:\\interop.

Although this tip demonstrates only one scenario, the directory structure below the interop directory is set up such that common artifacts are factored out to be used with other tests. The directory structure is as follows:

  common.xml
  rm     
       build.xml
       netbeans
           ReliableOneWayService
               ...
       src
           reliableoneway
               build.props
               build.xml
               client
                   ReliableOneWay.java
                   ...
               server
                   etc
                       EchoServiceRMCustomOnly.wsdl
                       ReliableOneWay.xsd

At the top level of the directory structure, the build.xml file imports common.xml, where the real action takes place, and defines one target: run-reliableoneway. The run-reliableoneway file cleans the build directory. It then:

  • Runs wsimport
  • Compiles the generated code and the ReliableOneWay.java code
  • Runs the test

Running wsimport

Here is the snippet of code in the build.xml file that runs wsimport:

   <target name="run-reliableoneway">
        
        <ant target="run-wsimport" 
             antfile="src/reliableoneway/build.xml" 
             inheritall="false"/>

Notice that it uses the build.xml file in the rm/src/reliableoneway directory. That file, in turn, uses the build.props file in the rm/src/reliableoneway directory. Here is the contents of build.props:

   test.wsdl=
    http://131.107.72.15/ReliableMessaging_Service_ ...
    
   client.dir=client
   className=reliableoneway.client.ReliableOneWay

The build.props file is a property file that defines test.wsdl to be the location of the WSDL file of the service. It also sets two other parameters used by common.xml so it can be used for other tests that are not covered in this tip.

The build.xml file in the rm/src/reliableoneway directory then uses the run-wsimport target from the common.xml file.

The wsimport task fetches the WSDL file specified in parameter test.wsdl. It then generates the proxy code into the rm/build/classes/org/tempuri directory, and the data schema class into the rm/build/classes/com/microsoft/schemas/_2003/_10/serialization directory. This class is large because it is a superset of all data used by all the interoperability test scenarios.

Compiling the Code and Running the Test

The final two steps in the run-reliableoneway target are:

   <ant target="compile" 
        antfile="src/reliableoneway/build.xml" 
        inheritall="false"/>
   <ant target="run-tests" 
        antfile="src/reliableoneway/build.xml" 
        inheritall="false"/>

The compile step runs the Java Programming Language compiler, javac, on the developer-written code, ReliableOneWay.java. The run-tests step executes the main test class as specified in the className parameter set in build.props file. In this case, className is set to reliableoneway.client.ReliableOneWay.

Note that sysproperty is set in the run-tests target of the common.xml file.

   <sysproperty 
   key="com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump" 
   value="true"/>

This enables the client to send and receive messages.

Setting Environment Variables

Four ant parameters are set from environment variables (here shown in bash syntax):

   export PROXY_HOST=-DproxyHost=my.proxy.example.com
   export PROXY_PORT=-DproxyPort=8765
   export METRO_HOME=/glassfish/b58g
   export TEST_HOME=~/metro-wcf-interop-tests/rm

If you are not behind a firewall then explicitly set PROXY_* to nothing:

   export PROXY_HOST=
   export PROXY_PORT=

Set METRO_HOME to the top-level installation direction of GlassFish. That setting is used to locate Metro JAR files such as webservices-rt.jar and webservices-tools.jar in $METRO_HOME/lib. (If you are using Tomcat or another web container you need to update common.xml to correctly reference the location of the Metro JAR files.)

Executing the Test

If you haven't already done so, start GlassFish by entering the following command:

   $METRO_HOME/bin/asadmin start-domain domain1

Then change to the $TEST_HOME directory and enter the following command on the command line:

   ant  

Note: This test is designed to run with JDK 5. If you want to run the test with JDK6, you need to use the Java Endorsed Standards Override Mechanism.

Test Results

The output of the test should look similar to the content in the example-output-wcf-endpoint.txt file in the rm/src/reliableoneway/client directory.

You can ignore all the WARNING messages at the beginning of the test run, such as the following:

    [java] WARNING: WSP0075: Policy assertion 
    "{http://docs.oasis-open.org/ws-rx/wsrmp/200702}RMAssertion" 
    was evaluated as "UNKNOWN".

These warnings are from the numerous policies for bindings in the WSDL that are not used in this test. Similarly, you can ignore the non-standard SOAP 1.2 binding warning messages in the run-wsimport step.

In the output, search for BEFORE FIRST MESSAGE. This is printed to the console just before the first invocation of port.ping. When port.ping is called, the RM infrastructure holds the application message back -- it first establishes a reliable channel by sending a CreateSequence protocol message.

   Content-Type: application/soap+xml;charset="utf-8";
   action="http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequence"

The CreateSequenceResponse protocol message returned from the service contains an Identifier that will be used to identify the reliable channel.

After the reliable channel is established, the application message is sent containing <Text>FIRST MESSAGE</Text> in the Body element. The header contains a Sequence element that contains the reliable channel Identifier along with a MessageNumber, in this case the number 1.

   <S:Envelope xmlns:..."><S:Header>...
   <ns2:MessageNumber>1</ns2:MessageNumber>...
   </S:Header>...<Text>FIRST MESSAGE</Text>...
   </S:Envelope>

Because this is a oneway message, the response to this message contains an empty Body. The header contains a SequenceAcknowledgement element that contains the Identifier and an AcknowledgementRange with attributes Lower and Upper, in this case the numbers 1 and 1 respectively.

   <s:Envelope xmlns:...><s:Header>...
   <r:SequenceAcknowledgement>
   <r:Identifier>urn:...</r:Identifier>
   <r:AcknowledgementRange Lower="1" Upper="1"/>...
   </r:SequenceAcknowledgement>...
   </r:SequenceAcknowledgement>

This means the lowest message number received by the service was 1 and the highest message number was 1. When there are gaps in the acknowledgement range the client RM infrastructure resends lost messages. It releases message copies (for garbage collection) after those messages have been acknowledged.

Two more application messages are sent with MessageNumbers 2 and 3 respectively.

   <S:Envelope xmlns:...><S:Header>...
   <ns2:MessageNumber>2</ns2:MessageNumber>...
   </S:Header>...><Text>SECOND MESSAGE</Text>...
   </S:Envelope>
   
   <S:Envelope xmlns:...><S:Header>...
   <ns2:MessageNumber>3</ns2:MessageNumber>...
   </S:Header>...<Text>THIRD MESSAGE</Text>...
   </S:Envelope>

The responses contain AcknowledgementRanges with Lower/Upper attributes 1/2 and 1/3 respectively.

TERMINATE is printed to the console then the port.close() is called. This causes the RM infrastructure to send a message with an empty Body. The header of this message contains a Sequence element with the Identifier and a MessageNumber of 4. The header also contains an Action element specifying LastMessage to let the service know the reliable channel is going to be closed.

   <S:Envelope xmlns:...><S:Header>...
   <ns2:MessageNumber>4</ns2:MessageNumber>
   <ns2:LastMessage/>...   </ns2:Sequence>...
   <Action xmlns=...">
   http://schemas.xmlsoap.org/ws/2005/02/rm/LastMessage
   </Action>...

The service responds with a SequenceAcknowledgement containing AcknowledgementRange 1/4 indicating all messages have been received.

   <s:Envelope xmlns:...><s:Header>
   <r:SequenceAcknowledgement>...>
   <r:AcknowledgementRange Lower="1" Upper="4"/>...
   </r:SequenceAcknowledgement>...
   </s:Envelope>

If messages are missing the client resends them.

After the client RM infrastructure sends LastMessage and receives a SequenceAcknowledgement response indicating that all messages have been received, it sends a message with an Action header element containing TerminateSequence.

    Content-Type: application/soap+xml;charset="utf-8";
    action=
   "http://schemas.xmlsoap.org/ws/2005/02/rm/TerminateSequence"

This lets the service know that it can release all resources associated with the reliable channel identified by the Identifier element. The service responds with an HTTP 202 response.

      null: HTTP/1.1 202 Accepted

Summary

This tip showed you how to build and run a reliable messaging test in which a Metro-based client communicates with a WCF-based service, in other words, a public WCF endpoint.

Of course, you can also run the same interoperability test or other interoperability tests using a WCF-based client or a Metro-based service. Running the tests with different combinations of Metro-based and WSF-based clients and servers should enable you to verify interoperability between Metro and .NET. It will also enable you to become a contributor to the open source Metro project and test the interoperability of the code you contribute.

About the Author

Harold Carr is the engineering lead for enterprise web services interoperability at Sun Microsystems. Previous to this role, Harold was responsible for RMI-IIOP load-balancing and fail-over in the Sun Java System Application Server. He designed the core architecture used in Sun's CORBA ORB and in the JAX-RPC 2.0 reference implementation and the scalable socket communications architecture used in SJSAS HTTP and IIOP remoting. Harold helped write the OMG Portable Object Adapter specification and was chairperson of the OMG Portable Interceptor specification. Previous to Sun, he did distributed computing research at Hewlett-Packard Research Laboratories and Schlumberger Research Laboratories, was Chief Architect of Visual Lisp technology at Autodesk, and was a logic simulation consultant for Cirrus Logic. He holds a Ph.D., in Computer Science from the University of Utah.

Comments:

please fix html references to images locations

Posted by Valery on September 29, 2010 at 10:13 PM PDT #

Post a Comment:
Comments are closed for this entry.
About

edort

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today