Using Google Web Toolkit (GWT) and NetBeans for Building AJAX Applications

Sang Shin, sang.shin@sun.com, Sun Microsystems, www.javapassion.com/ajaxcodecamp



This hands-on lab takes you through the basics of using Google Web Toolkit (GWT) for developing AJAX-based web applications. This document is designed to get you going as quickly as possible.  In this hands-on lab, you will exercise the following features of GWT. 
  1. How to build GWT-based application using GWT NetBeans IDE plug-in
  2. How to build and run sample applications that come with GWT package from Google using NetBeans IDE
  3. How to use GWT widgets
  4. How to create and use custom widgets
  5. How to perform RPC operation
  6. How to fetch data from a server in a form of JSON.
  7. How to attach a CSS style to a widget
  8. How to call native JavaScript code from Java and vice versa


Expected duration: 300 minutes

Prerequisites

This hands-on lab assumes you have some basic knowledge of, or programming experience with, the following technologies.

Software Needed

Before you begin, you need to install the following software on your computer.  The GWT NetBeans IDE plug-in is included as part of the hands-on lab zip file. The GWT NetBeans IDE  plug-in at this point is still in alpha quality but it provides a good enough template for building and running GWT application using NetBeans IDE. More functionality is being added to the plug-in.  This hands-on lab will be updated when the new plug-in is available.


OS platforms you can use for this lab


Google Web Toolkit 1.3.3 (the latest version as of May 16th, 2007) supports only the following three OS platforms.

Change Log


Things to be done (by Authors of this lab)


Lab Exercises


You would not need an internet connection to this lab once you have downloaded and installed the software mentioned above.


Exercise 0: Installation and Configuration

In this exercise, you are going to install GWT NetBeans plug-in to the NetBeans IDE.

    1. Install GWT NetBeans Plug-in to the NetBeans IDE

(0.1) Install GWT NetBeans Plug-in to the NetBeans IDE 6.0






Exercise 1: Build and run a simple HelloWorld application

In this exercise, you are going to build a simple HelloWorld GWT application using NetBeans.  You will also configure the Google Web Toolkit installation directory to the NetBeans IDE, which you have to do only once. 

  1. Create a GWT Web Application project
  2. Add another button to the GWT Application

(1.1) Create a GWT Web Application project

0. Start NetBeans IDE if you have not done so yet. 
1. Create a GWT NetBeans project.


Figure-1.10: Create a new Web application project


Figure-1.11: Specify Project Name

2.  Choose Google Web Toolkit as a Framework to use and specify the GWT installation directory.

The first time you are creating a GWT project, NetBeans IDE asks for the location of Google Web Toolkit(GWT) package you have downloaded and unzipped as mentioned above under Software required section. 

Figure-1.11.1: GWT Configuration


Figure-1.12: GWTApplication project

3. Build and run the application.


Figure-1.13: First page


Figure-1.14: Display

                                                                                                    return to  the top of exercise

(1.2) Add another button to the GWT Application


1. Open the MainEntryPoint.java file under GWTApplication->Source Packages->org.yournamehere.client as shown in Code-1.20 below.  Pay special attention to the bold-fonted part.

/*
 * MainEntryPoint.java
 *
 * Created on May 18, 2007, 5:31 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.yournamehere.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 *
 * @author sang
 */
public class MainEntryPoint implements EntryPoint {
   
    /** Creates a new instance of MainEntryPoint */
    public MainEntryPoint() {
    }
   
    /**
     * The entry point method, called automatically by loading a module
     * that declares an implementing class as an entry-point
     */
    public void onModuleLoad() {
        final Label label = new Label("Hello, GWT!!!");
        final Button button = new Button("Click me!");
       
        button.addClickListener(new ClickListener(){
            public void onClick(Widget w) {
                label.setVisible(!label.isVisible());
            }
        });
       
        RootPanel.get().add(button);
        RootPanel.get().add(label);
    }
   
}
Code-1.20: Main.java which contains a button

2. Modify the MainEntryPoint.java file as shown in Code-1.21 below  to add the 2nd button.  The code fragments that need to be added are highlighted in bold and blue-colored font.

package org.yournamehere.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 *
 * @author sang
 */
public class MainEntryPoint implements EntryPoint {
   
    /** Creates a new instance of MainEntryPoint */
    public MainEntryPoint() {
    }
   
    /**
     * The entry point method, called automatically by loading a module
     * that declares an implementing class as an entry-point
     */
    public void onModuleLoad() {
        final Label label = new Label("Hello, GWT!!!");
        final Button button = new Button("Click me!");
       
        button.addClickListener(new ClickListener(){
            public void onClick(Widget w) {
                label.setVisible(!label.isVisible());
            }
        });
       
        Button button2 = new Button("I am the 2nd button. Click me!");
       
        button2.addClickListener(new ClickListener(){
            public void onClick(Widget w) {
                Window.alert("Life is worth living.. with Passion!");
            }
        });
       
        RootPanel.get().add(button);
        RootPanel.get().add(button2);
        RootPanel.get().add(label);
    }
   
}
Code-1.21: The 2nd button is added

3. Build and run the project.

Figure-1.22: The 2nd button is displayed.


Figure-1.23: Alert message from the 2nd button event handler

                                                                                                    return to  the top of exercise

(1.3) Debugging



















Summary

In this exercise,  you learned how to build and run a HelloWorld GWT application using NetBeans. 

                                                                                                                        return to the top



Exercise 2: Build and run GWT sample applications "Hello" and "Kitchen Sink", Add CSS Style

In this exercise, you are going to build and run two sample applications - "Hello" and "Kitchen Sink" using NetBeans IDE.  Both applications come with the GWT package.  These are the same sample applications you can run and build using command line shell commands that come with GWT package.  You have to do the Exercise 1 first so that the location of the GWT is correctly configured to the NetBeans IDE.


(2.1) Build and run "Hello" sample application

In this step, you are going to build and run "Hello" sample application using NetBeans.  The application is already provided as "ready-to-build" NetBeans project called GWTHello as part of hands-on lab zip file.  This application works pretty much the same as the GWTApplication you built in Exercise 1.

0. Start NetBeans IDE if you have not done so yet. 
1. Open GWTHello NetBeans project.


Figure-2.10: Open GWTHello NetBeans project

3. Build and run GWTHello NetBeans project.

Figure-2.12: Application is opened in a browser

4. Add another button to the GWTHello application.
/*
 * Copyright 2006 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.sample.hello.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;

public class Hello implements EntryPoint {
   
    public void onModuleLoad() {
        Button b = new Button("Click me", new ClickListener() {
            public void onClick(Widget sender) {
                Window.alert("Hello, AJAX");
            }
        });
       
        RootPanel.get().add(b);
       
        // Create a new button along with event listener.
        // The event listener has listener method called onClick().

        Button c = new Button("Click me 2", new ClickListener() {
            public void onClick(Widget sender) {
                Window.alert("Hello, AJAX2");
            }
        });
       
        RootPanel.get().add(c);
    }
   
}
Code-2.15: Add another button

5. Build and run the project.


Figure-2.16: Modified GWTHello application in hosted mode.

5. [For your own exercise]  Add your own button - you can name it as Click me 3 - to the application.

                                                                                                    return to  the top of exercise


(2.2) Build and run "Kitchen Sink" sample application using NetBeans - Modify Buttons.java

In this step, you are going to build and run "Kitchen Sink" sample application using NetBeans and then modify Buttons.java to add your own buttons.  The application is already provided as "ready-to-build" NetBeans project called GWTKitchenSink as part of hands-on lab zip file.

0. Start NetBeans IDE if you have not done so yet. 
1. Open GWTKitchenSink NetBeans project.

2. Resolve references (as described above) if you experience reference problems.

3. Build and run GWTKitchenSink project.


Figure-2.22: GWTKitchenSink page

4. Check each of the widgets in the left starting from Buttons.  Play around with them. (Figure-2.23 below)


Figure-2.23: Buttons

5. Try the following:
6. For Frames, click Back and Forward buttons and see if they are working as expected. (Figure-2.24 below)


Figure-2.24: Try Back and Forward buttons.

                                                                                                    return to  the top of exercise

(2.3) Modify Buttons.java


1. Modify Buttons.java under GWTKitchenSink->com.google.gwt.sample.kitchensink.client as shown in Code-2.30 below.  The bold-fonted comments are added to aid your understanding - you will not see them in the actual code.  The new code fragments that need to be added are highlighted in bold and blue-colored font.  The new code is to add another menu bar called "Life" with its own menu items.

/*
 * Copyright 2006 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.sample.kitchensink.client;

import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Demonstrates the various button widgets.
 */
public class Buttons extends Sink {
   
    public static SinkInfo init() {
        return new SinkInfo("Buttons",
                "GWT supports all the myriad types of buttons that exist in HTML.  "
                + "Here are a few for your viewing pleasure.") {
            public Sink createInstance() {
                return new Buttons();
            }
        };
    }
   
    // Create button and checkbox objects
    private Button disabledButton = new Button("Disabled Button");
    private CheckBox disabledCheck = new CheckBox("Disabled Check");
    private Button normalButton = new Button("Normal Button");
    private Button myOwnButton = new Button("My Own Button");
    private CheckBox normalCheck = new CheckBox("Normal Check");

    // Create a vertical panel
    private VerticalPanel panel = new VerticalPanel();

    // Create radio buttons
    private RadioButton radio0 = new RadioButton("group0", "Choice 0");
    private RadioButton radio1 = new RadioButton("group0", "Choice 1");
    private RadioButton radio2 = new RadioButton("group0", "Choice 2 (Disabled)");
    private RadioButton radio3 = new RadioButton("group0", "Choice 3");
    private RadioButton radio4 = new RadioButton("group0", "Choice 4");
   
    // Constructor of the Buttons class
    public Buttons() {
        HorizontalPanel hp;
       
        //  Create a horizontal panel object and add buttons to it.
        //  Also add the horizontal panel object to the vertical panel.
        panel.add(hp = new HorizontalPanel());
        hp.setSpacing(8);
        hp.add(normalButton);
        hp.add(disabledButton);
        hp.add(myOwnButton);
       
        //  Create a horizontal panel object and add checkboxes to it.
        //  Also add the horizontal panel object to the vertical panel.
        panel.add(hp = new HorizontalPanel());
        hp.setSpacing(8);
        hp.add(normalCheck);
        hp.add(disabledCheck);
       
        //  Create a horizontal panel object and add radion buttons to it.
        //  Also add the horizontal panel object to the vertical panel.
        panel.add(hp = new HorizontalPanel());
        hp.setSpacing(8);
        hp.add(radio0);
        hp.add(radio1);
        hp.add(radio2);
        hp.add(radio3);
        hp.add(radio4);
       
        // Set the disabled flags to widget objects
        disabledButton.setEnabled(false);
        disabledCheck.setEnabled(false);
        radio2.setEnabled(false);
       
        panel.setSpacing(8);
        setWidget(panel);
    }
   
    public void onShow() {
    }
}
Code-2.30: Modified Buttons.java

2. Build and run the project.


Figure-2.31: Add your own buttons

3. Add another panel to the GWTKitchenSink application.
/*
 * Copyright 2006 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.sample.kitchensink.client;

import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Demonstrates the various button widgets.
 */
public class Buttons extends Sink {
   
    public static SinkInfo init() {
        return new SinkInfo("Buttons",
                "GWT supports all the myriad types of buttons that exist in HTML.  "
                + "Here are a few for your viewing pleasure.") {
            public Sink createInstance() {
                return new Buttons();
            }
        };
    }
   
    // Create button and checkbox objects
    private Button disabledButton = new Button("Disabled Button");
    private CheckBox disabledCheck = new CheckBox("Disabled Check");
    private Button normalButton = new Button("Normal Button");
    private Button myOwnButton = new Button("My Own Button");
    private CheckBox normalCheck = new CheckBox("Normal Check");

    // Create a vertical panel
    private VerticalPanel panel = new VerticalPanel();

    // Create radio buttons
    private RadioButton radio0 = new RadioButton("group0", "Choice 0");
    private RadioButton radio1 = new RadioButton("group0", "Choice 1");
    private RadioButton radio2 = new RadioButton("group0", "Choice 2 (Disabled)");
    private RadioButton radio3 = new RadioButton("group0", "Choice 3");
    private RadioButton radio4 = new RadioButton("group0", "Choice 4");
   
   
// Constructor of the Buttons class
    public Buttons() {
        HorizontalPanel hp;
       
        //  Create a horizontal panel object and add buttons to it.
        //  Also add the horizontal panel object to the vertical panel.
        panel.add(hp = new HorizontalPanel());
        hp.setSpacing(8);
        hp.add(normalButton);
        hp.add(disabledButton);
        hp.add(myOwnButton);
       
        //  Create a horizontal panel object and add checkboxes to it.
        //  Also add the horizontal panel object to the vertical panel.
        panel.add(hp = new HorizontalPanel());
        hp.setSpacing(8);
        hp.add(normalCheck);
        hp.add(disabledCheck);
       
        //  Create a horizontal panel object and add radion buttons to it.
        //  Also add the horizontal panel object to the vertical panel.
        panel.add(hp = new HorizontalPanel());
        hp.setSpacing(8);
        hp.add(radio0);
        hp.add(radio1);
        hp.add(radio2);
        hp.add(radio3);
        hp.add(radio4);

        // Add my own panel
        panel.add(hp = new HorizontalPanel());

        hp.setSpacing(8);
        hp.add(normalButton);
        hp.add(normalCheck);
        hp.add(radio0);
       
        // Set the disabled flags to widget objects
        disabledButton.setEnabled(false);
        disabledCheck.setEnabled(false);
        radio2.setEnabled(false);
       
        panel.setSpacing(8);
        setWidget(panel);
    }
   
    public void onShow() {
    }
}
Code-2.32: Add another panel

4. Build and run the project.

Figure-2.33: Result of running the modified application

                                                                                                    return to  the top of exercise


(2.4) Modify Menus.java


1. Modify Menus.java under GWTKitchenSink->com.google.gwt.sample.kitchensink.client as shown in Code-2.40 below.  The bold-fonted comments are added to aid your understanding - you will not see them in the actual code.  The new code fragments that need to be added are highlighted in bold and blue-colored font.  The new code is to add another menu bar called "Life" with its own menu items.

/*
 * Copyright 2006 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.sample.kitchensink.client;

import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.MenuItem;

/**
 * Demonstrates {@link com.google.gwt.user.client.ui.MenuBar} and
 * {@link com.google.gwt.user.client.ui.MenuItem}.
 */
public class Menus extends Sink implements Command {
   
    public static SinkInfo init() {
        return new SinkInfo("Menus",
                "The GWT <code>MenuBar</code> class makes it easy to build menus, "
                + "including cascading sub-menus.") {
            public Sink createInstance() {
                return new Menus();
            }
        };
    }
   
    // Create empty master MenuBar object
    private MenuBar menu = new MenuBar();
   
    public Menus() {

        // Create a sub-sub-menu bar and add items to the sub-sub-menu bar
        MenuBar subMenu = new MenuBar(true);
        subMenu.addItem("<code>Code</code>", true, this);
        subMenu.addItem("<strike>Strikethrough</strike>", true, this);
        subMenu.addItem("<u>Underlined</u>", true, this);
       
        // Create a new sub-menu bar and add items to it
        MenuBar menu0 = new MenuBar(true);
        menu0.addItem("<b>Bold</b>", true, this);
        menu0.addItem("<i>Italicized</i>", true, this);
        menu0.addItem("More &#187;", true, subMenu);

        // Create a new sub-menu bar and add items to it
        MenuBar menu1 = new MenuBar(true);
        menu1.addItem("<font color='#FF0000'><b>Apple</b></font>", true, this);
        menu1.addItem("<font color='#FFFF00'><b>Banana</b></font>", true, this);
        menu1.addItem("<font color='#FFFFFF'><b>Coconut</b></font>", true, this);
        menu1.addItem("<font color='#8B4513'><b>Donut</b></font>", true, this);

        // Create a new sub-menu bar and add items to it
        MenuBar menu2 = new MenuBar(true);
        menu2.addItem("Bling", this);
        menu2.addItem("Ginormous", this);
        menu2.addItem("<code>w00t!</code>", true, this);

        // Create a new sub-menu bar and add items to it
        MenuBar menu3 = new MenuBar(true);
        menu3.addItem("Life is good!", this);
        menu3.addItem("Life is OK!", this);
        menu3.addItem("Life sucks!", this);
       
        // Add sub-menu bar's  to the master menu bar
        menu.addItem(new MenuItem("Style", menu0));
        menu.addItem(new MenuItem("Fruit", menu1));
        menu.addItem(new MenuItem("Term", menu2));
        menu.addItem(new MenuItem("Life", menu3));
       
        menu.setWidth("100%");
       
        setWidget(menu);
    }
   
    public void execute() {
        Window.alert("Thank you for selecting a menu item.");
    }
   
    public void onShow() {
    }
}

Code-2.40: Add your own menu bar

2. Build and run the project.

Figure-2.41: New menubar is displayed


                                                                                                    return to  the top of exercise


(2.5) Modify Trees.java


1. Modify Trees.java under GWTKitchenSink->com.google.gwt.sample.kitchensink.client as shown in Code-2.50 below.  The bold-fonted comments are added to aid your understanding - you will not see them in the actual code.  The new code fragments that need to be added are highlighted in bold and blue-colored font. 

  private static Proto[] fProto = new Proto[]{
    new Proto("Beethoven", new Proto[]{
      new Proto("Concertos", new Proto[]{
        new Proto("No. 1 - C"), new Proto("No. 2 - B-Flat Major"),
        new Proto("No. 3 - C Minor"), new Proto("No. 4 - G Major"),
        new Proto("No. 5 - E-Flat Major"),}),
      new Proto("Quartets", new Proto[]{
        new Proto("Six String Quartets"), new Proto("Three String Quartets"),
        new Proto("Grosse Fugue for String Quartets"),}),
      new Proto("Sonatas", new Proto[]{
        new Proto("Sonata in A Minor"), new Proto("Sonata in F Major"),}),
      new Proto("Symphonies", new Proto[]{
        new Proto("No. 1 - C Major"), new Proto("No. 2 - D Major"),
        new Proto("No. 3 - E-Flat Major"), new Proto("No. 4 - B-Flat Major"),
        new Proto("No. 5 - C Minor"), new Proto("No. 6 - F Major"),
        new Proto("No. 7 - A Major"), new Proto("No. 8 - F Major"),
        new Proto("No. 9 - D Minor"),}),}),
    new Proto("Sang Shin", new Proto[]{
      new Proto("Rock and Roll", new Proto[]{
        new Proto("Love me tender"), new Proto("Let it Be"),
        new Proto("Hey Jude"),}),
      new Proto("Country music", new Proto[]{
        new Proto("Lost Highway"), new Proto("Six Days on the Road"),
        new Proto("Wide Open Road"),}),
      new Proto("Tango", new Proto[]{
        new Proto("Jealousy"), new Proto("Tango of Roses"),}),
      new Proto("Hip Hop", new Proto[]{
        new Proto("No. 1 - C Major"), new Proto("No. 2 - D Major"),
        new Proto("No. 9 - D Minor"),}),}),
    new Proto("Brahms", new Proto[]{
      new Proto("Concertos", new Proto[]{
        new Proto("Violin Concerto"), new Proto("Double Concerto - A Minor"),
        new Proto("Piano Concerto No. 1 - D Minor"),
        new Proto("Piano Concerto No. 2 - B-Flat Major"),}),
      new Proto("Quartets", new Proto[]{
        new Proto("Piano Quartet No. 1 - G Minor"),
        new Proto("Piano Quartet No. 2 - A Major"),
        new Proto("Piano Quartet No. 3 - C Minor"),
        new Proto("String Quartet No. 3 - B-Flat Minor"),}),
      new Proto("Sonatas", new Proto[]{
        new Proto("Two Sonatas for Clarinet - F Minor"),
        new Proto("Two Sonatas for Clarinet - E-Flat Major"),}),
      new Proto("Symphonies", new Proto[]{
        new Proto("No. 1 - C Minor"), new Proto("No. 2 - D Minor"),
        new Proto("No. 3 - F Major"), new Proto("No. 4 - E Minor"),}),}),
    new Proto("Mozart", new Proto[]{new Proto("Concertos", new Proto[]{
      new Proto("Piano Concerto No. 12"), new Proto("Piano Concerto No. 17"),
      new Proto("Clarinet Concerto"), new Proto("Violin Concerto No. 5"),
      new Proto("Violin Concerto No. 4"),}),}),};

Code-2.50: Modified Trees.java

2. Build and run the project.

Figure-2.51: Newly added Tree nodes

                                                                                                    return to  the top of exercise

(2.6) Change the CSS style


In this step, you are going to learn how to create and use CSS style.

0. Open KitchenSink.css file under GWTKitchenSink->Source Packages->com.google.gwt.sample.kitchensink.public directory.



1. Create a new style .ks-List .ks-SinkItem-selected-myown in the KitchenSink.css file as shown in Code-2.60 below.  You might want to add it after .ks-List .ks-SinkItem-selected which starts from line number around 203.

.ks-List .ks-SinkItem-selected {
  background-color: #C3D9FF;
}

/* -------------- This is my own ------ */

.ks-List .ks-SinkItem-selected-myown {
  background-color: #EEFFEE;
  font-weight: bold;
  font-style: italic;
}
Code-2.60: Modify the attributes of the .ks-List .ks-SinkItem-selected

2. Modify setSinkSelection method (starting from line number  59) of the SinkList.java under GWTKitchenSink->Source Packages->com.google.gwt.sample.kitchensink.client to use the newly created style as shown in Code-2.61 below.  The code fragments that need to changed are highlighted in bold and blue-colored font.

  public void setSinkSelection(String name) {
    if (selectedSink != -1)
      list.getWidget(selectedSink).removeStyleName("ks-SinkItem-selected-myown");

    for (int i = 0; i < sinks.size(); ++i) {
      SinkInfo info = (SinkInfo) sinks.get(i);
      if (info.getName().equals(name)) {
        selectedSink = i;
        list.getWidget(selectedSink).addStyleName("ks-SinkItem-selected-myown");
        return;
      }
    }
  }
Code-2.61: Use new style

3. Build and run the project.

Figure-2.62: Different style is used

                                                                                                    return to  the top of exercise

Summary


In this exercise, you have built two GWT sample applications - "Hello" and "Kitchen Sink" - using NetBeans IDE.  You have learned how to use various widgets that are provided as part of GWT package.  You also learned how to set a style to a widget.
   
                                                                                                                                   Return to the top


Exercise 3: Create custom widgets


In this exercise, you are going to create a simple custom widget using Composite class first.  A Composite widget is a type of widget that can wrap another widget, hiding the wrapped widget's methods. When added to a panel, a composite behaves exactly as if the widget it wraps had been added. The composite is useful for creating a single widget out of an aggregate of multiple other widgets contained in a single panel.  You will also create another custom widget by extending the first custom widget.

(3.1) Create a new GWT project


0. Start NetBeans IDE if you have not done so yet. 
1. Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
2. Under Choose Project pane, select Web under Categories and Web Application under Projects. Click Next.  The New Project dialog box appears.


GW
3. In the Project Name field, type in GWTCompositeExample
4. Click Next. (Figure-3.10 below)


Figure-3.10: Create a new project called GWTComposteExample

5. Observe that Frameworks pane appears.
6. Select Google Web Toolkit.
7. For GWT Module field, type in my.company.Main.  (Or you can just use the default value.)
8. Click Finish.



9. Observe that GWTCompositeExample project node appears.

                                                                                                    return to  the top of exercise


(3.2) Create a custom widget called "OptionalTextBox"


This example is based on the code in the JavaDoc of Composite class in Google Web Toolkit website - please read it  before you proceed with this step.

1. Replace IDE generated MainEntryPoint.java under GWTCompositeExample->Source Packages->my.company.client with the code shown in Code-3.20 below. 

This code creates a custom widget called OptionalTextBox extending Composite class.  The OptionalTextBox widget lets to you type something in the text field when you enabled it.  When it is not enabled, it will disable the typing.  You can copy and paste the code from Code-3.20 below.

package my.company.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 *
 * @author sang
 */
public class MainEntryPoint implements EntryPoint {
   
    /** Creates a new instance of MainEntryPoint */
    public MainEntryPoint() {
    }
   
    /**
     * A composite of a TextBox and a CheckBox that optionally enables it.
     */
    public static class OptionalTextBox extends Composite implements
            ClickListener {
       
        private TextBox textBox = new TextBox();
        private CheckBox checkBox = new CheckBox();
       
        /**
         * Constructs an OptionalTextBox with the given caption on the check.
         *
         * @param caption the caption to be displayed with the check box
         */
        public OptionalTextBox(String caption) {
            // Place the check above the text box using a vertical panel.
            VerticalPanel panel = new VerticalPanel();
            panel.add(checkBox);
            panel.add(textBox);
           
            // Set the check box's caption, and check it by default.
            checkBox.setText(caption);
            checkBox.setChecked(true);
            checkBox.addClickListener(this);
           
            // All composites must call initWidget() in their constructors.
            initWidget(panel);
           
            // Give the overall composite a style name.
            setStyleName("example-OptionalCheckBox");
        }
       
        public void onClick(Widget sender) {
            if (sender == checkBox) {
                // When the check box is clicked, update the text box's enabled state.
                textBox.setEnabled(checkBox.isChecked());
            }
        }
       
        /**
         * Sets the caption associated with the check box.
         *
         * @param caption the check box's caption
         */
        public void setCaption(String caption) {
            // Note how we use the use composition of the contained widgets to provide
            // only the methods that we want to.
            checkBox.setText(caption);
        }
       
        /**
         * Gets the caption associated with the check box.
         *
         * @return the check box's caption
         */
        public String getCaption() {
            return checkBox.getText();
        }
    }
   
    public void onModuleLoad() {
        // Create an optional text box and add it to the root panel.
        OptionalTextBox otb = new OptionalTextBox("Check this to enable me");
        RootPanel.get().add(otb);
    }
     
}
Code-3.20: Modified MainEntryPoint.java

                                                                                                    return to  the top of exercise


(3.3) Build and run the application


1. Right click GWTCompositeExample project node and select Run.
2. Click GWT page
3. Since the Check this to enable me checkbox is checked, you can type in the text field.  Type some string as shown in Figure-3.30 below.


Figure-3.30: OptionalTextBox widget in action

4. Now uncheck the Check this to enable me checkbox.  Now you should notice that the characters you previously typed in are grayed out and you cannot type in any characters. (Figure-3.31 below)


Figure-3.31: OptionalTextBox widget in action

                                                                                                    return to  the top of exercise



Summary


In this exercise, you have created and used two custom widgets.  You have created the first custom widget by extending Composite class.  You have created the second custom widget by extending the first widget.


                                                                                                                        return to the top



Exercise 4: Invoke remote service via RPC


In this exercise, you are also going to build an application that uses RPC for communicating with the server in asynchronous fashion.   There are both server and client code.  Before you do this exercise, it is recommended - but not required - you read through description of Remote Procedure Call feature of GWT.
  1. Create a new NetBeans project
  2. Create a sample RPC code using NetBeans GWT plug-in's wizard
  3. Look under the hoold of the codes that are generated
  4. Look web.xml file that is modified
  5. Modify client code, ManinEntryPoint.java, to invoke remote service
  6. Build and run the application
  7. Debug server side code
  8. Debug client side code

(4.1) Create a new GWT NetBeans project


1. Create GWTHelloRPC project.

Figure-4.10: Create GWTHelloRPC project

2.  Choose Google Web Toolkit as a Framework.

Figure-4.11: Select Google Web Toolkit as a framework

                                                                                                   return to  the top of exercise

(4.2) Create a sample RPC code


In this step, you are going to create a RPC project using NetBeans GWT plug-in's RPC wizard.

1. Right click GWTHelloRPC projecyt node and select New->File/Folder. (Figure-4.21 below)


Figure-4.21: Create File/Folder

2. Choose Google Web Toolkit under Categories and GWT RPC Service under File Types. (Figure-4.22 below)


Figure-4.22: Create GWT RPC Service

3. For the Service Name field, just leave the default value - GWTService - or type in whatever Service name of your choice. In this example, we are going to use the default name.
4. Check Create Usage Example Class check box.  The IDE will generate example RPC code.
5. Click Finish.  (Figure-4.23 below)


Figure-4.23: Check Create Usage Example Class.

                                                                                                   return to  the top of exercise

(4.3) Look under the hood of the codes that were generated


The wizard generates the following source files.  In this step, you will study these source files.
The wizard also modifies web.xml file.

1. Open GWTService.java and study the code.  Bold-fonted comments are added to aid your understanding.  These comments are not present in the actual code that are generated by the IDE. (Code-4.31 below)

package my.company.client;
import com.google.gwt.user.client.rpc.RemoteService;

// Service interface, which has a single method called myMethod.
public interface GWTService extends RemoteService{
    public String myMethod(String s);
}
Code-4.31: GWTService.java

2. Open GWTServiceAsync.java and study the code.  Bold-fonted comments are added to aid your understanding. (Code-4.32 below)

package my.company.client;
import com.google.gwt.user.client.rpc.AsyncCallback;

// Asynchronous Service interface. Note that a AsynchCallBack
// object needs to be passed as a parameter.
public interface GWTServiceAsync {
    public void myMethod(String s, AsyncCallback callback);
}
Code-4.32: GWTServiceAsync.java

3. Open GWTServiceImpl.java and study the code. Bold-fonted comments are added to aid your understanding. (Code-4.33 below)

package my.company.server;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import my.company.client.GWTService;

// Service implementation, which provides the implementation of
// GWTService service interface.
public class GWTServiceImpl extends RemoteServiceServlet implements
        GWTService {
   
    public String myMethod(String s) {
        // Do something interesting with 's' here on the server.
        return "Server says: " + s;
    }
}
Code-4.33: GWTServiceImpl.java

4. Open GWTServiceUsageExample.java and study the code by paying special attention to bold-fonted comments. (Code-4.34 below)

package my.company.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

public class GWTServiceUsageExample extends VerticalPanel {
    private Label lblServerReply = new Label();
    private TextBox txtUserInput = new TextBox();
    private Button btnSend = new Button("Send to server");
   
    public GWTServiceUsageExample() {
        add(new Label("Input your text: "));
        add(txtUserInput);
        add(btnSend);
        add(lblServerReply);
       
        // Create an asynchronous callback to handle the result.
        // The AynchCallBack object has to provide implementation
        // of onSuccess() and onFailure() metods.
        final AsyncCallback callback = new AsyncCallback() {
            public void onSuccess(Object result) {
                lblServerReply.setText((String)result);
            }
           
            public void onFailure(Throwable caught) {
                lblServerReply.setText("Communication failed");
            }
        };
       
        // Listen for the button clicks. When "Send to server"
        // button is pressed, the RPC operation occurs.
        btnSend.addClickListener(new ClickListener(){
            public void onClick(Widget w) {
                // Make remote call. Control flow will continue immediately and later
                // 'callback' will be invoked when the RPC completes.
                getService().myMethod(txtUserInput.getText(), callback);
            }
        });
    }
   
    public static GWTServiceAsync getService(){
        // Create the client proxy. Note that although you are creating the
        // service interface proper, you cast the result to the asynchronous
        // version of
        // the interface. The cast is always safe because the generated proxy
        // implements the asynchronous interface automatically.
        GWTServiceAsync service = (GWTServiceAsync) GWT.create(GWTService.class);
        // Specify the URL at which our service implementation is running.
        // Note that the target URL must reside on the same domain and port from
        // which the host page was served.
        //
        ServiceDefTarget endpoint = (ServiceDefTarget) service;
        String moduleRelativeURL = GWT.getModuleBaseURL() + "gwtservice";
        endpoint.setServiceEntryPoint(moduleRelativeURL);
        return service;
    }
}
Code-4.34: GWTServiceUsageExample.java

                                                                                                   return to  the top of exercise


(4.4) Look under the hood of the web.xml file


1. Open web.xml under GWTHelloRPC->Configuration Files and study the changes that has been made by the IDE by paying special attention to the bold-fonted part. (Code-4.40 below)

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <servlet>
        <servlet-name>GWTService</servlet-name>
        <servlet-class>my.company.server.GWTServiceImpl</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>GWTService</servlet-name>
        <url-pattern>/my.company.Main/gwtservice</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
    <welcome-file>
            index.jsp
        </welcome-file>
    </welcome-file-list>
</web-app>
Code-4.40: Modified web.xml

                                                                                                   return to  the top of exercise


(4.5) Modify MainEntryPoint.java


Now in this step, you are going to modify MainEntryPoint.java so that you can test the RPC operation.

1. Modify MainEntryPoint.java under GWTHelloRPC->Source Packages->my.company.client as shown in Code-4.51 below.  The modification is to use and display GWTServiceUsageExample object in the RootPanel so that you can test the code.

package my.company.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 *
 * @author sang
 */
public class MainEntryPoint implements EntryPoint {
   
    /** Creates a new instance of MainEntryPoint */
    public MainEntryPoint() {
    }
   
    /**
     * The entry point method, called automatically by loading a module
     * that declares an implementing class as an entry-point
     */
    public void onModuleLoad() {
        final Label label = new Label("Hello, GWT!!!");
        final Button button = new Button("Click me!");

        // The GWTServiceUsageExample is a VerticalPanel object, the constructor of
        //  which performs RPC operation with the server.
        GWTServiceUsageExample rpcCallingPanel = new GWTServiceUsageExample();
       
        button.addClickListener(new ClickListener(){
            public void onClick(Widget w) {
                label.setVisible(!label.isVisible());
            }
        });
       
        RootPanel.get().add(button);
        RootPanel.get().add(label);

        // Add the GWTServiceUsageExample to the panel
        // so that you can test it.
        RootPanel.get().add(rpcCallingPanel);
    }
   
}
Code-4.51: Modified MainEntryPoint.java

                                                                                                   return to  the top of exercise


(4.6) Build and run the application


1. Build and run the project.

Figure-4.60: Enter value into the input text field
Note: For information on how to install Firebug debugger, please see here.  For information on how to use Firebug debugger, please see here.


Figure-4.61: Display the data that was returned from the server

                                                                                                   return to  the top of exercise


(4.7) Debugging the server side code