I'm trying to understand how Jax-WS web services work but can't find any resources on the specifics of them. By way of example:
I create a very simple Java web service using Jax-WS annotations, like so
#WebService(name = "MyService", serviceName = "MyService", portName = "MyServicePort")
public class MyService {
private int val;
public MyService() {
val = 0;
}
#WebMethod(action = "setVal")
public void setVal(#WebParam(name = "arg") int arg) {
val = arg;
}
#WebMethod(action = "getVal")
public int getVal() {
return val;
}
}
If I generate a web service from this (using WS-Gen, say), build a client and make the following calls from a single client: setVal(5), getVal(), what value will be returned to the client? Why?
What about if client A calls setVal(5), and client B calls getVal(), what value will be returned to the client? Why?
Naturally I could build a web-service myself and test it, but I was hoping for an explination to go with the answer. Does Jax-Ws create a new instance of the annotated class for each request? Does it somehow map the same source to the same annotated class instance? Does it just map all requests to a singleton instance of the annotated class? Is there a finite pool of annotated class instances that picked from in some fashion?
Web Services are stateless by default because of the underlying HTTP protocol. The server processes each web service request as a new interaction even though it is from the same client
Normally, a JAX-WS Web service is stateless: that is, none of the
local variables and object values that you set in the Web service
object are saved from one invocation to the next. Even sequential
requests from a single client are treated each as independent,
stateless method invocations.
There are Web service use cases where a client may want to save data
on the service during one invocation and then use that data during a
subsequent invocation. For example, a shopping cart object may be
added to by repeated calls to the addToCart web method and then
fetched by the getCart web method. In a stateless Web service, the
shopping cart object would always be empty, no matter how many
addToCart methods were called. But by using HTTP Sessions to maintain
state across Web service invocations, the cart may be built up
incrementally, and then returned to the client.
Enabling stateful support in a JAX-WS Web service requires a minimal
amount of coding on both the client and server.
http://docs.oracle.com/cd/E17904_01/web.1111/e13734/stateful.htm
Related
So I have a Jersey REST service on a Tomcat server that takes client requests, processes them with an Entity Manager to get data from a database, then sends back a response to the client. So my question is, when is my REST class (containing the URL paths and such) created/destroyed? Is it created fresh with every new AJAX request or does it stay running and open on the server indefinitely?
Thanks!
Jersey basically runs as a single servlet that handles all of the requests. When a request is received, the URI+media types is matched (by the servlet implementation) against all the paths you have defined in your various Jersey-annotated classes. If a match is found, Jersey instantiates the relevant class and invokes the proper method and does all the appropriate magic based on annotations and return types.
The one Jersey servlet gets started once. Your Jersey-annotated class gets a new instance for each request that it handles. I usually have a bunch of #Context-annotated parameters for my constructor, so that I have all the relevant context for the request (request, URI, headers, security context, etc.) available to my API implementations.
I am very much confused about the concept behind the QName.
lets take for example (I have taken these examples from http://www.mkyong.com/):
ServerInfoService sis = new ServerInfoService();
ServerInfo si = sis.getServerInfoPort();
System.out.println(si.getServerName());
And with QName :
URL url = new URL("http://localhost:8888/ws/image?wsdl");
QName qname = new QName("http://ws.mkyong.com/", "ImageServerImplService");
Service service = Service.create(url, qname);
ImageServer imageServer = service.getPort(ImageServer.class);
Now my question is :
1) Is there any concepts based on which we have to decide which type of client we can write
2) What is the purpose or additional benefits in using QName because all I can see here is that it increases complexity as compared to simple client.
Here is what i know:-
It depends on how you would want to make use of your client to invoke the web service.
The first approach
ServerInfoService sis = new ServerInfoService();
ServerInfo si = sis.getServerInfoPort();
is the plain simple proxy generation approach; where-in you use a tool like wsimport to generate proxies/stubs to your SEI(Service Endpoint Interface)/web-service interfaces and invoke methods on it like any other java method call. Is mostly used in clients where you simply need to invoke methods on the web-service without getting into granular details.
The QName or rather the Service approach offer finer controls over how the client and webservice communicate. JAXWS 2.0 introduced something called as a Provider interface which was an alternative to your SEI which basically let a client communicate at the XML message level and provide a dynamic representation/view of your web-service to the client. More here. The primary use of Service API is mostly to create Dispatch instances which basically let a client dispatch to a speicific port(method qualified using QName api) using JAXB messages as XML payloads.
Other uses of Service api let a client call methods on the webservice asynchronously; provide access to handlers; etc. A good example of using the Service and QName approach to help you understand further and to relate to what i have said is this link here:- Dispatching Web Service Calls.
This being said there is a lot more to know and understand; but hope this gives you a start.
We have been provided with a wsdl and xsd schema by a company we are working with via email. The web-services we are interfacing with are accessed through a IPsec tunnel. There are local references(on their end) in the published WSDL which means we cannot consume it.
1st question: Is this a common setup? I thought the point of having a WSDL was not only to define the contract but to also expose the service to consumers.
I can easily generate client/server code off of the provided WSDL using wsimport, wsconsume, etc.. I know when my generated client makes a call to my generated service it produces the correct message I need.
2nd Question: Is there an easy way to route this to a different soap address?
I just want to be able to do something like:
SalesTaxService svc = new SalesTaxService();
SalesTax tax = svc.getSalesTaxPort()
tax.getRate("NY");
But not use the soap address defined in the WSDL. I would like to avoid writing a bunch of dispatch clients for each method.
Am I missing something?
*In response to skaffman:
This is what was generated. It defaulted to wsdlLocation as a name shrug
#WebServiceClient(name = "SomeService")
public class SomeService_Service extends Service {
public SomeService_Service(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public SomeService_Service(URL wsdlLocation) {
super(wsdlLocation, new QName("urn:some_service", "SomeService"));
}
}
I thought the point of having a WSDL
was not only to define the contract
but to also expose the service to
consumers.
No, WSDL is purely a descriptive tool, it has no real runtime role. The web service operates completely independently of the WSDL. It's not uncommon for the WSDL to not be exposed.
Is there an easy way to route this to
a different soap address?
That depends entirely on what web service implementation you're using, and you don't say, although I'm guessing JAX-WS. If that's the case, the artifacts that JAX-WS's tools generate allow you to pass in the URL to the client stub constructors, I think.
So I figured out why I was having a problem. I was assuming that the wsdlLocation had to be the WSDL that the actual service was publishing. This of course is not the case. The solution is to package a local WSDL with the correct SOAP:Address for the actual service into the client.
edit
I found out that you can alter the endpoint address programmatically without having to alter the actual WSDL:
HelloService service = new HelloService (
this.getClass().getResource("originalHello.wsdl"),
new QName("http://example.org/hello", "HelloService "));
HelloPort proxy = service.getHelloPort();
Map<String, Object> ctxt = ((BindingProvider)proxy ).getRequestContext();
ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);
ctxt.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://new/endpointaddress");
proxy.sayHello("Hello World!");
Credit goes to : Jianming Li
I'm using Netbeans 6.5 to generate the JAX-WS Metro service and Glassfish 2.1 as the application server.
Assume I have two web services e.g.
...
#WebMethod(operationName = "doXXX")
public String doXXX(
#WebParam(name = "id") String id
...
...
#WebMethod(operationName = "doYYY")
public String doYYY(
#WebParam(name = "result") String result
...
and I have a Web Service client (a Java application) that happily calls both.
I now want method XXX to call method YYY i.e. I need to place the client proxy for YYY inside of web service XXX.
How do I do this?
You shouldn't attempt to proxy a request to invoke a method inside the same application - this will incur needless serialization/deserialization of Objects to XML messages and back.
If you need to call another method inside the same application, re-design your application so that you can gain access to whatever area of the application you need to invoke.
I played around and figured it out.
You don't want to call the actual web service via a proxy client because then you will needlessly serialize / deserialize the data.
Assume in the example above, that the doXXX method is inside a class called XXX and that the doYYY method is inside a class called YYY.
(Note that the class would be annotated by a #WebService() tag.)
To call doYYY() from the doXXX method:
YYY yyy = new YYY ();
yyy.doYYY ();
Lets assume a simple Spring MVC Controller that receives the ID of a domain object. The Controller should call a service that should do something with that domain object.
Where do you "convert" the ID of the domain object into the domain object by loading it from the database? This should not be done by the Controller. So the service method interface has to use accept the ID of the domain object instead of the domain object itself. But the interface of the service would be nicer if it takes the domain object as a parameter.
What are your thoughts about this common use case? How do you solve this?
The controller should pass the id down into the service layer and then get back whatever is needed to render the rest of the HTTP response.
So -
Map<String,Object> doGet (#RequestParam("id") int id) {
return serviceLayer.getStuffByDomainObjectId(id);
}
Anything else is just going to be polluting the web layer, which shouldn't care at all about persistence. The entire purpose of the service layer is to get domain objects and tell them to perform their business logic. So, a database call should reside in the service layer as such -
public Map<String,Object> getStuffByDomainObjectId(int id) {
DomainObject domainObject = dao.getDomainObjectById(id);
domainObject.businessLogicMethod();
return domainObject.map();
}
in a project of mine I used the service layer:
class ProductService {
void removeById(long id);
}
I think this would depend on whether the service is remote or local. As a rule I try to pass IDs where possible to remote services but prefer objects for local ones.
The reasoning behind this is that it reduces network traffic by only sending what is absolutely necessary to remote services and prevents multiple calls to DAOs for local services (although with Hibernate caching this might be a mute point for local services).