I have an asynchronous JAX-WS web service (#WebService and #WebMethod annotations). I am invoking it in Java. and I would like to know how to get HTTP response code from that service in Java code.
I couldn't find anything on that subject, but I deduced solution based on how my request context is built, because I needed response context so I thought they may be similar. Request context:
((BindingProvider)port).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpoint)
So I thought that this may work:
int responseCode = (int)((BindingProvider) port).getResponseContext().get(MessageContext.HTTP_RESPONSE_CODE);
And it works. ; )
Related
I need to manage different versions that come in the URL of the Webservice. I'm using a common method in the Webservice for SOAP and REST, and when I tried to get the path in the endPoint class I got the correct path for REST, but not for SOAP(I got a null in this case), does anybody how to get the path in soap?
The url looks like: http://localhost:8083/webService/v1/test and the code is:
#Stateless
#WebService(endpointInterface = "ItestgEndpoint", serviceName="testService")
#Component("testEndpoint")
#Path("/webService")
#Consumes({MediaType.APPLICATION_XML})
#Produces({MediaType.APPLICATION_XML})
public class TestEndpoint implements ItestgEndpoint{
#PUT
#Path("/{version}/test")
#Consumes({MediaType.APPLICATION_XML })
#Produces({MediaType.APPLICATION_XML })
#WebResult(name="testResponse")
public testResponse testEvent(#WebParam(targetNamespace="http://test/web", name="message")
#RequestParam MessageClass message,
#WebParam(name="version") #PathParam("version") String version
) throws TimeoutException, EMSException, ValidationException, AuthenticationException {
logger.info(version);
}
I saw this post SOAP and REST Webservice with one implementation in Java EE, but it didn't solve my problem.
Thanks
SOAP has no "path" like REST has. Depending on the service toolkit you use (CXF, axis, ...) you may need to collect the information in the request that you can extract from the transport mechanism of the soap message. This may or may not be available to you.
Usually, you wire the SOAP service to a path in a configuration. For example in axis, you set the soap servlet dispatcher in the web.xml, same is for cxf. The actual service is then wired in the beans.xml or services.wsdd.
The SOAP handler finds the service by the name of the endpoint and will then send the call to that endpoint which will dispatch it to the right method. The method is in the transmitted SOAP header, not in the URI.
In REST, the identification of the target service/method is in the URI, not in the XML.
So, in my opinion, for SOAP, this is by declaration and the wiring is static, while in REST, you can have the version as a path parameter.
UPDATE: Since everything is possible if you just try hard enough :-) you could rewrite the dispatcher code to allow an extra path parameter on SOAP, maybe the available packages allow some kind of interceptor class, that allows you to rewrite the SOAP header to point to another endpoint, depending on a header attribute that you invent.
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 presuming that GWT RPC actually uses RequestBuilder.
Is there a way to extract the RequestBuilder instance used by my RPC service async requestor?
Actually, my question is, how do you extract the RequestBuilder instance to insert the authentication token as a http header? Is there a way to insert http headers into an RPC service request?
Even if I could insert a http header into the request, how then would the remote servlet be told to expect that auth token? Therefore, in fact, does GWT RPC provide a framework for secure authentication at all?
I am thinking the answer is NO, or at least not in a convenient way. Am I right?
I am coming from having used RestEasy in combination with RestyGWT over SSL, where we can insert headers anytime we wish. BTW, RestyGWT constructs its request to use RequestBuilder.
My actual motivation is comparing the security effectiveness between GWT RPC and GWT JAX-RS (RestyGWT + RestEasy). So if you, as the answerer, have an alternative detailed discourse comparing the security effectiveness of RPC with direct use of RequestBuilder or REST (rather than answering this question directly) please feel free to elaborate.
Am I right to presume that GWT RPC is not security friendly/effective and I should avoid using GWT RPC for secure authenticated requests?
You can have your async method return a Request or a RequestBuilder instead of void. Request allows you to abort() a pending request, whereas RequestBuilder allows you to modify the request before its sent (if you declare the return-type as RequestBuilder, you're responsible for calling send() to actually make the request).
Alternately, you can use an RpcRequestBuilder to customize the RequestBuilder for each and every call made with a specific async service proxy.
As far as I know there is no built in security solution for gwt rpc.
But If I need such authentication I would make the following steps:
1) To be able to set http headers you can make your custom request builder, as I do myself:
MyServiceAsync myService = GWT.create(MyService.class);
MyRequestBuilder myRequestBuilder = new MyRequestBuilder();
myRequestBuilder.addHeader("header", "value");
((ServiceDefTarget) serviceInstance).setRpcRequestBuilder(myRequestBuilder);
MyRequestBuilder extends RpcRequestBuilder. And inside MyRequestBuilder I override method doFinish(RequestBuilder rb) where I put my headers.
Maybe it is not a super solution, but I haven't yet found anything better.
2) For the server side I would implement the AuthenticationFilter for checking the headers and perform server side auth functions prior calling the Servlet.
I have written a web service client (using Java Spring and JAXB Marshaller) that works with the UPS web service. When I send a valid request everything works well. When I send an invalid request (weight > 150 lbs) then the UPS web service responds with a SOAP Fault. The client application just fails with a
org.springframework.oxm.UnmarshallingFailureException: JAXB unmarshalling
exception; nested exception is javax.xml.bind.UnmarshalException:
unexpected element (uri:"http://schemas.xmlsoap.org/soap/envelope/", local:"Fault").
Obviously my program isn't able to decipher the SOAP fault returned by the web service. I wrote a custom FaultMessageResolver, but it doesn't get invoked. Here's the code:
public class UpsRateClient extends WebServiceGatewaySupport {
public UpsRateClient(WebServiceMessageFactory messageFactory) {
super(messageFactory);
getWebServiceTemplate().setFaultMessageResolver(new UpsFaultMessageResolver());
}
public RateResponse getRate(RateRequest rateRequest) {
return (RateResponse) getWebServiceTemplate().marshalSendAndReceive(rateRequest, new UpsRequestWSMC());
}
private class UpsFaultMessageResolver implements FaultMessageResolver {
public void resolveFault(WebServiceMessage message) throws IOException{
System.out.println("Inside UpsFaultMessageResolver");
}
}
}
Thanks for your time!
I had the same problem (SOAP error with HTTP 200OK) and I solved it setting the CheckConnectionForFault property to false. See.
Take a wireshark trace.My thought is that perhaps the web service sends the SOAP fault using (erroneously) a HTTP 200OK instead of a 500 Internal Server error and your client tries to handle it as a valid response.
If this is the case this is then the problem lies in the web service which does not addere to SOAP standard(my emphasis):
From SOAP RFC
In case of a SOAP error while processing the request, the SOAP HTTP
server MUST issue an HTTP 500 "Internal Server Error" response and
include a SOAP message in the response containing a SOAP Fault element
(see section 4.4) indicating the SOAP processing error.
If you do not own the web service, they should fix this.
To be honest I am not sure what the work arround would be in Spring-WS.
If I really needed a work arround in Jax-Ws I would replace the stub call with a Dispatcher to handle the raw xml myself and avoid the automatic marshal/demarhal.
Look into Spring-Ws if you can do the same, but this is a bug of the web service, not your client
I'm writing a simple Google Web Toolkit service which acts as a proxy, which will basically exist to allow the client to make a POST to a different server. The client essentially uses this service to request an HTTP call. The service has only one asynchronous method call, called ajax(), which should just forward the server response. My code for implementing the call looks like this:
class ProxyServiceImpl extends RemoteServiceServlet implements ProxyService {
#Override
public Response ajax(String data) {
RequestBuilder rb = /*make a request builder*/
RequestCallback rc = new RequestCallback() {
#Override
public void onResponseReceived(Response response) {
/* Forward this response back to the client as the return value of
the ajax method... somehow... */
}
};
rb.sendRequest(data, requestCallback);
return /* The response above... except I can't */;
}
}
You can see the basic form of my problem, of course. The ajax() method is used asynchronously, but GWT decides to be smart and hide that from the dumb old developer, so they can just write normal Java code without callbacks. GWT services basically just do magic instead of accepting a callback parameter.
The trouble arises, then, because GWT is hiding the callback object from me. I'm trying to make my own asynchronous call from the service implementation, but I can't, because GWT services assume that you behave synchronously in service implementations. How can I work around this and make an asynchronous call from my service method implementation?
You are mixing up client and server side code. In ProxyServiceImpl, you CANNOT use RequestBuilder. RequestBuilder is a client side class which will only execute in the browser.
A server-to-server http call is always synchronous. Instead of using RequestBuilder, you should make use of a library like HttpClient, get the results and then send it back to the client. That would solve the problem you are facing.
But I should add, you DO NOT want to build a proxy at the application level. You could just as well use a http proxy such as apache's mod_proxy.