Comment lines: Combining Dojo and JAX-RS to create a RESTful service

JAX-RS (JSR 311) is an API that enables fast and easy creation of RESTful services. Combine JAX-RS with the Dojo JavaScript™ library and you have a powerful way to create Ajax-style RESTful architectures. The article illustrates the combination of JAX-RS and Dojo by creating a sample service to display file system information. This content is part of the IBM WebSphere Developer Technical Journal.

Share:

Kevin Haverlock (kbh@us.ibm.com), Software Development, IBM

Author photoKevin Haverlock is a software engineer for IBM in Research Triangle Park, NC. He has worked on various portions of WebSphere Application Server dating back to 5.0. His most recent assignment was the Web 2.0 Feature Pack for WebSphere. Kevin is currently working on web development tooling to help customers enhance their serviceability of WebSphere Application Server.


developerWorks Contributing author
        level

14 July 2010

Also available in Chinese

Easy implementation on both client and server

The latest release of the IBM® WebSphere® Application Server Feature Pack for Web 2.0, gives you an end-to-end solution for creating Ajax style architectures. On the client side, the feature pack provides the open source Dojo JavaScript toolkit. With the latest release of the feature pack, JAX-RS (based on the Apache Wink project) provides server-side libraries that can be used to implement RESTful services to which Dojo can connect.

Along with the extensive set of user interface widgets, Dojo provides a rich set of data service APIs that can easily connect to server-side Web services. The Dojo data APIs abstract the concept of unique data formats from the widgets that display the user interface. Dojo data provides basic data stores for reading JSON data, along with other formats such as XMLStore, CsvStore and many more. For example, if you wanted to use Dojo's tree widget, then you would select the data store you want to use and the data store takes care of the data handling services for the tree widget.

Dojo's data stores easily connect to RESTful services, which is where JAX-RS comes in. The Apache Wink implementation of JAX-RS enables the easy creation of your own customized Web service. Therefore, if you wanted to, say, use Dojo's tree widget to display a customized view of a directory structure on the server, you would need to implement the protocol Dojo uses to describe the representation of a file system. While Dojo provides you the client-side services, you would need to write the server side implementation. JAX-RS helps to make the server implementation straightforward.


An example

Let’s illustrate this with an example. Figure 1 shows the interaction between the server and the client. In this case, you are displaying the initial FIFA World Cup Soccer groups in a directory format. You are taking the directory structure represented on the server and creating a tree representation on the client. On the left, diji.Tree is the Dojo UI widget being used to display directory information contained on the server. Dijit.Tree relies upon dijt.tree.ForestStoreModel and dojox.data.FileStore. The dijit.tree.ForestStoreModel is a mapping layer between the data returned from dojox.data.FileStore. The ForestStoreModel handles creating a dummy root node called "Files" which contains the directory listing and handles putting everything under a root node. The dojox.data.FileStore handles opening the connection to the server’s RESTful service which is implemented with JAX-RS.

The server side runs a RESTful service that implements the rest/filestore/filelist request. The JAX-RS service reads the HTTP GET request from the dojox.data.FilesStore and returns the data in JSON format to the dojo.data.FileStore. The format in which the data is returned is JSON, which the dojox.data.FileStore supports.

Figure 1. RESTful interaction between server and client
Figure 1. RESTful interaction between server and client

Let’s look at the JSON data attributes returned by the server. In Figure 1, the JSON data format returned to the server is shown:

  • path represents the current directory.
  • modified contains data concerning when the directory was last modified.
  • size indicates the directory’s size on the file system.
  • name is the display name of the directory.
  • children is a JSON array that contains the names of the child directories that are part of the current parent.

It’s worth noting that in this instance a lazy loading model is being used. Lazy loading means only the directory the user is currently navigating is returned. Lazy loading is more efficient because you are only requesting the data that needs to be displayed.


Client side implementation

Taking a closer look at an implementation design, Listing 1 shows part of the client side code listing for an HTML page that uses Dojo. The code uses the three JavaScript classes provided by Dojo: dijit.Tree, dijit.tree.ForestStoreModel, and dojox.data.FileStore.

Listing 1
<body class="soria">
  <div dojoType="dojox.data.FileStore" jsId="countryStore"   
       url="rest/filestore/filelist" pathAsQueryParam="true"></div>
  <div dojoType="dijit.tree.ForestStoreModel" jsId="countryModel"     
       store="countryStore" rootId="myfiles" rootLabel="Files"  
       childrenAttrs="children">
  </div>
  <div dojoType="dijit.Tree" id="mytree" model="countryModel" ></div>
  </body>

In this code, the dojox.data.FileStore provides a lightweight JavaScript implementation for reading file information from a file system. The implementation provides information such as file size, last modified data, if the entry is a directory and, if so, what children are in the directory. The URL parameter for dojox.data.FileStore is the location of the rest service. The pathAsQueryParam parameter enables you to either provide a URL query parameter containing the path to the file or directory, or include the path as part of the URL request, if the value is set to false.

The dijit.tree.ForestStoreModel in Listing 1 connects a root node with multiple root items in a diji.tree. For example, the dijit.tree.ForestStoreModel enables you to show the directory under another root node called "Files," as shown in Figure 1. The dijit.tree.ForrestStoreModel provides parameters to set a rootId that can be used to query for the root node in your JavaScript code. Additionally, a rootLabel can be set which contains the text label that should be displayed. The childrenAttrs parameter specifies what the attribute for child items should be named. If you recall from Figure 1, the JSON data contains an array for the children. The childrenAttrs parameter gives you flexibility as to how the attribute should be named.

Finally, dijit.Tree is the UI widget that will display the tree. The parameters include the name of the model along with the JavaScript ID for the tree.


Server side implementation

With the browser side client implementation complete, let’s look at an example of a JAX-RS back end implementation. The dojox.data.FileStore has a protocol implementation that enables the data store to understand the JSON content that is received back from the server. Along with JAX-RS, you are also using a helper utility library provided with the Web 2.0 feature pack called JSON4J. The JSON4J library provides a set of classes for easily constructing JSON data formats.

Let’s look at the WorldCupGroup class and it’s two methods shown in Listing 3.0. JAX-RS uses annotations to cut down on the amount of boiler plate code and provides a short hand notation. Listing 2 shows the class definition.

Listing 2
 @Path("/filestore")
public class WorldCupGroup { … }  

Listing 3
@GET 
@Path("filelist")
@Produces(MediaType.APPLICATION_JSON) 
// returns a list of files in JSON format that match the request  
public JSONObject getFileList(@QueryParam("path") String path) {

In this case, @Path value is relative to the URI path. For example, in the RESTful service request defined in Listing 3 for /rest/filestore/filelist, the /filestore/ represents the PATH URI to the RESTful service.

Listing 3 defines the method to be invoked for your RESTful service. The @GET defines the HTTP GET method and @PATH further refines the URI to something more specific; in this case, /rest/filestore/filelist. The @Produces defines the MIME media type that will be returned; in this case, the method returns JSON data that translates into a MIME type of application/json, which is what Dojo’s dojo.data.FileStore expects. The @QueryParam is used by JAX-RS to tell what query parameter value to pass to the getFileList method. For example, in the HTTP GET request in Listing 4, the @QueryParam(“path”) value would be C://artifactstore//FIFA World Cup Group.

Listing 4
GET http://localhost:8080/rest/filestore/filelist?path=C://artifactstore//FIFA World 
Cup Group

Other parts of the code contain information for constructing the JSON data stream that describes the file system. For example, the createFileItem method reads information from the file system and constructs a JSON object that is later returned to the dojox.data.FileStore. Listing 5 shows the complete code for the server server-side implementation.

Listing 5
package com.example.filestore;

import java.io.File;
import java.io.IOException;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;

import com.ibm.json.java.JSONArray;
import com.ibm.json.java.JSONObject;

@Path("/filestore")
public class FIFAWorldCup {   
  public static final String ROOT_DIR = "C:\\artifactstore\\";	
	
  // returns a list of files in JSON format that match the request	
  @GET 
  @Path("filelist")
  @Produces(MediaType.APPLICATION_JSON)   
  public JSONObject getFileList(@QueryParam("path") String path) {
	   
    JSONObject ret     = new JSONObject();
    JSONArray filelist = new JSONArray();
    JSONObject items   = new JSONObject();
	   
    if (path == null) {
      path=this.ROOT_DIR;
    }
     

   /** Method to construct a JSONObject representing the File 
    *  as a DataStore item.
    *
    * @param file The file contained within rootDir to reference.
    *
    * @return JSONObject of the file, or null if file was null or not 
    * contained within the root path of the FileStore.
    */
   private JSONObject createFileItem(String parent,File file) throws
                                                       IOException {
    JSONObject item = new JSONObject();
    if (parent != null && file != null) {           
      String filePath = file.getAbsolutePath();
           
      //Make sure the request is contained within the root directory           
      if (filePath.startsWith(this.ROOT_DIR)){
        item.put("name", file.getName());
        item.put("modified", new Long(file.lastModified()));
        item.put("size", new Long(file.length()));
        item.put("path", filePath);
        item.put("directory", new Boolean(file.isDirectory()));	
        // if this is a directory, then add the children
        if (file.isDirectory()) {               	
          File[] child = file.listFiles();                    
          JSONArray children = new JSONArray();
          if (child.length > 0) {  
            for (int j = 0; j < child.length; j++) {              	 
              children.add(child[j].getName());                         
              item.put("children", children);
            }
          }      
          else { 
           // since this directory has no children, place an empty child
           item.put("children",children);
          }
        }
      }
    }
    return item;
   }
} // end of class definition

Conclusion

The latest version of the IBM WebSphere Application Server Feature Pack for Web 2.0 provides the libraries necessary to create end-to-end RESTful services. On the client side, you have a powerful open source JavaScript toolkit in the form of Dojo. For the server-side implementation, you have the JAX-RS library based on the Apache Wink project. The code provided here represents a simple sample back end implementation for dojox.data.FileStore. Additional protocol implementation can be added, such as querying and user defined options that might be unique to your own data. See the Resources below for a list of helpful links to get you on your way to creating RESTful services using Dojo and JAX-RS.

Resources

Learn

Get products and technologies

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere, Web development
ArticleID=500172
ArticleTitle=Comment lines: Combining Dojo and JAX-RS to create a RESTful service
publish-date=07142010