Friday, April 8, 2011

GWT Server-side Internationalization With Hermes

Greetings interwebs! My name is Matt Bertolini and I am an engineer here at Travel Tripper. I thought it was about time I made an appearance on our tech blog. I want to talk about a new project called Hermes that I have recently finished and am sharing with the world.



A Little Backstory



Our application, RezTrip, is in the process of being internationalized. Since it is a GWT based application, we chose to use the GWT static string internationalization features. Unfortunately, these features only work on the GWT client-side and we have lots of other client-facing strings that need to be internationalized (client emails, legacy HTML pages, etc.).

The gwt-i18n-server Library

A quick Google search on the subject of "server-side GWT i18n" found a library called gwt-i18n-server. This library gives the server-side support for the GWT static string i18n interfaces and properties files. We quickly incorporated the library into RezTrip and found it was pretty buggy. Worse yet, development on the library had stagnated and hadn't been updated in over a year. This is where I come in. Not satisfied with admitting defeat and implementing a separate i18n system just for server-side content, I decided to fork the gwt-i18n-server library and fix the bugs.

Enter Hermes

Hermes is the name of my fork of the gwt-i18n-server library. It is named after the Greek god Hermes (the god of language, and the great messenger of the gods). While technically a fork, every line of code has been re-written to improve compatibility with GWT and fix bugs. Here are the list of features and supported technologies found in the library:
  • GWT Constants, ConstantsWithLookup, and Messages interface support

  • Plural forms support
  • Date and number sub-formatting

  • UTF-8 properties file support
Using Hermes is very simple. All you need to do is pass the your GWT i18n class and the desired language tag to Hermes and it will create the necessary proxy class and load the appropriate properties file. Then all you need to do is call the methods on your class just like you do on the GWT client-side. Here is a small example to get you started:
ExampleMessages messages = Hermes.get(ExampleMessages.class, "en-us");
messages.sampleString();
Hermes also has a complete suite of unit tests to make sure the library is functioning as intended. The best part of Hermes it is completely free and open source, licensed under the same LGPL license as the gwt-i18n-server library. I encourage anyone using GWT to check out the library. To grab a copy or download/view the source, visit the Hermes page on GitHub. If you do use Hermes, feel free to let us know how it goes.

Thursday, March 24, 2011

Racing Gmail Superstars

The Problem
Something happened in the last few weeks and my Gmail accounts started locking up and becoming totally unresponsive. All of a sudden:
  • Some keyboard commands worked (the "/" to go to the search bar, "g-l" to go to the search bar pre-populated with "label:" --> actually entering a label and hitting return didn't work though)
  • opening messages failed
  • navigating message lists with the keys (j/k) wasn't showing the cursor moving
  • using the "g-" combo keyboard commands (to navigate to other labels, inbox, buzz, etc.) wasn't working,
  • using the mouse to click around didn't work at all
The Hunt for the Cure

At first I thought it might be connection problems, or something specific to one of my accounts or browser. But it was happening in both Chrome and Firefox, and with multiple Google accounts... so I knew something was really wrong.

I loaded up a Gmail in Firefox and turned on Firebug. Sure enough, after the lock-up, when clicking around, I was getting script errors.

I tried posting to the Gmail Help forum, but the specifics of the bug were so odd and vague that (understandably) nobody was interested in looking into the issue.

So, all that was left to me was to try to hone in on the bug myself. After hours and hours of careful observation, I finally figured out a sequence that was reliably causing the problem.

Reproducing The Bug
1) Navigate to a label or inbox (any list of multiple messages)



2) Use the "j" and "k" keys to navigate to the 2nd message in the list (note: this step is probably not strictly necessary)



3. Use the "s" shortcut to unstar the message



4. Use the "x" key to select the just-unstarred message



5. Use the "y" key to archive the message



6. Try clicking on one of the other two emails, or using the "o" key to open and see script error:



The Conclusion


My hunch was that the problem was probably related to a labs feature (or it would have already been reported).

I tried disabling the Superstars labs feature and repeating the above steps.... no script error!

Postlude: Race Condition (Out of my league?)


Having figured this out, I noticed a couple of other things:

1) If I perform the above steps slowly, I don't get the lockup.
2) Starring and Refreshing:
  • Fast: If I use the keyboard to star a bunch of messages and then immediately hit F5, Gmail refreshes, and the messages I'd starred are not starred.
  • Medium: If I use the keyboard to star a bunch of messages, wait a few seconds, then hit F5, Chrome warns me that Gmail is working and that I should stay on the page.
  • Slow: If I use the keyboard to star a bunch of messages and then wait a while, then hit F5, Gmail refreshes, and the messages I'd starred are starred.
My guess from the above is that on un-starring the message, an AJAX call goes out... but performing an action on the message before the response comes back causes an inconsistency, which causes the lock up.

PostScript:

27/3 - Bug now seems to be fixed. :-)

Tuesday, March 8, 2011

Styling/Skinning Our Application

The styling of our application was a unique design/architectural challenge for the team at TravelTripper.... read all about it in our guest post on the Google's GWT Blog:

At TravelTripper, we make hotel reservation software. Our main product is a "booking engine" called RezTrip, a web based application that allows visitors of a hotel’s website to directly book a stay with that hotel.



As GWT applications go, we think RezTrip, when it comes to the question of styling, presents an interesting departure from traditional development. As a "white label" application, we needed to create our app in such a way that allows our hotel clients the ability to customize not only the "frame" around the application, but also the internal style of the application itself, such as fonts, colors, etc.



In other words, each hotel needs the ability to create their own custom header, footer, or sidebar and have it wrap the booking "application" portion of the page. Furthermore, each hotel needs to be able to change all the colors, fonts, and even some icons within the application.



The desired end result is a single booking engine application, running on multiple web sites, but always mimicking the look and feel of each individual hotel site.


Read the whole article at: Styling and Skinning Your Apps With GWT

Monday, January 17, 2011

Today's Twitter WTF moment (or, put a "?" in your invalid url)

We learned something very interesting over at Travel Tripper these last few days while using Twitter's sharing API. Erik and I spent a good amount of time scratching our heads because every time we tried to share one of our RESTful URLs, Twitter would hit us with a "URL Required" error and would complain that the "url parameter does not contain a valid URL".


The even stranger thing was that when we manually replaced the url parameter in the twitter share query string with one from our demo server, it would work!

At first I was convinced that Twitter did some sort of pingback to our url to do it's URL shortening bit, making all calls to http://localhost#key1=value1 invalid, but even if we used demo.testdomain.com, we had a 50/50 chance of success. Sip coffee, look at each other in frustration, rinse and repeat.


In a moment of desperation, I noticed that our demo server was adding a query parameter to our RESTful url, making it look something like http://demo.testdomain.com?lang=en_us#key1=value1, and for some odd reason Twitter liked it (for the record, our RESTful URLs use everything after the "#" symbol, so having a URL with "#" and no "?" was perfectly valid). In between fits of cursing at Twitter and some key pounding, we managed to insert a "%3F" (the url encoding for "?") in between our domain and our "#" symbol and VOILA!

For the record, I still have no idea why it would matter to Twitter whether or not we included the query string identifier, but it's most likely an issue with their regex expression. Lots of URLs have "#" to denote the anchor on the current page, so we're not quite sure why their URL shortener would throw up whenever it came across this format. BUT, if you are having issues with an invalid URL parameter on Twitter, you might want to throw a "%3F" in the URL parameter value between your domain and the "#" symbol.


The final url format before url encoding would look like this:

http://demo.testdomain.com?#key1=value1

Hope this helps.