Monday, December 19, 2011

A Javascript script with query string parameters?

TopUp is one of the more popular so-called "lightbox" libraries that allows you to create Web 2.0 popups for tasks such as viewing full resolution images and playing videos. It works like this: Instead of opening a new browser window, like traditional popups do, TopUp uses Javascript to modify the webpage's DOM and display a popup window inside the webpage. This creates a more fluent user experience because it doesn't push the user away from the webpage they're currently viewing, like traditional popups tend to do.

Lightboxes are popups that are part of the webpage itself.

I was reading the library's documentation and noticed that you can pass configuration settings via query string parameters in the URL to the Javascript file. For example, to enable "fast mode" (a setting that improves support for IE 6 and 7), you would import the TopUp script into your page like so:

<script
  type="text/javascript"
  src="path/to/top_up-min.js?fast_mode=1">
</script>

The question I asked myself was, "How are they passing query string parameters into a Javascript file?" If top_up-min.js was really a server-side script that returned Javascript code, then I could understand. But it's an ordinary, plain-text .js file! The file can't be aware of its own URL, so it can't see the parameters!

I opened up the source code to have a look. The author queries the DOM to get a reference to the <script> element that imported the file, and then parses the element's src attribute to get the query string parameters. Pretty clever!

But how does he get a reference to the <script> element? There's nothing unique about this element that you can use to pull it out from the DOM. No unique ID. No specially-named class attribute. How does he do it? What he does is he adds a dummy element to the DOM as soon as the script loads. This guarantees that the dummy element will be added immediately after the <script> element, so he can just get the dummy element's previous sibling and wham...you've got your <script> node.

var scriptElement = (function deriveScriptElement() {
  var id = "tu_dummy_script";
  document.write('<script id="' + id + '"></script>');

  var dummyScript = document.getElementById(id);
  var element = dummyScript.previousSibling;

  dummyScript.parentNode.removeChild(dummyScript);
  return element;
}());

Some people say that programming is not a skill that requires creativity. I would ask these people to look at this code sample and tell me that it's not creative!

Thursday, December 15, 2011

GWT History Mechanism

GWT provides a way to let you interact with the history of the client's browser. This helps to better integrate your GWT application with the browser and provide a more streamlined experience to the user. It allows the application to respond to the user clicking the "back" and "forward" buttons.

In this tutorial, I'm going to add history support to my TwitterSearch application that I created in some previous blog posts. This is a simple app that allows the user to perform tweet searches, as well as view the Twitter privacy policy. By adding history support, the user will be able to navigate back to searches that she made previously. Feel free to download the complete source code so that you can better follow along with this blog post.

What the TwitterSearch application looks like

Because GWT apps never navigate away from the main, HTML page, the way GWT implements history is by adding a fragment identifier to the URL. The fragment identifier starts with a hash (#) and comes at the end of the URL. You often see fragment identifiers being used on large webpages. It allows you to jump around to different parts of the same page by clicking links that have fragment identifiers in their URLs. GWT, however, uses them to identify the "state" that the application was in at a specific point in history.

Enable history support

The first thing to do is make sure your GWT application has history support enabled. This is done by adding an <iframe> element to the HTML page (if you've created your GWT application using Eclipse, then it will be enabled by default):

<html>
  [...]
  <body>
    <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
    [...]
  </body>
</html>

Adding history tokens

Next, we must figure out when to add entries to the browser's history. In our case, we want to add an entry when the user performs a search and when the user views the privacy policy.

searchButton = new Button("Search");
searchButton.addClickHandler(new ClickHandler() {
  @Override
  public void onClick(ClickEvent event) {
    String query = searchQueryTextBox.getText();
    History.newItem(query);
    doSearch(query);
  }
});

privacyPolicyButton = new Button("Privacy Policy");
privacyPolicyButton.addClickHandler(new ClickHandler() {
  @Override
  public void onClick(ClickEvent event) {
    History.newItem("_privacyPolicy");
    doGetPrivacyPolicy();
  }
});

Here, we're adding a new history token when the "Search" and "Privacy Policy" buttons are clicked by calling the static History.newItem() method (new instances of the History class are never created--only its static methods are used). This method simply takes a String as an argument, which is the text that will appear in the fragment identifier. We use the search query as this string for tweet searches, and we use the hard-coded string _privacyPolicy for when the privacy policy is viewed. The doSearch() and doGetPrivacyPolicy() methods call the Twitter API and then update the UI with the results (download the complete TwitterSearch project to see how this is done, or read my previous blog posts).

Try performing a search now--you'll see the search query appear in the fragment identifier of the URL. But if you click "back", nothing will happen! We must explicitly tell our application how to respond to these events.

The history token is added to the fragment identifier in the URL

Handling history change events

Now, let's handle what happens when the user clicks the "back" or "forward" buttons. We'll do this in our onModuleLoad() method, so that the handler we define is registered as soon as our app loads.

@Override
public void onModuleLoad() {
  History.addValueChangeHandler(new ValueChangeHandler<String>() {
    @Override
    public void onValueChange(ValueChangeEvent<String> event) {
      String token = event.getValue();
      if ("_privacyPolicy".equals(token)){
        doGetPrivacyPolicy();
      } else {
        searchQueryTextBox.setText(token);
        doSearch(token);
      }
    }
  });

  [...]
}

As you can see, we call the History.addValueChangeHandler() method and pass in an implementation of the ValueChangeHandler interface. This handler will be invoked every time the user goes back or forward in their browser history. In the handler's only method, onValueChange(), we get the history token (which is the fragment identifier in the URL), and then use it to update our UI accordingly.

Handling history tokens on app startup

Besides giving the user the ability to use "back" and "forward", another good thing about using history is that the user can save bookmarks of our app. For example, a user might want to frequently check Twitter for news on her favorite celebrity, Brad Pitt. She might want to bookmark her search, so that she can reopen the bookmark at a later time and immediately see the latest search results.

To do this, we need to check for an existing history token on startup. We must check for it manually because the presence of a history token on startup will not fire a ValueChangeEvent (this event is only fired when the user clicks "back" or "forward").

@Override
public void onModuleLoad() {
  [...]

  String token = History.getToken();
  if (!token.isEmpty()){
    if ("_privacyPolicy".equals(token)){
      doGetPrivacyPolicy();
    } else {
      searchQueryTextBox.setText(token);
      doSearch(token);
    }
  }
}

The History.getToken() is called to get the current history token. The method returns an empty string if there is no token, so we first check to see if the string empty. If it's not, then we update the UI according to the token. Note that this should happen at the very end of the onModuleLoad() method because the UI widgets must be created first in order for the UI to be updated.

Does this code look familiar? It should because much of it is identical to the code we wrote for the History.addValueChangeHandler() method, so let's refactor it out into its own method:

@Override
public void onModuleLoad() {
  History.addValueChangeHandler(new ValueChangeHandler<String>() {
    @Override
    public void onValueChange(ValueChangeEvent<String> event) {
      String token = event.getValue();
      handleHistoryToken(token);
    }
  });

  [...]

  String token = History.getToken();
  if (!token.isEmpty()){
    handleHistoryToken(token);
  }
}

private void handleHistoryToken(String token){
  if ("_privacyPolicy".equals(token)){
    doGetPrivacyPolicy();
  } else {
    searchQueryTextBox.setText(token);
    doSearch(token);
  }
}

Changing the window title

It's also helpful to change the window title of the web page to reflect the history token. That way, when the user views their entire history, they can have a better idea of what Twitter searches they performed at a glance. To do this, we'll modify two sections of code. First, we'll modify the place where we add new history tokens.

searchButton = new Button("Search");
searchButton.addClickHandler(new ClickHandler() {
  @Override
  public void onClick(ClickEvent event) {
    String query = searchQueryTextBox.getText();
    History.newItem(query);
    Window.setTitle("Twitter Search - " + query);
    doSearch(query);
  }
});

privacyPolicyButton = new Button("Privacy Policy");
privacyPolicyButton.addClickHandler(new ClickHandler() {
  @Override
  public void onClick(ClickEvent event) {
    History.newItem("_privacyPolicy");
    Window.setTitle("Twitter Search - Privacy Policy");
    doGetPrivacyPolicy();
  }
});

Here, we've added calls to Window.setTitle() to set the title of the browser window. It's very important that you call this method after adding the history entry. Otherwise, the titles will not be synced properly with the history entries.

Second, we'll modify our handleHistoryToken() method to set the proper Window title when a history token is loaded.

private void handleHistoryToken(String token){
  if ("_privacyPolicy".equals(token)){
    Window.setTitle("Twitter Search - Privacy Policy");
    doGetPrivacyPolicy();
  } else {
    searchQueryTextBox.setText(token);
    Window.setTitle("Twitter Search - " + token);
    doSearch(token);
  }
}

Now, when you view your history, you'll get a good glimpse of all your past searches.

What the browser history looks like before and after setting window titles.

I hope you've enjoyed my GWT History tutorial. For more information, please see the GWT History page in the GWT Developer's Guide.

Sunday, December 11, 2011

GWT RPC (Part 3 of 3) - Take a ride on the client-side

GWT is all about creating web applications. And a web application wouldn't be a web application without client/server communication. A mechanism called GWT RPC (remote procedure call) is used for this communication in GWT. In this series of tutorials, I'm going to show you how GWT RPC works by building a simple GWT application that uses the Twitter API to perform tweet searches and retrieve the Twitter privacy policy.

The process involves three steps. I'll be covering step 3 in this blog post.

  1. Create the synchronous and asynchronous interfaces that define each RPC method
  2. Create the server-side implementation of each RPC method
  3. Create the UI (user interface) that the client will use perform the searches

You can download the entire sample project used in this tutorial here.


In this blog post, I'll show you how to design a basic UI that will call the RPC methods we created in the previous post. This UI will give us the ability to search for tweets and to view the Twitter privacy policy. Along with explaining how to call the GWT RPC methods from client code, I'll also give you a brief introduction into UI programming.

EntryPoint

package com.acme.twittersearch.client;

[imports...]

public class TwitterSearch implements EntryPoint {
[...]
  @Override
  public void onModuleLoad() {
    createWidgets();
    layoutWidgets();
  }
[...]
}

The first thing to notice is that the class implements the EntryPoint interface. Every GWT application must have one class that implements this. It tells GWT where to start when a user loads the application in her web browser. The interface consists of only one method, onModuleLoad(), which can be thought of as the GWT-equivalent of the public static void main(String args[]) method you see in command-line Java programs.

In our class, onModuleLoad() calls two private methods (that I've created), createWidgets() and layoutWidgets(). The createWidgets() method initializes our buttons, text boxes, etc. The second method, layoutWidgets(), adds those widgets to the page, positioning them in just the way that we want. You are not required by GWT to organize your code in this way, but I find it helpful to do so because UI code is very verbose and can quickly grow in size as your application becomes more complex.

Also, the fully-qualified class name of our entry point class must be added to the GWT module definition file (TwitterSearch.gwt.xml), as shown below:

<module rename-to='twittersearch'>
  [...]
  <entry-point class='com.acme.twittersearch.client.TwitterSearch'/>
  [...]
</module>

Widgets

I've defined my widget objects as class-level fields at the top of the class:

public class TwitterSearch implements EntryPoint {
  private Button privacyPolicyButton;
  private Button searchButton;
  private TextBox searchQueryTextBox;
  private Panel resultsPanel;
  private Label errorLabel;
  private Image loadingImage;
  [...]
}
  • privacyPolicyButton: This button will call the getPrivacyPolicy() RPC method and display the returned privacy policy on the page.
  • searchButton: This button will call the searchTweets() RPC method and display the search results on the page.
  • searchQueryTextBox: This is where the user will enter her Twitter search query.
  • resultsPanel: We'll display the results from each RPC call here.
  • errorLabel: If an error occurs while calling one of the RPC methods, we'll put the error message in here.
  • loadingImage: We'll display an animated loading icon when the client sends an RPC request to let the user know that their request is being processed. It's a good idea to always display some sort of loading image or message while an RPC request is being sent. Even the simplest requests can take several seconds to complete, especially if the user is on a slow network or the server is experiencing heavy load. In our case, we actually end up having to make two network calls per request, (1) the call to the GWT server and (2) the call to the Twitter server. So for us, having a loading image is essential (by the way, I got mine from loaderinfo.net).

The HTML page

Every GWT application has an HTML file that is loaded when the user navigates to the application in her browser. Here, I'm creating the "Twitter Search App" header and adding an image of the Twitter bird. I also have a CSS file which adds some extra formatting. The Javascript file that is being included is what the browser will use when the GWT application is compiled and run in production. The widgets that we load from our Java code will be added to the page dynamically at run time and be placed below the <h1> header (at the end of the <body> tag).

<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <link type="text/css" rel="stylesheet" href="TwitterSearch.css">
    <title>Twitter Search App</title>
    <script type="text/javascript" language="javascript" src="twittersearch/twittersearch.nocache.js"></script>
  </head>

  <body>
    <img src="twitter-bird.png" align="right"/>
    <h1>Twitter Search App</h1>
  </body>
</html>
What the app will look like.

Calling the RPC methods

Calling the RPC methods involves us using the asynchronous interface we created back in step 1 of this blog series. You might be thinking, "But TwitterSearchServiceAsync is an interface and we never created an implementation class for it." You are correct. But this is actually not a problem--GWT uses a technique called "deferred binding", which means that GWT will create a implementation for us during runtime. This is done by calling the GWT.create() method:

public class TwitterSearch implements EntryPoint {
  private final TwitterSearchServiceAsync service = GWT.create(TwitterSearchService.class);
  [...]
}

Even though we want an instance of the asynchronous interface, we pass it the class object of the synchronous interface, TwitterSearchService. The method then returns an instance of the asynchronous interface, TwitterSearchServiceAsync.

Remember how each method in the asynchronous interface took an extra AsyncCallback parameter? We will be using this now. Let's write the code that will do the Twitter search:

searchButton = new Button("Search");
searchButton.addClickHandler(new ClickHandler() {
  @Override
  public void onClick(ClickEvent event) {
    setLoading(true);
    String query = searchQueryTextBox.getText();
    service.searchTweets(query, new AsyncCallback<List<Tweet>>() {
      @Override
      public void onFailure(Throwable caught) {
        errorLabel.setText(caught.getMessage());
        errorLabel.setVisible(true);
        setLoading(false);
      }

      @Override
      public void onSuccess(List<Tweet> result) {
        resultsPanel.clear();
        for (Tweet tweet : result) {
          SafeHtmlBuilder builder = new SafeHtmlBuilder();
          builder.appendHtmlConstant("<b>User: </b>");
          builder.appendEscaped(tweet.getFrom_user());
          builder.appendHtmlConstant("<br /><b>Created: </b>");
          builder.appendEscaped(tweet.getCreated_at());
          builder.appendHtmlConstant("<br /><b>Tweet: </b>");
          builder.appendEscaped(tweet.getText());
          builder.appendHtmlConstant("<br /><br />");
          resultsPanel.add(new HTML(builder.toSafeHtml()));
        }
        setLoading(false);
      }
    });
  }
});

As you can see, we add a ClickHandler to the search button to define what happens when the search button is clicked. When the button is clicked, we first set the page to a "loading" state by calling setLoading(true). This method disables the buttons so the user can't click them and displays the loading image. We then grab the search query from the search text box and make a call to the searchTweets RPC method using the asynchronous interface.

A loading animation appears when a RPC request is made.

The onFailure() method of the AsyncCallback class is called when the RPC method throws an exception. The thrown exception is passed in as an argument to the method. If this happens, we put the exception message in our error label so the user can get an idea of what went wrong. We then set the page back to its normal, "non-loading" state by calling setLoading(false), which will re-enable the buttons and hide the loading image.

An error is thrown when no search query is specified.

The onSuccess() method of the AsyncCallback class is called when the RPC method completes without error. Here, we clear the results panel of past searches, and then loop through the list of returned tweets, adding each one of them to the page. After all tweets are displayed, we call setLoading(false) to re-enable the buttons and hide the loading image.

Search results for "#christmas".

I'm using the SafeHtmlBuilder class here to generate the HTML that is used to display each tweet. This class is like the StringBuilder and StringBuffer classes in that it allows you to efficiently create a large string in a peace-meal fashion. However, SafeHtmlBuilder specializes in making strings of HTML code. The appendEscaped() method escapes all HTML special characters in the string before appending it (for example, converting all < characters to &lt;). The appendHtmlConstant() method does not escape HTML special characters, so you can use this to add HTML tags to the string.

The RPC method call for the getPrivacyPolicy() method follows the same pattern:

privacyPolicyButton = new Button("Privacy Policy");
privacyPolicyButton.addClickHandler(new ClickHandler() {
 @Override
 public void onClick(ClickEvent event) {
    setLoading(true);
    service.getPrivacyPolicy(new AsyncCallback<String>() {
      @Override
      public void onFailure(Throwable caught) {
        errorLabel.setText(caught.getMessage());
        errorLabel.setVisible(true);
        setLoading(false);
      }

      @Override
      public void onSuccess(String result) {
        resultsPanel.clear();

        // convert newlines to  <br / >
        SafeHtmlBuilder builder = new SafeHtmlBuilder();
        builder.appendEscapedLines(result);

        resultsPanel.add(new HTML(builder.toSafeHtml()));

        setLoading(false);
      }
    });
  }
});

I hoped you've enjoyed my three part series on GWT RPC. Creating and calling GWT RPC methods is very easy to do once you become familiarized with these three steps. Simply create the synchronous/asynchronous interfaces, create your server-side RPC implementation, and then call the RPC methods from the client using the asynchronous interface.

For more information on GWT, check out the GWT Developer's Guide.

Friday, December 9, 2011

GWT RPC (Part 2 of 3) - The server-side RPC implementation

GWT is all about creating web applications. And a web application wouldn't be a web application without client/server communication. A mechanism called GWT RPC (remote procedure call) is used for this communication in GWT. In this series of tutorials, I'm going to show you how GWT RPC works by building a simple GWT application that uses the Twitter API to perform tweet searches and retrieve the Twitter privacy policy.

The process involves three steps. I'll be covering step 2 in this blog post.

  1. Create the synchronous and asynchronous interfaces that define each RPC method
  2. Create the server-side implementation of each RPC method
  3. Create the UI (user interface) that the client will use perform the searches

You can download the entire sample project used in this tutorial here.


Since we've already defined our RPC methods in the TwitterSearchService synchronous interface, we're now ready to write the implementations of those RPC methods. We'll create a new class named TwitterSearchServiceImpl (the naming convention is to use the synchronous interface's name with "Impl" appended to the end). It will be located in the "server" package because it's meant to only run on the server. It will extend the RemoteServiceServlet class and implement our TwitterSearchService synchronous interface (it should not implement the asynchronous interface).

package com.acme.twittersearch.server;

[imports...]

public class TwitterSearchServiceImpl extends RemoteServiceServlet implements TwitterSearchService {
  [...]
}

We do a little bit of error checking in the searchTweets method. If the search query is empty, then an IllegalArgumentException is thrown. With GWT RPC, exceptions are sent over the wire to the client. So the exact same exceptions can actually be handled in the client code (as you'll see in my next blog post). Exceptions can be used to return validation errors, as well as return unexpected server-side errors to the client.

@Override
public List<Tweet> searchTweets(String query) throws IllegalArgumentException, IOException {
  query = query.trim();
  if (query.isEmpty()) {
    throw new IllegalArgumentException("No search query specified.");
  }

  // see: https://dev.twitter.com/docs/api/1/get/search
  String q = URLEncoder.encode(query, "UTF-8");
  URL url = new URL("http://search.twitter.com/search.json?q=" + q);
  HttpURLConnection connection = (HttpURLConnection) url.openConnection();
  InputStream response = null;
  try {
    response = connection.getInputStream();
    return parseSearchResponse(response);
  } finally {
    if (response != null) {
      response.close();
    }
  }
}

Also in the searchTweets method, notice how the search query is passed into the URLEncoder.encode() method. This URLEncoder.encode() method encodes the search query so that it can be safely included in the query string of the Twitter API URL. You should always encode query string parameters in this way (just like you should always encode data before passing it into a SQL query string to avoid SQL injection). If a value happens to contain a character that has a special meaning in a URL (like an equals sign or ampersand), then you're likely to run into trouble.

We use the HttpURLConnection class to make the calls to the Twitter API. This class is not on the JRE Emulation list, but that's OK because we're only using it on the server. If we were to use it on the client, we'd get an error because GWT does not know how to convert this class to Javascript.

We also use the google-gson library to parse the JSON-encoded responses that are returned from the Twitter API. The way google-gson works is that you create a class that mirrors the JSON data you are unmarshalling. Each field in the class is named after a field in the JSON data. Google-gson looks at these field names to determine how to unmarshall the JSON message. So, we've created a SearchResponse class for our tweet search API call and a PrivacyPolicyResponse class for our privacy policy API call to do just that. However, for this demonstration, we don't need to unmarshal all the data in each response, so I've only included fields for the data that we need. You can see examples of the full JSON responses for the search and legal/privacy methods on the Twitter API documentation page.

private List<Tweet> parseSearchResponse(InputStream response) throws IOException {
  Reader reader = new InputStreamReader(response);
  SearchResponse searchResponse = new Gson().fromJson(reader, SearchResponse.class);
  return searchResponse.results;
}

private class SearchResponse {
  public List<Tweet> results;
}

Under the covers, TwitterSearchServiceImpl is a plain old Java servlet, which means that only one instance of this class is created to handle all requests. Therefore, be sure to keep thread-safety in mind.

web.xml

Our TwitterSearchServiceImpl class must also be added to the web application's deployment descriptor (web.xml).

<web-app ...>
  [...]

  <servlet>
    <servlet-name>twitterSearchServlet</servlet-name>
    <servlet-class>com.acme.twittersearch.server.TwitterSearchServiceImpl</servlet-class>
  </servlet>  

  <servlet-mapping>
    <servlet-name>twitterSearchServlet</servlet-name>
    <url-pattern>/twittersearch/search</url-pattern>
  </servlet-mapping></span>

  [...]
</web-app>

As you can see, the url-pattern for the servlet is /twittersearch/search. The first part, twittersearch, is the name of our GWT module, which is defined in the module definition file (TwitterSearch.gwt.xml). The second part, search, is the value of the @RemoteServiceRelativePath annotation in the TwitterSearchService interface that we created in the previous blog post.

Tweet class

Let's finish by creating the Tweet class. Because we're unmarshalling JSON data into this class using google-gson, the field names in this class must be named after the fields in the JSON message. Also, GWT requires that all objects that are sent over the wire implement Serializable, so let's do that too. The class must also be put in the "client" package, because it will be used in client code.

package com.acme.twittersearch.client;

import java.io.Serializable;

public class Tweet implements Serializable {
  private String id;
  private String from_user;
  private String created_at;
  private String text;

  [getter/setter methods...]
}

In the next and final blog post of my GWT RPC series, you'll learn how to create a basic UI and how to call these RPC methods from the client.

Thursday, December 8, 2011

GWT RPC (Part 1 of 3) - Synchronous and asynchronous interfaces

GWT is all about creating web applications. And a web application wouldn't be a web application without client/server communication. A mechanism called GWT RPC (remote procedure call) is used for this communication in GWT. In this series of tutorials, I'm going to show you how GWT RPC works by building a simple GWT application that uses the Twitter API to perform tweet searches and retrieve the Twitter privacy policy.

The process involves three steps. I'll be covering step 1 in this blog post.

  1. Create the synchronous and asynchronous interfaces that define each RPC method
  2. Create the server-side implementation of each RPC method
  3. Create the UI (user interface) that the client will use perform the searches

You can download the entire sample project used in this tutorial here.


Synchronous interface

The first thing to do is figure out what kind of communication you need to do with the server. What actions do you need to perform? What data do you need to retrieve? In this case, we need to do two things: perform tweet searches and get the Twitter privacy policy.

These actions are defined in the what's called the synchronous interface. I'll create two RPC methods in my synchronous interface (there's no limit to how many you can define). The interface must extend RemoteService and have a @RemoteServiceRelativePath annotation (which we'll revisit later). It must also be in the client package.

package com.acme.twittersearch.client;

[imports...]

@RemoteServiceRelativePath("search")
public interface TwitterSearchService extends RemoteService {
  List<Tweet> searchTweets(String query) throws IOException, IllegalArgumentException;
  String getPrivacyPolicy() throws IOException;
}

The first method, searchTweets, will take a search query as input and then return a list of tweets in the response. Tweets contain a lot of information (such as an ID, author, and creation date, not to mention the actual tweet message), so I'm going to create a Tweet class that encapsulates all of this information. I'm not going to worry about creating this class right now, though. For now, just assume that the Tweet class holds all the information about a tweet that we need it to.

Also notice how searchTweets throws two exceptions. An IOException will be thrown if there's a problem querying the Twitter API. We'll also have it throw an IllegalArgumentException if the search query is empty. Even though IllegalArgumentException is a runtime exception and doesn't have to be defined in the method's throws clause in order for the Java compilation to pass, GWT requires it to be declared here. Otherwise, it will send a generic "500 error" exception to the client instead of the real exception if that exception is thrown.

The second method, getPrivacyPolicy, doesn't need any parameters. It will return the Twitter privacy policy, which is a block of text that we will hold in a String object. As with searchTweets, it too will throw an IOException if there's a problem calling the Twitter API.

Asynchronous interface

Now that we've defined our RPC methods in the synchronous interface, we're ready to create the asynchronous interface. This interface will contain the exact same methods that are in the synchronous interface, but in a slightly different form:

package com.acme.twittersearch.client;

[imports...]

public interface TwitterSearchServiceAsync {
  void searchTweets(String query, AsyncCallback<List<Tweet>> callback);
  void getPrivacyPolicy(AsyncCallback<String> callback);
}

The interface can be named anything, but I've named it TwitterSearchServiceAsync because the convention is to use the synchronous interface's name with "Async" appended to the end.

As you may have noticed, unlike their counterparts in the synchronous interface, the methods don't return anything. They also take an extra parameter--an AsyncCallback object. This object will be used by the client to handle the response when the response is returned from the server. Since this interface will be used by the client, it must be located in the client package. Also, note that, while the methods in the synchronous interface throw exceptions, the methods in the asynchronous interface do not.

Both of these interfaces must remain in-sync. By that I mean, if one interface changes, the other must also change. For example, if I change the return value of a method in the synchronous interfaces, I must make the same, corresponding change to the asynchronous interface (by changing the generics parameter of the AsyncCallback parameter). The Eclipse GWT plugin is helpful in this regard. If it notices that the two interfaces are not in-sync, it will throw a Java compilation error.


In my next blog post, I'll talk about creating the server-side implementation of the RPC methods.

Saturday, December 3, 2011

GWT Introduction

The Google Web Toolkit allows you to write Javascript-based web applications without having to write any Javascript yourself. It translates Java code that you write into Javascript automatically. In this informational overview, I'm going to walk you through creating a GWT application and then describe the basic components that make up a GWT application.

Install the Eclipse plugin

Google provides an Eclipse plugin you can use for developing GWT applications. This is what I'll be using here, but the raw GWT SDK is available as well for command-line junkies.

The Eclipse update URL for the plugin is:

http://dl.google.com/eclipse/plugin/<version>

where <version> is your Eclipse version (3.7, 3.6, etc).

You'll need to install these modules:

  • Google Plugin for Eclipse
  • SDKs > Google Web Toolkit SDK 2.4.0

Create a new project

Once the Eclipse plugin is installed, create a new "Web Application Project".

Enter "SimpleApp" for the project name and "com.acme.simpleapp" for the package. The package name will be the "base" package for all of the packages in your project as you'll see in a minute. If you haven't installed the Google App Engine plugin, then uncheck the "Use Google App Engine" checkbox (I was on my netbook when I wrote this, so it's hard to see in the screenshot). The Google App Engine is a cloud-based service that lets you upload your application to the web, but that's out of the scope for this article.

Running the project

When you create a new GWT project in Eclipse, it creates a sample application, so let's run it. Right click on the project folder and select "Run As > Web Application". A "Development Mode" view will appear, showing a URL.

Let's quickly take a look at the URL:

http://127.0.0.1:8888/SimpleApp.html?gwt.codesvr=127.0.0.1:9997

The web server (GWT uses jetty, a light-weight web container) runs on port 8888 (remember that "127.0.0.1" is the same as "localhost"). The "gwt.codesvr" query string parameter is how GWT is able to run the application without compiling the project into Javascript. This is called running it in "hosted mode" (which is what you'll always want to do while developing and debugging a project). If this parameter is removed, it will instead use the Javascript code that was generated the last time the project was compiled (more on compilation later). This is called running it in "web mode". We haven't compiled the project yet, so running it in web mode will throw an error because there's no Javascript code to use.

Now, load the URL in your browser. In order to run the application in hosted mode, you have to install a browser plugin, so install the plugin and then refresh the page.

After a few seconds the web page will appear, asking you to enter your name. Enter your name and click send.

A popup message will appear with some information. What it's doing here is sending a message to the server using GWT RPC, which is the main mechanism GWT uses to communicate between the client (a Javascript-powered web page) and the server (a Java web application).

Debugging the application

You can set breakpoints and debug the GWT application just like any other Java application. Just be sure to select "Debug As > Web Application" instead of "Run As > Web Application" when running the application.

Translatable vs non-translatable code

One thing to keep in mind when developing a GWT application is the idea of distinguishing between Java code that should be converted to Javascript, from the Java code that shouldn't be converted to Javascript. This is defined in the "SimpleApp.gwt.xml" file, which is a configuration file for the application.

<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='simpleapp'>
  <!-- Inherit the core Web Toolkit stuff.                        -->
  <inherits name='com.google.gwt.user.User'/>

  <!-- Inherit the default GWT style sheet.  You can change       -->
  <!-- the theme of your GWT application by uncommenting          -->
  <!-- any one of the following lines.                            -->
  <inherits name='com.google.gwt.user.theme.clean.Clean'/>
  <!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> -->
  <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
  <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/>     -->

  <!-- Other module inherits                                      -->

  <!-- Specify the app entry point class.                         -->
  <entry-point class='com.acme.simpleapp.client.SimpleApp'/>

  <!-- Specify the paths for translatable code                    -->
  <source path='client'/>
  <source path='shared'/>
</module>

As you can see, the <source> tags mark the "client" and "shared" packages as Javascript-compatible, which means they will be converted to Javascript code when the application is complied.

Keep in mind that, GWT can only convert certain Java classes to Javascript (for a complete list, see the JRE Emulation Reference). So, for example, even though creating a FileOutputStream in the Java code won't throw any errors when the Java class is complied, an error will be thrown when the project is compiled to Javascript or run in hosted mode. To help you remember which Java classes are translatable, just remember that you're writing code for Javascript and there's certain things you can't do in this environment (like save files to disk, for example). As long as you keep this in mind, you won't need to refer to the JRE Emulation Reference very often.

Packages that are not defined as translatable code will run on the server as real Java code, so you can do whatever you want with them.

Source code

Let's just drill down each of the files in the "src" directory and describe what they do:

  • SimpleApp.gwt.xml: This file is called the "module definition". It contains the project's configuration settings including which Java classes are translatable to Javascript, the "entry point" class (like the "main" method for the client), and the application's look and feel.
  • GreetingService.java: An interface which defines the GWT RPC methods that are used by the client to communicate with the server.
  • GreetingServiceAsync.java: An alternate version of the GreetingService interface that the client uses to perform asynchronous communication with the server. Note that these two interfaces must remain in-sync, so any time the GreetingService interface is changed, the GreetingServiceAsync interface must also be changed.
  • SimpleApp.java: Contains all of the client-side GUI code. It is also the entry point class.
  • GreetingsServiceImpl.java: The server-side code that is called when the client sends requests to the server via GWT RPC. It provides the implementation of all of GWT RPC methods defined in GreetingService.
  • FieldVerifier.java: Contains validation code that is used on both the client and server. This is one of the advantages to using GWT--because the same code can be used for both the client and server, only one version needs to be maintained.

Client-side code

Let's quickly take a look at the client-side code. In this sample application most of the code is in one class, SimpleApp.

public class SimpleApp implements EntryPoint {

  private final GreetingServiceAsync greetingService = GWT.create(GreetingService.class);

  public void onModuleLoad() {
    [...]
  }
  [...]
}

The SimpleApp class implements the EntryPoint interface and thus must implement the onModuleLoad() method. This method is where the application "starts" when the client loads it in her browser (like a "main" method). To communicate with the server over GWT RPC, an instance of the GreetingServiceAsync class is created.

Server-side code

When the client communicates with the server via GWT RPC using the GreetingServiceAsync class, the code in GreetingServiceImpl class is executed.

public class GreetingServiceImpl extends RemoteServiceServlet implements GreetingService {

  public String greetServer(String input) throws IllegalArgumentException {
    [...]
  }
  [...]
}

Under the covers, this class is just a plain Java servlet, but with some GWT additions. Notably, it does the work of converting all requests and responses to JSON when sent over the wire.

The only GWT RPC method here is greetServer. It accepts a String as the request and returns a String in the response.

Compiling

When you're ready to deploy your GWT application to production, you'll want to compile it. This will translate all the client-side Java code into Javascript code, making it a fully-functional web application that you can run from a web container like Tomcat.

To do this, right click on the project folder and select "Google > GWT Compile". When it's done, just copy the "war" directory into the web container.

Friday, December 2, 2011

Apache Commons IO Introduction

The Apache Commons project is a collection of over 40 individual Java libraries that provide convenience methods to eleviate the developer from having to write tedious, boiler-plate code. The libraries try to stay as close to the core Java API as possible, so they have few or no dependencies on other libraries.

One of the libraries that I use a lot is the IO library. It contains features that build upon the core Java IO API and also make it easier to interact with the filesystem. I'm going to list three of the methods that I use a lot (and that you should use too). Looking at the API though, there's a ton more stuff this library can do, so don't let my tiny blog post keep you from exploring it.

IOUtils.copy()

The IOUtils.copy() method is great for copying data from an InputStream (or Reader) to an OutputStream (or Writer). No more creating arbitrarily-sized buffers and parenthesis-laden while loops! What it does here isn't rocket-science--any programmer worth their salt could code this up themselves. The point of using it is to make your code easier to read, less error-prone, and more consistent with the broader Java programming community.

These two code samples show just how much less code you have to write if you use this method:

Plain Java:

InputStream in = ...
OutputStream out = ...
byte buffer[] = new byte[4096];
int read;
while ((read = in.read(buffer)) != -1){
  out.write(buffer, 0, read);
}
in.close();
out.close();

Commons IO:

InputStream in = ...
OutputStream out = ...
IOUtils.copy(in, out);
in.close();
out.close();

IOUtils.closeQuietly()

The IOUtils.closeQuietly() method eliminates the boiler-plate required to close a stream in Java. It (1) checks to make sure the stream isn't null, (2) closes the stream, and (3) catches the IOException that is thrown when the stream's close() method is called. Again, what it does here isn't rocket-science. Its purpose is to reduce the amount of fluff in your code:

Plain Java:

InputStream in = null;
try{
  in = ...
  ...
} catch (IOException e){
  ...
} finally{
  try{
    if (in != null){
      in.close();
    }
  } catch (IOException e){}
}

Commons IO:

InputStream in = null;
try{
  in = ...
  ...
} catch (IOException e){
  ...
} finally{
  IOUtils.closeQuietly(in);
}

FileUtils.writeStringToFile()

Whenever I switch from coding in PHP to coding in Java, my heart sinks a little bit when I have to write some text to a file. In PHP, you can do this with a single function call. But in Java, you need to write a dozen or so lines of code. The FileUtils.writeStringToFile() method, however, allows you to write text to a file in one fell swoop.

Plain Java:

String text = "some text";
File file = new File("myfile.txt");
Writer writer = null;
try{
  writer = new PrintWriter(file);
  writer.write(text);
} catch (IOException e){
  ...
} finally {
  if (writer != null){
    try{
      writer.close();
    } catch (IOException e){}
  }
}

Commons IO:

String text = "some text";
File file = new File("myfile.txt");
try{
  FileUtils.writeStringToFile(file, text);
} catch (IOException e){
  ...
}

I hope you've enjoyed my little introduction to Commons IO. Using this library can greatly increase the readability and reliability of your code.