Distinguish between server-side errors and connection problems - codenameone

As described in the Codename One blog post "Terse Table, Radar Chart and Networking Enhancements":
Better Error Code Handling
Up until recently if we got an error response code it wasn’t sent
through the global error handler and was handled via the local error
handling chain first. This is no longer the case and these errors are
now handled correctly.
However, if you relied on that misbehavior of older versions we have
setHandleErrorCodesInGlobalErrorHandler(boolean). This defaults to
true, you can set it to false to change the default behavior.
So, the global error handler is invoked both by server-side errors and connection problems. It's a very good thing to be able to manage networks errors in the most generic way, however I need to distinguish between server-side errors and connection problems.
After some testing, I wrote the following code, tested on Simulator, Android and iOS:
addNetworkErrorListener(err -> {
// prevents the event from propagating
err.consume();
if (err.getError() != null) {
// this is the case of a network error,
// like: java.io.IOException: Unreachable
Log.p("Error connectiong to: " + err.getConnectionRequest().getUrl());
// maybe there are connectivity issues, let's try again
ToastBar.showInfoMessage("Trying to reconnect...");
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
err.getConnectionRequest().retry();
}
}, 2000);
} else {
// this is the case of a server error
// logs the error
Log.p("REST ERROR\nURL:" + err.getConnectionRequest().getUrl()
+ "\nMethod: " + err.getConnectionRequest().getHttpMethod()
+ "\nRequest body: " + err.getConnectionRequest().getRequestBody()
+ "\nResponse code: " + err.getConnectionRequest().getResponseCode()
+ "\nResponse message: " + StringUtilities.toString(err.getConnectionRequest().getResponseData()),
Log.ERROR);
Log.sendLogAsync();
ToastBar.showErrorMessage("Server Error", 10000);
}
});
In the tested platforms, server-side errors are reported, but no further action follows; connectivity errors are both reported and managed by retrying the connection every two seconds.
So, that code works.
Anyway, what I don't like is the assumption that err.getError() != null is true for connectivity errors, false for server-side errors. I came to this assumption after several tests, but I didn't find it documented anywhere.
So my question is whether:
my assumption is always correct;
there is a better way to distinguish server-side errors from connectivity errors.
Thank you

Related

Handle Network Thread exceptions in Codename One

My app tries to do an async network request at app launch, using RequestBuilder request = Rest.get, as described in this article: https://www.codenameone.com/blog/rest-api-error-handling.html. If I power off my testing server, at the app launch I have this exception:
[Network Thread] 0:0:0,586 - Exception: java.net.ConnectException - Connection refused
but no info, message or dialog is shown to the user. The following boilerplate code in the init() is not called:
addNetworkErrorListener(err -> {
// prevent the event from propagating
err.consume();
if (err.getError() != null) {
Log.e(err.getError());
}
Log.sendLogAsync();
Dialog.show("Connection Error", "There was a networking error in the connection to " + err.getConnectionRequest().getUrl(), "OK", null);
});
If I provide a custom network error handler, with request.onError(networkError);, the issue is the same: my network error handler is not called. I tried to implement it so (it's very similar to the above boilerplate code):
private static final ActionListener<NetworkEvent> networkError = new ActionListener<NetworkEvent>() {
#Override
public void actionPerformed(NetworkEvent err) {
Log.p("NETWORK ERROR connecting to the server");
err.consume();
if (err.getError() != null) {
Log.e(err.getError());
}
Log.sendLogAsync();
DialogUtilities.genericNetworkError();
}
};
I tried using the Simulator with the server offline. Then I tried with Android and iOS app, disconnecting the device from the Internet, but also in this case there is no message to the user. What's wrong?
Note that the error code handlers used with onErrorCodeBytes, onErrorCodeJSON and onErrorCodeString seem to work correctly (they are invoked, for example, if I have a 404 http code).
Did you define onError?
It should be invoked for exceptions and might override the global error handling logic once defined.
I tried this case with wifi turned off and it seems to have worked correctly:
Button test = new Button("Test");
test.addActionListener(e -> {
Rest.get("https://www.codenameone.com/").
onError(ee -> {
if(ee.getError() != null) {
Log.e(ee.getError());
}
}).
fetchAsBytes(call -> {});
});

codenameone: how to handle exception java.net.ConnectionException explicitly

codenameone: how to handle exception java.net.ConnectionException explicitly
I want to handle exception explicitly.Currently when I am handling exception It handled implicitly first in which shows the exception message on screen in detail.I don't want to show in detail error message on screen(pop up dialog).
right now it shows the exception Java.net.Connection Exception: Connection refused for URL http:localhost/login connection refused.instead of this message i just want to show "connection refused" message on pop-up dialog
Can you please let me know how to resolve it.
On mobile devices the error might be quite different to the one on the simulator since we are dealing with native API's under the surface. See the error handling section of the networking section in the developer guide:
There are two distinct placed where you can handle a networking error:
The ConnectionRequest - by overriding callback methods
The NetworkManager error handler
Notice that the NetworkManager error handler takes precedence thus allowing you to define a global policy for network error handling by consuming errors.
E.g. if I would like to block all network errors from showing anything to the user I could do something like this:
NetworkManager.getInstance().addToQueue(request);
NetworkManager.getInstance().addErrorListener((e) -> e.consume());
The error listener is invoked first with the NetworkEvent matching the error. Consuming the event prevents it from propagating further down the chain into the ConnectionRequest callbacks.
We can also override the error callbacks of the various types in the request e.g. in the case of a server error code we can do:
ConnectionRequest request = new ConnectionRequest(url, false) {
protected void handleErrorResponseCode(int code, String message) {
if(code == 444) {
// do something
}
}
protected void handleException(Exception err) {
// handle exception that occurred. Notice you can either have this or have the listener on the NetworkManager
}
protected void readResponse(InputStream input) {
// just read from the response input stream
}
};
NetworkManager.getInstance().addToQueue(request);

java.sql.SQLRecoverableException: Connection is already in use

In my java code, I am processing huge amount of data. So I moved the code as servlet to Cron Job of App Engine. Some days it works fine. After the amount of the data increases, the cron job is not working and shows the following error message.
2012-09-26 04:18:40.627
'ServletName' 'MethodName': Inside SQLExceptionjava.sql.SQLRecoverableException:
Connection is already in use.
I 2012-09-26 04:18:40.741
This request caused a new process to be started for your application, and thus caused
your application code to be loaded for the first time. This request may thus take
longer and use more CPU than a typical request for your application.
W 2012-09-26 04:18:40.741
A problem was encountered with the process that handled this request, causing it to
exit. This is likely to cause a new process to be used for the next request to your
application. If you see this message frequently, you may be throwing exceptions during
the initialization of your application. (Error code 104)
How to handle this problem?
This exception is typical when a single connection is shared between multiple threads. This will in turn happen when your code does not follow the standard JDBC idiom of acquiring and closing the DB resources in the shortest possible scope in the very same try-finally block like so:
public Entity find(Long id) throws SQLException {
Connection connection = null;
// ...
try {
connection = dataSource.getConnection();
// ...
} finally {
// ...
if (connection != null) try { connection.close(); } catch (SQLException ignore) {}
}
return entity;
}
Your comment on the question,
#TejasArjun i used connection pooling with servlet Init() method.
doesn't give me the impression that you're doing it the right way. This suggests that you're obtaining a DB connection in servlet's init() method and reusing the same one across all HTTP requests in all HTTP sessions. This is absolutely not right. A servlet instance is created/initialized only once during webapp's startup and reused throughout the entire remaining of the application's lifetime. This at least confirms the exception you're facing.
Just rewrite your JDBC code according the standard try-finally idiom as demonstrated above and you should be all set.
See also:
Is it safe to use a static java.sql.Connection instance in a multithreaded system?

HttpWebRequest.BeginGetResponse results in System.NotSupportedException on Windows Phone

I realise that similar questions have been asked before however none of the solutions provided worked.
Examining the token returned from the BeginGetResponse method I see that the following exception is thrown there:
'token.AsyncWaitHandle' threw an exception of type 'System.NotSupportedException'
This page tells me that this exception means the Callback parameter is Nothing, however I'm passing the callback - and the debugger breaks into the callback method when I insert a breakpoint. However the request object in the callback is always null. I can view the same exception detail in the result object in the callback method.
I've tried using new AsyncCallback(ProcessResponse) when calling BeginGetResponse
I've tried adding request.AllowReadStreamBuffering = true;
I've tried this in-emulator and on-device, with no luck on either.
public static void GetQuakes(int numDays)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://magma.geonet.org.nz/services/quake/geojson/quake?numberDays=" + numDays);
// Examining this token reveals the exception.
var token = request.BeginGetResponse(ProcessResponse, request);
}
static void ProcessResponse(IAsyncResult result)
{
HttpWebRequest request = result.AsyncState as HttpWebRequest;
if (request != null)
{
// do stuff...
}
}
So I'm at a bit of a loss as to where to look next.
'token.AsyncWaitHandle' threw an exception of type
'System.NotSupportedException'
This page tells me that this exception means the Callback parameter is
Nothing
The documentation you are looking at http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetresponse%28v=vs.95%29.aspx is for BeginGetResponse. Silverlight does not use the AsyncWaitHandle, and correctly throws a NotSupportedException. You are seeing the exception System.NotSupportedException is for call to IAsyncResult.AsyncWaitHandle you are making when you inspect token.
The documentation on IAsyncResult.AsyncWaitHandle says explicitly that it is up to the implementation of IAsyncResult whether they create a wait handle http://msdn.microsoft.com/en-us/library/system.iasyncresult.asyncwaithandle(v=vs.95).aspx. Worrying about this is sending you down th wrong path.
I think you need to descibe the actual problem you are seeing. It is great to know what you have investigated, but in this case it does help resolve the problem.
The code should work and in ProcessResponse request should not be null when you test it in the if statement. I just copied the code you have provided into a windows phone application and ran it with no problems.

GWT RequestFactory not firing properly after using edit()

I have a problem using "fire()" with a GWT RequestFactory after I've used it to unfreeze and edit a proxy.
If I have two request factory objects and their associated contexts like this:
private SyntheticRequest req1 = requestFactory.someRequest();
private Request<xProxy> sendRequest1 = req1.something();
private SyntheticRequest req2 = requestFactory.someRequest();
private Request<xProxy> sendRequest2 = req2.something();
using "fire()" on the first request works fine:
sendRequest1.fire(new Receiver<xProxy>() {
#Override
public void onSuccess(xProxy response) {
...
if (somethingIsTrue){
xProxy x = req2.edit(response); //<-- **I think this causes a problem later, although the proxy "x" works as expected here.**
x.setSomething("something");
update();
}
});
that part runs ok because I get to the "onSuccess". But when this one runs "update()", which looks like this:
private void update(){
sendRequest2.fire(new Receiver<xProxy>(){
...onFailure...
...onSuccess...
});
}
sendRequest2 always fails, with the error
Server Error Index:0 Size:0
and I put a breakpoint in the code for the "something()" service and it never even gets to that code! There must be something about the "req2.edit()" that hurts req2 and sendRequest2, but what?
Thanks.
what is 'b'? the line xProxy x = req2.edit(b); is the first time it's mentioned? is it supposed to be xProxy x = req2.edit(response);
Anyway.. that is not the problem..
'Server Error' indicates that RequestFactory caught an exception during the processing of a request, server-side. Something (but maybe not something()) is throwing an IndexOutOfBounds exception.
If you have a look at RequestFactoryServlet.java (which you can replace with your own very easily btw) you can see it setting up a try catch block that catches all exceptions when processing a request. It passes them to 'DefaultExceptionHandler' which wraps them in a ServerFailure, and that gets returned to you GWT code as an onFailure() call.
An easy way to find where the exception is being thrown is set a breakpoint on IndexOutOfBoundsException, making sure to catch 'caught' exceptions as well as uncaught.

Resources