There is two ways to invoke the web service dynamically :
- Using the Jax-Rpc's dynamic call api (jax.xml.rpc.Call)
- Using the Jax-Ws dynamic Dispatch api
First of all, you will find here under the code of a simple web service we will use in the sample :
package test;
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
@Stateless
@WebService(name="DynamicWs",
serviceName="DynamicWsService",
portName="DynamicWsPort",
targetNamespace="http://test"
)
public class DynamicWs {
@WebMethod(operationName="hello")
@WebResult(name="result",
targetNamespace="http://test")
public String hello( @WebParam(name="name", targetNamespace="http://test") String name)
{
return "hello " + name;
}
}
This sample exposes the hello method which receives a string in parameter and returns a string in response to the client.
Dynamic invocation using jax.xml.rpc.Call api
The client code for dynamic method invocation using the rpc Call api :
package client;
import java.rmi.RemoteException;
import javax.xml.namespace.QName;
import javax.xml.rpc.Call;
import javax.xml.rpc.ParameterMode;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceException;
import javax.xml.rpc.ServiceFactory;
import javax.xml.rpc.encoding.XMLType;
import org.junit.Test;
public class TestDynamicWs {
private static final String END_POINT = "http://localhost:8080/DynamicWsService/DynamicWs";
private static final String TNS = "http://test";
@Test
public void testDynamicInvocation() throws ServiceException, RemoteException
{
Service service = ServiceFactory.newInstance().createService (
new QName( TNS, "DynamicWsService")
);
Call call = service.createCall ();
call.setTargetEndpointAddress ( END_POINT);
// Set call properties
call.setProperty(Call.SOAPACTION_USE_PROPERTY, new Boolean(true));
call.setProperty(Call.SOAPACTION_URI_PROPERTY, "");
call.setProperty(Call.ENCODINGSTYLE_URI_PROPERTY , "");
call.setProperty(Call.OPERATION_STYLE_PROPERTY, "rpc");
// Set the name of the operation to call
call.setOperationName( new QName( TNS, "hello"));
// Define and add the parameter value
call.addParameter(
"name", // parameter name
XMLType.XSD_STRING, // parameter XML type QName
String.class, // parameter Java type class
ParameterMode.IN); // parameter mode
// Define the type of the result returned by the method
call.setReturnType(XMLType.XSD_STRING);
// Call the method with parameters
String response = (String) call.invoke(new String[] {"franck"});
System.out.println ("Response is '" + response + "'");
}
}
Fist of all, we have to create the service using the javax.xml.rpc.ServiceFactory and instanciate the javax.xml.rpc.Call object.
This Call object will be configured using some properties :
- Call.SOAPACTION_USE_PROPERTY : this property indicates whether or not SOAPAction is to be used. We set it to TRUE.
- Call.OPERATION_STYLE_PROPERTY : this property is set to "rpc" to indicates that the operation will be accessed by rpc.
call.setOperationName( new QName( TNS, "hello"));
and the type of input and output parameters
// Define and add the parameter value
call.addParameter(
"name", // parameter name
XMLType.XSD_STRING, // parameter XML type QName
String.class, // parameter Java type class
ParameterMode.IN); // parameter mode
// Define the type of the result returned by the method
call.setReturnType(XMLType.XSD_STRING);
The XMLType class contains all QName that defines the type of parameters we could use.
Now, it's time to invoke the remote method using rpc call and encoding
// Call the method with parameters
String response = (String) call.invoke(new String[] {"franck"});
Remark : Just note that the client never recovered the wsdl file on the server !
The message that has been sent by the client code :
<env:envelope enc="http://schemas.xmlsoap.org/soap/encoding/" env="http://schemas.xmlsoap.org/soap/envelope/" ns0="http://test" xsd="http://www.w3.org/2001/XMLSchema" xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:body>
<ns0:hello>
<name>franck</name>
</ns0:hello>
</env:body>
</env:envelope>
The response received by the client :
<s:envelope s="http://schemas.xmlsoap.org/soap/envelope/">
<s:body>
<helloresponse xmlns="http://test">
<result>hello franck</result>
</helloresponse>
</s:body>
</s:envelope>
Dynamic call using the jax-ws dynamic Dispatch api
In this level we will the Dispatch api of the jax-ws api to create a SOAP envelop and invoke the web service.
You will find here under the source code to invoke the hello method through the Dispatch api :
package client;
import java.net.URL;
import java.util.Iterator;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.soap.Text;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import org.junit.Test;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class TestDynamicWs2 {
private static final String TNS = "http://test";
private static final String WSDL = "http://localhost:8080/DynamicWsService/DynamicWs?wsdl";
@Test
public void testDynamicInvocation() throws Exception
{
/* wsdl url you can get from link provided by glassfish server.*/
URL url = new URL( WSDL);
/* service name & port name as mentioned in wsdl, which can also be viewed in glassfish */
QName serviceName = new QName( TNS, "DynamicWsService");
QName portName = new QName( TNS, "DynamicWsPort");
Service service = Service.create(url, serviceName);
/** Create a Dispatch instance from a service.**/
Dispatch dispatch = service.createDispatch( portName,
SOAPMessage.class,
Service.Mode.MESSAGE
);
MessageFactory mf;
try {
mf = MessageFactory.newInstance(SOAPConstants.DEFAULT_SOAP_PROTOCOL);
// Create a message. This example works with the SOAPPART.
SOAPMessage req = mf.createMessage();
SOAPPart part = req.getSOAPPart();
// Obtain the SOAPEnvelope and header and body elements.
SOAPEnvelope env = part.getEnvelope();
SOAPHeader header = env.getHeader();
SOAPBody body = env.getBody();
// Construct the message payload.
SOAPElement operation = body.addChildElement( "hello", "ns", TNS);
SOAPElement value = operation.addChildElement( "name", "ns", TNS);
value.addTextNode( "franck");
req.saveChanges();
// Invoke the service using the soap request
SOAPMessage res = (SOAPMessage)dispatch.invoke(req);
SOAPPart soapPart = res.getSOAPPart();
NodeList list = soapPart.getElementsByTagNameNS (TNS, "result");
// Read the first node
Node node = list.item ( 0);
// Display the result
System.out.println ( "Server say : " + node.getTextContent ());
} catch (Exception ex) {
ex.printStackTrace ();
throw ex;
}
}
First of all, we have to connect to server to retrieve the wsdl file and the port associated to the service :
/* wsdl url you can get from link provided by glassfish server.*/
URL url = new URL( WSDL);
/* service name & port name as mentioned in wsdl, which can also be viewed in glassfish */
QName serviceName = new QName( TNS, "DynamicWsService");
QName portName = new QName( TNS, "DynamicWsPort");
Service service = Service.create(url, serviceName);
The wsdl file will contains the end point definition to find the right service deployed on the right server.
After we create a Dispatch object on the port and indicates that we want to deal with soap message :
/** Create a Dispatch instance from a service.**/
Dispatch dispatch = service.createDispatch( portName,
SOAPMessage.class,
Service.Mode.MESSAGE
);
It is now the time to create a soap message and fill it with invocation parameters :
MessageFactory mf = MessageFactory.newInstance(SOAPConstants.DEFAULT_SOAP_PROTOCOL);
// Create a message. This example works with the SOAPPART.
SOAPMessage req = mf.createMessage();
The api used to set attributs in the soap envelop are very similar to the DOM api used in xml parsing.
SOAPElement operation = body.addChildElement( "hello", "ns", TNS);
SOAPElement value = operation.addChildElement( "name", "ns", TNS);
value.addTextNode( "franck");
req.saveChanges(); // Save the changes made on the soap envelop
Now invoke you service :
// Invoke the service using the soap request
SOAPMessage res = (SOAPMessage)dispatch.invoke(req);
And retrieve your result :
SOAPPart soapPart = res.getSOAPPart();
NodeList list = soapPart.getElementsByTagNameNS (TNS, "result");
// Parse the node list here...