How to propagate an HttpServletResponse to a client? - java

We're working on a new web application to replace an old one that is commonly being used by our company. They both will ultimately have the exact same API. What we'd like to do initially is test out the new functionality by having clients send requests to the new web app, but then have our new web app propagate their requests to the old web app and send the old web app's http responses back to our clients (so that from client point of view, nothing has changed).
What I'd like to do is get the exact HttpServletResponse object that we're getting back from the old web app and send that back to clients of the new web app. What is the best way of performing this? I know that once I can retrieve the HttpServletResponse, I can just set it equal to the one we have as a parameter to our functions (API handlers) in our new web app's REST controller, but I'm having trouble retrieving it.
Is there any way of retrieving the HttpServlet response via Spring's RestTemplate?

You can use org.apache.commons.httpclient.HttpClient
It has public int executeMethod(HttpMethod method) where you can define request and after checking status is success
you can use all the HttpMethod methods.
InputStream getResponseBodyAsStream()
Header[] getResponseHeaders();
and pass to your response. Like this
public static void main(String[] args) throws Exception {
HttpClient client = new HttpClient();
GetMethod method = new GetMethod("http://The old service url");
method.addRequestHeader("X-Username", "user");
method.addRequestHeader("X-Password", "password");
// Execute the HTTP GET request
int status = client.executeMethod(method);
if(status == 200){
InputStream in = method.getResponseBodyAsStream();
OutputStream out=the out of your response
IOUtils.copy(in, out);
in.close();
out.flush();
out.close();
}
}

Related

Java httpClient streaming request

I'm trying to reproduce some behavior provide by my front end app by using a java http client.
I'm trying to send (stream) binary data from httpClient to server over PUT request. So content type is application/octet-stream. I've to send an unknown amount of data that is incoming.
Firstly, I used Apache HttpClient because it can handle digest authentication easily (that's is a requirement). For it, I use ContentProducer that enable writing directly to the OutputStream.
Below is an example:
HttpPut sendDataReq= new HttpPut(
HTTP_URI);
ContentProducer myContentProducer = new ContentProducer() {
#Override
public void writeTo(OutputStream out) throws IOException
{
out.write("ContentProducer rocks!".getBytes());
out.write(("Time requested: " + new Date()).getBytes());
}
};
HttpEntity myEntity = new EntityTemplate(myContentProducer);
sendDataReq.setEntity(myEntity );
HttpResponse response= httpClient.execute(sendDataReq);
I expect from this piece of code to stream request (AND NOT RESPONSE) from client to server.
By using Wireshark, I'm able to see my PUT request but it is send over TCP protocol and then nothing. When I try to listen using my front end web app, I can see that the PUT request is sent over HTTP protocol with 0 content length, data is then sent bytes by bytes (packet of some amount of bytes) over HTTP protocol with a log info: CONTINUATION.
Also, I tried with httpUrlConnection but there is no digestAuthentication implementation. So, I give up to use it.
Any hints of what is bad in my ContentProducer and how to accomplish it? Using other java HTTP clients? I can provide Wireshark log of what is expected and what I have.

Code position of keystore and truststore in java servlet

I'm working with an organization's payment API. The API automatically posts a soap request to our server when a customer makes payment and I response with an acknowledgement message in xml. (Check out the screenshots show a simple demonstration in SOAP UI)
SOAP UI Test Response
SOAP UI Test Raw XML
I made this code in Java to receive the soap request and send a response.
`public class testsoap extends HttpServlet {
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)throws ServletException, IOException {
response.setContentType("text/xml;charset=UTF-8");
ServletInputStream out = request.getInputStream();
String xmlrpc = "";
int c = 0;
while((c = out.read()) != -1 ){ xmlrpc += (char)c; }
int startTag = xmlrpc.indexOf("<TransID>");
int endTag = xmlrpc.indexOf("</TransID>");
String parameter = xmlrpc.substring(startTag,endTag).replaceAll("<TransID>","");
String result="";
//result +="<?xml version=\"1.0\"?>\n";
result +="<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:c2b=\"http://cps.huawei.com/cpsinterface/c2bpayment\">\n";
result +="<soapenv:Header/>\n";
result +="<soapenv:Body>\n";
result +="<c2b:C2BPaymentConfirmationResult>C2B Payment Transaction "+parameter+" result received.</c2b:C2BPaymentConfirmationResult>\n";
result +="</soapenv:Body>\n";
result +="</soapenv:Envelope>\n";
response.getWriter().println(result);
}
}`
Now I need to add the location of my keystore and truststore.
Should I add this code just before I start preparing a response?
` System.setProperty("javax.net.ssl.keyStore",path_to_keystore);
System.setProperty("javax.net.ssl.keyStorePassword",akeystorepassword);
System.setProperty("javax.net.ssl.trustStore",path_to_your_cacerts_file);
System.setProperty("javax.net.ssl.trustStorePassword",atrustsorepassword)`
Or do I need to make a snippet that makes secure connection using the keystore and truststore rather than just setting a system property?
Create a Java class and write all the functionalities that you need to publish as a methods. Then you need to publish those functionalities as a WSDL to be consumed by your clients. See the following tutorial that will take you in step by step to publish a web services:
Step by Step JAX-WS Web Services with Eclipse, TomEE, and Apache CXF
Building a Simple Web Service ? A Tutorial
Implementing a simple web service
Further based on your requirements you can have complex object as an input parameter like C2BPaumentConfirmationRequest and KYCInfo in your case

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.

best practice invoking webservices

I'm doing a school project where we are supposed to tap into an existing database using web services. I'm trying to figure out what best practice is when calling a web service from back end. I've been working with Servlets before and I know them pretty well.
This is my web service that front end uses and I need to know what the best practice is when calling an external web service within my application:
#GET
#Path("requestAccess")
public void getAccessToken(#Context HttpServletRequest request, #Context HttpServletResponse response)
{
String code = request.getParameter("code");
String clientId = "4_4inr3rkl04ys44kowwgoo0w4g8gow0s84cw0o0cg48kogsosc0";
String clientSecret = "4cxgpduio8isgcc8oggsw8wkcokcksk8wc8cc088w4w40owg4s";
String redirectUrl = "http://localhost:8080/salesgoals/rest/oauth/requestAccess";
try {
URL url = new URL("https://.../oauth/v2/token?client_id="+clientId+"&client_secret="+clientSecret+"&grant_type=authorization_code&redirect_uri="+redirectUrl+"&code="+code);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()));
String strTemp = "";
while(null != (strTemp = bufferedReader.readLine())){
System.out.println(strTemp);
}
} catch(Exception e){e.printStackTrace();}
}
This returns me an access token and the results from the external web service are JSON objects and the url object with inputstreamReader is something temp. I used to see if I was successful receiving access token.
Now I need to use the access token to invoke external web services but I dont know what best practice is when it comes to calling it within the application. I'm used to HttpServletRequest/Response objects. As I said all the data is returned as json.
I doubt there is 100% best practice, but take a look at
Jersey
It is both client and server RESTful web services implementation.

How can I forcefully cache all my HTTP responses?

I'm using the DefaultHTTPClient to make some HTTP GET requests. I'd like to forcefully cache all the HTTP responses for a week. After going through the docs and some SO answers, I've done this:
I installed an HttpResponseCache via the onCreate method of my main activity.
try {
File httpCacheDir = new File(getApplicationContext().getCacheDir(), "http");
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
HttpResponseCache.install(httpCacheDir, httpCacheSize);
} catch (IOException e) {
Log.i("dd", "HTTP response cache installation failed:" + e);
}
I added a custom HttpResponseInterceptor for my HTTP client, but I still don't get a cache hit. Here's my response interceptor that decompresses GZIPped content, strips caching headers and adds a custom one:
class Decompressor implements HttpResponseInterceptor {
public void process(HttpResponse hreResponse, HttpContext hctContext) throws HttpException, IOException {
hreResponse.removeHeaders("Expires");
hreResponse.removeHeaders("Pragma");
hreResponse.removeHeaders("Cache-Control");
hreResponse.addHeader("Cache-Control", "max-age=604800");
HttpEntity entity = hreResponse.getEntity();
if (entity != null) {
Header ceheader = entity.getContentEncoding();
if (ceheader != null) {
HeaderElement[] codecs = ceheader.getElements();
for (int i = 0; i < codecs.length; i++) {
if (codecs[i].getName().equalsIgnoreCase("gzip")) {
hreResponse.setEntity(new HttpEntityWrapper(entity) {
#Override
public InputStream getContent() throws IOException, IllegalStateException {
return new GZIPInputStream(wrappedEntity.getContent());
}
#Override
public long getContentLength() {
return -1;
}
});
return;
}
}
}
}
}
}
Here's how I make my request:
String strResponse = null;
HttpGet htpGet = new HttpGet(strUrl);
htpGet.addHeader("Accept-Encoding", "gzip");
htpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20100101 Firefox/15.0.1");
DefaultHttpClient dhcClient = new DefaultHttpClient();
dhcClient.addResponseInterceptor(new Decompressor(), 0);
HttpResponse resResponse = dhcClient.execute(htpGet);
Log.d("helpers.network", String.format("Cache hit count: %d", HttpResponseCache.getInstalled().getHitCount()));
strResponse = EntityUtils.toString(resResponse.getEntity());
return strResponse;
I can't seem to pinpoint what I'm doing wrong. Would any of you know?
Not sure if this answers your question, but instead of relying on an HTTP server interpreting your cache control headers, have you thought about simply adding a client-side cache using Android's own cache directories?
What we did in ignition is simply write server responses to disk as byte streams, thus having full control over caching (and expiring caches.)
There's a sample app here, but it would require you to use the library's HTTP API (which, however, is merely a thin wrapper around HttpClient.) Or simply look at how the cache works and go from there.
I failed miserably with this. According to the Android documentation, it specifically says about the HttpResponseCache — "Caches HTTP and HTTPS responses to the filesystem so they may be reused, saving time and bandwidth. This class supports HttpURLConnection and HttpsURLConnection; there is no platform-provided cache for DefaultHttpClient or AndroidHttpClient."
So that was out.
Now Apache's HTTP client has a CachingHttpClient and this new version of HTTP client has been back ported to Android through this project. Of course, I could use this.
I didn't want to use the hackish version of the Apache HTTP Client libraries so one idea was to cannibalise the caching related bits from the HTTP Client and reoll my own but it was too much work.
I even considered moving to the recommended HttpURLConnection class as recommended but I've run into other issues. There doesn't seem to be good cookie-persistence implementation for that class.
Anyway, I skipped everything and though. I'm reducing the loading time by caching, why not got go a step further and since I was using jSoup to scrape records from the page and create an ArrayList of a custom structure, I might as well serialize the whole ArrayList by implementing the Serializable method on my structure. Now I don't have to wait for the page request, not do I have to wait for the jSoup parsing slowness. Win.

Categories

Resources