Friday, May 24, 2013

ExtJS tips

My boss always joked about being impressed by my front-end skills listed on my resume (of course I was hired to do back-end work primarily) It seems that I'm considered to be more of a back-end guy throughout my IT career even though I have built UI for every job I had, including those used by engineers in manufacturing and IT, B2B buyers and sellers, etc. I have even built a tutorial/demo of using that B2B site in Flash! After a few years of hiatus from building UI, I'm finally back in the game, "fast-forwarding" from Weblogic/NetUI (yes, that's ancient technology I used last time) to ExtJS by Sencha. I visited them earlier this year. The offices and the atmosphere was so dot-com! The web UI created with ExtJS looks very slick with tons of eye-candies (which a lot of people like) You could build a good-looking basic web app with it quickly and easily. However, there are quite a few gotchas that have to do with its association model. Let's say you are a publisher who sells magazines to your subscribers. You have a one-to-many relationship between your customer and your magazines. So you created a class for the magazine model and another for the customer model. Then specify in the customer model a hasMany relationship with magazine. This is to be used with a REST-ful webservice for CRUD of customer (along with magazine relationships)

1)  You cannot create a separate store class in which you define a REST proxy with the URL of the aforementioned webservice. Instead, the proxy must be defined within the model class. Stores for customers and magazines are implicitly created. To load these stores, call Ext.ModelManager.getModel to obtain the model object and call load(<id>) on it.

2) Query of your customer REST-ful webservice could return magazines subscribed by the customer as a JSON array, named the same as the hasMany relationship. The implicitly created store for magazines associated with the customer will be populated properly. However, when you call customer.save(), the payload to the REST proxy's URL will not include the array of subscribed magazine. To make this happen, you have to override the default JSON writer of the proxy. See the second part of this post for a generic implementation that works for all associations. Alternatively, you could just implement a customer JSON writer that handles your customer/magazine relationship only, which is much simpler: basically you implement the getRecordData function. Add the fields of customer to the data object to be returned. Also loop through the associated magazine stores and add the fields to an array inside that data object.

3) Let's say you implement a drag-and-drop UI that allows user to drag magazines between the 'subscribed' and 'not subscribed' lists. Check out this example from Sencha. Each of such list is actually an ExtJS grid panel defined with its store. However, you want the 'subscribed' grid to use the implicitly created associated magazine store at run time. The name of the method to use is not that obvious. It is 'reconfigure.' I learned that from this post.

Thursday, May 23, 2013

Implementing RESTful Webservice using Wicket

Wicket alone might not be the ideal framework (check out this project that extends Wicket for such purpose) but this could be done. Simply write a class that extends WebPage. Override the renderPage method and write to the response. Finally, mount that page in Application.init() to a URL for its client. Here is the syntax for specifying the id in the URL with mountPage. (For example, a typical RESTful query looks like this: http://youraddress/order/<order id> )
  mountPage("/order/${orderId}", Order.class);

More tips:
1) PUT and POST
One of the key features of REST is using the "verb" (i.e., the method of the servlet request) to determine which of the CRUD (create, read, update, destroy) action is to be performed. It took me a while to figure out how to extract this "method" value:
        HttpServletRequest servletReq = (HttpServletRequest) getRequest().getContainerRequest();
        String method = servletReq.getMethod();
        if ("GET".equals(method))
        {
            // logic to read the object
            ...
        }

2) the payload
To create or update an object via RESTful Webservice, the payload includes a serialized form of the object (e.g., in JSON format) Again, it took me a while to figure out how to extract the payload:
        HttpServletRequest servletReq = (HttpServletRequest) getRequest().getContainerRequest();
        BufferedReader br = servletReq.getReader();
        String payload = null;
        if ((payload = br.readLine()) != null)
        {
            // process payload
            ...
        }

3) HTTP Status code
The page should return a meaningful code to the user. I found this table quite useful. Set it in renderPage() like this:
    public final void renderPage()
    {
        WebResponse response = (WebResponse) getResponse();
        response.setStatus(200); // for OK
    }

4) Return a download file
This is not RESTful but I just want to mention it here. Sometimes you want to provide a URL that would serve the browser content not in a browser window but in a download file. HTTP actually supports this using the Content-Disposition value (set to 'attachment') in the header. Let's say my page/class that extends WebPage create a zip file to be downloaded by the browser. Implement renderPage() like this:
    public final void renderPage()
    {
        WebResponse response = (WebResponse) getResponse();
        response.setHeader("Content-Type", "application/zip");
        response.setAttachmentHeader(fileName);
    }
BTW, don't rely on overriding the getMarkupType() method to set Content-Type in the header. It doesn't work that way for some reason. Set it explicitly like the above.

Wednesday, May 22, 2013

The Amazingly Flexible Jackson

Continuing my praises for Jackson, the JSON processor. I have a fairly unusual requirement for JSON generation: for a certain class of object in the hierarchy, the JSON representation needs to be all on one line. I have been using JsonGenerator instead of the ObjectMapper to generate my JSON and I knew injecting my own newlines could be done by simply JsonGenerator.writeRaw("\n") However, I rely on writeObject for that class of object, which is in an array, and writeObject is responsible for writing the commas before every elements after the 1st element in the array. So there are commas after the newlines but before the { of the object. I need to have these commas on their own line.

What I ended up doing is "hacking" the pretty printing support of Jackson. Jackson allows you to set a pretty printer to the JsonGenerator (or perform no pretty printing by setting it to null) Jackson also provided a full-blown pretty printer (the default) and a minimal one (that basically print as if no pretty printing and expect you to override some of its method to customize its behavior) I needed the JsonGenerator to add newlines surrounding the comma when writing array separators. However, this should only happen before the first { of the object, i.e., for the arrays nested within the object, it must not add newlines. Otherwise it violates the requirement of getting everything on one line! My subclass that inherits the minimal pretty printer has a boolean flag to control adding newlines so that it only adds the first time. Sounds tricky, right? Yes, it is.   

Tuesday, May 21, 2013

Jackson and polymorphism

Believe it or not, I have been manually adding {[': ......etc to generate my JSON for a while, until I discovered the open-source library Jackson, which I should have been using all along. It is very easy to turn a Java POJO into JSON and vice versa (i.e., serialization and deserialization) Check out the simple examples provided by this fellow. The only hiccup I had was related to deserialization and polymorphism. Imagine you are Jackson and parsing a block of JSON. According to the class definition, that block belongs to an abstract class or interface. Which subclass would you choose to deserialize this? Obviously you need some hints. Jackson actually includes mechanism to handle this. It's easy if you have something like 'dog' and 'cat' extending 'animal' and there is a type variable in the classes that could be used to tell whether the object is a dog or a cat. (See example 4 from this post) However, I have 2 subclasses of an abstract class that could only be distinguished by the class variables (i.e., unique attributes.) Fortunately I've found a way to solve this (See example 6 from the same post as above) Basically I wrote a custom deserializer for my abstract class. This deserializer looks for the unique attribute and find the corresponding subclass for deserialization.

Monday, May 20, 2013

Running a daemon using Tomcat

From Wikipedia:
a daemon is a computer program that runs as a background process, rather than being under the direct control of an interactive user.
Anyone who know Java could write a standalone one easily. My main concern is ease of management and deployment. Since I am using Tomcat as app server already, I decided to find out how to have a daemon running inside and managed by Tomcat. It turns out to be a popular choice. I've found quite a few links (1, 2) about it. Basically the daemon class needs to implement ServletContextListener. Then mention the class in web.xml like this:
<listener>
    <listener-class>MyDaemonServletContextListener</listener-class>
</listener>

For deployment, I use the Maven tomcat plugin and simply specify the server URL in the pom.xml.

Sunday, May 19, 2013

Open another browser from a hyperlink using Javascript

This sounds like a trivial and common task but I just learned how to write that. First, include a function like this:


Then use it in the A HREF like this:
<a href="javascript:void(0)" onclick="javascript:openInNewTab('blog.00zine.com'); return false;">00zine</a>


BTW, I have also just learned the above way of publishing code on Blogger from this post, which is linked to the useful HTML encoder (turns your angle brackets to < and >)