Friday, March 28, 2014

GWT - ClientBundle in Action

ClientBundle is the GWT's way to organize the non-js resources, such as css codes, images.
Getting resources into client bundle is simple as declaring a method with some annotations. 
public interface AppBundle extends ClientBundle {

    interface Style extends CssResource {

        String appleBackground();

        String orangeBackground();
    }

    @Source({"App.gwtcss", "App.css"})
    Style style();

    @Source("orange.html")
    TextResource orangeDescription();

    @Source("apple.html")
    TextResource appleDescription();

    @Source("apple.jpg")
    ImageResource appleImage();

    @Source("orange.jpg")
    ImageResource orangeImage();
}
As shown above we have 2 html files included as text, 2 jpg images and 2 css files mashed into a single Style interface.
The tricky part is how do we reference the images inside the css code.
@url appleUrl appleImage;
@url orangeUrl orangeImage;
these two lines instruct the GWT compiler to create two variable appleUrl and ornageUrl out of the images we included, then we can write out css codes as
.appleBackground {
    background-repeat: no-repeat;
    background-image: appleUrl;
    background-position: right center;
}

.orangeBackground {
    background-repeat: no-repeat;
    background-image: orangeUrl;
    background-position: right center;
}
there is one caveat about this @url codes, netbeans is not happy with non standard css codes, if we keep the codes inside the App.css, we will have a red face netbeans like this

so i decided to move the @url codes into a special App.gwtcss file.
The .ensureInjected method of the generated Style must be called, otherwise we will have the correct class name but the css content will NOT be injected into the page.
Pulling resources out of the ResouceBundle is straight forward
FlowPanel panel = new FlowPanel();
panel.setStyleName(bundle.style().appleBackground());
panel.add(new Image(bundle.appleImage()));
panel.add(new HTML(bundle.appleDescription().getText()));
RootPanel.get().add(panel);
here is the final result, we have a FlowPanel with a "right center" positioned background apple image, also containing an apple image tag and some random html codes from the apple.html.
There are more black magics to discover from the CssResource doc.
Code is available here https://github.com/verydapeng/gwt-tutorials, under ClientBundle folder.
Happy Coding

Tuesday, March 18, 2014

GWT - client server communication - json

So far my discussions about GWT are exclusively front end technologies, today let's move on to the more exciting client server communication world.

By far, I think the easiest way to expose server side functionality is to build some JSON services. There is even a funny name for it, "thin server architecture". Without further ado, let's build the simplest possible JSON service and deploy to tomcat.
@WebServlet("/serverTime")
public class ServerTimeServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.setContentType("application/json");
        resp.getWriter().write(String.format("{\"time\":\"%s\"}",
                new Date().toString()));
    }
}

and test it
Now setup a new gwt client project, to access the XMLHttpRequest functionality, we need to make use of the RequestBuilder.
RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, "/gwtjson-server/serverTime");

rb.setCallback(requestCallback);
rb.setRequestData("");
rb.send();

the vanilla RequestCallback can only accept text response, we need to parse the JSON string using JSONParser.
private void processJson(String jsonText) {
    JSONValue json = JSONParser.parseStrict(jsonText);
    String serverTime = json.isObject().get("time")
                            .isString().stringValue();
    Window.alert("Server time is: " + serverTime);
}

However, JSON package is not enabled by default, so we need to add the following line to the gwt.xml file
<inherits name="com.google.gwt.json.JSON" />
Now run the gwtjson-client project as well as start the super dev mode,

Navigate to sdm.html (super dev mode host page), compile the project if necessary. For working with super dev mode, please refer to my previous post.
Notice, we are not constrained with java servers here, it is possible to serve the serverTime request with any capable servers, Apache, Node.js, .Net etc. The client project has nearly zero knowledge of the server side technology.

And for any sensible team you should not stop here, the request builder api is still quite primitive and cumbersome to use (Java 8 I am looking at you!). You are encouraged to come up with your own wrappers with a more fluent API. Here is an example
Ajax.url("/login")
    .param("username", username)
    .param("password", password)
    .post(callback);


Codes are available here https://github.com/verydapeng/gwt-tutorials, under gwtjson-client and gwtjson-server folders.

Happy Coding

Tuesday, March 11, 2014

GWT - Super Dev Mode

We are losing the classical GWT dev mode pretty soon, Firefox support is already removed, and soon will be the end of Chrome support. For the teams that are using GWT, it is time to jump to the new ship, Super Dev Mode.
The idea is pretty straightforward, the super dev mode will dump the compiled javascript codes to the browser as well as the original java files and their bindings, so that we can leverage the browser's built-in debugger.
In classical dev mode, the server serves both the GWT related javascript codes as well as the non gwt stuff, things like the host page, some other external css, images. The GWT super dev mode server ONLY serves the GWT-Javascript related stuff, so we need another server to serve the host page. We literally need to run two servers during development. The good news is the host server can be anything, Tomcat, Glassfish, Jetty, Jboss, or even non Java servers like ngix, apache, IIS, depends on the server technology you choose.
Since we are using maven, let's make use of the embedded jetty for the sake of simplicity.
First, create the GWT project as you always do.
Now edit the pom to add jetty, add the following lines to section

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <configuration>
        <scanIntervalSeconds>10</scanIntervalSeconds>
        <webApp>
            <contextPath>/test</contextPath>
        </webApp>
    </configuration>
</plugin>
Now make sure the jetty plugin is doing its job by running custom maven goals, "jetty:run"


Now let's start the GWT code server by running "gwt:run-codeserver", after a short compilation you should see this

Follow the url http://localhost:9876/ and drag the "dev mode on" to your bookmark bar.

Now we need a new html page to load the resource from the code server. Let's call it superDevMode.html
<script src="http://localhost:9876/app/app.nocache.js"></script>
Notice the only difference here is we are using a different src url that the original index.html. I am sure that most of you can comfortably merge the two files with any sensible server side template framework, jsp, php, asp.  It is your own call. Open the newly created page in browser, and click the bookmark.
From now on, every time you make a change to the java codes, you need to click the compile button. Here you may want to bookmark the compile button as well. As soon as the background compilation is done, your page will be reloaded. Now come to the debugging business. Make sure your browser's debugger is loading source maps. This are chrome's instructions, and this are firefox's instructions. Time the press the glorious F12, and set the mighty break point. Chrome and Firefox screenshots are included. IE11 doesn't support source maps, however the classical dev mode still works for IE, so there is no big deal here.

What are you waiting for? huh? Go press the F5!
Codes are available from https://github.com/verydapeng/gwt-tutorials under the SuperDevMode folder. Happy Coding.

Friday, March 7, 2014

GWT - images and uibinder

Today we will meet a new friend in the ui:binder's world, <ui:image>. It is used to tag images to be included into the uibinder.
<ui:image field='logoImage' src='gwt.png' />
<ui:style>
    @url logoUrl logoImage;
    .logo {
      background-repeat: no-repeat;
      background-image: logoUrl;
      width: 100px;
      height: 100px;
    }
</ui:style>

<g:FlowPanel>
    <g:Image resource='{logoImage}' />
    <g:HTML styleName='{style.logo}'>
        hello image
    </g:HTML>
</g:FlowPanel>
We need to give a name to the newly included image via the "field" attribute. There are two ways access the image, both are demonstrated in the above codes

  1. use <Image> widget 
  2. use the image as css background-image. notice the @url rule 

There are several benefits of letting GWT compiler handles the images for you.

  1. Images can be anywhere on the classpath, instead of being canned inside the /images/ folder. Now suppose we are writing a reusable component, the component can be nicely encapsulated inside a dedicated package, and the client of the component is hassle free, just include the jar and we are good to go.
  2. GWT compiler will do extra work to make the image cache friendly. The image will be either be assigned a random name, or embedded directly into the css codes using data url. The file name is determined by hashing the content of the image, so in case the image never changes, the name remains the same, now we can happily set the TTL of the image to be 1 year at the cache layer. By default, GWT will make a smart guess if the images is small enough, it will be included as data url. You can disable this feature by explicitly set <set-property name="ClientBundle.enableInlining" value="false" /> in the prod.gwt.xml. 
  3. Since the original image file name is not used in the final output, we are free of naming collision. Dev A can have a logo.png under packages com.verydapeng.mod1, Dev B can have a logo.png under package com.verydapeng.mod2. There is no need to come up any naming scheme like /images/logo_mod1.png, /images/logo_mod2.png
Codes are available from github https://github.com/verydapeng/gwt-tutorials, under the /Images/ folder

Happy coding ...