The program Java 2 Platform 1.3 version adds an extremely useful extension to the Java Image API (Reflection API): Dynamic proxy classes. A dynamic proxy class is a class that implements the interface specified by a series of runtimes. This proxy can be used as if it really implements these interfaces. In other words, any method that can invoke any interface directly on the proxy object--and of course, the necessary type stereotypes (casting) must be done first. Thus, we can use dynamic proxy classes to create a type-safe proxy object for a set of interfaces, and do not have to generate a proxy like a compile-time tool (for a more detailed description of a dynamic proxy class, see the reference resources at the end of this article).
Next I'll introduce a framework based on a dynamic proxy class that makes soap (Simple Object Access Protocol) client creation simpler and more intuitive. SOAP is a wired protocol that uses XML to encode data. In the second and third article of this series, we found that the developer of the client program had to do a lot more work than was necessary to build the SOAP service. To help recall, you can look at the SOAP service code in the second article to see how trivial the service program's SOAP code is compared to the client code. The simple SOAP services created earlier in this series show that SOAP based services only contain code that must be supplied regardless of the use of soap. The developer of the service program has few extra code to write, and the client developer has a lot of extra work to do. The classes described in this article will minimize these additional work.
I. Introduction to SOAP proxy classes
First, I'm going to give you an account of what it would look like if the client used the framework created by this article:
Package Hello;
Import soapproxy.*;
public class Client
{
public static void Main (string[] args)
{
Try
{
Class[] interfaces = new class[] {hello. Hello.class};
Hello hello = (hello) (proxy.newinstance ("Urn:hello", interfaces));
Calling the Sayhelloto method
This Sayhelloto method requires a string parameter
System.out.println (Hello.sayhelloto ("John"));
Calling the Sayhelloto method
This Sayhelloto method requires a name JavaBean parameter
Name thename = new name ();
Thename.setname ("Mala");
System.out.println (Hello.sayhelloto (thename));
}
catch (Exception e)
{
E.printstacktrace ();
}
}
}
Maybe it's my personal hobby, and I think the client code above is better than the client code in the second and third article. If you can't understand the above code now, it's normal, but I think you'll understand it at the end of this article.
To understand the client's code, you must drill down into the SOAP proxy class, which is within the Soapproxy package and can be found within Proxy.java (see the reference resources at the end of this article). The proxy class has a private constructor, which means that the proxy instance cannot be created from outside the proxy; the only way to create a new proxy instance is through a static newinstance () method. The Newinstance () method has two parameters: the object ID of the SOAP service, and an array containing a set of names of the interfaces that the proxy will implement. Object IDs are simple, but what are the names of these interfaces? Where do I get the names of these interfaces? The developer of the SOAP service directly stacks all the methods on the service that can be invoked by the client to get an interface. Pretty simple, isn't it?
Now we define an interface for the HelloWorld service. In the second article, the final version of this service has two overloaded versions of the Sayhelloto () method: One version of the argument is a string, and the other version of the argument is a name JavaBean. These two methods can form an interface, called Hello, as follows:
Package Hello;
public interface Hello
{
public string Sayhelloto (string name);
Public String Sayhelloto (name name);
}
The service developer decides how many interfaces to create and what names to give to those interfaces. For example, you can create two interfaces for the HelloWorld service, each containing a method. Generally, you should avoid creating an interface with a number of methods greater than seven. Also, note that only those methods that appear necessary to be put together are organized using an interface. For example, if the HelloWorld service has a Saybyeto () method that returns a custom good-bye message to the caller, it might be wise to design two separate interfaces: an interface for the Sayhelloto () method, and an interface for the Saybyeto () method.
Now that we have an interface that defines the contract between the HelloWorld service and the client, the following returns a look at the newinstance () method. As mentioned earlier, the Newinstance () method creates a new instance of the proxy class. The Newinstance () method can create a new instance because it belongs to the proxy class and has access to the private constructor. The Newinstance () method calls the Initialize () method for the newly created instance. Initialize () is a concern because dynamic proxies are created and returned here. The code for Initialize () looks like this:
Private Object Initialize (class[] interfaces)
{
Return (Java.lang.reflect.Proxy.newProxyInstance (getclass). getClassLoader ()
, Interfaces,this));
}
Note the application of the Newproxyinstance () method. The only way to create a dynamic proxy class instance is to invoke the static Newproxyinstance () method of that class (that is, the Java.lang.reflect.Proxy class). The Java.lang.reflect.Proxy class provides a static method for creating dynamic proxy classes, and it is the superclass of all dynamic proxy classes created by these methods. In other words, it's not just a factory that creates dynamic proxy classes, but it's also a dynamic proxy class! Thus, in our case, the SOAP proxy is not a dynamic proxy; instead, the dynamic proxy is actually an instance of the Java.lang.reflect.Proxy class returned by the Newproxyinstance static method. As you can see later in this article, this dynamic proxy actually completes all of its work through the Invoke () method implemented by the SOAP proxy. So how does this dynamic proxy establish a connection to the SOAP broker? Because a reference to the SOAP proxy is passed to the Newproxyinstance () method. It may sound a bit confusing now, but as long as you analyze the Invoke () method, all this is clear.
The first parameter of the Java.lang.reflect.Proxy class constructor is a class loader instance, and the second parameter is an array of interfaces that need to be implemented dynamically (it is the array that the client program passes to Newinstance ()), The third parameter is an instance of a class that implements the Java.lang.reflect.InvocationHandler interface. Because the SOAP proxy class implements the Invocationhandler interface, the third argument is the proxy instance itself (that is, this). The Invocationhandler interface has a method invoke (). The Invoke () method is invoked by the Java Runtime Environment when a dynamic proxy's dynamically implemented interface is invoked. Thus, for example, when the client program invokes the Sayhelloto () method of the dynamic proxy's Hello interface, the Java Runtime Environment invokes the SOAP Proxy's Invoke () method.
You may have discovered that the soap proxy's newinstance () method does not return an instance of the SOAP proxy; instead, it returns the dynamic proxy that newinsance () has just created, and the dynamic proxy dynamically implements the array of interfaces passed in by the client. The client program can stereotype this returned dynamic proxy as an arbitrary interface type for incoming newinstance () and invoke each method defined by the interface on a dynamic proxy as if the dynamic proxy really implements those interfaces.
.
.
Try
{
Class[] interfaces = new class[] {hello. Hello.class};
Hello hello = (hello) (proxy.newinstance ("Urn:hello", interfaces));
Sayhelloto method that invokes the argument as a string
System.out.println (Hello.sayhelloto ("John"));
The Sayhelloto method that invokes the parameter to name JavaBean
Name thename = new name ();
Thename.setname ("Mala");
System.out.println (Hello.sayhelloto (thename));
}
.
.
In the above code, the Invoke () method is invoked two times, one at a time when the Sayhelloto () method is invoked. Now let's look at the Invoke () method. In short, the Invoke () method is the work of each client program in the second article that must be done manually, including: Setting a Call object with the appropriate invocation parameters, and the type mappings required for the calling parameter customization. Because the Invoke () method in the SOAP proxy assumes all of these tasks, the client program frees up the burden.
Of the three parameters received by the Invoke () method, we are only interested in the following two. The second parameter, the method object, gives the name of the called methods. Remember that the name of the invoked method corresponds to a known method of the SOAP service export. The object ID of the service is passed as a parameter to the Newinstance () method, so the Invoke () method already owns the object ID. The Invoke () method uses this information to set the Call object as follows:
Call call = new Call ();
Call.settargetobjecturi (URN);
Call.setmethodname (M.getname ());
Call.setencodingstyleuri (CONSTANTS.NS_URI_SOAP_ENC);
All you have to do now is set the parameters for the remote service invocation. To do this, we use the third parameter of the Invoke () method: An array of arguments to the invoked method on the dynamic proxy. A parameter with an index of 0 in an array is the leftmost parameter in the method invocation, and the parameter with index 1 is the second parameter of the method, and so on. For example, if the client program calls the Sayhelloto (string name) method, then the parameter array is an array containing a string. The Invoke () method processes each element of the array and creates a vector (vector) consisting of a Parameter object (as the client program does in the second article):
Java.util.Vector params = new Java.util.Vector ();
for (int i=0; i<args.length; i++)
{
if (IsSimple (args[i)) | | | Issimplearray (ARGS[I))
{
Params.add (i+1), New Parameter (_paramname+),
Args[i].getclass (), args[i],null));
}
else if (Isvector (Args[i]))
{
Addmapping ((java.util.Vector) args[i]);
Params.add (New
Parameter (_paramname+ (i+1), Args[i].getclass (), args[i],null));
}
If the elements of this array are not part of the Java basic data type
It is assumed that this is an array of JavaBean
else if (IsArray (Args[i]))
{
if (SMR = null)
SMR = new Soapmappingregistry ();
if (Beanser = null)
Beanser = new Beanserializer ();
Arrayserializer arrayser = new Arrayserializer ();
Smr.maptypes (Constants.ns_uri_soap_enc,
NULL, NULL, Beanser, beanser);
Smr.maptypes (Constants.ns_uri_soap_enc,
Null,args[i].getclass (), Arrayser, Arrayser);
Params.add (i+1), New Parameter (_paramname+),
Args[i].getclass (), args[i],null));
}
Suppose this is a bean
Else
{
if (SMR = null)
SMR = new Soapmappingregistry ();
if (Beanser = null)
Beanser = new Beanserializer ();
String Qnamepart = Args[i].getclass (). GetName ();
Smr.maptypes (Constants.ns_uri_soap_enc,
New QName (URN, qnamepart), Args[i].getclass (), Beanser,
Beanser);
Params.add (New Parameter (_paramname+ (i+1), Args[i].getclass (), args[i],null));
}
}
The Invoke () method uses a number of proprietary helper methods, such as IsSimple () to determine the type of the parameter. If the parameter is a JavaBean or an array, then the program must set up a custom SOAP map registry and set the call object by the Setsoapmappingregistry () method (see the second article). The SOAP proxy assumes that when javabean occurs, all JavaBean used by the SOAP service are mapped as follows: NameSpace URI set to object id,local part set to JavaBean complete class name. This is exactly what we are doing when we deploy the HelloWorld service, so there is no problem with everything.
The remainder of the Invoke () method is fairly simple: Set the call object parameter, set the custom SOAP map registration entry (if necessary), emit the invocation, and receive the return value of the method call. As shown below:
if (params.size ()!= 0)
Call.setparams (params);
if (SMR!= null)
Call.setsoapmappingregistry (SMR);
Emit call
Response resp = Call.invoke (ServerURL, "");
if (!resp.generatedfault ())
{
Parameter ret = Resp.getreturnvalue ();
Return (Ret.getvalue ());
}
Else
{
Fault Fault = Resp.getfault ();
throw new
SoapException (Fault.getfaultcode (), fault.getfaultstring ());
}
Second, HelloWorld service
Here is the complete code for the HelloWorld service. Any sense of déjà vu?
Package Hello;
public class HelloServer
{
public string Sayhelloto (string name)
{
System.out.println ("Sayhelloto (String name)");
Return "Hello" + name + ", how are you doing?"
}
Public String Sayhelloto (Name thename)
{
System.out.println ("Sayhelloto (Name thename)");
Return "Hello" + thename.getname () + ", how to Are you doing?"
}
}
Recall that name is a simple javabean with the following code:
Package Hello;
public class Name
{
private String name;
Public String GetName ()
{
return name;
}
public void SetName (String name)
{
THIS.name = name;
}
}
In fact, the code for the service here is exactly the same as the Service program code in the second article. The only additional job for service developers is to create a Java interface. The method of deploying the service is exactly the same as that discussed in the second article, so I'm not going to introduce it here. The same place is more than that, the method of compiling and running the client program is the same as the one described in the second article. Why are there so many similarities? Because the proxy we create is a pluggable framework, it does not modify and interfere with the internal work of any Apache SOAP widget-either the client or the server side.
Iii. Other Notes
The SOAP proxy discussed in this article, which can be downloaded from behind the article, supports the following parameter types:
⑴ The following Java basic data types and their corresponding object forms.
Boolean, Boolean,
Double, Double,
float, float,
Long, long,
int, Integer,
Short, short,
BYTE, byte
Note: The server side always receives the base data type.
⑵ any JavaBean
Note:
The JavaBean cannot contain other javabean.
If an array or vector contains a type other than a string or 1 list of data types, JavaBean cannot contain such an array or vector.
⑶ The following class: String, Vector
Note:
The vector can contain all the types and strings listed in 1, 2.
The server side receives vectors as an array of objects.
⑷ Array. Array elements can be all types and strings listed in 1, 2 (except as noted above).
Concluding remarks
In this four article series, I not only introduced the basics of soap, but also introduced an excellent implementation of the SOAP 1.1 standard: Apache soap. In this article, I provide a framework based on a dynamic proxy class that greatly simplifies the work of client developers using Apache soap.
I deeply feel that soap has a bright future, at least two reasons I think so: first, soap is based on some open standards, such as XML. This allows soap to be widely accepted by both Microsoft and anti-Microsoft businesses. For developers, this is undoubtedly a great news. Second, soap is becoming the basis for many other standards, such as UDDI (Universal Description,discovery,and Integration). Many people believe that Web services represent the next generation of Web application development, while SOAP and UDDI are key components of Web services.
Reference Resources
Download the complete code for this article: Javaandsoap4_code.zip
The SOAP 1.1 specification for the consortium:
http://www.w3.org/TR/SOAP/
For more information about dynamic proxy classes:
Http://java.sun.com/j2se/1.3/docs/guide/reflection/proxy.html
For more information on IBM SOAP Engineering:
Http://www.alphaworks.ibm.com/tech/soap4j
Download Apache SOAP:
http://xml.apache.org/dist/soap/