You will find here some client using the DII technique. Our first DII client will be very simple and you will find several others on the internet. Progressively we will test more advanced DII client, like remote procedure returning an array of simple type or (array of) object. There we will need a regular use of wscompile tool.
I mention in the title of each section if the example is for a rpc/encoded or document/literal WSDL web service.
By using DII (Dynamic Invocation Interface) you do not need a tool like WSDL2Java nor wscompile, if you consume a remote procedure returning only simple type and only for rpc/encoded, but your code will not be so short. And if you are dealing with complex type, you have to use another tool: wscompile
But find a template of our simple example first, so the client (ClientDII class) will just comport one file: ClientDII.java as we do not need anymore the class types generated by WSDL2Java for this method returning a simple type (int readLSpercent(int int_1)).
![]() | Note |
|---|---|
The code below is for my rpc/encoded web service (real dii without the use of any tools) and you can use it as a template for your own use. You can also test my document/literal operation style web service, go to the Section called DII client for document/literal operation style. |
So the code is not so short isn't it? But the advantage is a code not dependant of any tool. To execute your client just type:
[your_prompt]$ java diiclient.ClientDII
Like usually, you should be able to read the light sensor value on my RCX. Now let's see how to consume a remote procedure returning an array of int (like the remote procedure collInt()) with the DII technique.
Here we will just need the technique using the registering of our int[] type, to consume the remote procedure collInt(). I rewrited completely the client allowing to add easily portion of code to demo the other remote procedure also returning complex types.
We see here that it is still possible to consume a remote procedure returning an array of simple type, using the DII technique, without the need of an external tool. Just register your serializer/deserializer using the technique explained for the sei example, see: register array of simple type
Unfortunately, using DII we will already need to use the TypeMapping for registering purpose of our RcxResponse object and also wscompile tool to generate the RcxResponse_SOAPSerializer deserializer class. Feel free to check how to generate this class here.
![]() | We will need another file in this specific case: RcxResponse_SOAPBuilder.java (needed by RcxResponse_SOAPSerializer.java), copy also the RcxResponse.java file. |
Like usually, we have to register our RcxResponse type, so add the following code in the myInit() function, just after the registration of the int[] type.
// start of register Response complex type object
rcxResponseQname = new QName("http://phonedirlux.homeip.net/types", "rcxResponse");
CombinedSerializer rcxResponseSerializer = new RcxResponse_SOAPSerializer(rcxResponseQname,
ENCODE_TYPE, NULLABLE, SOAPConstants.URI_ENCODING);
rcxResponseSerializer = new ReferenceableSerializerImpl(SERIALIZE_AS_REF, rcxResponseSerializer);
SerializerFactory rcxResponseSerializerFactory = new SingletonSerializerFactory(rcxResponseSerializer);
DeserializerFactory rcxResponseDeserializerFactory = new SingletonDeserializerFactory(rcxResponseSerializer);
typeMapping.register(RcxResponse.class, rcxResponseQname, rcxResponseSerializerFactory,
rcxResponseDeserializerFactory);
// end of register Response complex type objectYou can add to your class the function below to create the call:
public void callReadResponse( )
{
try
{
// Create the Call object using Service
Call call = service.createCall();
QName operationName = new QName(
"http://phonedirlux.homeip.net/wsdl", "status");
call.setOperationName(operationName);
call.setReturnType(rcxResponseQname);
// The operation is an RPC-style operation.
call.setProperty(
Call.OPERATION_STYLE_PROPERTY, "rpc");
call.setProperty(
Call.ENCODINGSTYLE_URI_PROPERTY,
"http://schemas.xmlsoap.org/soap/encoding/");
// The target endpoint
call.setTargetEndpointAddress(
"http://www.pascalbotte.be/rcx-ws-rpc/rcx");
RcxResponse respVal = (RcxResponse)call.invoke(null);
System.out.println("Object response:\n" +
"\t- Status: " + respVal.getStatus() +
"\n\t- Memory free: " + respVal.getMemory() +
"\n\t- Memory total: " + respVal.getMemoryTot() +
"\n\t- Battery level: " + respVal.getBattery() +
"\n\t- Time: " + respVal.getCurrentTime());
}
catch(Throwable th)
{
th.printStackTrace();
}
}Then make the call:
RcxClientObj.callReadResponse();
Now execute your client and you should see some internal value of my RCX. If my RCX brick is down you can mail me at pascal botte I will turn it on if possible.
And what about to consume a remote procedure returning an array of object (like our collPos() function with a return type of PosCol[] class). The class PosCol is a simple class with two integer value (XPos and YPos) supposed to define a position.
First, we have to copy two new files generated by the wscompile tool: PosCol.java and PosCol_SOAPSerializer.java. Like usually, put these files in your /diiclient directory. Now we are ready to add some more code to our client class.
Add the lines below to register our PosCol[] type.
// start of register PosCol complex type object + array
// don't forget to define PosColQname and PosColArrayTypeQname as a QName type member of your class
PosColQname = new QName("http://phonedirlux.homeip.net/types", "PosCol");
PosColArrayTypeQname = new QName( "http://phonedirlux.homeip.net/types" ,
"ArrayOfPosCol");
QName PosColArrayElementQname = new QName("","PosCol");
CombinedSerializer PosColSerializer = new PosCol_SOAPSerializer(PosColQname,
ENCODE_TYPE, NULLABLE, SOAPConstants.URI_ENCODING);
PosColSerializer = new
ReferenceableSerializerImpl(SERIALIZE_AS_REF, PosColSerializer);
SerializerFactory PosColSerializerFactory =
new SingletonSerializerFactory(PosColSerializer);
DeserializerFactory PosColDeserializerFactory =
new SingletonDeserializerFactory(PosColSerializer);
CombinedSerializer PosColArraySerializer =
new ObjectArraySerializer(PosColArrayTypeQname,
ENCODE_TYPE, NULLABLE, SOAPConstants.URI_ENCODING,
PosColArrayElementQname, PosColQname, PosCol.class, 1, null);
PosColArraySerializer =
new ReferenceableSerializerImpl(SERIALIZE_AS_REF, PosColArraySerializer);
SingletonSerializerFactory PosColArraySerializerFactory =
new SingletonSerializerFactory(PosColArraySerializer);
SingletonDeserializerFactory PosColArrayDeserializerFactory =
new SingletonDeserializerFactory(PosColArraySerializer);
typeMapping.register(PosCol.class, PosColQname,
PosColSerializerFactory, PosColDeserializerFactory);
typeMapping.register(PosCol[].class, PosColArrayTypeQname,
PosColArraySerializerFactory, PosColArrayDeserializerFactory);
// end of register PosCol complex type object + arrayAdd the import directive:
import com.sun.xml.rpc.encoding.ObjectArraySerializer;
Now, add the function below to make the call:
public void callCollPos( )
{
try
{
// Create the Call object using Service
Call call = service.createCall();
QName operationName = new QName(
"http://phonedirlux.homeip.net/wsdl",
"collPos");
call.setOperationName(operationName);
// The return
call.setReturnType(PosColArrayTypeQname);
// The operation is an RPC-style operation.
call.setProperty(
Call.OPERATION_STYLE_PROPERTY,
"rpc");
call.setProperty(
Call.ENCODINGSTYLE_URI_PROPERTY,
"http://schemas.xmlsoap.org/soap/encoding/");
// The target endpoint
call.setTargetEndpointAddress(
"http://www.pascalbotte.be/rcx-ws-rpc/rcx");
// Invoke the method collPos
PosCol[] pcaVal = (PosCol[])call.invoke(null);
for(int x=0; x < pcaVal.length; x++)
System.out.println("element " + x +
"\n\tx: " + pcaVal[x].getXPos() + ", y: " + pcaVal[x].getYPos() + "\n");
}
catch(Throwable th)
{
th.printStackTrace();
}
}You are ready to make the call:
RcxClientObj.callCollPos();
Very straight-forward and tools-not-dependant method, in the case of a remote procedure returning a simple type. Already not so easy for a procedure returning an array of simple type (need the use of the TypeMapping object for registering). By consuming a procedure returning an object, or an array of object, (class composed with simple type) we need the wscompile tool. So we are about to obtain the usual conclusion, the best practise for the design of the interface of a web service is to avoid the use of complex type, dealing with an array of simple type is still possible without the use of specific tools but don't try to return an object or a collection of object, you will make the creation of the client too much difficult.
If you want to use JAX-RPC for a DII client, for a document/literal web service, you must use wscompile, even for a procedure returning a simple type. Then could we really call that DII? This example comes from the JWSDP 1.3 tutorial, advanced clients samples (DIINoWSDLHelloClient). I decided to choose the no-WSDL access method because we have to generate our wrapper class prior to make the call - in all the cases -, so we have less interest to read the WSDL at runtime for a document/literal web service.
Here, I had to make a little adaptation on a file generated by wscompile: the wrapper for the class ReadLS(request type for the rpc String readLS(String) has a variable "string_1" and not "String_1", like in the WSDL. So you have to change that variable's name in the file ReadLS.java for a correct wrapper treatment. You won't probably encounter the problem if you use the last JAX-RPC package or JWSDP 1.4.
Note: See here for how to use wscompile. For this example replace the option -gen by -import and add -f:wsi, do not forget to eventually change the package name in the file config.xml.
For a document/literal web service we must generate the wrapper classes prior to build our client (because of the use of literal and not encoded on the server side). I think the DII technique, in this case, is not a so interesting technique to use, refering to the fact that we should discover at runtime the interface and create the stub dynamically and then make the call. With the tool I see here it is not yet possible. Now, using this technique is relatively easy. You can make a call on any type of value returned by a remote procedure and JAX-RPC do the things for you! I would prefer to mention this techique as an alternative to the SEI technique covered in the beginning of my documentation and not as a "real" DII.
![]() | ![]() | ![]() |
| Advanced AXIS and JAX-RPC client: rpc operation style, serializer/deserializer howto | ![]() My home page Index RSS | Java HTTP post for XML SOAP message. |