Editor's note: IBM® WebSphere® sMash and IBM WebSphere sMash Developer Edition are based on the highly acclaimed Project Zero incubator project. Project Zero is the development community for WebSphere sMash and will continue to offer developers a cost-free platform for developing applications with the latest builds, the latest features, and the support of the community.
This article assumes that you have downloaded Project Zero M4 and used it to create one or more applications. You will need a basic understanding of Groovy scripting, Ajax techniques, and HTML, all of which are demonstrated in Zero's tutorials and samples. For links to introductory material on Project Zero and related technologies, check out the Resources section.
Introduction: The Google Charts API
Google Charts is a neat service that lets developers generate charts and graphs using a simple HTTP GET request. Clients send requests to http://chart.apis.google.com/chart along with one or more query parameters indicating the type of chart they want; a complete list of these query parameters is provided in the Google Charts API documentation (see Resources). Currently, the API allows for control of a broad range of attributes, including a chart's title, layout, colors, axes, data, and legends. Figure 1 is a simple example of the API in action.
Figure 1. Sample chart: (Source: Google.com)
If you right-click on the image and select Properties, you can see the URL that was used to generate the chart. I will cover the specific roles of the query string parameters in future sections. The important thing to take away from this inspection is that the query parameter names are rather trite, and when you combine them all into one URL, the result is long and cumbersome. In the next section, you'll start to encapsulate these complex URLs with some Groovy code running on Project Zero.
Exposing a more RESTful charts API
It's nice to be able to create charts in a browser using only the address bar, but as noted in the Introduction, this could actually be quite tedious. Being able to create a chart in the address bar might seem useful from a non-developer's perspective, but once beyond the point of simple examples, the URLs are simply too long. A better design approach would be to expose chart creation with HTTP POST and JSON (for developers) and provide a graphical interface on top of it (for non-developers). This would make it easier for both sets of users to debug problems with their chart layout or data. You can implement this approach with Project Zero by encapsulating chart URL creation in a Groovy script and then making an Ajax-based Web interface that invokes that script via HTTP.
To show off your work, you will need to create two projects: one to hold your
Groovy wrapper code and one to hold your sample Ajax UI. You should create two
Zero applications—one named zero.charts
and one named chart.maker
—to hold the Groovy code and Ajax code, respectively. The two projects were kept separate so that the Groovy code can be easily reused by different applications. You'll start your work in the zero.charts application.
Generating chart URLs in Groovy
The first step towards simplifying chart creation with Groovy is to define the data structure(s) used to specify chart details. Instead of the original parameter names used by Google Charts, you will define a more verbose data structure with JSON; the use of JSON means you can rely on normal data types (for example, an actual array of integers instead of a string with serialized integers delimited by commas) and make it easier to see what values are being passed to the chart generator. Listing 1 shows the data structure you'll use to communicate between Ajax clients and your Groovy script.
Listing 1. Sample chart definition with JSON
{
title: "Sales for 1H 2008",
type: "bvg",
height: 300,
width: 300,
data: [34, 21, 28, 19, 48, 40],
xaxis: ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
yaxis: [0, 40]
}
|
A JSON object like the one shown in Listing 1 can be inspected during development time using tools like FireBug or simple JavaScript alerts. This will be much easier to debug and validate than a long string such as http://chart.apis.google.com/chart?cht=bvg&chs=500x600&chtt=Sales%20for%201Q%202008&chd=t:134,219,188&chxt=x,y&chxl=0:|Jan|Feb|Mar|1:||300.
Of course, when all is said and done, you still need to send such a URL to Google's server to get the desired chart. To do that, you will write a simple Groovy method that copies the field values in a JSON object into a chart URL. With the help of Groovy's GString type, you can make the URL string on one line, without creating a java.lang.StringBuilder and appending values piece by piece. The code for this Groovy method is shown in Listing 2.
Listing 2. Groovy code for chart URL construction
def create(chart)
{
return "http://chart.apis.google.com/chart?chxt=x,y" +
"&cht=${chart.type}&chs=${chart.width}x${chart.height}" +
"&chtt=${chart.title}&chd=t:${chart.data.join(',')}" +
"&chxl=0:|${chart.xaxis.join('|')}|1:|${chart.yaxis.join('|')}";
}
|
For the most part, the code in Listing 2 takes values directly from a JSON object and embeds them (using the $ syntax) in the URL. The only places where this is not the case is where the JSON fields are arrays, which must have their values concatenated into a single string. You can do this easily with the join() method.
You should copy the code from Listing 2 into a file named
/zero.charts/app/scripts/charts.groovy. By putting the code in the /app/scripts
directory, you are making it available to all other Groovy scripts in the
application, as well as to any applications that include zero.charts in their list
of dependencies. The final step towards making the code easily reusable is to
create a Groovy binding for it; this will allow developers to invoke the create() method from their code directly without using Zero's more
generic
invokeMethod()
. To add the Groovy binding,
copy the Java™ class definition in Listing 3 into the /zero.charts/java directory. The line in bold is what developers would have to type if you did not provide this binding.
Listing 3. Groovy bindings for charts.groovy
package zero.charts;
import java.io.FileNotFoundException;
import java.util.Map;
import org.codehaus.groovy.runtime.MethodClosure;
import zero.core.groovysupport.bindings.InvokeBindings;
public class ChartsBindings extends InvokeBindings
{
public void addVariables(Map<String, Object> variables)
{
super.addVariables(variables);
variables.put("create", new MethodClosure(this, "create"));
}
public Object create(Map<String, Object> chart)
throws FileNotFoundException, NoSuchMethodException
{
return invokeMethod("charts.groovy", "create", new Object[]{ chart });
}
}
|
Before we move on, take note that the type of the parameter that you're passing to create() in Listing 3 is a java.util.Map. In Zero, JSON objects and Maps are the same thing. All of Zero's I/O APIs know how to serialize a Map to and from JSON when appropriate, so you don't need to learn a special API just to manipulate JSON objects.
As soon as the Java class from Listing 3 is in place, you just have to let Zero know it exists by registering it in the configuration file. Listing 4 has the text that must be added to /zero.charts/config/zero.config to ensure that your Groovy binding works and calls to create() are resolved properly.
Listing 4. Configuration for Groovy binding
/config/bindings/.groovy += ["zero.charts.ChartsBindings"]
|
Request charts through HTTP POST
Now that you have your URL construction code in place, you just need to expose it
with a RESTful API. You will do that by creating a RESTful resource type called charts and using the HTTP POST method to accept chart specifications (in JSON) and return chart URLs. This behavior is slightly different than what is normally implemented in a RESTful application. Normally, an HTTP POST results in the execution of code that creates a resource in the same domain as the request URI and returns a URI for that new resource. You will be "creating" a resource by constructing a URI that points to the Google Charts service, and when clients follow that URI, they will get their chart. Thus, the only thing that is really created and returned by your service is a chart URI in the Location header of the HTTP response.
Listing 5 has the Groovy code for the charts resource. Its only HTTP method is POST, which is implemented in the onCreate() method. You should copy this code into a file named /zero.charts/app/resources/charts.groovy.
Listing 5. REST API for chart creation
import zero.json.Json;
/**
*
* @success 201 Returns the URI for the desired chart in the Location header.
* @error 500 The chart definition in the request body was not valid JSON.
* @format application/json
*
*/
def onCreate()
{
def chart = Json.decode(request.input[]);
def chartImageURL = create(chart);
request.headers.out.Location = chartImageURL;
request.status = 201;
}
|
Before we move on to the user interface, take a moment to test the REST API using
the RESTdoc test interface. Start the zero.charts application (zero run) and go to http://localhost:8080/resources/docs/charts in
your Web browser. You will see that the charts resource
has one method (POST), and if you click on it, you will be presented with a test
form (see Figure 2). Copy the JSON data from Listing 1 into the request body and click Send. The response you see should include a Location header that has a Google Charts URI.
Figure 2. RESTdoc test form for chart creation
With the REST API in place, you're now ready to use it in an application. The next section will show how to use Ajax to create a visual chart builder.
Designing a more helpful interface
Your REST API might make it easier for developers to generate charts, but that
doesn't help the 99% of computer users who don't code but who occasionally create charts and graphs for their documents and presentations. For those users, you can make a simple Web-based chart builder with an HTML form, a little JavaScript, and the simplest of Ajax APIs, XMLHttpRequest. Figure 3 shows what the end result will be: One side of the Web page allows the user to enter the chart description while the other shows the generated chart.
Figure 3. Web interface for chart generation
To get started on the user interface, you must first create a dependency between the chart.maker application and the zero.charts application. You can do this by adding zero:zero.charts to /chart.maker/config/ivy.xml. The next two sections will show the most important parts of the markup and code that are required for the interface. You can see the complete markup and code by downloading the sample projects included with this article and looking at the chart.maker project.
Mapping user input to API input
As you can see from Figure 3, the form needed to get the user's chart specification is fairly simple. With the exception of one input value, everything on the form can be converted into the required JSON format rather easily. The only input that requires an extra step is the chart type, which is represented by the Google Charts API using two- or three-letter abbreviations. The form shows the full description of the chart types (Line Graph, Bar Chart - Vertical, and Bar Chart - Horizontal), so your HTML drop-down menu needs to map between these descriptions and the abbreviations (lc, bvg, and bhg, respectively). Listing 6 shows the definition of the HTML drop-down menu that you need; you can see the chart type codes in bold. All of the other form inputs are simple text boxes (<input type="text"/>)
Listing 6. HTML drop-down menu for chart types
<select id="chartType">
<option value="lc">Line Graph</option>
<option value="bvg">Bar Graph - Vertical</option>
<option value="bhg">Bar Graph - Horizontal</option>
</select>
|
In addition to the drop-down menu markup, some code is also provided to retrieve
the selected value from the menu for those that aren't as familiar with this
control. Unlike simple text boxes, you can't just read the value property of the control—you must iterate over the drop-down menu's options until you find the one that is currently selected. Listing 7 has the code that you'll need to do this.
Listing 7. JavaScript for finding selected chart type
function getSelection(elementName)
{
var select = document.getElementById(elementName);
for (var i = 0; i < select.options.length; i++)
if (select.options[i].selected)
return select.options[i].value;
return null;
}
|
Another important UI element is the Create It! button that appears at the bottom of the form. Rather than have this button cause a form submission, you are going to link it to a JavaScript function that makes an Ajax request to your REST API. To do this, you just need to add a JavaScript function call to the button's onClick event. Listing 8 shows the button click linked to a function named createChart(), which you will implement in the next section.
Listing 8. Initiating chart creation with JavaScript
<input type="button" value="Create It!" onClick="createChart();"/>
|
The last UI element to cover in detail is the image that shows the generated charts. Listing 9 shows how to write an HTML <img/> tag that is hidden when the page loads. You will use JavaScript to set the source of the tag to the generated chart's URL and then make it visible.
Listing 9. HTML image for chart display
<img id="chartImage" style="display:none;" src=""/>
|
You should look at the /public/index.html file in the chart.maker sample project to see all of these pieces of markup and code together. The next section will cover the Ajax-oriented JavaScript (also included in the file) that manipulates the UI elements to show the charts that reflect the user's input.
Displaying generated charts with Ajax
Interacting with your REST API is a matter of implementing the createCharts() function so that it reads all the form input values, packages them in a JSON object, and sends that JSON object as part of an HTTP POST request to your charts resource. Once the HTTP POST request is complete, you will read the chart URL from the Location response header and (re)set the source of the chart image. Listing 10 shows the code to do just that.
Listing 10. Chart creation and display with Ajax
function getHttpClient()
{
var hasXHR = window.XMLHttpRequest;
return hasXHR ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
}
function createChart()
{
// step 1
var chart = {
title: getValue("chartTitle"),
type: getSelection("chartType"),
height: getValue("chartHeight"),
width: getValue("chartWidth"),
data: getValues("chartData"),
xaxis: getValues("xaxis"),
yaxis: getValues("yaxis")
};
// step 2
var http = getHttpClient();
http.open("POST", "/resources/charts", true);
// step 3
http.onreadystatechange = function() {
if (http.readyState != 4)
return;
var chartImage = document.getElementById("chartImage");
chartImage.src = http.getResponseHeader("Location");
chartImage.style.display = "block";
}
// step 4
http.send(JSON.stringify(chart));
}
|
Let's walk through this code step-by-step:
The first thing that you do in createCharts() is to
create a JSON object with the proper name-value pairs. The getValue(s) methods are simple utilities similar to the getSelection() method in Listing 7. Their implementations are rather trivial, and you can see them by looking through the sample project. The important thing to note here is that the field names match what is expected by the /app/scripts/charts.groovy file and the values are in the proper format.
The second step is to create an XMLHttpRequest object and start an HTTP POST request to /resources/charts. The getHttpClient() method hides the conditionals that make sure to instantiate the right class for the right Web browser.
The third step is to define what happens after the request is sent and the response is received. In this case, you will take the value of the Location header and use it to set the value of chartImage.src; you then alter the chartImage style so that it is no longer hidden from the user.
The last step is to send the HTTP POST request. This involves converting the JSON object into a string that can be put in the HTTP POST request body. Because there is no standard JSON-to-string API, an open source library from http://json.org has been used. The JSON.stringify() API call that you see at the end of createChart() is defined in a file called json2.js, which can be obtained from http://www.json.org/json2.js. You should download this JavaScript library from http://json.org and add it to the /chart.maker/public directory. Once the library is in place, the last line of createCharts() will run without issues.
You have seen how to create a slick mashup application and, in the process, make the Google Charts API more easily reusable across your Zero applications. The sample Ajax interface only touched on the basic features that are possible in a visual chart builder, but your server-side code can support any other features that you want to add on. Once again, Zero's integration of Groovy scripting has proven to be a huge time saver when it comes to putting RESTful APIs in front of valuable services and data.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample application for this article | zero-chart-maker.zip | 7KB | HTTP |
Information about download methods
Learn
-
Learn what the Google Charts API has to offer.
-
Need an introduction to Project Zero? Take a look at "Get started with Project Zero and PHP" (developerWorks, updated January 2008).
-
The developerWorks Ajax resource center is packed with tools, code, and information to get you started developing slick Ajax applications today.
- With Web 2.0 being a hot area within development
circles, you'll find an ever-growing collection of resources in the Web development zone.
- Need to get up to speed on PHP? Take a look at our
PHP area.
-
The developerWorks Project Zero space is packed with resources to get you started developing with Project Zero now.
-
You'll find a nicely growing library of Project Zero content here on developerWorks.
Get products and technologies
-
Download Project Zero M4 to re-create the projects illustrated in this article.
Discuss
-
Participate in the projectzero.org discussion forum.
-
developerWorks
blogs: Get involved in the developerWorks community.

Dan Jemiolo is an Advisory Software Engineer on IBM's Project Zero team in Research Triangle Park, NC. He is currently working on reusable components for the Zero platform and its service catalog. His previous work includes the design and development of Apache Muse 2.0 and participation in OASIS Web services standards bodies. Dan came to IBM after earning his Master of Science degree in Computer Science from Rensselaer Polytechnic Institute.
Comments (Undergoing maintenance)





