How to parse XML return from OkHttp? - java

This is my OkHttp Post Form Parameter Method using OkHttp's Async Get
public Call postGetCountries(Callback callback) {
RequestBody body = new FormEncodingBuilder()
.add("op", "op")
.build();
Log.d(TAG_PARAMS, "op=sgetcountrylist, app_type=1");
Request request = new Request.Builder()
.url(GATEWAY_URL)
.post(body)
.build();
Call call = CLIENT.newCall(request);
call.enqueue(callback);
return call;
}
This is my custom Callback.
private class GetCountriesCallback implements Callback {
#Override
public void onFailure(Request request, IOException e) {
Log.e("OkHttp", e.getMessage());
}
#Override
public void onResponse(Response response) throws IOException {
Log.d("PASSED", "PASS");
Log.d(Connection.TAG_RETURN, response.body().string());
try {
InputStream is = response.body().byteStream();
List test = connectionParser.parse(is, "op");
} catch (XmlPullParserException e) {
Log.e("PARSE ERROR", e.getMessage());
}
}
}
This is my instantiated parse method.
public List parse(InputStream in, String op) throws XmlPullParserException, IOException {
try {
XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(in, null);
parser.nextTag();
return readFeed(parser, op);
} finally {
in.close();
}
}
I'm currently testing if it works unfortunately I receive a return of
10-06 11:54:42.492 6336-6892/ D/PASSED: PASS
10-06 11:54:42.692 6336-6892/ E/PARSEĀ ERROR: Invalid stream or encoding: java.io.IOException: closed (position:START_DOCUMENT null#1:1) caused by: java.io.IOException: closed
This is what I use on my onCreate on the activity to start the whole process:
private Connection connect = Connection.getInstance();
connect.postGetCountries(new GetCountriesCallback());
I don't understand as to why the InputStream gets closed.

Two things could be going on. First, you can only read the body once. If you want to read it more than once, you need to store the result somewhere. You are reading the body twice, once here --
Log.d(Connection.TAG_RETURN, response.body().string());
and then here --
InputStream is = response.body().byteStream();
List test = connectionParser.parse(is, "op");
by the time you start to parse, you have already exhausted the available input in the stream. The quick solution is to remove the log statement.
Another thing that might be tripping you up, or could trip you up in the future is onResponse is called even in the event of HTTP returning an error code. You should check the Response's code() or isSuccesful() methods to decide if you should even attempt to parse the response.

Related

OKHTTP GET and POST request return empty body message

I want to a upload file on my server and I've decided to try OKHTTP instead of my current method which is based on android own HTTP implementation and AsyncTask.
Anyway, I used OKHTTP and its asynchronous implementation (from its own recipes) but it returns an empty message (the request code is ok, the message is empty) in both GET and POST methods.
Did I implement it wrong or is there anything else remained that I did not considered? In the meantime, I couldn't find a similar case except this which says used AsyncTask.
Here's the code:
Request request;
Response response;
private final OkHttpClient client = new OkHttpClient();
private static final String postman_url = "https://postman-echo.com/get?foo1=bar1&foo2=bar2";
String message_body;
public void Get_Synchronous() throws IOException
{
request = new Request.Builder()
.url(postman_url)
.build();
Call call = client.newCall(request);
response = call.execute();
message_body = response.toString();
//assertThat(response.code(), equalTo(200));
}
public void Get_Asynchronous()
{
request = new Request.Builder()
.url(postman_url)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
public void onResponse(Call call, Response response)
throws IOException
{
message_body = response.toString();
}
public void onFailure(Call call, IOException e)
{
}
});
}
Edit:
I catch the log on response:
onResponse: Response{protocol=h2, code=200, message=, url=https://postman-echo.com/get?foo1=bar1&foo2=bar2}
OK, for anyone who wants to receive an string from a call, response and response.messgage() don't provide that. To catch the response from your provider, you just need to call response.body().string() inside onResponse which returns the message inside your request.
But after all, Retrofit is a better choice if you want to receive a JSON file using
.addConverterFactory(GsonConverterFactory.create(gson)).
If you still want to receive an string just use .addConverterFactory(ScalarsConverterFactory.create()) as explained here.

Continue after exception or Error in Rest Api call using OAuth2RestTemplate

i am making a rest call using Spring Oauth2RestTemplate. I am trying to catch any exception while trying to make a restAPI call and continue the flow of Exception.
Two ways i tried:
Way I(Using try catch).
public ResponseEntity<Object> getResponse(URI uri, HttpHeaders httpHeaders,
Object obj) {
ResponseEntity<Object> response = null;
try {
response = restTemplate.exchange(uri, HttpMethod.POST, new HttpEntity<>(obj, httpHeaders),
Object.class);
} catch (Exception serverEx) {
LOGGER.error("ERROR while calling API.Full Exception: ",serverEx);
response.getBody().setLink(object.getUrl());
}
return response;
}
Way II(Custom Handling).
public class RestTemplateResponseErrorHandler implements ResponseErrorHandler {
private static final Logger LOGGER = LogManager.getLogger(RestTemplateResponseErrorHandler.class);
#Override
public boolean hasError(ClientHttpResponse httpResponse) throws IOException {
return (httpResponse.getStatusCode().series() == Series.CLIENT_ERROR
|| httpResponse.getStatusCode().series() == Series.SERVER_ERROR);
}
#Override
public void handleError(ClientHttpResponse httpResponse) {
//Log The Error but contibue the flow
}
}
But neither way the execution gets stopped. I want to continue the flow of the execution. if the call fails i want to handle it and continue the flow. Can any one please suggest whats happening here?
Exception:
Caused by: java.io.IOException: Attempted read from closed stream.
at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:131)
at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:118)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at java.io.PushbackInputStream.read(PushbackInputStream.java:139)
at org.springframework.web.client.MessageBodyClientHttpResponseWrapper.hasEmptyMessageBody(MessageBodyClientHttpResponseWrapper.java:102)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:82)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:932)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:916)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:663)
... 223 more
Error Response OutboundJaxrsResponse{status=500, reason=Internal Server Error, hasEntity=true, closed=false, buffered=false}
Any suggestion on this please?

Stop an async Spring method from caller class

I've a class that call a Rest web service to receive a file from server. While bytes are transferred, I've created an Async task, it checks if connection with server is fine to allow the stop connection if an error appears.
This async task has a loop that I have to stop:
#Component
public class ConnectionTest {
#Async
//Check connection with the server, if for three attemp it failes, throw exception
public void checkServerConnection(String serverIp) throws Exception{
int count=0;
for(;;Thread.sleep(7000)){
try{
System.out.println("TEST");
URL url = new URL(serverIp);
HttpURLConnection con = (HttpURLConnection) url
.openConnection();
con.connect();
if (con.getResponseCode() == 200){
System.out.println("Connection established!!");
}
if (count>0) count=0;
}catch(Exception e){
count++;
if (count==3)
throw new Exception("Connection error");
}
}
}
}
but how can I stop this method from the caller?
#Autowired
private ConnectionTest connectionTest;
#Override
public Response getFile(String username, String password, String serverIp, String toStorePath, String filePath){
ResponseEntity<byte[]> responseEntity = null;
try{
//it is used to check if connection of the client with the server goes down
connectionTest.checkServerConnection();
RestClient restClient = new RestClient(username, password);
// SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
// requestFactory.setBufferRequestBody(false);
// restClient.setRequestFactory(requestFactory);
// RestTemplate restClient = new RestTemplate();
responseEntity = restClient.getForEntity(serverIp + "client/file/?filePath={filePath}", byte[].class, filePath);
//TODO kill async task and return false
UPDATE: as #Thomas has suggested I've used a boolean variable in ConnectionTest, I changed for cycle with while (!stop) and after the web service call I set ConnectionTest.setStop(true).
Pay attention to set stop=false before loop (and not as instance field) otherwise only the first request has this value and goes inside the while.
UPDATE 2
This is the my last code, it seems to work, maybe I should change while loop with wait-notify:
public Response getFile(String username, String password, String serverIp, String toStorePath, String filePath){
try{
//it is used to check if connection of the client with the server goes down
Future<Boolean> isConnect = connectionTest.checkServerConnection(serverIp);
Future<ResponseEntity<byte[]>> downloadResult = downloadAsync.makeRequest(username, password, serverIp, filePath);
while(!isConnect.isDone() && !downloadResult.isDone()){
}
if (isConnect.isDone()){
downloadResult.cancel(true);
return new Response(false, false, "Error with server connection!", null);
}else{
connectionTest.setStop(true);
ResponseEntity<byte[]> responseEntity = downloadResult.get();
if (MediaType.TEXT_PLAIN.toString().equals(responseEntity.getHeaders().getContentType().toString())){
ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(new FileException("Error with file transfert!"));
return new Response(false, false, new String(Base64.decodeBase64(responseEntity.getBody()),Charset.forName("UTF-8")), errorResponse);
}else{
Path p = Paths.get(filePath);
String fileName = p.getFileName().toString();
FileOutputStream fos = new FileOutputStream(toStorePath+"\\"+ fileName);
fos.write(responseEntity.getBody());
fos.close();
return new Response(true, true, "Your file has been downloaded!", null);
}
}
}catch(Exception e){
ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(e);
return new Response(false, false, "Error on the client side!" , errorResponse);
}
}
connection check async:
#Component
public class ConnectionTest {
private boolean stop;
#Async
//Check connection with the server, if for three attemp it failes, throw exception
/**
*
* #param serverIp
* #throws IOException
*/
public Future<Boolean> checkServerConnection(String serverIp) throws IOException {
int count=0;
stop = false;
while (!stop){
try{
Thread.sleep(7000);
System.out.println("TEST");
//java.net.InetAddress.getByName(SERVER_ADDRESSS);
URL url = new URL(serverIp);
HttpURLConnection con = (HttpURLConnection) url
.openConnection();
con.connect();
if (count>0) count=0;
}catch(Exception e){
count++;
System.out.println(count);
if (count==3)
return new AsyncResult<Boolean>(stop);
}
}
return new AsyncResult<Boolean>(stop);
}
/**
* #return the stop
*/
public boolean isStop() {
return stop;
}
/**
* #param stop the stop to set
*/
public void setStop(boolean stop) {
this.stop = stop;
}
}
download async:
#Component
public class DownloadAsync {
#Async
public Future<ResponseEntity<byte[]>> makeRequest(String username, String password, String serverIp, String filePath){
RestClient restClient = new RestClient(username, password);
ResponseEntity<byte[]> response= restClient.getForEntity(serverIp + "client/file/?filePath={filePath}", byte[].class, filePath);
return new AsyncResult<ResponseEntity<byte[]>>(response);
}
}
When you deal with an #Async method, a good practice is to return a Future object from it because you need a connection point between the client and task code.
Let's make your task method return a Future:
public Future<Integer> checkServerConnection(String serverIp) {
// other code here
return new AsyncResult<>(count);
}
You'll need to add a couple of imports:
import java.util.concurrent.Future;
import org.springframework.scheduling.annotation.AsyncResult;
Finally, in the client code let's get the Future:
Future<Integer> checkTask = connectionTest.checkServerConnection();
Now, you can do some useful things with the checkTask. For example:
// Check if the task was completed including by an exception being thrown.
checkTask.isDone();
// Get the task result.
Integer count = checkTask.get(); // Note: this is a blocking method.
// If the task was finished by throwing an exception,
// get() method will also throw an exception.
// You can get the cause exception like this:
if (checkTask.isDone()) {
try {
checkTask.get();
} catch(Exception e) {
Exception cause = e.getCause(); // this will be your new Exception("Connection error")
}
}
// Not recommended, but you can also cancel the task:
checkTask.cancel(mayInterruptIfRunning);
first off I don't want to perplex the issue any further so I am going to give you a high level description for doing this. Particularly, look how this is done very elegantly in android, using publish delegates.
Basically, a publish delegate consists of 2 portions. First, an overridden method to publish changes, and another method to receive changes. The time interval in which changes are received, depend on the "CHUNK" size currently in the queue and the data size, but generally, you can think of this as a best effort attempt to receive publish events.
So a big high level picture is this.
ASYNCTASK
IN BACKGROUND (DOWNLOAD OVER TIME)
IN BACKGROUND (PUBLISH DOWNLOAD PROGRESS)
PUBLISH RECEIVER ( RECEIVE UPDATE OF THE DOWNLOAD [perhaps in percent]
MAKE A DECISION FROM HERE.
I am not neglecting the importance of the Spring context here, but I think once you receive this post, you will accept it's applicability, regardless of framework.
Best,
Mobile Dev
AT

Get opened input stream from rest template for large file processing

I am looking for a way to get opened input stream from rest template - I was trying to used ResponseExtractor, but the stream is getting closed before returning, as written here:
https://jira.spring.io/browse/SPR-7357
"Note that you cannot simply return the InputStream from the extractor, because by the time the execute method returns, the underlying connection and stream are already closed"
I hope that there is a way and I will not have to write to my output stream directly in the rest template.
I didn't find a way to do it, the stream is always getting closed. As a workaround I created the following code:
public interface ResourceReader {
void read(InputStream content);
}
with the following implementation:
public class StreamResourceReader implements ResourceReader {
private HttpServletResponse response;
public StreamResourceReader(HttpServletResponse response) {
this.response = response;
}
#Override
public void read(InputStream content) {
try {
IOUtils.copy(content, response.getOutputStream());
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
}
then in controller:
#RequestMapping(value = "document/{objectId}")
public void getDocumentContent(#PathVariable String objectId, HttpServletResponse response) {
ResourceReader reader = new StreamResourceReader(response);
service.readDocumentContent(objectId, reader);
}
call to rest template:
restTemplate.execute(uri, HttpMethod.GET, null,
new StreamResponseExtractor(reader));
and the string response extractor:
#Override
public ResponseEntity extractData(ClientHttpResponse response) throws IOException {
reader.read(response.getBody());
return null;
}
and it works like a charm! :)

Cannot find a handler for POST with boundary

I'm in the midst of testing my application which is using an HTTP-server. Instead of mocking I decided to go with a HTTP server fixture. Meaning that I do not have to mock any productional code. To accomplish this goal I currently chose for a free to use 3rd party library fixd.
I was able to successfully create several unit tests - which are working by means of a GET request. Most are quite simple, i.e.:
#Test
public void verifyConnectionTest()
{
try
{
final String body = FileUtils.readFileToString(RESOURCE);
final String path = "/";
this.server.handle(Method.GET, path).with(
new HttpRequestHandler() {
#Override
public void handle(final HttpRequest request,
final HttpResponse response)
{
response.setStatusCode(200);
response.setContentType("text/xml");
response.setBody(body);
}
});
// Setting up my HTTP client
// Execute some tasks
// asserting of everything was valid
}
catch (final IOException e)
{
fail(e.getMessage());
}
}
But I now have to send a POST request with multipart/form-data. Which does not make much of a difference other than changing the method and content-type:
#Test
public void executeStepTest()
{
try
{
final String body = FileUtils.readFileToString(SERVICE_RESPONSE);
final String path = "/";
this.server.handle(Method.POST, path, "multipart/form-data").with(
new HttpRequestHandler() {
#Override
public void handle(final HttpRequest request,
final HttpResponse response)
{
response.setStatusCode(200);
response.setContentType("text/xml");
response.setBody(body);
}
});
// Setting up my HTTP client
// Execute some tasks
// asserting of everything was valid
}
catch (final IOException e)
{
fail(e.getMessage());
}
}
However I get the following error: [ERROR] could not find a handler for POST - / - multipart/form-data; boundary=bqCBI7t-VW1xaJW7BADmTiGMg9w_YM2sHH8ukJYx and my guess is that fixd doesn't recognize the boundary-party. Since the documentation does not show an example I'm quite stuck on this part.
I tried using some wildcards such as '*', no succes. Thus; I need a way to either tell fixd to accept that boundary or use some wildcards I didn't yet discover. Any help would be great, thanks!
I've been making some debug and it seems to be that the problem is in the fixd core.
Basically, fixd indexes every RequestHandlerImpl by a HandlerKey (which includes ContentType as part of the key) in the map handlerMap. See method org.bigtesting.fixd.core.FixtureContainer#resolve.
...
HandlerKey key = new HandlerKey(method, route, contentType);
RequestHandlerImpl handler = handlerMap.get(key);
if (handler == null) {
// Error
}
...
Problem: When the request is multipart/form-data, boundary data (which it's generated dinamically every request) is part of the content type. So, any handler is found in handlerMap because the key changes with every running.
I've made a little test only to check that this is the cause of the problem, passing the contentType to fixd server.handle after the creation of the multipart request, and it works fine.
See the test below:
#Test
public void verifyConnectionTest_multipart() {
try {
// 1. Create multipart request (example with http-commons 3.1)
PostMethod filePost = new PostMethod(url);
Part[] parts = { new StringPart("param", "value") };
MultipartRequestEntity request = new MultipartRequestEntity(parts, filePost.getParams());
filePost.setRequestEntity(request);
// 2. fixd server handle (passing the request content type)
this.server.handle(Method.POST, "/", request.getContentType()).with(
new HttpRequestHandler() {
#Override
public void handle(final HttpRequest request,
final HttpResponse response) {
response.setStatusCode(200);
response.setContentType("text/xml");
}
});
// 3. Execute multipart request
HttpClient client = new HttpClient();
int status = client.executeMethod(filePost);
// 4. Assertions
Assert.assertEquals(200, status);
} catch (Exception e) {
Assert.fail(e.getMessage());
}
}
Hope it helps you to clarify the problem. Cheers
This was a bug in fixd, and has been fixed in version 1.0.3. Your original code should work using this new version of fixd.

Categories