Dynamic Web service invocation from a WSDL endpoint
2010Dynamically parse a WSDL and invoke it.
This can be used to develop an abstract or wrapper service for concrete Web services for applications or BPEL.
Step 1:
WSDL parsing
Step 2:
Dynamic client with JAX-WS
or
Dynamic client with Axis2
About other approaches:
Apache WSIF (Web Service Invocation Framework): It is based on Axis1. Last updated was on 2006, we recommend ignoring it.
WSDL parsing
Excepting request input message, we need following service information from WSDL to enable dynamic invocation.- serviceName
- portName
- endpointUrl
- operation SOAPAction (This apperas in .Net based web services )
Dynamic client with JAX-WS
1. Dispatch client
javax.xml.ws.Dispatch : It works at the XML message level.
http://java.boot.by/scdjws5-guide/ch04s08.htmlThe Dispatch client can send data in either MESSAGE or PAYLOAD mode.
- When using the javax.xml.ws.Service.Mode.MESSAGE mode, the Dispatch client is responsible for providing the entire SOAP envelope including the soap:Envelope, soap:Header, and soap:Body elements.
- When using the javax.xml.ws.Service.Mode.PAYLOAD mode, the Dispatch client is only responsible for providing the contents of the soap:Body and JAX-WS includes the payload in a soap:Envelope element.
http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/twbs_jaxwsdynclient.html
Following code use JAX-WS dispatch API
The SOAPACTION_URI_PROPERTY is set, is not in above reference. This is need for .Net based web services.
public SOAPMessage invoke(QName serviceName, QName portName, String endpointUrl, String soapActionUri) throws Exception { /** Create a service and add at least one port to it. **/ Service service = Service.create(serviceName); service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointUrl); /** Create a Dispatch instance from a service.**/ Dispatch dispatch = service.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE); // The soapActionUri is set here. otherwise we get a error on .net based services. dispatch.getRequestContext().put(Dispatch.SOAPACTION_USE_PROPERTY, new Boolean(true)); dispatch.getRequestContext().put(Dispatch.SOAPACTION_URI_PROPERTY, soapActionUri); /** Create SOAPMessage request. **/ // compose a request message MessageFactory messageFactory = MessageFactory.newInstance(); SOAPMessage message = messageFactory.createMessage(); //Create objects for the message parts SOAPPart soapPart = message.getSOAPPart(); SOAPEnvelope envelope = soapPart.getEnvelope(); SOAPBody body = envelope.getBody(); //Populate the Message. In here, I populate the message from a xml file StreamSource preppedMsgSrc = new StreamSource(new FileInputStream("req.xml")); soapPart.setContent(preppedMsgSrc); //Save the message message.saveChanges(); System.out.println(message.getSOAPBody().getFirstChild().getTextContent()); SOAPMessage response = (SOAPMessage) dispatch.invoke(message); return response; }
Content of req.xml :
public class Main { public static void main(String[] args) { //proxy setting, only if you need System.setProperty("http.proxyHost", "proxy.dcu.ie"); System.setProperty("http.proxyPort", "8080"); System.setProperty("sun.net.client.defaultConnectTimeout", "" + 2000); System.setProperty("sun.net.client.defaultReadTimeout", "" + 2000); Main m = new Main(); String targetNameSpace = "http://microsoft.com/webservices/"; String endpointUrl = "http://www50.brinkster.com/vbfacileinpt/np.asmx"; QName serviceName = new QName(targetNameSpace, "PrimeNumbers"); QName portName = new QName(targetNameSpace, "PrimeNumbersSoap"); String SOAPAction = "http://microsoft.com/webservices/GetPrimeNumbers"; SOAPMessage response; try { response = m.invoke(serviceName, portName, endpointUrl, SOAPAction); if (response.getSOAPBody().hasFault()) { System.out.println(response.getSOAPBody().getFault()); } else { System.out.println("ok"); } } catch (Exception ex) { ex.printStackTrace(); } } public SOAPMessage invoke(QName serviceName, QName portName, String endpointUrl, String soapActionUri) throws Exception { ... } }Source code in NetBeans project: here
Dynamic client with Axis2
http://today.java.net/pub/a/today/2006/12/13/invoking-web-services-using-apache-axis2.html
Two steps.
// step 1. create a dynamicClient; ServiceClient dynamicClient = new ServiceClient(configContext, wsdlURL,wsdlServiceName, portName); // step 2. then send a payLoad and get a response. OMElement res = dynamicClient.sendReceive(createPayLoad()); System.out.println(res);Following is a function to create a payload
public OMElement createPayLoad() { OMFactory fac = OMAbstractFactory.getOMFactory(); OMNamespace omNs = fac.createOMNamespace( "http://ws.apache.org/axis2/xsd", "ns1"); OMElement method = fac.createOMElement("echo", omNs); OMElement value = fac.createOMElement("value", omNs); value.setText("Hello , my first service utilization"); method.addChild(value); return method; }While, above does not work with wsdl has soapAction element for me. and cause following error
org.apache.axis2.AxisFault: Server did not recognize the value of HTTP Header SOAPAction: urn:anonOutInOp. at org.apache.axis2.util.Utils.getInboundFaultFromMessageContext(Utils.java:435) ...Another way is using an Option Object, and set SOAPAction in the Option. This works without above error.
1. create an Options object, and set xxx properties.
2. create a ServiceClient, and set the Options object.
3. send the PayLoad and receive a response.
ServiceClient serviceClient = new ServiceClient(); // create option object Options opts = new Options(); opts.setProperty(HTTPConstants.CHUNKED, false); opts.setTo(new EndpointReference(endpointUrl)); // >> set the SOAPAction value here !! To fix above error !! opts.setAction("http://ws.fraudlabs.com/PostalCodeWorld_Mexico"); serviceClient.setOptions(opts); OMElement res = serviceClient.sendReceive(createPayLoad()); System.out.println(res);
Following is additional information with OMElement for manipulating PayLoad
AXIOM stands for AXIs Object Model and is a based on StAX(Streaming API for XML) and was developed to improve performance in XML parsing mechanism. AXIOM uses light weight XML with smaller hierarchy of XML elements than traditional XML technologies. It was initially developed for Axis but is now an Apache Commons project. AXIOM uses a technology called pull parsing where required parsing is done by the AXIOM engine rather than depending on externals parsers. Axiom comprises two layers
- Object Model(OM) Layer which takes care of the XML processing
- SOAP Layer sits over the Object Model layer and takes care of the SOAP modeling.
option 1: create an OMElement from a java bean
option 2: create an OMElement from a xml file
OMFactory fac = OMAbstractFactory.getOMFactory(); // option 1: create a xmlstreamreader from a bean XMLStreamReader reader = BeanUtil.getPullParser(new Person("wong")); // option 2: create a xmlstreamreader from a file FileInputStream inputStream = new FileInputStream("1.xml"); XMLInputFactory inputFactory = XMLInputFactory.newInstance(); XMLStreamReader reader = inputFactory.createXMLStreamReader(inputStream); // Finally, create a OMElement from a xmlstreamreader StreamWrapper parser = new StreamWrapper(reader); StAXOMBuilder stAXOMBuilder = OMXMLBuilderFactory.createStAXOMBuilder(OMAbstractFactory.getOMFactory(), parser); OMElement element = stAXOMBuilder.getDocumentElement(); System.out.println("element::" + element.toString());http://www.computing.dcu.ie/~mwang/index1.html