What is difference, philosophical or otherwise, between calling a web service from Java code using Service and Dispatch classes, vs a SOAPConnection class?
For example, something like this:
SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance();
SOAPConnection soapConnection = scf.createConnection();
SOAPMessage reply = soapConnection.call(soapMessage, url);
vs something roughly along these lines?
svc = Service.create(url, serviceName);
Dispatch<SOAPMessage> dispatch = svc.createDispatch(portName, SOAPMessage.class, service.Mode.MESSAGE);
SOAPMessage reply = (SOAPMessage)dispatch.invoke(soapMessage);
What is the difference between these, and why select one approach over the other?
The following line are excerpt from Java SOA Cookbook - O'Reilly
"The SOAP connection allows you to send a SOAP message to a resource at the end of
a URL. This is convenient to use in any situation, but necessary if that service does not
have a defined WSDL. That’s because calling Service.create requires passing in the
location of the WSDL. It may be rare that you don’t have a WSDL with a SOAP-based
service, but it does happen, and you’ll be prepared.
To create a connection to a web service that does not expose a WSDL, you can use the
SOAPConnection class to communicate directly with the remote resource. You then create a URL object representing the remote
resource (servlet) you want to call. Pass the SOAP request message and the endpoint
you want to invoke to the call method on your connection object, and then wait for
it to return a SOAP response.
• The endpoint URL passed to the connection.call method can be either a string or
a java.net.URL."
I have a feeling that at the end, the Dispatch simply delegates the actions to a SAAJ layer. However, I haven't been able to confirm that.
From the perspective of what's a better practice, then i feel the Dispatch methodology is more appropriate since it abstracts away some of the overheads of working with the lower level SAAJConnection API. Like - there's no need to do a close() on the connection instance, the dispatch reference need not be re-created unlike the SOAPConnection instance.
Related
I faced this question on one of interviews, so could you please tell whether SOAP Web services support only "POST" http method or there is some way to accept other methods on the server side?
I always used POST but according to the W3C standard, SOAP supports both POST and GET methods.
Edit: After some research, it seems that it's not completely true, as you can see here. It is theoretically possible to use GET because POST and GET are methods of HTTP transport protocol and SOAP can be used over HTTP.
But as you know, GET includes the request in the query string. SOAP requests (XML messages) are usually too complex and verbose to be included in the query string, so almost every implementation (for example JAX-WS) supports only POST.
Thread is three years old but I think that there will be still a lot of people who will give this same question to themselves and will find wrong answer in the web. The answer to the question is no, GET method can be used too.
According to SOAP specification, which can found here: https://www.w3.org/TR/2007/REC-soap12-part0-20070427/#transport
both GET and POST methods can be used to exchange SOAP messages over http.
The use of the HTTP POST method for conveying SOAP messages in the bodies of HTTP request uses a pattern called SOAP request-response message exchange pattern. In the case of HTTP GET a pattern is used called SOAP response message exchange pattern. The main difference of this two patterns is:
The first type of interaction allows for the use of data within the body of a HTTP POST to create or modify the state of a resource identified by the URI to which the HTTP request is destined. The second type of interaction pattern offers the ability to use a HTTP GET request to obtain a representation of a resource without altering its state in any way. In the first case, the SOAP-specific aspect of concern is that the body of the HTTP POST request is a SOAP message which has to be processed (per the SOAP processing model) as a part of the application-specific processing required to conform to the POST semantics. In the second case, the typical usage that is forseen is the case where the representation of the resource that is being requested is returned not as a HTML, or indeed a generic XML document, but as a SOAP message. That is, the HTTP content type header of the response message identifies it as being of media type "application/soap+xml"
So both GET and POST methods can be used. The other thing is that in practice mostly POST method is used.
The bad thing is that when comparing RESTful services with SOAP services, as an advantage of REST people are bringing caching, which is not available in SOAP, because SOAP uses only POST. This is totally wrong.
This is an implementation of GET in SOAP:
#WebServiceProvider(targetNamespace="http://attachment.service.soap.com/download")
#ServiceMode(value = javax.xml.ws.Service.Mode.MESSAGE)
#BindingType(value = HTTPBinding.HTTP_BINDING)
public final class ImageDownloadServiceProvider implements Provider<DataSource> {
#Resource
private WebServiceContext wsContext;
#Override
public DataSource invoke(DataSource request) {
if (wsContext == null)
throw new RuntimeException("dependency injection failed on wsContext");
MessageContext msgContext = wsContext.getMessageContext();
HttpExchange exchange = (HttpExchange) msgContext.get("com.sun.xml.internal.ws.http.exchange");
String filename = exchange.getRequestURI().getQuery().replace("file=", "");
switch ((String) msgContext.get(MessageContext.HTTP_REQUEST_METHOD)) {
case "GET":
return doGet(filename);
default:
throw new HTTPException(405);
}
}
private DataSource doGet(String filename) {
FileDataSource fds = new FileDataSource(filename);
MimetypesFileTypeMap mtftm = new MimetypesFileTypeMap();
mtftm.addMimeTypes("image/jpeg jpg");
fds.setFileTypeMap(mtftm);
return fds;
}
i am creating a http REST service that consumes other http REST services.
I am using Jersey Client to call other services and i have many doubt about which creation pattern of the http client is the best.
Currently i am using EJB with injection of the client that is a Singleton shared by every methods, but i would like to remove java ee dependency and use Jetty as embedded application server.
I see from the doc that Client creation is an expensive operation so i cannot create one every time i need it.
I think about creating 1 in the constructor of every Servlet/Rest class is the simpler solution but i am not sure about the lifecycle of the servlet (if an instance is created for every request, this method is quite the same as the previous)
Or maybe is better to create a Singleton shared by every Servlet/Rest class
Or maybe better a pool of N client.
About this last two solution i need some advice... What do you think it's the better solution?
Thanks
According to you, there is a REST Service deployed in some environment and there is one application, a client or consumer, which wants to access that service.
If i am writing a normal Java class as client using Jersey API, then i will write something lime this :
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
Client client = Client.create();
WebResource webResource = client
.resource("http://localhost:8080/rest/example/employees");
ClientResponse response = webResource.accept("application/json")
.get(ClientResponse.class);
String result = response.getEntity(String.class);
Now say you are writing a servlet, which does some defined job in you application, also it makes a call to the REST Service using client block of code, everytime you access the servlet it will create a instance of com.sun.jersey.api.client.Client each time.
If you want to avoid this then you can create a initial class that will create an instance of com.sun.jersey.api.client.Client, one and only, and make it static and use the same reference where ever you want. WebResource should be created as and when required, because you might be interested to call different URIs.
I would have followed this approach, if i were in your situation.
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
I'm creating a webservice client using Metro with jax-ws and I want to override the endpoint address.
Using the following example from 2.11.1. BindingProvider.ENDPOINT_ADDRESS_PROPERTY I can do that:
http://metro.java.net/guide/How_to_invoke_and_endpoint_by_overriding_endpoint_address_in_the_WSDL.html
//Create service and proxy from the generated Service class.
HelloService service = new HelloService();
HelloPort proxy = service.getHelloPort();
((BindingProvider)proxy).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"http://new/endpointaddress");
proxy.sayHello("Hello World!");
But I don't understand why I can't use the service.getHelloPort().sayHello("Hello World!") instead of proxy.sayHello("Hello World!") as the example shows. If I do, the webservice client is using its default endpoint address instead of the one I want to use.
It looks like I'm getting a new instance of HelloPort every time I call getHelloPort()
Can anyone explain this?
there is little (read: no) difference between these:
service.getHelloPort().sayHello("Hello World");
and
HelloPort proxy = service.getHelloPort();
proxy.sayHello("Hello World!");
the service.getHelloPort() call will always return a new proxy/port instance. so any time you modify the request context for a given port object that modification is local to the specific port instance.
generally speaking the port instance you get back is re-usable and thread safe as long as you dont modify the request/response contexts. for the code sample you posted, it is modifying the request context to set the endpoint address, so it is advisable to get a new port object either every time you need one, or at the very least get a new object for each thread that needs one. (threadlocal is your friend for this)