Obtaining response from API in Android - java

I have a problem with obtaining the response from API connection, I used logcat(Log.wtf) testing it then found the logcat in the first class which in my ConnectAPI.java had received the data, but the logcat(Log.wtf) in the second class which in my main.java unable to obtain the response from the first class, please helping me figure it out what the wrong it is, many thanks!
first class(in ConnectAPI.java)
public static void A020 (final Context context, String Manual, final ZooCallback callback){
HttpUrl url = new HttpUrl.Builder()
.scheme(SCHEME)
.host(HOST)
.port(PORT)
.addPathSegments(A020_PATH)
.addQueryParameter("LId", PersonID.getID(context))
.addQueryParameter("Coordinates", getGPS(context))
.addQueryParameter("Manual", Manual)
.build();
Request request = new Request.Builder()
.url(url)
.build();
Log.d("A020 printing out the url", url.toString());
mClient.newCall(request).enqueue(new Callback() {
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
Log.wtf("A020 print out in connectapi",response.toString());
if (response != null && response.isSuccessful()) {
String jsonData = response.body().string();
final JSONObject Jobject = new JSONObject(jsonData);
handler.post(new Runnable() {
#Override
public void run() {
callback.onSuccess(Jobject);
}
});
}
} catch (final JSONException e) {
handler.post(new Runnable() {
#Override
public void run() {
callback.onFail("exception", e.getMessage());
}
});
}
}
#Override
public void onFailure(Call call, final IOException e) {
handler.post(new Runnable() {
#Override
public void run() {
callback.onFail("onFailure", e.getMessage());
}
});
}
});
Second class(in main.java)
ConnectAPI.A020(context, Manual, new ZooCallback(){
#Override
public void onSuccess(JSONArray response){
super.onSuccess(response);
try{
Log.wtf("A020 printing the response in mainjava", response.toString());
}catch(JSONException e){
Log.d("probleminA020", e.getMessage());
}catch(Exception e){
Log.d("probleminA020", e.getMessage());
}
}
public void onFail(String title, String error){
super.onFail(title, error);
Log.d(TAG, error);
}
});

What a Terrible Failure: Report a condition that should never happen. The error will always be logged at level ASSERT with the call stack. Depending on system configuration, a report may be added to the DropBoxManager and/or the process may be terminated immediately with an error dialog.
That is the documentation behind Log.wtf. When you use Log.wtf, there is a chance it throws an error. In which case it is caught by the try-catch you have. Don't use Log.wtf for debug, as this can crash your app.
Use Log.d (or Log.d or whatever you feel like) but not under any circumstance use Log.wtf for debug.
Replace Log.wtf with a different Log call (I recommend Log.d) and try again.
What is most likely happening is that Log.wtf throws an exception. This exception is then caught by the handy try-catch you have there. The code then prints out the error message instead. The reason it isn't printing is because it also throws an exception which you then aren't printing out fully, which explains why you don't know what is causing it
And for future purposes, when printing a stacktrace, use e.printStackTrace as it prints the entire stacktrace and not just the error message.
Another error you are facing is an issue related to your tag length. If oyu target API 24 or above, there is a 23 char limit:
IllegalArgumentException is thrown if the tag.length() > 23 for Nougat (7.0) releases (API <= 23) and prior, there is no tag limit of concern after this API level.
If you don't target API 24 or above, ignore this part.
If you do target API 24 or above, you have to shorten the tag to 23 chars or less. It is generally a good idea to keep the tag short, API 24+ will crash the app if it isn't

Related

Parse exception in try catch block to assign a response code - 2xx, 4xx or 5xx

I have Jenkins plugin written in Java. I am capturing all the workflows of execution of plugin in a integer variable in three ways 0(2xx workflows), 1(4xx workflows), 2(5xx workflows) and sending them to SignalFX for metrics. Since this is not an API and errors will be mainly caught in try catch workflow.
I wanted to ask how to read error codes from exception class and categorize them in 2xx, 4xx or 5xx. Are there some rules which I can follow by?
try {
Thread.sleep(60 * 1000);
} catch (InterruptedException e) {
sendToSignalFX(0,data); // 0 means successful state
}
Some of the exceptions classes I will be using are -
Exception, IOException, InterruptedException, ParserConfigurationException, SAXException
I believe you may have to add a method to identify the failure reason from e.getMessage() for one OR have a custom exception to help with your case.
Also if it’s an HTTP request-related exception (from the error response code mentioned in the question details) or something, you may want to add a custom exception, instead of throwing the original exception. In the custom exception, you can add a custom field to get errorCode from the response code.
// MyCustomException.java
public class MyCustomException extends Exception {
String errorReason;
int errorCode;
public MyCustomException(Throwable throwable, String errorReason, int errorCode) {
super(errorReason, throwable);
this.errorReason = errorReason;
this.errorCode = errorCode;
}
}
And in your request handler code:
try {
// otherCode which might cause IOException
// ...
Response response = myHttpRequest();
if (!response.isSuccessful()) {
// identify the error code and set corresponding errorCode to MyCustomException. errorCode
int errorCode = 0;
// parse response.getStatusCode() or equivalent of the library and reassign the value of errorCode
throw new MyCustomException(e, e.getMessage(), errorCode);
}
// ...
// otherCode which might cause IOException
} catch (Exception | IOException e) {
throw new MyCustomException(e, e.getMessage(), 0);
}

FirebaseVisionImage: variable 'image' might not have been initialized

I'm trying to use the example for Google Firebase (machine learning kit) in Android Studio. I'm getting an error when passing the image variable into the detector.processImage method (error shown below).
How can I get past this error? I have to use the FirebaseVisionImage.fromFilePath within a try-catch block, but the error message is telling me that the image variable may not be initialized.
error: variable image might not have been initialized
FirebaseVisionImage image;
try {
image = FirebaseVisionImage.fromFilePath(MainMenuActivity.this,
Uri.fromFile(new File("/sdcard/Download/test.jpg")));
} catch (IOException e) {
e.printStackTrace();
}
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance().getOnDeviceTextRecognizer();
Task<FirebaseVisionText> result = detector.processImage(image)
.addOnSuccessListener(new OnSuccessListener<FirebaseVisionText>() {
#Override
public void onSuccess(FirebaseVisionText firebaseVisionText) {
// Task completed successfully
mainText.setText("Hello!");
}
})
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
// Task failed with an exception
}
}
);
That error emerges because of this piece of code
FirebaseVisionImage image;
try {
image = FirebaseVisionImage.fromFilePath(
MainMenuActivity.this,
Uri.fromFile(new File("/sdcard/Download/test.jpg"))
);
} catch (IOException e) {
e.printStackTrace();
}
Now, ask yourself, what happens to image if an Exception is thrown inside the try block?
The variable might have been assigned a valid value, or it might have not.
Because you're letting the execution flow to continue (you aren't throwing the Exception to the upper level), the compiler cannot know that for sure, since the exception is thrown at run-time.
And because in Java a local variable must be initialized before usage (even with = null), the compiler is telling you to do so.
error: variable image might not have been initialized
The solution might be to initialize it with null
FirebaseVisionImage image = null;
Or, a better one, to let escape the Exception. That will signal there is a bug.
You'll also be able to completely unwrap your code from the try - catch block.
All code that needs the image should be inside the try block:
try {
FirebaseVisionImage image = FirebaseVisionImage.fromFilePath(MainMenuActivity.this,
Uri.fromFile(new File("/sdcard/Download/test.jpg")));
Task<FirebaseVisionText> result = detector.processImage(image)
.addOnSuccessListener(new OnSuccessListener<FirebaseVisionText>() {
#Override
public void onSuccess(FirebaseVisionText firebaseVisionText) {
// Task completed successfully
mainText.setText("Hello!");
}
})
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
// Task failed with an exception
}
}
);
} catch (IOException e) {
e.printStackTrace();
}
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance().getOnDeviceTextRecognizer();
Note that a catch statement that just prints the runtime exception like yours does, should usually be as high as possible in the callstack. So I'd recommend moving it to the code that alls this code, or even higher up. And keep in mind: if you don't catch that error at all, Android will print it too. So consider what you're trying to accomplish with this catch and implement it accordingly.

How to handle exceptions in SpringBoot ListenableFuture

so I have a SpringBoot end point controller that starts like this:
#RequestMapping(value = "/post", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public Response post(#Valid #RequestBody Message message) throws FailedToPostException {
message.setRecieveTime(System.currentTimeMillis());
return this.service.post(message);
}
And the post function:
public Response post(Message message) throws FailedToPostException{
ListenableFuture<SendResult<String, Message>> future = kafkaTemplate.send("topicName", message);
future.addCallback(new ListenableFutureCallback<SendResult<String, Message>>() {
#Override
public void onSuccess(SendResult<String, Message> result) {
LOGGER.info("Post Finished. '{}' with offset: {}", message,
result.getRecordMetadata().offset());
}
#Override
public void onFailure(Throwable ex) {
LOGGER.error("Message Post Failed. '{}'", message, ex);
long nowMillis = System.currentTimeMillis();
int diffSeconds = (int) ((nowMillis - message.getRecieveTime()) / 1000);
if (diffSeconds >= 10) {
LOGGER.debug("timeout sending message to Kafka, aborting.");
return;
}
else {
post(message);
}
}
});
LOGGER.debug("D: " + Utils.getMetricValue("buffer-available-bytes", kafkaTemplate));
return new Response("Message Posted");
}
Now you can see, that we are trying to make sure, if a kafkaTemplate.send failed, we are going to recursively invoke post(message) again for up to 10 seconds, until the producer memory buffer clears and the message gets through.
The problems are:
We want to be able to return failure response to the endpoint's client (eg: "Failed to acknowledge the message").
Is there any better way to handle exceptions from a Future in a piece of code like that above?
Is there a way to avoid using a recursive function here? We did that, because we wanted to attempt delivery of the message to Kafka for like 10 seconds, before sending it as an email to look at.
Side note: I still didnt use buffer-available-bytes attribute from kafkaTemplate.metrics(), I intend to use it to minimize the chance of this problem, but still need to handle the above just in case of some race conditions
There are a few ways to do this, but I really like Spring Retry as a way to solve this kind of problem. It's a bit of pseudo code here, but if you need more specifics on how to do it, I could make things more explicit:
#Retryable(maxAttempts = 10, value = KafkaSendException.class)
public Response post(Message message) throws FailedToPostException{
ListenableFuture<SendResult<String, Message>> future = kafkaTemplate.send("topicName", message);
try {
future.get(1. TimeUnit.SECONDS);
} catch(SomeException ex) {
LOGGER.error("Message Post Failed. '{}'", ex.getCause().getMessage(), ex);
throw ex;
}
LOGGER.info("Post Finished. '{}' with offset: {}", message,
result.getRecordMetadata().offset());
}
Effectively does the same thing without recursing. I wouldn't recommend recursing code for error handling.
The controller should be able to massage the actual KafkaSendException with a nice #ExceptionHandler.

Download files with netty

I am creating a very basic webserver using netty and java. I will have basic functionality. It's main responsibilities would be to serve responses for API calls done from a client (e.g a browser, or a console app I am building) in JSON form or send a zip file. For that reason I have created the HttpServerHanddler class which is responsible for getting the request, parsing it to find the command and call the appropriate api call.It extends SimpleChannelInboundHandler
and overrides the following functions;
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
LOG.debug("channelActive");
}
#Override
public void channelReadComplete(ChannelHandlerContext ctx) {
LOG.debug("In channelComplete()");
ctx.flush();
}
#Override
public void channelRead0(ChannelHandlerContext ctx, Object msg)
throws IOException {
ctx = processMessage(ctx, msg);
if (!HttpHeaders.isKeepAlive(request)) {
// If keep-alive is off, close the connection once the content is
// fully written.
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(
ChannelFutureListener.CLOSE);
}
}
private ChannelHandlerContext processMessage(ChannelHandlerContext ctx, Object msg){
if (msg instanceof HttpRequest) {
HttpRequest request = this.request = (HttpRequest) msg;
if (HttpHeaders.is100ContinueExpected(request)) {
send100Continue(ctx);
}
//parse message to find command, parameters and cookies
ctx = executeCommand(command, parameters, cookies)
}
if (msg instanceof LastHttpContent) {
LOG.debug("msg is of LastHttpContent");
if (!HttpHeaders.isKeepAlive(request)) {
// If keep-alive is off, close the connection once the content is
// fully written.
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(
ChannelFutureListener.CLOSE);
}
}
return ctx;
}
private ChanndelHandlerContext executeCommand(String command, HashMap<String, List<String>>> parameters, Set<Cookie> cookies>){
//switch case to see which command has to be invoked
switch(command){
//many cases
case "/report":
ctx = myApi.getReport(parameters, cookies); //This is a member var of ServerHandler
break;
//many more cases
}
return ctx;
}
In my Api class that has the getReport function.
getReport
public ChannelHandlerContext getReportFile(Map<String, List<String>> parameters,
Set<Cookie> cookies) {
//some initiliazations. Actual file handing happens bellow
File file = new File(fixedReportPath);
RandomAccessFile raf = null;
long fileLength = 0L;
try {
raf = new RandomAccessFile(file, "r");
fileLength = raf.length();
LOG.debug("creating response for file");
this.response = Response.createFileResponse(fileLength);
this.ctx.write(response);
this.ctx.write(new HttpChunkedInput(new ChunkedFile(raf, 0,
fileLength,
8192)),
this.ctx.newProgressivePromise());
} catch (FileNotFoundException fnfe) {
LOG.debug("File was not found", fnfe);
this.response = Response.createStringResponse("failure");
this.ctx.write(response);
} catch (IOException ioe) {
LOG.debug("Error getting file size", ioe);
this.response = Response.createStringResponse("failure");
this.ctx.write(response);
} finally {
try {
raf.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return this.ctx;
}
Response class is responsible for handling various types of response creations (JsonString JsonArray JsonInteger File, etc)
public static FullHttpResponse createFileResponse(long fileLength) {
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
HttpHeaders.setContentLength(response, fileLength);
response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "application/octet-stream");
return response;
}
My Api works great for my Json responses(easier to achieve) but It won't work well with my json responses, but not with my file response. When making a request from e.g chrome it only hangs and does not download the file. Should I do something else when downloading a file using netty? I know its not the best wittern code, I still think I have some bits and pieces missing from totally understanding the code, but I would like your advice on how to handle download on my code. For my code I took under consideration this and this
First, some remarks on your code...
Instead of returning ctx, I would prefer to return the last Future for the last command, such that your last event (no keep alive on) could use it directly.
public void channelRead0(ChannelHandlerContext ctx, Object msg)
throws IOException {
ChannelFuture future = processMessage(ctx, msg);
if (future != null && !HttpHeaders.isKeepAlive(request)) {
// If keep-alive is off, close the connection once the content is
// fully written.
future.addListener(ChannelFutureListener.CLOSE);
}
}
Doing this way will allow to directly close without having any "pseudo" send, even empty.
Important: Note that in Http, the response is managed such that there are chunk send for all data after the first HttpResponse item, until the last one which is empty (LastHttpContent). Sending another empty one (Empty chunk but not LastHttpContent) could break the internal logic.
Moreover, you're doing the work twice (once in read0, once in processMessage), which could lead to some issues perhaps.
Also, since you check for KeepAlive, you should ensure to set it back in the response:
if (HttpHeaders.isKeepAlive(request)) {
response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
}
On your send, you have 2 choices (depending on the usage of SSL or not): you've selected only the second one, which is more general, so of course valid in all cases but less efficient.
// Write the content.
ChannelFuture sendFileFuture;
ChannelFuture lastContentFuture;
if (ctx.pipeline().get(SslHandler.class) == null) {
sendFileFuture =
ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise());
// Write the end marker.
lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); // <= last writeAndFlush
} else {
sendFileFuture =
ctx.writeAndFlush(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)),
ctx.newProgressivePromise()); // <= last writeAndFlush
// HttpChunkedInput will write the end marker (LastHttpContent) for us.
lastContentFuture = sendFileFuture;
}
This is this lastContentFuture that you can get back to the caller to check the KeepAlive.
Note however that you didn't include a single flush there (except with your EMPTY_BUFFER but which can be the main reason of your issue there!), contrary to the example (from which I copied the source).
Note that both use a writeAndFlush for the last call (or the unique one).

GWT Catching exception thrown by HttpServlet

From the server Code (in an HttpServlet) I'm throwing an exception if the file is too large:
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
...
// Check if the blob has correct size, otherwise delete it
final BlobInfo blobInfo = new BlobInfoFactory().loadBlobInfo(blobKey);
long size = blobInfo.getSize();
if(size > 0 && size <= BasicConstants.maxImageSize){
res.sendRedirect("/download?blob-key=" + blobKey.getKeyString());
} else { // size not allowed
bs.delete(blobKey);
throw new RuntimeException(BasicConstants.fileTooLarge);
}
From the client code I'm missing to successfully catch the exception with this snippet:
try {
uploadForm.submit(); // send file to BlobStore, where the doPost method is executed
} catch (Exception ex) {
GWT.log(ex.toString());
}
However, from this other client code snippet I'm somehow detecting when the exception was thrown with an ugly workaround that I don't trust at all:
uploadForm.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
#Override
public void onSubmitComplete(SubmitCompleteEvent event) {
// This is what gets the result back - the content-type *must* be
// text-html
String imageUrl =event.getResults();
// This ugly workaround apparently manages to detect when the server threw the exception
if (imageUrl.length() == 0) { // file is too large
uploadFooter.setText(BasicConstants.fileTooLarge);
} else { // file was successfully uploaded
...
}
The Development Mode view in Eclipse reports an error of type "uncaught exception", which suggests that I'm really doing a bad job at detecting it.
Can anyone tell me how to properly catch the exception, and if the workaround I'm using makes any sense?
Thanks!
Your first attempt
try {
uploadForm.submit(); // send file to BlobStore, where the doPost method is executed
} catch (Exception ex) {
GWT.log(ex.toString());
}
doesn't work, because submit() doesn't wait until the browser receives the response (it's an asynchronous call).
uploadForm.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
#Override
public void onSubmitComplete(SubmitCompleteEvent event) {
...
Here you actually receive the response from the server. But it's a form submission, not a GWT-RPC call, so the result is just plain text, not GWT Java Objects.
When you throw a RuntimeException in a Servlet, the server will simply send a response with an error code (probably '500', but ideally use the "Network" tab in Firebug or Chrome Developer Tools to see the actual response and response code.) So in the success case you'll get the URL, otherwise the response is empty.
Possible solution
You can catch Exceptions on the server side, and send better descriptions explicitly:
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
try {
...
if (...) {
throw new MyTooLargeException();
} else {
...
res.getWriter().write("ok " + ...);
}
} catch (MyTooLargeException e) {
res.getWriter().write("upload_size_exceeded"); // just an example string
// (use your own)
res.sendError(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE);
}
}
Then, on the client, check for
"upload_size_exceeded".equals(event.getResults()).

Categories

Resources