1.2. First Java SOAP client (rpc/encoded or literal and document/literal in section 1.2.5)

You need to have your RcxReadLS.java file, see the Section called Use AXIS and JAX-RPC to create a SOAP client with WSDL2Java (for rpc encoded or document literal operation style) and after you can create your ClientSEI class.

1.2.1. The client class

Here you will need to have the package javax/xml available on your machine (download and install JWSDP (or just JAX-RPC) at java.sun.com/webservices.), so put jaxrpc-*.jar and jax-qname.jar (should be in /lib) in your library path. Then write and compile the following class in the rcxwsclient package associated directory (your_project/rcxwsclient directory of your project):

Example 1-3. The client using the Service Endpoint Interface class: ClientSEI.java

NoteNote
 

This code is the same (from the point 1 to the point 6 of this listing) for RPC/encoded or document/literal operation style web service. Change eventually the point 7 of this listing if you want to consume my on-line document/literal operation style web service.

I have a little tool that could help you to extract all the attributes and namespaces needed from a WSDL. So you can use it if you want to consume another Java web service, or another web service returning simple types (check my home page to see if the tool is on-line). I'm still working on this project to extends its capabilities to more complex WSDL. Check my home page regularly for updates and news. If something doesn't work, you can always mail me at pascal botte for help and support.


package rcxwsclient;

import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;

import rcxwsclient.sei.RcxReadLS;

/**
 * @author
 *
 * You can use this code "as is" for my on-line RPC/encoded
 * web service (http://www.pascalbotte.be/rcx-ws-rpc/rcx). You also have the opportunity to use
 * a document/literal version on-line (http://www.pascalbotte.be/rcx-ws/rcx).
 * See the comments. 
 * The point seven (/*7*/)
 * need to be changed if you want to consume my on-line
 * document/literal web service. In this case follow the code
 * of the section 1.2.5 for the point seven of this listing.
 * Here we will just use the Service Endpoint Interface (SEI) 
 * to generate our stub (RcxReadLS object).
 * This example use only the method readLS of the interface.
 */

public class ClientSEI {

  public static void main(String[] args) 

  /*
  * Send the string : "RCX with Lejos" and echo the response of the web service
  */
  {
		
    try {
	  // Create a service class with WSDL information.
          // "http://phonedirlux.homeip.net/wsdl" is the targetnamespace 
          // in the wsdl for my web service. You will find it under the
          // WSDL namespace denomination
          // at the end of the little report generated by my on-line
          // WSDL parser (http://www.pascalbotte.be/service.php).
          // "MyRcxService" is the value of the "name" attribute 
          // of the tag "definitions" in the wsdl.
          // You will also find it at Service name
          // still in my WSDL parser.
  /*1*/	  QName serviceName = new QName(
		"http://phonedirlux.homeip.net/wsdl",
		"MyRcxService");
          
          // If necessary, replace the url by the one linking to 
          // the WSDL of the web service you want to consume.
          // The url below is the one for my rpc/encoded web service
          // Use http://www.pascalbotte.be:80/rcx-ws/rcx?WSDL to
          // consume my document/literal on-line version.
  /*2*/	  URL wsdlLocation = new URL
		("http://www.pascalbotte.be:80/rcx-ws-rpc/rcx?WSDL");

          // Service
  /*3*/	  ServiceFactory factory = ServiceFactory.newInstance();
  /*4*/	  Service service = factory.createService(
		wsdlLocation,
		serviceName);
							
	  // Get sei implementation for port, create our RcxReadLS object
          // Again, you have to use the WSDL namespace.
          // "RcxReadLSPort" is the name attribute of "port" under "service" at the end of wsdl,
          // you will also find it as Port name
          // in my WSDL parser.
  /*5*/	  QName  portName = new QName("http://phonedirlux.homeip.net/wsdl", "RcxReadLSPort");
  /*6*/	  RcxReadLS objRcx = (RcxReadLS) service.getPort(portName, RcxReadLS.class);
					
	  // Invoke the remote procedure: just send the static string
          // of your choice
          // Use this code "as is" for my on-line RPC/encoded web service or
          // change the following lines by the ones in the 1.2.5 section
          // if you want to consume my on-line document/literal web service.
          // Here you can send a string message of your choice.
          // You can send your e-mail address if you want, so I will find
          // it in my log, and if something goes wrong I can eventually
          // help you.
  /*7*/	  String val = objRcx.readLS("Your message here, with eventually your e-mail address");
	  System.out.println("Rcx web service message: " + val);

	}
    catch (Throwable t) {
      t.printStackTrace();
    }
  }

1.2.2. Test the client

Now check if my web service is on-line at availability. You can also mail me at pascal botte, I will turn on my RCX if possible.

If the service is on-line, execute the client with your favorite IDE, or just with a command line. Here is what you should see (if you begin with Java: go to the directory containing /rcxwsclient):

[your_prompt]$java rcxwsclient.ClientSEI
Rcx web service message: Value: 0 (test) with the RCX running Lejos JVM

Congratulation, you just created your (first?) client of a SOAP web service.

1.2.3. View the SOAP messages

Now that we have something working, it's time to see the SOAP messages exchanged between the web service and your client with the TcpTunnelGui tool. Go to Apache Soap and install the package. Then put the file soap.jar under your library path and you can invoke the tool.

[your_prompt]$java org.apache.soap.util.net.TcpTunnelGui 8070 www.pascalbotte.be 80

Here we use the tool to listen on localhost:8070, so change the line

 URL wsdlLocation = new URL
		("http://www.pascalbotte.be:80/rcx-ws/rcx?WSDL"); // or rcx-ws-rpc if you use my rpc/encoded web service

by

 URL wsdlLocation = new URL
		("http://localhost:8070/rcx-ws/rcx?WSDL"); // or rcx-ws-rpc if you use my rpc/encoded web service

in your client class. Compile and execute your client. You should see in the TcpTunnelGui application the SOAP messages listed (what your client send in the left pane, what you receive in the right pane). You will also find the wsdl returned by the web service in the right pane. We will see later how to create a simple XML message and send it to the web service by studying the messages showed in TcpTunnelGui.

1.2.4. Rcx live, reading light sensor (still rpc/encoded)

Here is how to test my rpc/encoded remote procedure: int readLSpercent(int int_1) which send an id (value 1) and return a real light sensor value in percent from the RCX (0 meaning totally dark and 100 meaning maximum light)! You have to make two very simple changes:

NoteNote
 

This code is for my rpc/encoded operation style. To consume my document/literal web service, go to the Section called Simple SEI client for document/literal operation style.

  1. Uncomment the line:

    public int readLSpercent(int int_1) throws java.rmi.RemoteException;

    in your RcxReadLS.java file.

  2. Add the line

    System.out.println("Light sensor value: " + objRcx.readLSpercent(1));

    at the end of your try{} bloc, after the call to the method readLS() in your ClientSEI.java file.

You can now compile and run your project, you should have something like (ask me to turn on my RCX brick: pascal botte).

[your_prompt]$java rcxwsclient.ClientSEI
Rcx web service message: Value: 0 (test) with the RCX running Lejos JVM
Light sensor value: 53

You can test it at different time of the day, it's GMT + 2 here...

1.2.5. Simple SEI client for document/literal operation style

Few things change if you want to consume a document/literal web service using this technique, so I will just mention what you have to change to build your client.

  1. Add the option -W when you call the application WSDL2Java, so the tool will generate all the class wrapper your client need. Do not forget to use the url for my document/literal web service: http://www.pascalbotte.be/rcx-ws/rcx?WSDL .

  2. See Example 1-3 for the creation of the object objRcx and replace the point seven of this example by the code below to consume the readLS() remote procedure. Again, do not forget to use the url above (document/literal version).

    // Invoke the remote procedure readLS
    // Use the wrapper class ReadLS to compose the request type
      net.homeip.phonedirlux.types.ReadLS req = new net.homeip.phonedirlux.types.ReadLS();
      req.setString_1("your message or your e-mail");
    
    // Again, use the wrapper class ReadLSResponse as the return type of your call,
    // and your request type as param
      net.homeip.phonedirlux.types.ReadLSResponse ret = objRcx.readLS(req);
      System.out.println("Rcx light sensor simulation: " + ret.getResult());

1.2.6. SOAP Clients: Axis and JAX-RPC "drink" complex type (document/literal)

You can use the same structure for all the other remote procedure call of my (or another?) document/literal web service. Find below the listing for all the call involving the use of complex type:

// Invoke the remote procedure status

  net.homeip.phonedirlux.types.Status reqS = new net.homeip.phonedirlux.types.Status();

  net.homeip.phonedirlux.types.StatusResponse retS = objRcx.status(reqS);
  net.homeip.phonedirlux.types.RcxResponse rcxrespObj = retS.getResult();
  System.out.println("Remote procedure status(): ");
  System.out.println("Rcx message: "+ rcxrespObj.getStatus());
  System.out.println("Free memory: "+ rcxrespObj.getMemory());
  System.out.println("Total memory: " + rcxrespObj.getMemoryTot());
  System.out.println("Internal clock: " + rcxrespObj.getCurrentTime());
  System.out.println("Battery level: " + rcxrespObj.getBattery());

// Invoke the remote procedure collInt()
  net.homeip.phonedirlux.types.CollInt reqCI = new net.homeip.phonedirlux.types.CollInt();
  net.homeip.phonedirlux.types.CollIntResponse retCI = objRcx.collInt(reqCI);
  int[] array = retCI.getResult();
  for(int x=0; x < array.length; x++)
    System.out.println("Value" + x + ": " + array[x]);

// Invoke the remote procedure collPos()
  net.homeip.phonedirlux.types.CollPos reqCP = new net.homeip.phonedirlux.types.CollPos();
  net.homeip.phonedirlux.types.CollPosResponse retCP = objRcx.collPos(reqCP);
  net.homeip.phonedirlux.types.PosCol[] objPC = retCP.getResult();
  for(int x=0; x<objPC.length; x++)
    System.out.println("Object" + x + ": x-> " + objPC[x].getXPos() + ", y-> " + objPC[x].getYPos());