Wednesday, April 18, 2007

Webservice client using dynamic proxy

In one of my previous posts, i explained how to create a WebService and access it from a simple client. If you look at the client code which accesses the webservice, you will find that the client is using the stubs that were created at deploy time. Such clients which use "static stubs" for accessing webservices are known as "Static Stub Clients". In such approach, the clients will have to have the stubs in their classpath.

Another approach of accessing the webservices is through Dynamic Proxies where the proxies are generated at runtime. I will be showing a simple client which uses dynamic proxies to access an webservice. I wont be explaining the steps to deploy the webservice (which i have already done in my other post). This example assumes that the webservice is already deployed on the server.

The client code will be accessing the HelloWorld service and invoking the sayHelloTo method on that service (Refer my other post to see how the service has been deployed onto the server)

Here's the code for the client:


package org.myapp.service.client;

import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceException;
import javax.xml.rpc.ServiceFactory;

import org.myapp.service.HelloWorldService;

/**
* Simple webservice client which uses dynamic proxy
*
* @author Jaikiran Pai
*/
public class DynamicProxyClient {

public static void main(String args[]) {

try {

// ServiceFactory instance
ServiceFactory serviceFactory = ServiceFactory.newInstance();
System.out.println("Got the service factory");
String wsdlURLString = "http://localhost:8080/axis/services/HelloWorld?wsdl";
URL wsdlURL = new URL(wsdlURLString);
String serviceName = "HelloWorldServiceService";
String nameSpaceURI = "http://jaikiran.com";
String portName = "HelloWorld";
// get hold of the service by passing the URL of the wsdl and the
// service name
Service service = serviceFactory.createService(wsdlURL, new QName(
nameSpaceURI, serviceName));
System.out.println("Got the service: " + service);
// create the service proxy
HelloWorldService serviceProxy = (HelloWorldService) service
.getPort(new QName(nameSpaceURI, portName),
HelloWorldService.class);
System.out.println("Got the service proxy: " + serviceProxy);
System.out.println("Invoking method on service proxy........");
System.out.println(serviceProxy.sayHelloTo("Dynamic user"));

} catch (ServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}



1) Our first step would be to create a ServiceFactory instance, using which we can get access to a deployed service.


ServiceFactory serviceFactory = ServiceFactory.newInstance();


2) Once the ServiceFactory has been created, we will be getting hold of the service which is deployed on the server. To do this, we require
a) The url of the wsdl of the deployed service. In this example it will be http://localhost:8080/axis/services/HelloWorld?wsdl

b) The namespace uri. In this example it will be http://jaikiran.com (You can get this uri from the wsdl file)

c) The name of the service which you want to access. In this example it will be HelloWorldServiceService



String wsdlURLString = "http://localhost:8080/axis/services/HelloWorld?wsdl";
URL wsdlURL = new URL(wsdlURLString);
String serviceName = "HelloWorldServiceService";
String nameSpaceURI = "http://jaikiran.com";

// get hold of the service by passing the URL of the wsdl and the
// service name
Service service = serviceFactory.createService(wsdlURL, new QName(
nameSpaceURI, serviceName));



3) At this point you have got access to the service. But in order to invoke an method on the service, you will have to create a proxy (dynamic proxy) from this service. The Service class, has an API getPort, which creates the proxy. In order to create the proxy, we will have to pass the portName of the service (again, this can be obtained in the wsdl file), the namespace uri and the class type of the service. In this example the service interface is org.myapp.service.HelloWorldService, so we will be passing this as the class as follows:


String portName = "HelloWorld";
// create the service proxy
HelloWorldService serviceProxy = (HelloWorldService) service
.getPort(new QName(nameSpaceURI, portName),
org.myapp.service.HelloWorldService.class);


4) At this point we have got the service proxy which is of type org.myapp.service.HelloWorldService. We can now invoke our sayHelloTo method on this proxy:


System.out.println(serviceProxy.sayHelloTo("Dynamic user"));


Simple, isnt it? You have successfully invoked the webservice through a standalone client using dynamic proxy.

14 comments:

rlogiacco said...

I'm wondering the advantages of such approach...

Srikanth said...

I was planning to learn and create some simple Web Services and I happened to visit your blog, looks like a good collection.

Will go through it one by one.

Thanks,
Srikanth

Jaikiran said...

rlogiacco,

Sorry about this really late reply.

Having dynamic proxies reduces the classes that you have to package with your application. Also in case of dynamic proxies, whenever you add new methods to your webservice, you dont have to regenerate those static stubs.

Anonymous said...

Hi, I don't know execute the program. I get error "cannot find symbol HelloWorldService".

I'm trying "javac DynamicProxyClient.java"

what is the problem?

Thanks

____ said...

hey really nice article but what in my company i have to access the webservice that is located on the main server and to access that i have to undergo proxy settings with username & password.

So can you help me how to proceed ?
reply to my mail dhavalmania27@gmail.com will be thankful.

uiyui said...
This comment has been removed by a blog administrator.
Anonymous said...

This was the most helpful information I've found on web services and how to make the wsdl url dynamic. Didn't resolve my specific problem, but with the explainations it got me moving in the right direction.
Thanks
B.Short

Deepak said...

Hi,

I am trying to use same logic but I am getting ServiceException in CreateService method. like Unable to read wsdl file. I am using IBM web sphere as app server. when I access the same url through browser i can see the wsdl file. Can you help me?

Thanks,
Deepak.

Anonymous said...

I have been looking for this for 2 or 3 days, and after gettin the solution I found your post...wich by the way is fantastic.

Thanks

manu said...

Thanks for the solution!! However I am facing a strange problem when i create the proxy. After creating the proxy, when I type serviceProxy. I cannot see the methods of the Server. The best thing I can do is
serviceProxy.getHelloWorld.sayHelloto(...);

When I execute it I get an exception in the line I am creating the proxyserver that says:

Only interfaces which extend java.rmi.Remote may be used for the proxy class argument.




Any idea?? Thanks

Laxmikanth said...

can some one tell me that in shown example, how did we get the HelloWorldService class

If it is dynamic proxy, we will not be having any kind of binding classes upfront.

Thanks
Laxmikanth Rajuri

abcdefghijkl said...

I have a problem on using dynamic webservice on java. Basing on your post, i solved my problem. Thank you so much!
I also try 2 day to get this solution (just because i forget to extend java.rmi.Remote for interface!

Anonymous said...

[Help!!!!] Does anybody call a webservice from another webservice by the sulution in this post? I try but it's fail!

client -> WS1 -> WS2

in ws1, when I call .getport method, it return port: "{} does not contain operation: "

Can anybody help me? Thanks in advance!

abcdefghijkl said...

I have already solved the problem ws call ws.
I don't use ServiceFactory instance to create new Service, I create new Service by its Generator method:
Service s2 = new org.apache.axis.client.Service(wsdlURL, new QName(nameSpaceURI, serviceName));

then i use .getport() method normally !