Perplexity is the beginning of knowledge ~ Khalil Gibran
Perplexed I have been all this week.
The problem : A GWT application was throwing weird errors at different times when it was enabled with access control(ACL).
The one thought on an age old idiom
We had a vague idea that this is happening because of the user session timing out. And so began a week of research and debugging to unravel these mysterious errors. The first mystery was the random periods at which with the errors would occur. There was no explicit time out setting anywhere in the code. After much staring at the code and logs the design flaw emerged. We had violated a cardinal rule of programming: Thou shalt not use magic numbers.
The application under discussion is a distributed application with multiple modules and each was setting a user session cache expiry period. This turned out to be the varied time outs in the application. Depending on the user activity something would time out some time and some thing else some other time. So that was the one thought on design. Quite rudimentary but important none the less. A few days of painful debugging is a sure way to imbibe this lesson: Thou shalt not use magic numbers.
Interesting note: it turns out magic numbers has multiple meanings. The one I mean is "Unique values with unexplained meaning or multiple occurrences which could (preferably) be replaced with named constants". Avoid those my friend, always.
Now the many on GWT
The next challenge was the error handling when the user session timed out and I plunged into the rabbit hole called GWT.
GWT - The beauty and the beast
Now this was my first foray into GWT debugging and my what an API this API is. The myriad array of interfaces and proxies and handlers and presenters and controllers just boggled my mind. I was a blind man observing an elephant. After much research I can see maybe twenty percent of the elephant. Many parts of the API are just beautiful and make complete sense. Many others seem ugly. Not because they are ugly but because I don't understand enough to appreciate their beauty.
It is Java but not exactly Java is the toughest thing to get while using this API. One of the ugly parts were some of the error messages during GWT compile which point to something wrong but not exactly where and what is wrong.
Here a hook, there a hook
In the end I marveled at the immensity and detail of the API. It's a wonderful lesson in API design. The options available to customize the application behavior were just astounding. Too many options can be a good thing and also painful. Because the unwise and inexperienced(many folks like me) many times prefer just one way to do something. Not having too many options makes life much simpler. And that can soon become boring.
Journey to the solution to a problem
Arriving at a solution to a problem is such a mysterious journey. I know there are scientific methods and I envy those who are methodical and organized in their approach. The ones I envy the most are the lateral thinkers. There is a colleague of mine whom I admire for his problem solving skills. He can jump lateral, vertical, forward, backward and spiral around a problem with such ease that the problem disappears in no time. Soon we end up with now having to just choose an acceptable solution. My style is still random, peek here, poke there and maybe I will find something that will work. I hope to evolve it into something more organized.
Back to GWT
After another few days of code, javadoc and log browsing I realized there were a few options and improvements I should try. The following notes should give you some help in coding better GWT applications.
GWT in Action
1) Error handling : The proof of an good system is how gracefully and informatively it fails.
When it comes to Exceptions - Catch only what you can handle and throw exactly what you mean.
We made the mistake of catching Exception, Throwable at some points in the handlers. Not a good idea. We cleaned that part up and that helped in bubbling up the exceptions to the right points in the stack. Cleaning up the exception handling made the errors much more manageable and understandable.
2) Catch all exception handler: This was one idea that didn't work and I could figure out the implementation. The idea was bubbling up the exception and hooking in a catch all exception handler. That catch all exception handler would then examine the user session time out and give the appropriate error message and redirect to the login page.
public class MyEntryPoint implements EntryPoint { public void onModuleLoad() { //other things on module load GWT.setUncaughtExceptionHandler(new UncaughtExceptionHandler() { @Override public void onUncaughtException(Throwable arg0) { //do whatever needs to be done. } }); } }
Most of the examples I saw just logged the exception. I could not figure out how to display an error message and redirect to another URL.
Request to other GWT bloggers: Anyone else posting anything about GWT. Please don't just say or call this method. But also indicate in which place(class/interface/method) the method should be called. The sequence and place of operations in GWT is very important and sensitive.
3) Redirecting to another URL on detecting an exception - Maybe from a base handler, maybe from a base callback, maybe not.
When you don't understand something. It's a guarantee: You will mess it up.
So we had these handlers that were failing with an exception they could not handle when the user session time out. They inherited from some base handler. I had the brilliant idea of catching and detecting the session time out exception in the base handler and then show an informative error message and redirect to a new URL.
Could not implement it. I have some but not a clear idea why. The handler could just return a message to a callback from presenter.
Next brilliant idea: I tried doing it in a base callback in the presenter but always got a presenter does not exist error when doing the GWT compile. These are the parts of the elephant I still do not see.
If somebody reads this blog and wants details on what I was trying I will be more than happy to share.
GWT in Practice
4) Check before you leap
Finally the solution I arrived at was the light bulb which went off when I saw onXYZ( ), onABC( ). First I put in the check for user session and redirect in each of the methods in one presenter.
Copy paste of the same code in many places is a good sign of bad design.
So I thought this is GWT, we are using Guice. And I started to implement an aspect and an annotation for doing the user session check and redirect. Soon I realized that was not needed.
I stumbled upon a onBeforeEvent method call that gets called before every event in a presenter.
public class MyPresenter extends BasePresenter{ @Override public void onBeforeEvent() { super.onBeforeEvent(); //check user session and redirect to new url if needed } }
This is the solution I went with and it is a decent choice for common logic that needs to be executed before every event.
Drawbacks I still trying to overcome.
1) I could not figure out a way to implement the onBeforeEvent in a base class that all presenters would inherit from. Got the same Presenter does not exist error during GWT compile.
2) There was some code that bypassed the GWT event bus and some controls called some presenter methods directly. Most of them were of the kind Presenter.updateSomething kind. I think defining and implementing events for those is the right thing to do.
So that's all I have from my one week GWT foray. It's been a good week!
Drawbacks I still trying to overcome.
1) I could not figure out a way to implement the onBeforeEvent in a base class that all presenters would inherit from. Got the same Presenter does not exist error during GWT compile.
2) There was some code that bypassed the GWT event bus and some controls called some presenter methods directly. Most of them were of the kind Presenter.updateSomething kind. I think defining and implementing events for those is the right thing to do.
So that's all I have from my one week GWT foray. It's been a good week!