Skip to main content

skip to main content

developerWorks  >  Java technology | Web development  >

Take a legacy path to advanced GWT controls

Integrate JavaScript libraries to enhance Google Web Toolkit widgets

developerWorks
Document options

Document options requiring JavaScript are not displayed

Sample code


Rate this page

Help us improve this content


Level: Advanced

Sergey Odobetskiy (s.odobetsky@gmail.com), Software development consultant , Freelance

24 Apr 2007

The Google Web Toolkit (GWT) provides libraries and tools that let you develop Ajax applications in the Java™ programming language. Unfortunately, GWT's standard gallery of UI controls (widgets) doesn't provide the advanced features that modern enterprise applications require. This article shows a technique that addresses this deficiency. Find out how to give GWT controls advanced functionality with relatively simple coding by integrating a popular JavaScript grid component with a GWT application.

Open source Ajax frameworks and commercial toolkits try to make Ajax development more accessible by hiding complexity and the burden of low-level JavaScript and Document Object Model (DOM) operations. They often help to reduce development time, but using them to achieve advanced functionality usually requires a skill set and level of JavaScript knowledge that aren't trivial to acquire. Google has come up with innovative technology that brings Ajax application development to a completely new level. The GWT is a comprehensive set of APIs and tools that lets you create dynamic Web applications in Java code. GWT does this through code generation: The GWT compiler generates cross-browser compatible JavaScript from client-side Java code.

Unfortunately, the standard UI controls (widgets) Google offers have a limited feature set and in many cases cannot satisfy modern enterprise-grade applications. Although you can extend basic GWT controls with a set of custom properties, this path often requires significant development effort. Fortunately, an easier approach is available. With the help of a sample application (see Download), this article shows how to integrate the popular ActiveWidgets JavaScript grid component with a GWT application and achieve advanced functionality with relatively simple coding.

Dynamic Web UI controls

JavaScript Web UI controls are designed to eliminate server roundtrips by generating HTML dynamically inside the browser. Instead of sending static HTML, the server adds data structures and JavaScript code for the dynamic components into the page content. During page load, the browser runs the scripts to create active components, configures them, and then inserts the HTML string each component generates into the proper place on the page. From this point, the JavaScript component code is connected to the HTML fragment on the page. The component manages user interactions, updates the HTML according to the data changes, and provides an API to manipulate its content, behavior, and visual style.

GWT controls developed in Java code and compiled into JavaScript work exactly the same way. This makes them fully compatible with commercial controls and JavaScript libraries. JavaScript libraries are more mature and provide a complete set of cross-browser advanced features such as intelligent scrolling, column resizing, sorting, dynamic loading, and paging for large data sets. GWT's open architecture lets you integrate commercial controls and legacy JavaScript libraries with new applications and focus on solving enterprise challenges rather then reinventing the proverbial wheel.



Back to top


Automatic resource injection

This article's sample GWT application (see Download) uses a handy GWT feature: automatic resource injection. A project module includes references to external JavaScript and Cascading Style Sheets (CSS) files, causing them to load automatically when the module itself is loaded. Listing 1 shows the declarations in the sample application's module-definition XML file (GridDemo.gwt.xml) that achieve this:


Listing 1. GWT module definition
                
<module>
  <inherits name='com.google.gwt.user.User'/>
  <entry-point class='com.mycompany.project.client.GridDemo'/>
  
  <source path="client"/>

  <stylesheet src="runtime/styles/xp/aw.css"/>
  <script src="runtime/lib/aw.js"> 
    <![CDATA[ 
     if ($wnd.AW.Grid.Control.create) 
       return true; 
     else 
       return false; 
   ]]> 
  </script>
</module>


Injection of JavaScript files and stylesheets is a convenient way to associate external files automatically with your GWT module. All injected resources must be placed in the com\mycompany\project\public directory, which defines the GWT Web server root.

AW.Grid.Control.create is a script ready-function that returns true when the grid-control script is known to be initialized. The ready-function's purpose is to determine unambiguously that the script is fully loaded so that your GWT code can use it and be sure the referenced identifiers are available. In the example in Listing 1, the existence of the AW.Grid.Control.create function indicates that the script is ready. This function is part of the control's library and as an external resource, it must be prefixed with $wnd.



Back to top


JavaScript Native Interface to the rescue

Integration of the JavaScript grid control itself is based on GWT's implementation of the JavaScript Native Interface (JSNI), a powerful feature that lets you include JavaScript code in Java source code. Listing 2 shows how the JavaScript grid control is instantiated and initialized via JSNI:


Listing 2. Grid control initialization (fragment)
                

native JavaScriptObject init(JavaScriptObject myColumns,JavaScriptObject myData)/*-{
  try{
    $wnd.mygrid = new $wnd.AW.UI.Grid;
    $wnd.mygrid.setSize(750, 350);

    // provide cells and headers text
    $wnd.mygrid.setCellText(myData);
    $wnd.mygrid.setHeaderText(myColumns);

    // set number of rows/columns
    $wnd.mygrid.setRowCount(myData.length);
    $wnd.mygrid.setColumnCount(myColumns.length);
    ...
    $doc.getElementById('mygrid').innerHTML = $wnd.mygrid;

    return $wnd.mygrid;
  }
  catch(e){
    $wnd.alert(e.description);
  }

  return null;

}-*/;

JSNI can be considered the Web equivalent of inline assembly code. You can use it to:

  • Implement a Java method directly in JavaScript.
  • Wrap type-safe Java method signatures around existing JavaScript.
  • Call from JavaScript into Java code and vice versa.
  • Throw exceptions across Java/JavaScript boundaries.
  • Read and write Java fields from JavaScript.
  • Use hosted mode to debug both Java source (with a Java debugger) and JavaScript (with a script debugger).

The GWT development documentation warns that JSNI must be used with discretion because browser portability isn't guaranteed, and the compiled code optimization is restrictive. In the case of commercial controls, you can rely on the vendors' commitment to supporting multiple browser types and deployment platforms.

When you access the browser's window and document objects from JSNI, you must reference them as $wnd and $doc, respectively. Your compiled script runs in a nested frame, and $wnd and $doc are automatically initialized to refer correctly to the host page's window and document.

The sample code demonstrates a useful technique, using JSNI for converting one- and two-dimensional Java string arrays into JavaScript arrays to populate a grid with data, as shown in Listing 3:


Listing 3. Java-to-JavaScript array transformation
                
public static JavaScriptObject arrayConvert(String[] array) { 
    JavaScriptObject result = newJSArray(array.length); 
    for (int i = 0; i<array.length; i++) { 
      arraySet(result, i, array[i]); 
    } 
    return result; 
} 

private static native JavaScriptObject newJSArray(int length) /*-{ 
    return new Array(length);  
}-*/; 

public static native int arrayLength(JavaScriptObject array) /*-{ 
    return array.length; 
}-*/; 

public static native String arrayGetObject(JavaScriptObject array, int index) /*-{ 
    return array[index]; 
}-*/; 

public static native void arraySet(JavaScriptObject array,int index,String value) /*-{ 
    array[index] = value; 
}-*/;



Back to top


Processing events

Event handlers defined in the JavaScript can be associated with methods implemented in your Java code. Listing 4 demonstrates how the grid control's onRowClicked event invokes the onRowSelect Java function:


Listing 4. Java function invocation from JavaScript
                
public void onRowSelect(String index){
  GWT.log("Row #" + index + "selected", null);
}

native JavaScriptObject init(JavaScriptObject myColumns, JavaScriptObject myData)/*-{
  var widget = this;
  
  try{
      ... 
      // set click action handler
      $wnd.mygrid.onRowClicked = function(event, index){

widget.@com.mycompany.project.client.GwtGrid::onRowSelect(Ljava/lang/String;)(index);
      };

      ...
 }
 catch(e){
  $wnd.alert(e.description);
 }
}-*/;

You must reference Java methods in JavaScript using the following notation: instance-expr.@class-name::method-name(param-signature)(arguments)

  • instance-expr. must be present when you call an instance method and must be absent when you call a static method.
  • class-name is the fully qualified name of the class in which the method is declared (or a subclass thereof).
  • param-signature is the internal Java method signature as specified here but without the trailing signature of the method return type (because it isn't needed to choose the overload).
  • arguments is the actual argument list to pass to the called method.


Back to top


Using the JavaScript control API

As you can see from Listing 2, the init method of the implementation's Java class returns JavaScriptObject, which represents a grid instance. You can store it as a class attribute and reference it later in the code to invoke JavaScript control API methods. Listing 5 shows how a Delete button click event is processed in Java code:


Listing 5. JavaScript method invocation
                
protected JavaScriptObject grid = null;

...

public void onLoad(){
  if(grid == null){
    grid = init(...);
  }
}

public void onDeleteButtonClick(){
  delete(grid, getCurrentRow(grid));
}


public native void delete(JavaScriptObject obj, int index) /*-{

 try{
    obj.deleteRow(index);
 }
 catch(e){
    $wnd.alert(e.description);
 }

}-*/;	

public native int getCurrentRow(JavaScriptObject obj) /*-{
 
  try{
    return obj.getCurrentRow();
  }
  catch(e){
    $wnd.alert(e.description);
  }

  return -1;

}-*/;

In Listing 5, a Java event handler calls JavaScript control API methods. This demonstrates the ability to interact with the control instance. You can define similar Java wrappers for all JavaScript control API methods and make them available to the GWT world.



Back to top


Runtime configuration

The demo application requires that you install the GWT SDK on your system. To run the sample code, simply unzip the downloaded archive with sources and compiled scripts into the GWT SDK distribution directory's samples folder. If you can run GWT samples, you can launch the sample application with following command (on Windows platforms):

                your_local_path\gwt-windows-1.3.3\samples\GridDemo\GridDemo-shell.cmd

The sample GWT application demonstrates integration of the commercial JavaScript grid component developed by ActiveWidgets and offered for evaluation download at company's Web site (see Resources). Figure 1 shows the result:


Figure 1. Advanced grid control in sample GWT application
Grid control in action

The demo application archive contains all required libraries except GWT. I've tested it with all major GWT releases, including version 1.3.



Back to top


Conclusion

This article presents an example of how to integrate legacy JavaScript grid controls with GWT applications. You can use the same approach for other advanced controls available on the market. As an alternative to commercial JavaScript controls, check out the Yahoo! User Interface Library, an open source set of JavaScript utilities and controls for building richly interactive Web applications using techniques such as DOM scripting, DHTML, and Ajax (see Resources).




Back to top


Download

DescriptionNameSizeDownload method
Sample GWT applicationj-gwtcontrols.zip503KBHTTP
Information about download methods


Resources

Learn

Get products and technologies

Discuss


About the author

Sergey Odobetskiy is a software development consultant specializing in Java and Web technologies. He has recently been involved in several telecom projects at Rogers Communications and is currently working in Toronto with ConceptWave Software Inc. on a telecom order-care product.




Rate this page


Please take a moment to complete this form to help us better serve you.



YesNoDon't know
 


 


12345
Not
useful
Extremely
useful
 


Back to top


Java and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both. Other company, product, or service names may be trademarks or service marks of others.