2009/12/09
9 Dec, 2009

Authoring, deploying and using XML Gadgets in WSO2 Gadget Server

  • Nuwan Bandara
  • Director - WSO2

Introduction
Gadgets are becoming an open standard with the increasing popularity to present chunks of data in personalized or enterprise portals. WSO2 Gadget Server is a portal solution specifically targeted to be deployed in SOAs as a presentation layer. WSO2 Gadget Server adheres to the Google Gadget Specification and supports the hosting and management of gadgets developed using this standard. This means that the gadgets written for Google gadget containers (and many other containers i.e : Hi5, Orkut, etc.) can be added to the WSO2 Gadget Server portal and vise versa.

What is a Gadget ?
Gadgets written according to the Google Gadget Specification are essentially HTML and Javascript applications that can be hosted in a platform of choice. The WSO2 Gadget Server only needs the publicly accessible URL of a gadget to add it to its portal. A major benefit of these mini-applications is that they have a higher reach, or in other words write once and run in multiple locations. The applications are simple to build with the help of many Javascript libraries available. It is simply an XML file which is located in any publicly accessible location. This file can contain all the logic within itself or it can refer to URLs to fetch content, this depends on the gadgets purpose.

WSO2 Gadget Server's Role
As mentioned in the article introduction, WSO2 Gadget Server provides the environment for the gadgets to function in harmony. It is a container built using open standards. Based on Apache Shindig, an Open Source implementation of the Google Gadget Specification, the Gadget server provides a comprehensive portal solution where users can write, deploy and use enterprise or open-social gadgets with ease. With the WSO2 Gadget Server you can also host your gadgets. With the Enterprise Gadget Repository, these hosted gadgets can be governed. Users can browse the repository and add gadgets to their portals with a click of a button. They can also rate and comment on each individual gadget.

This tutorial is a guide on how to create, deploy and use a gadget in WSO2 Gadget Server. Whether you are a developer or a simple user this guide will help you to write a simple gadget and get it running at no time. For a better understanding of gadgets, this tutorial will showcase three types;

  1. A simple “HelloWorld” gadget - A gadget with no logic, but shows the structure of fundamentals in gadget authoring
  2. An advanced gadget with the use of the Google Gadget API - This gadget shows more advanced features, i.e how the API can be used, etc
  3. A simple URL gadget (a hint on limitless possibilities) - The URL gadget is a demonstration of a gadgets extensibility factor.  

To follow this tutorial you will only need a text editor and some basic knowledge in HTML, JavaScript and XML.

The HelloWorld Gadget
The hello world gadget is the simplest of its kind and contains only XML and HTML.

<?xml version="1.0" encoding="UTF-8" ?> 
<Module>
  <ModulePrefs title="hello world example" /> 
  <Content type="html">
     <![CDATA[ 
       Hello, world!
     ]]>
  </Content> 
</Module>
  • The first line is the XML file declaration where it indicates that this files contains XML data.
  • The <Module> tag declares that this is a Gadget XML. This tag is declared in the gadget specification, so that the container will then know that the processing XML is a gadget.
  • <ModulePrefs /> contains metadata about the gadget (i.e : Title, Author name, etc). It can also have static rendering parameters for the gadget such as gadget height, width and scrollability.
  • In between <Content> tag, all the logic that belongs to the gadget resides (i.e JavaScript logic)
  • <![CDATA[ ...insert HTML here... ]]> is used to enclose HTML when a gadget's content type is html. It tells the gadget parser that the text within the CDATA section should not be treated as XML. The CDATA section typically contains HTML and JavaScript.

The following screen shows how the HelloWorld gadget will be rendered in the WSO2 Gadget Server.
Hello Gadget

Feed Reader Gadget (Use of the Google Gadgets API)
Blogs, magazines and newspapers allow their feeds to be read by third party software tools and they expose the content in RSS and Atom formats. With the use of the Google Gadgets API, we can write a simple feed reader gadget to retrieve these feeds and display inside your enterprise or personal portal.

The gadget which is demonstrated below, demonstrates more advanced features of gadget composition and the use of the Google Gadgets API. The gadget's task is to read an RSS or Atom feed from any given URL and display it in a nicely styled format.

<Module> 
    <ModulePrefs title="SOA Platform Blog" 
                 description="SOA blog articles Syndicated via WSO2 Blogs" 
                 author="WSO2 Gadget Server" 
                 author_email="[email protected]" 
                 author_link="https://www.wso2.org/" 
                 title_url="https://www.wso2.org/" 
                 height="100" 
                 scrolling="true"> 
        <Require feature="dynamic-height"/> 
        <Require feature="settitle"/> 
        <Require feature="setprefs"/> 
    </ModulePrefs> 
    <UserPref name="feed_url" display_name="Feed URL:" 
              default_value="https://soa-platform.blogspot.com/feeds/posts/default/"/> 
    <UserPref name="show_date" display_name="Show Dates?" datatype="bool" default_value="true"/> 
    <UserPref name="num_entries" display_name="Number of Entries:" default_value="5"/>
    <Content type="html">
    .................
    </Content> 
</Module>

There are a few syntaxes which are important and should be noted in the above code snippet. The XML element <Require feature=””> is the method to inform the gadget container (in our case the WSO2 Gadget Server) that this gadget needs a few extra features to function. These features are pre-written Javascript code, which will be loaded to the gadget on demand by the gadget container. For instance, if the gadget needs its height to be adjusted dynamically, the gadget author should import the dynamic-height feature. If he or she needs to set the gadget title the settitle feature needs to be imported. Likewise there are many features that the WSO2 Gadget Server supports. More information about these features can be found here.

<UserPrefs> is the mechanism to provide additional gadget specific preferences (Gadget Settings). These properties can be persisted and read from the gadget to do necessary processing. (i.e. Default feed URL for this sample gadget)

 

<Content type="html"> 
    <![CDATA[ 
    <style> 
       …............  
    </style> 
    <script type="text/javascript"> 
       .............
    </script> 
    <div id="content_div"><img src="waiting.gif" alt="" /> loading...</div> 
    ]]> 
</Content>

 

The gadget body skeleton looks like the above code, where we specify that the content type is HTML and in between meta-data tags, the styles and Javascript logic will be implemented. The javascript logic is as follows,

 

        var prefs = new gadgets.Prefs(); 
        var showdate = prefs.getBool('show_date'); 
        var entries = prefs.getInt('num_entries'); 
        var feedUrl = prefs.getString('feed_url'); 

        if (entries > 100) 
        { 
            alert('You cannot display more than 100 entries.'); 
            entries = 100; 
        } 

        var params = {}; 
        params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.FEED; 
        params[gadgets.io.RequestParameters.NUM_ENTRIES] = entries; 
        params[gadgets.io.RequestParameters.GET_SUMMARIES] = 'true'; 
        gadgets.io.makeRequest(feedUrl, readFeed, params);

 

What should be noted in the code snippet is the use of gadget.* API methods. This is called the Gadgets API originally developed by Google. Google Gadgets API provides many functionalities such as reading content from a given URL (in many formants), skins, tabs inside gadgets, flash content etc. The full reference for the Google Gadgets API can be found here.  

In the above code  var prefs = new gadgets.Prefs(); creates a preferences object and let us handle user preferences for this particular gadget.    

gadgets.io.makeRequest(feedUrl, readFeed, params);

The makeRequest API method retrieves the feed via HTTP from the given URL, and by providing a callback method (readFeed(feed)) we can do further processing on the retrieved feed.

    
    function readFeed(feed) { 
            if (feed == null) { 
                alert('There is no data.'); 
                return; 
            } 

            // Start building HTML string that will be displayed in gadget. 
            gadgets.window.setTitle(feed.data.Title + ' | ' + feed.data.Description); 
            var html = ''; 
            // Access the data for a given entry 
            if (feed.data.Entry) { 
                for (var i = 0; i < feed.data.Entry.length; i++) { 
                    html += '<div id="item-' + i + '">' 
                            + '<table id="feedTitle"><tr><td><a href="javascript:showContent(' + i + ')" style="text-decoration:none;">+</a></td>' 
                            + '<td><a target="_blank" rel="noopener" href="' + feed.data.Entry[i].Link + '">' 
                            + feed.data.Entry[i].Title 
                            + '</a></td></tr></table>'; 

                    if (showdate) { 
                        // The feed entry Date field contains the timestamp in seconds 
                        // since Jan. 1, 1970. To convert it to the milliseconds needed 
                        // to initialize the JavaScript Date object with the correct date, 
                        // multiply by 1000. 
                        var milliseconds = (feed.data.Entry[i].Date) * 1000; 
                        var date = new Date(milliseconds); 
                        html += '<span class="date">'; 
                        html += date.toLocaleDateString(); 
                        html += " "; 
                        html += date.toLocaleTimeString(); 
                        html += '</span>'; 
                    } 
                    var sumString = feed.data.Entry[i].Summary; 
                    html += '<div class="summary" id="sum-' + i + '" style="display:none;">' + sumString + '</div>'; 
                    html += '</div>'; 
                } 
            } 
            document.getElementById('content_div').innerHTML = html; 
            gadgets.window.adjustHeight(); 

        }

You can also provide a method to display the feed content on demand as follows,

    
    function showContent(id) { 
            if (document.getElementById('sum-' + id).style.display == '') { 
                document.getElementById('sum-' + id).style.display = 'none'; 
                document.getElementById('item-' + id).className = ''; 
            } else { 
                document.getElementById('sum-' + id).style.display = ''; 
                document.getElementById('item-' + id).className = 'item'; 
            } 
            gadgets.window.adjustHeight(); 
        }

A noteworthy point here is the use of dynamic height feature. The imported feature of the container <Require feature="dynamic-height"/> can be used by invoking gadgets.window.adjustHeight() to adjust the  gadget height according to the dynamically created content. With these simple steps, you can author your own feed reader gadget quite easily.

Bellow is how it looks like when deployed in the WSO2 Gadget Server,

Feed Reader

 

The URL Gadget (Pull content from a URL instead of embedding in the gadget XML)

In order to demonstrate that gadgets can be used to load external content directly, this example shows you how to display content from a URL. The Gadget XML logic is quite simple where instead of  <Content type="html"> it should be  <Content type="url" href="......"/> and point to the URL which will render the content you want to display inside the gadget. The ability to render external content comes handy, when the gadget author wants to implement the application with other programing languages and still display it as a gadget in a portal. A good example for a URL gadget is the Moon Phase gadget which is available in the iGoogle gadget repository.

Moon Phase

The gadget XML code looks like follows,

<?xml version="1.0" encoding="UTF-8" ?>

<Module>

  <ModulePrefs title="URL example" />

  <Content type="url" href="https://myURL"/>

</Module>

 

The Enterprise Gadget Repository shipped with WSO2 Gadget Server

WSO2 Gadget Server's Enterprise Gadget Repository is developed with two faces, the administrator's view and the user's view. In WSO2 Gadget Server 1.0.0, adding gadgets to the repository is only allowed for the server administrators, therefore an interface for the administrators to govern gadgets comes integrated to the Management Console. These gadgets can be managed by administrators, they can also be made default to new users that sign-in to the gadget server portal. Default gadgets are used to pre-populate the portal of a new user.

For end users, WSO2 Gadget Server provides a repository that can be browsed. Users can browse the repository for gadgets, they can add them to their portal, comment on them and rate the gadgets as a community contribution.

 

How To Deploy Gadgets in WSO2 Gadgets repository

Deploying Gadgets in the repository is quite straightforward. However this is an administrator's privilege. You need to login to WSO2 Gadget Server as the administrator at (https://localhost:9443/carbon) and navigate to the registry browser.

login

WSO2 Gadget Server is by default shipped with some of the WSO2 Governance Registry features. By using those registry/repository, a well equipped enterprise gadget repository can be maintained.

Reg-browser

Next you should browse to /registry/resource/system/gadgets. In the registry and at this location upload your gadget XML file as an XML resource.

Upload XML

Once the gadget XML is uploaded, you should navigate to the Gadget Repository in the administrators view and open the Add Gadget form (Gadget Repository → Add New Gadget),

add gadgets

 

Fill the Add New Gadgets form accordingly and for the gadgets URL, you should provide the registry URL for the resource, which is /registry/resource/system/gadgets/feedReader.xml and save the created gadget entry. Now the newly created gadget will be added to the repository, and all the users will be able to find this gadget simply by browsing the repository.

NOTE: If the Gadget XML is hosted in another Web Server, you can also add that to the repository by simply adding its https:// URL as the gadget URL.

If you are a normal user and just want to test your gadget in WSO2 Gadget Server, you can host your Gadget XML in a public location and provide its HTTP URL (The XML file should be able to access via HTTP) to the portal's add-gadget by URL location.

 

add-gadget url

 

Community Features of the WSO2 Gadget Server 

When gadgets are submitted to the gadget repository, administrators and users can view a particular gadget's usage. Users can comment and rate the gadgets and contribute to the community.

community

Summary

Gadgets are handy applications that can display chunks of data in a unified portal view. Even though portlets can be written in many different methods, authoring can be done simply with some HTML and JavaScript. Apart from that, with the least amount of changes, these gadgets can be embedded in many web pages over Internet that would make a great benefit. This tutorial is a complete guide demonstrating how to write, deploy and use gadgets for enterprises and for personal use using WSO2 Gadget Server. There are many resources about gadget authoring that can be found at [1]. [2], [3].

[1] https://code.google.com/apis/gadgets/

[2] https://www.google.com/webmasters/gadgets/guidelines.html

[3] https://code.google.com/apis/opensocial/

Author

Nuwan Bandara, Software Engineer, WSO2, nuwan[at]wso2[dot]com, @Blog : www.nuwanbando.com

 

About Author

  • Nuwan Bandara
  • Director
  • WSO2