Can we uniquely identify request to send respond from a POST method? - java

I am working on a web-service which is asynchronous. In my client code, I am using a boto3 session client to call a GET API of my Jetty Server which is S3 alike service. GET API fetched original data from S3 and modifies the request so as to be able to forward the request to flask server. Python flask then get the request processed (where data transformation is done) and calls the POST API of the Jetty Server.
Now I am stuck at figuring out how can I respond to the original caller? Because I am not sure if a API request can have a session-id to identify the original caller?
How can my POST API respond back to client? Following is the overall conceptualization of what I am trying to achieve. How can I do it?

Since I am using embedded Jetty, I used the built-in org.eclipse.jetty.server.HttpChannel.Listener.
I now have access to the raw internal Jetty org.eclipse.jetty.server.Request object that has the HTTP Fields for that request.
To use it, I'll create an instance of that HttpChannel.Listener, and add it as a bean to my connectors.
public class RequestChannelListener implements HttpChannel.Listener {
#Override
public void onRequestBegin(Request request) {
HttpFields.Mutable replacement = HttpFields.build(request.getHttpFields())
.put("X-Request-ID", UUID.randomUUID().toString().toUpperCase());
request.setHttpFields(replacement);
}
}
Add as a bean in the connector -
RequestChannelListener channelListener = new RequestChannelListener();
connector.addBean(channelListener);
Then all other access of that request, be it internal components of Jetty, a webapp, a specific servlet, filters, forwarding, includes, error handling in the servlet spec, error handling outside of a servlet context, etc can all see it.
To check if the custom header got added into the request or not -
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
System.out.println("Header Name - " + headerName + ", Value - " + request.getHeader(headerName));
}

Related

How to change endpoint reference address dynamically?

I'm trying to change the endpoint of the SOAP request at runtime. Because, same SOAP client would be used to request from different server (but API remain same). And, I tried following code
BindingProvider bp = (BindingProvider)repService.getPort (serviceInterface);
bp.getRequestContext ().put (BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"http://" + sHost + "/xxxxyu/somepath?SoapImpl=" + serviceName);
It does change the endpoint property in request context map. But, when I call the method using this service it is still hitting older endpoint. Also, when I wrote below line of code before and after change the endpoint property. I see in both output I'm getting older url not the new endpoint url.
System.out.println ( bp.getEndpointReference ());
I'm totally clueless on what to do and thinking if it is possible ? Let me know, if I missed to add any details.

Jersey/JAX-RS Client throwing 400 Bad Request

I have a RESTful Java web service that I built using Jersey. The client for it defines a resource with the following method:
#Override
public String saveWidget(Widget widget) {
return webResource.path("user").type(MediaType.APPLICATION_JSON).entity(widget).post(String.class, Widget.class);
}
Then, a driver using this client:
public class Driver {
public static void main(String[] args) {
WidgetClient client;
WidgetClientBuilder builder = new WidgetClientBuilder();
client = builder.withUri("http://localhost:8080/myapi").build();
Widget w = getSomehow();
String widgetUri = client.getWidgetResource().saveWidget(w);
System.out.println("Widget was saved URI was returned: " + widgetUri);
}
}
When I run this I get:
Exception in thread "main" com.sun.jersey.api.client.UniformInterfaceException: POST http://localhost:8080/myapi/widget returned a response status of 400 Bad Request
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:688)
at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
at com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:570)
at com.my.myapi.WidgetResource.saveWidget(WidgetResource.java:27)
at com.my.myapi.Driver.main(Driver.java:32)
I know the service endpoint is valid because I can hit it from another (non-Java) web client without issues. This means that either my Widget instance is malformed or that there is something with my Java client method (saveWidget). I ruled out my w Widget being bad by serializing it into JSON, and then copying it into my non-Java web client and POSTing to the same endpoint (no issues arose). So this tells me I have the client method configured wrong. Any ideas?
This is regarding making a call POST call using Jersey client.
For jersey client, default client configuration uses ChunkedEncoding and gzip. This can be checked in request headers for POST call. Content length of payload (JSON String or any object mapper pojo) and request headers received by post call i.e. header name CONTENT-LENGTH, CONTENT-ENCODING. If there is difference, POST call might return 400 bad request. (Something like unable to process JSON). To solve this, you can disable ChunkedEncoding, gzip encoding. Code snippet for the same:
clientConfiguration.setChunkedEncodingEnabled(false);
clientConfiguration.setGzipEnabled(false);
Client client = (new JerseyClientBuilder(environment)).using(clientConfiguration).using(environment).build("HTTP_CLIENT");
WebTarget webTarget = client.target(endpoint);
Response response = webTarget.path(path).request(MediaType.APPLICATION_JSON).post(Entity.json(jsonString));
.post(String.class, Widget.class);
You appear to be posting a Class object, not a Widget object.

CXF client proxy how to handle certain response codes within the client

When I send a request using a proxy client, if I get a certain response, I would like to be able to modify the request and then send the same request again for all requests.
Normally I would do something like:
BookStore proxy = JAXRSClientFactory.create("http://books", BookStore.class);
try
{
proxy.getBook("someId");
}
catch(WebApplicationException ex)
{
Response r = ex.getResponse();
if (r.getStatusCode() == 404)
{
proxy.getBook("anotherId");
}
}
But in this case, there is a common thing I want to do for all requests: If I get a specific http code, modify some header values, and then try again (probably with a limit on the amount of retries).
I haven't seen a way that cxf proxy clients explicitly support this, how could I go about implementing it?
You need to write an interceptor to do this for every request.
here you go for sample code and documentation http://cxf.apache.org/docs/jax-rs-filters.html

Java web service client generated in Netbeans - getting Http Status Code 307

I use Netbeans to generate web service client code, client-style JAX-WS, so i can invoke a web service API.
However, when I invoke the web service API, I get the exception:
com.sun.xml.internal.ws.client.ClientTransportException: The server sent HTTP status code 307: Temporary Redirect
Why do I get this? What is the workaround? I know the problem isn't with the web service itself, because I can get responses fine via soapUI and .Net.
Faced the same problem about a month ago.
Web service client classes were generated using Apache CXF and web service returned HTTP
status 307, which led to the same exception.
Invocation of the same web service method using soapUI with property Follow Redirects set to true was successful and returned needed data.
After googling awhile, it looked like there is no property to enable following redirects in the JAX-WS for this.
So, below is the code which is currently working, though I'm not sure it is compliant with any standards:
Supposing generated client classes looks like:
// generated service class
public class MyWebServiceClient extends javax.xml.ws.Service {
// ...
private final QName portName = "...";
// ...
public RetrieveMyObjects getRetrieveMyObjects() {
return super.getPort(portName, RetrieveMyObject.class);
}
// ...
}
// generated port interface
// annotations here
public interface RetrieveMyObjects {
// annotations here
List<MyObject> getAll();
}
Now, upon executing following code:
MyWebServiceClient wsClient = new MyWebServiceClient("wsdl/location/url/here.wsdl");
RetrieveMyObjectsPort retrieveMyObjectsPort = wsClient.getRetrieveMyObjects();
wsClient should return instance which is both instance of RetrieveMyObjects & javax.xml.ws.BindingProvider interfaces. It is not stated anywhere on the surface of JAX-WS, but it seems that a lot of code is based on that fact. One can re-assure him\herself by executing something like:
if(!(retrieveMyObjectsPort instanceof javax.xml.ws.BindingProvider)) {
throw new RuntimeException("retrieveMyObjectsPort is not instance of " + BindingProvider.class + ". Redirect following as well as authentication is not possible");
}
Now, when we are sure that retrieveMyObjectsPort is instance of javax.xml.ws.BindingProvider we can send plain HTTP POST request to it, simulating SOAP request (though it looks incredibly incorrect & ugly, but this works in my case and I didn't find anything better while googling) and check whether web service will send redirect status as a response:
// defined somewhere before
private static void checkRedirect(final Logger logger, final BindingProvider bindingProvider) {
try {
final URL url = new URL((String) bindingProvider.getRequestContext().get(ENDPOINT_ADDRESS_PROPERTY));
logger.trace("Checking WS redirect: sending plain POST request to {}", url);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setInstanceFollowRedirects(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "text/html; charset='UTF-8'");
connection.setDoOutput(true);
if(connection.getResponseCode() == 307) {
final String redirectToUrl = connection.getHeaderField("location");
logger.trace("Checking WS redirect: setting new endpoint url, plain POST request was redirected with status {} to {}", connection.getResponseCode(), redirectToUrl);
bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, redirectToUrl);
}
} catch(final Exception e) {
logger.warn("Checking WS redirect: failed", e);
}
}
// somewhere at the application start
checkRedirect(logger, (BindingProvider) retrieveMyObjectsPort);
Now, what this method does is: it takes BindingProvider.ENDPOINT_ACCESS_PROPERTY of retrieveMyObjectsPort i.e. the url to which this port method will be sending SOAP requests and sends plain HTTP POST request as described above. Then it checks whether response status is 307 - Temporary Redirect (other statuses like 302 or 301 may also be included) and if it is, gets the URL to which web service is redirecting and sets new endpoint for the specified port.
In my case this checkRedirect method is called once for each web service port interface and then everything seems to work fine:
Redirect is checked on url like http://example.com:50678/restOfUrl
Web service redirects to url like https://example.com:43578/restOfUrl (please note that web service client authentication is present) - endpoint of a port is set to that url
Next web service requests executed via that port are successful
Disclaimer: I'm quite new to webservices and this is what I managed to achieve due to the lack of solutions for this questions, so please correct me if something is wrong here.
Hope this helps
Yes I know this post is old, but I've had similar errors, and thought maybe somebody would benefit from my solution.
the one that plagued me the most was:
com.sun.xml.ws.client.ClientTransportException: The server sent HTTP status code 200: OK
Which turns out to mean an incomplete response header. Apparently jax-ws does some kind of validation that includes validating the HTTP headers as well. And the server I was using was just sending an empty header.
It worked like a charm after adding 'application/soap+xml' to the Content-Type header.

View response headers before they are sent to the client?

I am writing a project for school. I want to be able to display, on a web page, the response headers that the web server sent to the client. I am able to read request headers from HttpServletRequest and am able to write response headers to HttpServletResponse no problem.
Is there any way to do this? It is possible to make a copy of what the server is about to send?
I am using Eclipse Helios to develop this JSP with POJOs application, and am using Tomcat 5.5 running on Debian Lenny to serve it.
Thanks,
Ean
You can use a Filter and an HttpServletResponseWrapper.
Override the three addXHeader(..) methods with something like:
void addHeader(String name, String value) {
super.addHeader(name, value);
getWriter().write(name + " : " + value);
}
And then, in a Filter:
chain.doFilter(request, new HeaderHttpServletResponseWrapper(response));
But I would use Firebug to check headers.
Or see this question (the 2nd answer)
You probably want to write a servlet filter which can intercept both the request and response before it gets sent.

Categories

Resources