Bypassing JAX-WS SOAP overhead with JAX-RS/Jersey? - java

The only web services I've ever integrated with or used have been RESTful. I'm now trying to integrate with a 3rd party SOAP service and am awe-struck at how seemingly convoluted SOAP appears to be.
With REST, I use a JAX-RS client called Jersey that makes hitting RESTful endpoints a piece a' cake. For instance, if a service is exposing a POST endpoint at http://api.example.com/fizz (say, for upserting Fizz objects), then in Jersey I might make a service client that looks like this (pseudo-code):
// Groovy pseudo-code
class Fizz {
int type
boolean derps
String uid
}
class FizzClient {
WebResource webResource = initAt("https://api.example.com")
upsertFizz(Fizz fizz) {
webResource.path("fizz").post(fizz)
}
}
But Java-based SOAP clients seem, at first blush, to be fairly more complicated. If I understand the setup correctly, the general process is this:
Obtain an XML document called a WSDL from the service provider; this appears to be a language-agnostic description of all the available endpoints
Run a JDK tool called wsimport on the WSDL which actually generates Java source code, which implements JAX-WS APIs and actually represents my SOAP client
Import those generated source files into my project and use them
First off, if anything I have said about this process is incorrect, please begin by correcting me! Assuming I'm more or less correct, what I don't understand is: why is this necessary if its all an HTTP conversation? Why couldn't I achieve SOAP-based conversations with Jersey, and bypass all this source-generation boilerplate?
For instance, say the same endpoint exists, but is governed by SOAP:
class FizzClient {
WebResource webResource = initAt("https://api.example.com")
FizzSerializer serializer // I take Fizz instances and turn them into XML
FizzDeserializer deserializer // I take XML and turn them into Fizz instances
upsertFizz(Fizz fizz) {
String xmlFizz = serializer.serialize(fizz)
webResource.path("fizz").post(xmlFizz)
}
}
If I understand SOAP correctly, its just a way of utilizing HTTP verbs and request/response entities to send app-specific messages around; it's an HTTP "conversation". So why couldn't I hijack a REST framework like Jersey to HTTP POST messages, and in doing so, bypass this SOAP overhead?

This is going to attract opinion-based answers, but first, you should understand that
jax-rs is much younger than jax-ws (jax-ws had a final draft in 2006, JAX-RS came out in 2008-9).
RESTful webservices standard, for many purposes is quite amorphous - many businesses prefer the comfort of a contract in the form of a WSDL.
Not to mention that JAX-WS, in concert with WS-I provides many other standards that govern security, message reliability and other enterprise-goodies (under the generic "WS-*" banner) that businesses care about. There's a hodge-podge of libraries that are attempting to get that kind of uniformity on to the jax-rs platform, but for now, jax-ws/WS-I is the industry standard

Related

Spring: How to export objects methods via non-HTTP protocol

I have a collection of stateless scala/Java APIs, which might look like:
class UserService {
def get(id: UserIDType): User { ... }
def update( user:User): User { ... }
...
}
where User has a set of inspectable bean properties. I'd like to make these same APIs not only available over HTTP (which I know how to do), but also other, more performant non-HTTP protocols (ideally also running in the same process as the HTTP server). And more importantly, automate as much as possible including generation of client APIs that match the original Java API, and the dispatching of method calls following network requests.
I've found Spring's guide on remoting
However, this looks limited to HTTP (text not binary). What I'd really love is a library/other method that:
lets me scan for registered/annotated services and describes methods and parameters as data
lets me easily dispatch method calls (so that I'm in control of the sockets, communication protocols and whatnot and can chose a more performant one than HTTP).
i.e. the kinds of things that Spring's DispatcherServlet does internally, but without the HTTP limitations.
Ideas?
Background
I'd like to make a set of stateless service API calls available as network services with the following goals:
Some of the APIs should be available as REST calls from web pages/mobile clients
A superset of these APIs should be available internally within our company (e.g. from C++ libraries, python libraries) in a way that is as high-performance (read low-latency) as possible, particularly when the service and client are:
co-located in the same process, or
co-located on the same machine.
automate wrapper code for the client and server. If I add a method a service API, or and an attribute to a class, no-one should have to write additional code in client or server. (e.g. I hit a button and a new client API that matches the original Java/scala service is auto-generated).
(1) is easily achievable with Spring MVC. Without duplication of classes I can simply markup the service: (i.e. service is also a controller)
#Controller
#Service
#RequestMapping(...)
class UserService {
#RequestMapping(...)
def get(#PathVariable("id") id: UserIDType): User { ... }
#RequestMapping(...)
def update( #RequestBody user:User): User { ... }
...
}
With tools like Swagger (3) is easily achievable (I can trivially read the Swagger-generated JSON spec and can auto-generate C++ or Python code that mimics the original service class, it's methods, parameter names and the POJO parameter types).
However, HTTP is not particularly performant, so I'd like to use a different (binary) protocol here. Trivially, I can use the this same spec to generate a thrift .idl or even directly generate client code to talk Thrift/ProtocolBuffers (or any other binary protocol) while also providing to the client an API that looks just like the original Java/scala one.
Really -- the only tricky part is getting a description of the service method and then actually dispatching a method calls. So -- are there libraries to help me do that?
Notes:
I'm aware that mixing service and controller annotations disgusts some Spring MVC purists. However, my goal really is to have a logical API, and automate all of the service embodiments of it (i.e. the controller part is redundant boilerplate that should be auto-generated). I'd REALLY rather not spend my life writing boilerplate code.

Webservice communication between Java EE applications

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... ;) ;)

How can i send object in HTTP request

I am creating a Web Service that will handle incoming request properly (I knew, it is a description) I found some sample code which present SOAP WS and looks like:
#SoapAction("some fine url")
#ResponsePayload
public CertResponse getCert(#RequestPayload Cert param)
{...}
It takes Cert object from request and manages it properly. I want to do it in the REST approach and I changed this class to look like:
#RequestMapping(value="getCert", method = RequestMethod.POST)
#ResponseBody
public CertResponse getCert(#RequestBody Cert param)
{...}
But I have no idea how or even if it is possible to write a client that can send object through HTTP Post.
Can anyone give me a hint how can i send object Cert? Or if i have to stay with #SoapAction what should I do to make it work? I guess removing #Controller is not enough.
In SOAP approach, there is a well defined way to convert each class object to SOAP formatted XML. Thus, there is no effort.
If you will use RESTful approach, you have to describe how your Cert or CertResponse objects will be written to/read from the response/request.
Basically you have three options:
Use JSON or XML or plain String. Convert your Web service descriptor so that the request and response are one of those (JSON, XML, String). Then your getCert method should convert the request to Cert object, prepare your response as CertResponse object and convert it to an appropriate response type.
Leave your getCert method as is. But you need to specify "how Cert objects are read from request" and "how CertResponse objects are written to response" You need to define classes that extend interfaces MessageBodyReader and MessageBodyWriter. In these classes a similar conversion logic should be implemented that converts your objects to/from JSON or XML or String.
In any of these two options you need to implement two things : A method that converts JSON/XML/String to Cert, a method that converts CertResponse object to JSON/XML/String.
You can do a text based implementation, which parses/constructs the request/response by text processing and uses String class only. Or you can use some library such as JSON library with JSONObject class, or Java SAX or DOM based XML libraries that come with the Java bundle.
Check out for application frameworks such as Spring. They might provide ways to automatically convert your objects to JSON or XML, reducing the programming effort necessary.
Spring allows you to pass JSON objects from the client as a request parameters, it will convert them into your objects automatically. This discussion have some examples.
SOAP services are not really compatible with REST semantics. And it's not clear what SOAP framework do you use. Typically most SOAP frameworks offer you one way or another to generate a SOAP client code for you WSDL. You can check cxf.apache.org.
For REST services use something like Jersey or Spring MVC

GWT RequestFactory client scenarios

My understanding is that the GWT RequestFactory (RF) API is for building data-oriented services whereby a client-side entity can communicate directly with it's server-side DAO.
My understanding is that when you fire a RF method from the client-side, a RequestFactoryServlet living on the server is what first receives the request. This servlet acts like a DispatchServlet and routes the request on to the correct service, which is tied to a single entity (model) in the data store.
I'm used to writing servlets that might pass the request on to some business logic (like an EJB), and then compute some response to send back. This might be a JSP view, some complicated JSON (Jackson) object, or anything else.
In all the RF examples, I see no such existence of these servlets, and I'm wondering if they even exist in GWT-RF land. If the RequestFactoryServlet is automagically routing requests to the correct DAO and method, and the DAO method is what is returned in the response, then I can see a scenario where GWT RF doesn't even utilize traditional servlets. (1) Is this the case?
Regardless, there are times in my GWT application where I want to hit a specific url, such as http://www.example.com?foo=bar. (2) Can I use RF for this, and if so, how?
I think if I could see two specific examples, side-by-side of GWT RF in action, I'd be able to connect all the dots:
Scenario #1 : I have a Person entity with methods like isHappy(), isSad(), etc. that would require interaction with a server-side DAO; and
Scenario #2 : I want to fire an HTTP request to http://www.example.com?foo=bar and manually inspect the HTTP response
If it's possible to accomplish both with the RF API, that would be my first preference. If the latter scenario can't be accomplished with RF, then please explain why and what is the GWT-preferred alternative. Thanks in advance!
1.- Request factory not only works for Entities but Services, so you could define any service in server-side with methods which you call from client. Of course when you use RF services they are able to deal with certain types (primitive, boxed primitives, sets, lists and RF proxies)
#Service(value=RfService.class, locator=RfServiceLocator.class)
public interface TwService extends RequestContext {
Request<String> parse(String value);
}
public class RfService {
public String parse(String value) {
return value.replace("a", "b");
}
2.- RF is not thought to receive other message payloads than the RF servlet produces, and the most you can do in client side with RF is ask for that services hosted in a different site (when you deploy your server and client sides in different hosts).
You can use other mechanisms in gwt world to get data from other urls, take a look to gwtquery Ajax and data-binding or this article

How to implement Soap Faults in Java webservices?

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.

Categories