Build a pureXML and JSON application, Part 3: Create OpenSocial gadgets for pureXML

Define, deploy, and test OpenSocial gadgets to interact with JSON Universal Services

With the Web 2.0 technology of OpenSocial gadgets, developers can easily include their applications in popular Web sites, such as iGoogle, MySpace, Hi5, LinkedIn, and others. In this article, explore OpenSocial gadgets through hands-on construction of an application that leverages the pureXML® capability of DB2®. This article is the last in a series of three that illustrates how to build a pureXML application whose user interface is a gadget that you can deploy in any OpenSocial compliant Web site. Follow the steps in this article to build a user interface that stores and retrieves the JSON data described in the first article through JSON Universal Services created in the second article.

Han Nguyen (hnguy@us.ibm.com), Staff Software Engineer, IBM

Photo of Han NguyenHan Nguyen is a software engineer working on emerging standards with a focus on Social Computing across various industry verticals and products. She has previously worked on several technologies both in the services and software enablement.



Andy Smith (andybs@us.ibm.com), Advisory Software Engineer, IBM

Photo of Andy SmithAndy Smith is a software engineer working on emerging standards with a focus on the application of Social Networking related technologies across various industry verticals and products. He has previously worked on various Web and portal technologies both in the services and software enablement.



Mark Weitzel (weitzelm@us.ibm.com), Software Architect, IBM

Photo of Mark WeitzelMark Weitzel is a Senior Technical Staff Member in IBM Software Group Emerging Standards and Open Source team focusing on social networking. Prior to this, Mr. Weitzel, as part of Tivoli Autonomic Computing team, was responsible for several open source systems management initiatives at Eclipse and Apache.



10 November 2009

Also available in Russian Japanese Vietnamese Portuguese Spanish

Background on OpenSocial

OpenSocial is a community-driven specification that defines a browser-based component model, known as gadgets, and an API for accessing information about users' profile information, as well as their social graph (including things such as their friends and activities). Applications implementing the APIs will be interoperable with a broad set of social networking sites such as: iGoogle, MySpace, Yahoo, Orkut, Hi5, LinkedIn, and others. In this article, we will focus on OpenSocial gadgets and show how they can be a powerful way to extend the reach of your application across the Web.

Frequently used terms

  • API: Application programming interface
  • CSS: Cascading stylesheets
  • HTML: HyperText Markup Language
  • HTTP: Hypertext Transfer Protocol
  • JSON: JavaScript Object Notation
  • SOA: Service Oriented Architecture
  • UI: User interface
  • URL: Uniform Resource Locator
  • XML: Extensible Markup Language

What is an OpenSocial gadget?

  • An OpenSocial gadget is the small presentation of a Web application that implements a specific set of APIs. A gadget is described by an XML document that conforms to the OpenSocial specification. This definition contains the user interface such as HTML, CSS stylesheets, and JavaScript for the business logic, and additional metatdata for the author, title, and so on.
  • A site that implements the OpenSocial specification and can host applications is called an OpenSocial container. This means that it can process the gadget XML definitions, and serve up the proper HTML to the browser. It's important to realize that the gadget definitions are not required to be hosted on the site that provides the container. Further, gadgets typically expose a service from a completely different site. The container provides mechanisms, such as signed HTML requests, to provide a level of assurance that the calls originated from the gadget in its site. By being an OpenSocial container, a site can provide an easy way to aggregate a collection of services from across the Web.

Create the gadget

This page provides the user a facility to test the basic set of functions provided by the Universal Services and displays the results to the user.

Figure 1 is a screen capture of the sample test application. This will serve as the template you use to build the sample OpenSocial gadget. This provides the user with the basic UI capabilities required to interact with the Universal Services.

Figure 1. The sample test application
Sample test application to capture user inputs with a list of Web services, input, and actions

First, you will create a few JavaScript functions to provide the basic queries that control the connections to the pureXML services. Then you will add the supporting HTML along with the gadget specification. Finally, you see how to create and deploy this application.

JavaScript functions to connect to pureXML services

Listing 1 provides the sample JavaScript that was created to handle the requests.

Listing 1. PureJSON JavaScript functions
var prefs = new gadgets.Prefs();
function getPrimaryKeys()	{
	var args = {};
	doPOST("getPrimaryKeys",args,displayJSONobj);  
};
function getJSONDocumentByKey(key)	{
	var args = {
	  id: key
	};
	doPOST("getDocumentByKey",args,displayJSONobj);  
};
function insertJSON(key, data)	{
	var args = {
	  id: key,
	  doc: data
	};
	doPOST("insert",args,response);  
};
function updateJSON(key, data)	{
	var args = {
	  id : key,
	  doc : data
	};
    doPOST("update",args,response);    
};
function deleteDocument(key)	{
	var args = {
	  id : key
	};
    doPOST("delete",args,response);
};
function doPOST(command,args,processResponseCallback)	{
	var url = "http://" + prefs.getString("pureXMLHostAddress") + 
			"/" + prefs.getString("contextRoot") + "/query/"+command;
	var params = {};
	postdata = gadgets.io.encodeValues(args);
	params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.POST;
	params[gadgets.io.RequestParameters.POST_DATA]= postdata;
	gadgets.io.makeRequest(url, processResponseCallback, params);
};
function response(obj)	{
	alert("Gadget implementation responsibility.");
};
function displayJSONobj(obj)	{
	alert("Gadget implementation responsibility.");
};

Look at the purpose of each function:

  • getPrimaryKeys posts a getPrimaryKeys request to the service to retrieve all primary keys from the DB2 table and display the result using the callback function displayJSONobj when the transaction is completed.
  • getJSONDocumentByKey uses a key value to post a getDocumentByKey to the service to retrieve a single JSON record with the primary key matching the input value. It displays the result using the callback function displayJSONobj.
  • insertJSON expects two input parameters: the unique key value for primary key and the row data in JSON format. It posts a request to the service to create a new row in the DB2 table, and confirms the insert status when the transaction returns using the callback function response.
  • updateJSON provides the capability to post a request to the service to update a JSON record with the primary key matching the input key value, and the updated data specified as the input data in JSON format. It will also invoke the callback function response to confirm the update when the transaction completes.
  • deleteDocument provides the interface to post a remove record request to the service based on the specified input primary key. It also invokes the response callback function to confirm the deletion after the request completes.
  • displayJSONobj is an abstract JavaScript function that provides a hook for developers to provide different approaches to rendering the results of the call in the browser.
  • response is a function that handles return values that are not JSON. It follows a similar strategy as displayJSONobj by expecting developers to override the function with their own implementation.

The above functions call the doPOST function to submit their requests. The doPOST function expects the service query command, query input values, and a callback function to process the result returned from the services. It uses these input parameters to build gadgets.io.makeRequest calls to the services. gadgets.io.makeRequest is an OpenSocial gadgets function which provides the support for gadgets to get data from and post data to third party sites. Its signature looks like this: gadgets.io.makeRequest(url, callback, opt_params)

The parameters are:

  • url - A string containing the URL of the site you want to send the request to. You can see that, to build the URL, the doPOST function retrieves two strings from the prefs object using the getString method. (The parameters, pureXMLHostAddress and contextRoot, refer to element names in the gadget definition, which we cover in the next section.) These two strings are concatenated with /query/ and the command (insert, getDocumentByKey, update, delete,and so on). For example, when the insertJSON() function invokes doPOST, the URL is:
    http://xmlim.watson.ibm.com:9080/JSONUniversalServices/query/insert
  • callback - A reference to a function that will be called when the request returns. For example, response is a callback function that displays the status of a transaction, and displayJSONobj is a callback function that displays the returned JSON object or a message if the object is empty.
  • opt_params - A JavaScript object containing additional parameters for the call (the HTTP method and the POST data). We set the HTTP method of the request to gadgets.io.MethodType.POST to indicate it is a POST method. We also pass the post data in the postdata object (specified as an object containing key/value pairs by using gadgets.io.encodeValues() to format the input args).

Save Listing 1 as PureJSON.js. You will build the gadget definition and load this file in the next step.

OpenSocial gadget definition

Now that you have the necessary JavaScript, you will create the gadget definition.

Create a gadget definition XML

You need a simple gadget definition. Listing 2 provides the sample gadget definition. Each gadget definition is enclosed in a <Module> tag. The <ModulePrefs> defines the basic information and features for the gadget.

Listing 2. The XML definition for the OpenSocial gadget
<?xml version="1.0" encoding="UTF-8"?>
<Module>
 <ModulePrefs title="Universal Services">
   <Require feature="opensocial-0.8"/>
   <Require feature="dynamic-height"/>
   <Require feature="minimessage"/>
 </ModulePrefs>
 <UserPref name="pureXMLHostAddress" 
 	  display_name="PureXML Host Address" 
 	  default_value="xmlim.watson.ibm.com:9080"/>
 <UserPref name="contextRoot" 
 	  display_name="Context Root" 
 	  default_value="JSONUniversalServices"/>

 <Content type="html">
 <![CDATA[
	<!-- Note: We will add more code and expand this section later  -->
  ]]>
 </Content>
</Module>

The first thing you'll notice in the gadget definition is the <title> attribute on the <ModulePrefs> element. You can specify attributes defining information for the gadget such as title, author, e-mail, and so on. For the purpose this demo, we'll use only the title attribute. It's important to note, however, that some containers require certain attributes to be provided for live deployment. You'll need to refer to the platform developer documentation for this information.

You'll also provide features that the gadget requires. The sample gadget will load the following features:

  • opensocial-0.8 - This gadget uses the OpenSocial version 0.8 implementation APIs and therefore it can be deployed on containers that support OpenSocial v0.8 specification.
  • dynamic-height - With this feature, the gadget developer has the ability to resize the gadget height as content is added or removed. This is invoked when you display or remove the DB2 transaction messages in the gadget.
  • minimessage - This feature provides a set of APIs to create and display messages to users within the gadget. We use minimessage to create DB2 transaction status messages in this example.

You also defined a set of user preferences (<UserPref>) to dynamically set the pureXML Universal Service endpoint and the context path of the application that the gadget will be deployed to. The defined <UserPref> elements are exposed as user input in the gadget interface when the gadget is rendered. The user can then edit and modify these settings appropriately. Note that the name attribute for these <UserPref> elements are the same names used in the JavaScript doPOST function in Listing 1 to get the strings used to construct the endpoint URL.

Fourth, the content section <Content> defines the content type of the gadget which is HTML. Within the CDATA (character data) section, you define the gadget content itself where an HTML table is created to capture user input, combined with minimessage, user preferences, and JavaScript functions to become a running gadget. You will expand this section in the next step to build a client connecting to the pureXML services.

Adding content to the gadget

Within the CDATA section of gadget definition described in the previous step, now add the sample HMTL table and JavaScript functions to capture user input and actions.

First, add the stylesheet used in the HTML table as in Listing 3.

Listing 3. The stylesheet used for the table
  <style type="text/css">
   table.layout {border:0; width:50%;}
   td.green {background-color:#BFFF80; 
      font-family:sans-serif, verdana;}      
   td.white {background-color:#FFFFFF; 
      font-family:sans-serif, verdana;}      
   th.green {background-color:#BFFF80; 
      font-family:sans-serif, verdana;}   
   th.white {background-color:#FFFFFF; 
      font-family:sans-serif, verdana;}   
   td.row-bright{background-color:#FFFFBF; 
      font-family:sans-serif, verdana; 
      text-align:center;}
   td.row-dark {background-color:#FFFF8C; 
      font-family:sans-serif, verdana; 
      text-align:center;}
   tr.row-bright {background-color:#FFFFBF; 
      font-family:sans-serif, verdana;}
   tr.row-dark {background-color:#FFFF8C; 
      font-family:sans-serif, verdana;}
   tr.empty {background-color:#FFFFFF; 
      height: 10px;}
   tr.empty-small {background-color:#FFFFFF; 
      height: 5px;}
  </style>

Second, include the JavaScript file, PureJSON.js from Listing 1. At the time the gadget is loaded, the PureJSON.js will be included on the page making all the POST request functions available to the HTML table actions.

Listing 4. Loading the JavaScript file
    <script type="text/javascript" src="./PureJSON.js"></script>

Third, add another <script> tag as in Listing 5. Each JavaScript function matches a user action declared in the HTML table (which you will define in the next section), and calls one of the functions defined in PureJSON.js from Listing 1. When this block of code is loaded, a minimessage object is created using new gadgets.MiniMessage(_MODULE_ID_). Function gadgets.util.registerOnLoadHandler(gadgets.window.adjustHeight), at the bottom of the tag, is called to register the gadget with the OpenSocial container, telling it to modify the frame to fit the gadget content at render time. Within this script tag, we also override response and displayJSONobj functions to display query result to users.

Listing 5. Adding gadget functions
    <script type="text/javascript" src="./PureJSON.js"></script>   

    <script type="text/javascript">

    var msg = new gadgets.MiniMessage(__MODULE_ID__);

    function displayJSONobj(obj)	{
      var str = "The returned record is empty, it might not exist";
      if(obj.text!=""){
      	str = obj.text;
      }
      msg.createDismissibleMessage(str);
      gadgets.window.adjustHeight();
    };

    function callGetJSONDoc()	{
      getJSONDocumentByKey(document.getElementById("key1").value);
    };

    function getJSONDocumentByKeyReturn(obj)	{
      var str = obj.text;
      msg.createDismissibleMessage(str);
      gadgets.window.adjustHeight();
    };

    function callInsertJSON()	{
      insertJSON(document.getElementById("key2").value,
         document.getElementById("document1").value);
    };

    function callUpdateJSON()	{
      updateJSON(document.getElementById("key3").value, 
         document.getElementById("document2").value);
    };
    
    function callDeleteDoc()	{
      deleteDocument(document.getElementById("key4").value);
    };
    
   function response(obj)	{
     var str = gadgets.json.parse(gadgets.util.unescapeString(obj.text));

  if(str.updateCount == 1){
    var successMsg = msg.createDismissibleMessage(
        "Received returned code = 1. Transaction successful!");
    successMsg.style.color = "green";
  }
  else	{
   var failMsg = msg.createDismissibleMessage(
    "Did not receive returned code = 1. Transaction may have failed!");
      failMsg.style.color = "red";
  }
  gadgets.window.adjustHeight();
 };

  gadgets.util.registerOnLoadHandler(gadgets.window.adjustHeight);

  </script>

Finally, add the HTML table to capture the user input and actions. Listing 6 shows the HTML code. Save the gadget definition as JSONclient.xml. The screen capture in Figure 1 is what the table looks like when it is rendered.

Listing 6. The HTML table
<table class="layout" cellspacing="2">
  <tr>
    <th class="green">Web Service</th>
    <th class="green" colspan="2">Input</th>
    <th class="green">Action</th>
  </tr>
  <tr class="row-bright">
    <td>getPrimaryKeys</td>
    <td colspan="2" align="center">none</td>
    <td align="center">
      <input type="submit" value="Invoke" onClick="getPrimaryKeys()"/>
    </td>
  </tr>
 <tr class="row-dark" >
  <td>getJSONDocumentByKey</td>
  <td align="right">ID:</td>
  <td align="center"><input type="text" id="key1" size="40" /></td>
  <td align="center">
   <input type="submit" value="Invoke" onClick="callGetJSONDoc()"/>
  </td>
 </tr>
 <tr class="row-bright">
   <td rowspan="2">insertJSON</td>
   <td align="right">ID:</td>
   <td align="center"><input type="text" id="key2" size="40" /></td>
   <td align="center" rowspan="2">
     <input type="submit" value="Invoke" onClick="callInsertJSON()"/>
   </td>
 </tr>
  <tr class="row-bright">
    <td align="right">Document:</td>
    <td align="center">
      <textarea id="document1" cols="30" rows="5" ></textarea>
    </td>
  </tr>
  <tr class="row-dark" >
    <td rowspan="2">updateJSON</td>
    <td align="right">ID:</td>
    <td align="center"><input type="text" id="key3" size="40" /></td>
    <td rowspan="2" align="center">
	    <input type="submit" value="Invoke" onClick="callUpdateJSON()"/>
    </td>
  </tr>
  <tr class="row-dark">
    <td align="right">Document:</td>
    <td align="center">
     <textarea id="document2" cols="30" rows="5" ></textarea>
    </td>
  </tr>
  <tr class="row-bright">
    <td>deleteDocument</td>
    <td align="right">ID:</td>
    <td align="center"><input type="text" id="key4" size="40" /></td>
    <td align="center">
      <input type="submit" value="Invoke" onClick="callDeleteDoc()"/>
    </td>
  </tr>
</table>

Deployment and testing

You will now deploy the gadget and then test the gadget.

Deploy the gadget

To test the new Universal Services test application, you can simply deploy both the PureJSON.js and JSONclient.xml to an HTTP server. As long as the files are available through a URL, the OpenSocial container should be able to retrieve the gadget specification and render the content accordingly. An OpenSocial server has a number of options for both for local deployment available through open source projects as well as hosted platforms externally. For simplicity, you'll deploy this sample gadget to the iGoogle sandbox which will provide the OpenSocial container.

  1. Log into http://www.google.com/ig/sandbox
  2. Once logged in, navigate to the Add stuff link in the upper right section of the page. This will link to a page that provides search capabilities for existing registered gadgets. See Figure 2. Note that the URL must be accessible from the Web. For example, if you are running behind a firewall, then your deployment might not work because the gadget definition cannot be loaded and processed by the OpenSocial container, in this case iGoogle. ((View a larger version of Figure 2.
    Figure 2. Add applications to your iGoogle sandbox
    Screen capture of the iGoogle sandbox where you can add applications
  3. Next you need to add this new gadget by the URL. In the left navigation, you will see a link to Add feed or gadget. This will open a dialog where you will need to put in the full URL for the JSONclient.xml. See Figure 3.
    Figure 3. Add an OpenSocial gadget to the iGoogle sandbox
    Screen capture of the field to add an OpenSocial gadget to the iGoogle sandbox
  4. You should now be able to return to your iGoogle home page and see the newly added gadget on your page.

Test the gadget

Figure 4 shows the gadget rendered in iGoogle.

Figure 4. The gadget rendered in iGoogle
Screen capture of the gadget undergoing test after deployment
  1. To edit the gadget settings, select the triangle icon to open the options drop down list. Select Edit settings.
  2. Update the pureXML host address and the context root path to point to your universal services.
  3. In the getJSONDocumentByKey field, enter a document key to retrieve a JSON record, then click Invoke. To test other transactions, repeat this step.
  4. Minimessage displays the result. To remove the messages, select the x at the end of the row.

Conclusion

In this article, we provided a sample set of code that migrates the traditional test Web application to a configurable and portable application that can be quickly deployed to a number of platforms on the Web. While the application itself is relatively simple, this reference can be used to quickly assemble and prototype new applications. The OpenSocial gadget client provides users a convenient way to dynamically connect to any pureXML Universal Services through the UserPrefs support. With POST makeRequest, gadget developers can simply create queries connecting to the services to perform their database transactions. Gadget consumers can add the gadget to any OpenSocial container regardless where it is physically deployed and hosted keeping the consumers free of content and infrastructure management.


Downloads

DescriptionNameSize
JavaScript POST request functionsPureJSON.js.zip1KB
OpenSocial gadget definition XMLJSONclient.xml.zip2KB

Resources

Learn

  • Build a pureXML and JSON application, Part 1: Store and query JSON with DB2 pureXML (Nuno Job, Susan Malaika, and Michael Schenke; developerWorks, October 2009): See the first article in this series and begin to benefit from persisting JSON objects that maintain state across sessions. Store, manage, and query JSON with DB2 pureXML and a simple JSON-to-XML mapping. (Part 1 of three-part series.)
  • Build a pureXML and JSON application, Part 2: Create Universal Services for pureXML that expose JSON (Faton (Tony) Avdiu, Susan Malaika, and Michael Schenke; developerWorks, October 2009): Following the steps in this article, you will expose the JSON data described in the first article in the series, through JSON Universal Services. (Part 2 of three-part series.)
  • OpenSocial Community : Find links to articles, tutorials, and the technical specification and learn to embed OpenSocial APIs within a social network, to access or share social data on the Web.
  • See the iGoogle Sandbox Development Guide : See details on OpenSocial support and application development and deployment in this environment.
  • Apache Shindig: Explore this OpenSocial container to quickly host OpenSocial apps with code to render gadgets, proxy requests, and handle REST and RPC requests. This open source community is developing a reference implementation for the OpenSocial specification and deployment in this environment.
  • IBM XML certification: Find out how you can become an IBM-Certified Developer in XML and related technologies.
  • XML technical library: See the developerWorks XML Zone for a wide range of technical articles and tips, tutorials, standards, and IBM Redbooks.
  • developerWorks technical events and webcasts: Stay current with technology in these sessions.
  • developerWorks podcasts: Listen to interesting interviews and discussions for software developers.

Get products and technologies

Discuss

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 XML on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML, Information Management, Web development, SOA and web services
ArticleID=445247
ArticleTitle=Build a pureXML and JSON application, Part 3: Create OpenSocial gadgets for pureXML
publish-date=11102009