I've been searching for SOAP client libraries for Java and have found a plethora of libraries based on the idea of building stub and proxy classes based on a WSDL. I'm interested in allowing the user to enter a WSDL at runtime, parsing the WSDL, then allowing the user to perform operations on the Web Service.
Does anyone know of a good SOAP client library which will allow this runtime use? Or is there a way I can use the axis2 wsdl2java functionality to build stubs into the classloader and use them at runtime?
Later than never. :)
You should achieve that in two steps:
1) parse the WSDL informed by the user to retrieve the available operations. Refer to this question to know how to do this in a simple way.
2) Create a dynamic client to send a request using the selected operations. It can be done by using the Dispatch API from Apache CXF.
Build the Dispatch object for the dynamic client (It can be created on the fly by informing web service endpoint, port name, etc):
package com.mycompany.demo;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
public class Client {
public static void main(String args[]) {
QName serviceName = new QName("http://org.apache.cxf", "stockQuoteReporter");
Service s = Service.create(serviceName);
QName portName = new QName("http://org.apache.cxf", "stockQuoteReporterPort");
Dispatch<DOMSource> dispatch = s.createDispatch(portName,
DOMSource.class,
Service.Mode.PAYLOAD);
...
}
}
Construct the request message (In the example below we are using DOMSource):
// Creating a DOMSource Object for the request
DocumentBuilder db = DocumentBuilderFactory.newDocumentBuilder();
Document requestDoc = db.newDocument();
Element root = requestDoc.createElementNS("http://org.apache.cxf/stockExample", "getStockPrice");
root.setNodeValue("DOW");
DOMSource request = new DOMSource(requestDoc);
Invoke the web service
// Dispatch disp created previously
DOMSource response = dispatch.invoke(request);
Recommendations:
Use ((BindingProvider)dispatch).getRequestContext().put("thread.local.request.context", "true"); if you want to make the Dispatch object thread safe.
Cache the Dispatch object for using later, if it is the case. The process o building the object is not for free.
Other Methods
There are other methods for creating dynamic clients, like using CXF dynamic-clients API. You can read in project's index page:
CXF supports several alternatives to allow an application to
communicate with a service without the SEI and data classes
I haven't tried that myself but should worth giving it a try.
Related
I have two Java EE applications on two separate application servers. One of them already contains a working EJB. I want to be able to communicate with this EJB from the other application by using a JAX-WS webservice (the communication has to work between different application servers and different server versions, so remote EJB call is no option). It is no problem to expose the server api to the client application.
The server side is quite clear, adding #Webservice annotation seems to work quite well. But i wonder what is the best way to build the client: I don't really want to generate the client stub from the wsdl (which itself has been generated from the ejb code by the container in my case) and pack all these generated classes into the client ear - but this seems to be the only way i can make use of #WebServiceRef annotations.
The alternative to make a dynamic proxy myself with the help of the static methods of javax.xml.ws.Service (sth. like service=Service.create() and service.getPort()) is not recommended by the Spec and "container providers are not required to support managed Service Instances created using these methods".
But that is exactly sth. that I want to use:
Is there a way to get a dynamic proxy injected in my code, managed by the application server? Or is the only way to get a managed webservice client instance to be done with generated client stub classes?
Read JAX-WS 2.2 spec, Chapter 4: Client APIs.
1. Static Client Generation
Is really the simplest way to work with JAX-WS. From a web services perspective, the WSDL is the interface AND the connection properties. Even if you choose not to work with it physically, you still need to know it in a logical sense to make meaningful SOAP calls.
Note from JAX-WS spec: An Endpoint that uses the SOAP 1.1/HTTP binding MUST
make its contract available as a WSDL 1.1 document at the publishing address suffixed with ?WSDL or ?wsdl
2. Dynamic Client Programming
Is there a way to get a dynamic proxy injected in my code, managed by the application server?
This approach involves dynamic programming against the JAX-WS API to connect to a web service either with or without using WSDL. There's no way to just "inject" a dynamic proxy out of nowhere. You need to construct & configure one with the SEI's port URLs. The WSDL document is the standard place to store such configuration information, although it is possible to avoid it and to programmatically insert the info.
2A) Dynamic programming with WSDL:
javax.xml.ws.Service service = Service.create(
new URL("http://example.org/stocks.wsdl"),
new QName("http://example.org/stocks", "StockQuoteService"));
com.example.StockQuoteProvider proxy = service.getPort(portName,
com.example.StockQuoteProvider.class)
javax.xml.ws.BindingProvider bp = (javax.xml.ws.BindingProvider)proxy;
Map<String,Object> context = bp.getRequestContext();
context.setProperty("javax.xml.ws.session.maintain", Boolean.TRUE);
proxy.getLastTradePrice("ACME");
Advantages over (1): can dynamically dynamically change the WSDL doc after app is deployed, provided such changes do not affect the java interface to client.
i.e. very little benefit to you. Your WSDL is static. Whilst you could point your client to <service endpoint URL>?wsdl to dynamically lookup, this means you need to manually configure <service endpoint URL> AND that leaves little else that can change in the SEI/WSDL without impacting your client logic.
2B) Dynamic programming without WSDL:
String endpointUrl = ...;
QName serviceName = new QName("http://example.org/wssample/echo/", "EchoService");
QName portName = new QName("http://example.org/wssample/echo/", "EchoServicePort");
/** 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<SOAPMessage> dispatch = service.createDispatch(portName,
SOAPMessage.class, Service.Mode.MESSAGE);
/** Create SOAPMessage request. **/
// compose a request message
MessageFactory mf = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
// Create a message. This example works with the SOAPPART.
SOAPMessage request = mf.createMessage();
SOAPPart part = request.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("invoke", "ns1",
"http://com/ibm/was/wssample/echo/");
SOAPElement value = operation.addChildElement("arg0");
value.addTextNode("ping");
request.saveChanges();
/** Invoke the service endpoint. **/
SOAPMessage response = dispatch.invoke(request);
Advantage (not really): can eventually get it to carry out same behaviour as above.
Disadvantages: Complex programming. Non-standard configuration (outside of WSDL). Need to avoid hard-coding settings. Brittle to interface changes. Manually synchronising settings between server and client - easy to omit something, extremely difficult to debug.
Answer:
Go back to (1). Generate a client stub from the WSDL. Use it as an interface contract - it should be designed well and not change.
Then spend the time you save solving real problems... ;) ;)
I have the following problem: I am completely new to java EE (know only about servlets and JSPs) and especially web services.
I need to develop a client for a web service (it needs to query the service for useful information once in a minute).
In my mind this client would be a simple java-SWing-based program, which would query the web service through simple Socket when the application client runs. How can that be done?
Is it possible to do in that way? If not, which is the easiest way to create such a client?
I would suggest using Apache CXF. Simple and powerful framework.
And yes, that is possible to implement what you said using this framework. Just read tutorials and play around for a bit with it.
Inorder to connect to a web service using a java client follow the below mentioned steps:
1. Get the URL in which the webservice is hosted. This is usually of the fomat http://<IP_OF_SERVER>:<PORT_OF_SERVER>/<WEB_APP_NAME>?wsdl
2. Get the qualified name of the service:
// 1st arg is the service URI
// 2nd is the service name published in the WSDL
QName qname = new QName(<Service_URI>, <SERVICE_NAME_PUBLISHED_WSDL>);<br/>
3. Create a factory for the service:
Service service = Service.create(url, qname);
4. Extract the endpoint interface, the service "port":
<Port_Class_Name> eif = service.getPort(<Port_Class_Name>);
5. Now use the methods on the Port, which are the actual methods in your webservice.
You might want to try REST Webservice, try Jersey REST (or others). With rest you can connect it with http connection (GET and POST).
Inorder to connect to a web service using a java client follow the below mentioned steps:
1.URL wsdlUrl = new URL("your wsdl url);
2.QName qname = new QName("targetNamespace in ur wsdl file","service name in your wsdl file");
Service service = Services.create(wsdlUrl,qname);
4.suppose getData() is your SEI
GetData data = (GetData)service.getPort(GetData.class);
5.call the your methods using data object
ex:data.getId(String name); this will return your response
Am pretty new to web services and have been trying to implement Soap Faults. I used Apache Axis2 to generate webservice in the following manner.
public interface XYZ{
public String myMethod(User[] user)
}
Here I have created a User class with some variables so that I can generate User object at .Net environment to pass User[] of objects.
Public class Webservice implements XYZ
{
Public String myMethod(User[] user){
//My implementation
}
}
Now, I created a dynamic project using Eclipse and with the help of Axis2 plugin I created webservice for my "Webservice" class which generates wsdl file. I deployed the webcontent in the Tomcat folder and able to access the WSDL file in the .Net environment. I am able to pass array of objects (User[]) from .Net to Java and able to do my task. Now, I need to implement Soap Faults in Java which I am not sure how to implement.
Can anyone help me with an example or tutorial ?
Your best bet is to Google for something like "jax-ws faults". For example:
http://www.ibm.com/developerworks/webservices/library/ws-jaxws-faults/index.html
You can also implement an error handler, as discussed under "Using handlers in JAX-WS Web services" here:
http://axis.apache.org/axis2/java/core/docs/jaxws-guide.html#BottomUpService
Most frameworks will trigger a SOAP fault when you throw an Exception in the method implementing your operation. That will not give you much control on the SOAP fault content though.
See here for some details on Axis
Generally, You don't need any specific coding for implementing SOAP fault.. Whenever there is any exception thrown by the method (here myMethod in your example.), axis will automatically generate SOAPFault element in the resulting response. The exception is actually wrapped into AxisFault exception and sent to the client.
See here a i.
Can someone fill in the missing link in the code below?
First way:
The web service interface file is HappyService.
JaxWSProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.getInterceptors().add(new LoggingInInterceptor());
factory.getInterceptors().add(new LoggingOutInterceptor());
//MISSING LINK. Where does HappyService.class come from? I don't have it
factory.setServiceClass(HappyService.class);
factory.setAddress("http://......../happyService");
//Again how do I get HappyService?
HappyService client = (HappyService) factory.create();
Second way:
String UrlString = "Your WSDL URL";
String nameSpaceUri = "urn:Foo";
String serviceName = "MyHelloService";
String portName = "HelloIFPort";
URL helloWsdlUrl = new URL(UrlString);
ServiceFactory serviceFactory = ServiceFactory.newInstance();
Service helloService =
serviceFactory.createService(helloWsdlUrl,
new QName(nameSpaceUri, serviceName));
//Where did dynamicproxy.HelloIF come from? This code won't compile as that file does not exist anywhere
dynamicproxy.HelloIF myProxy =
(dynamicproxy.HelloIF)
helloService.getPort(
new QName(nameSpaceUri, portName),
dynamicproxy.HelloIF.class);
System.out.println(myProxy.sayHello("Buzz"));
Anyone that has a clue as to where these interface classes come from and how they are generated please let me know. It looks like the only way I can do an web service invocation is by writing the SOAP request by hand and I really don't want to do that as it can get very large and error prone.
There are many tools that generate webservices Java classes from WSDL definition files.
You could try JAXB, which is the standard Java tool for this task.
An other possibility is Axis, which a level higher.
You need a SOAP library such as Apache Axis2. The library will include tools for generating Java classes from WSDLs. You would use that generated code to make the web service calls.
Based on your first sample I think you use the CXF framework.
This framework provides a task named wsdl2java that allows to generate classes from a WSDL file.
Once your classes are generated you can use them in your code to call the Web Service in an easy way without having to build the SOAP message by hand. It's CXF's job to do this.
I think it helps if you refer few basics of web-services in java
http://www.oracle.com/technetwork/java/index-jsp-137004.html
http://metro.java.net/
I had a java project and after lots of research I managed to convert it to a Dynamic Web Project in Eclipse. Now I want to add a new Web Service to it. I have already developed a class. I want to convert it to a standard Web service so I can call it from my silverlight application. Here's my current class:
public class MyWebService
{
#Resource
WebServiceContext context;
#WebMethod
public String ProcessQuery(#WebParam(name="query") String q)
{
MessageContext messageContext = context.getMessageContext();
HttpServletRequest request = (HttpServletRequest) messageContext.get(SOAPMessageContext.SERVLET_REQUEST);
// now you can get anything you want from the request
}
public static void main(String[] args) throws Exception
{
String address = "http://127.0.0.1:8023/_WebServiceDemo";
Endpoint.publish(address, new MyWebService());
new DocumentServer();
System.out.println("Listening: " + address);
}
}
How can I do it in Eclipse? Please post a link to a tutorial or a quick step by step guide. I'm a .Net developer and I'm very new to Java.
Thank you.
PS: So basically I want to publish this service in a standard way rather than calling this main function and using Endpoint.publish() method.
The Eclipse wiki has a tutorial using the Web Tools Platform to do just what you are looking for. It requires WTP and Tomcat, if you don't have those already available to Eclipse. It starts with an unannotated class and finishes with a WSDL and test client. It allows you to view generated SOAP messages.
To create, it instructs you to select the file you want to convert into a web service and run File -> New -> Other... -> Web Services -> Web Service. Then you click Next, move the slider to the Start Service position, and client to Test Client. You select Monitor the Web Service and then click Finish. Then you can play with your Test Client and see your generated WSDL.
Note that the above paragraph is a summary of the tutorial, which you can find in full at the provided link.