Smarter collaboration for the education industry using Lotus Connections, Part 3: Use Profiles to share research interests and grant awards

Create the user interface with widgets and Lotus Connections

In this article, learn to augment IBM Lotus® Connections Profiles pages with information about research grant awards and academic research interests. An example application, including code samples, shows how to gather source content on grants and publications and store it for further text analysis. The content is ranked and shaped into a research interest tag cloud for the Profiles user. The UI is implemented using two custom widgets composed of XML and JavaScript files.


Ilya Afanasiev, Software Engineer, IBM

Photograph of Ilya AfanasievIlya Afanasiev is a software engineer with over seven years successful working experience and rich skill set in various fields, including software research, development, support, and quality assurance. He joined IBM in 2007 as z/OS Systems Programmer in Russian Systems and Technology laboratory. His current focus is web UI development and prototyping, information retrieval, and Java EE application development. His current research interests are text mining and unstructured text analysis.

Carl Osipov, Software Architect, IBM

CarlCarl Osipov is an experienced software architect with the Strategy and Technology organization in IBM Software Group. His skills are in the area of distributed computing, speech application development, and computational natural language understanding. He has published and presented on Service-Oriented Architecture and conversational dialog management to peers in the industry and academia. His current focus is on design of reuse techniques for composite business services.

22 February 2011

Also available in Russian Japanese Portuguese


IBM Lotus Connections is a social networking product designed for today's workplace. Profiles, which is just one component of the product, provides a customizable online directory of people.

In this article, learn to implement an extension to Lotus Connections Profiles that lets profile owners augment their profile page with information about their research grant awards and academic research interests. Other users (profile observers) who visit the page will see a list of titles for the profile owner's grant awards, and a tag cloud of keywords based on the profile owner's research interests.

The sample application in this article uses the Tracking Accountability in U.S. Government Grants System (TAGGS) website as the data source for the research grants awarded to a Profiles user by the National Institute of Health (NIH). Information about grants provides only a partial view of an awardee's research interests. The application can also be configured to collect the text of the profile owner's publications on the web (for example, articles from the Diabetes journal). All of the text data gathered for a user from TAGGS, and from online publications, is persisted to a IBM Content Analytics unstructured (text based) content database called a text analytics collection.

The application uses Content Analytics to turn content from the collection into insight about research interests. Though Content Analytics provides a range of complex text analytics capabilities, this article focuses on a simple term frequency analysis. The output of the analysis is a ranked list of most commonly occurring words in grant award titles and publication abstracts for a Profile user. The list is rendered as the research interest tag cloud on the profile page.

See Resources for information about Lotus Connections Profiles, the Tag Cloud widget, TAGGS, Content Analytics, and more.

Application architecture

The architecture of the sample application is shown in Figure 1. As is common with web applications, the server side consists of multiple conceptual tiers.

Figure 1. Application architecture
Architecture of the sample application
Presentation (or web) tier
Responsible for processing web browser client requests and for sending the Profiles user interface (UI) HTML to the browser. The web tier is based on a Connections server extended with the application-specific My Grant Awards and My Keywords widgets. As Profiles extensions, the widgets need to comply with IBM iWidget specifications. Instances of iWidget-compliant components are used by both widgets to contain custom functions implemented using Dojo and JavaScript. Both widgets are composed of XML and JavaScript files.

The XML file declares an iWidget instance in accordance with iWidget definition syntax (Section 9.1, iWidget specification 1.0). Conforming to this syntax, the XML file contains declaration of a JavaScript (Dojo) object that renders the widget's contents. This XML file also contains a section with native HTML markup and JavaScript source code to pass UI rendering control to the Dojo object.

The JavaScript file contains an implementation of the Dojo object responsible for UI rendering. The object uses asynchronous HTTP GET and HTTP POST calls (dojo.xhrGet and dojo.xhrPost) to retrieve data from the business tier using Java Servlet technology. The data is returned to the object in the form of a servlet (HTTP) response, and is then used to rewrite the DOM of the web page on the client side.

Business tier
Hosts the Profiles and the extension JEE applications. The latter contains Java servlets in support of the My Grant Awards and My Keywords widgets. The servlet logic relies on custom methods for data retrieval (in this case, from TAGGS or Diabetes Journal websites) and custom methods for data analysis (to calculate frequencies of keywords used in Diabetes Journal publications).

The servlets return HTTP response messages in XML or JSON format. Both Profiles and the extension JEE application are deployed as EAR files to WebSphere Application Server

Integration tier
Responsible for exposing Content Analytics web crawling and text analytics capabilities as services for the business tier. The extension JEE application interacts with Content Analytics via a Java API. Because Content Analytics does not provide the means of crawling dynamically-generated web pages, the application also contains a custom crawler implementation.

The rest of this article describes the client-side functions and UI implementation details for the widgets mentioned above: My Grant Awards and My Keywords. XML and JavaScript source code snippets are included.

My Grant Awards widget

The My Grant Awards widget displays a list of awarded research grants for a profile owner, as shown in Figure 2.

Figure 2. My Grant Awards widget appearance
My Grant Awards widget appearance

The widget's content is represented by a single element: an HTML table with information about awarded research grants. (Part 4 in this series will describe the data retrieval to fill in the table's content.)

iWidget XML

The XML file referenced in the widgets-config.xml file, shown in Listing 13, is used to declare the additional widget in the Profiles UI configuration. The Appendix to this article describes how to deploy additional widgets to the Profiles application.

Listing 1 shows the content of the My Grants Awards widget XML file.

Listing 1. iWidget XML for My Grant Awards widget
1 <iw:iwidget id="grants" xmlns:iw=
2 iScope="GrantsWidgetClass" 
3 supportedModes="view" 
4 title="My Grant Awards">
5 <iw:resource uri="grants.js" />
6 <iw:content mode="view">
7 <![CDATA[
8 <div id="grantsWidget">
9 <script type="text/javascript">
10 iContext.iScope().getGrantAwards();
11 </script>
12 </div>
13 ]]>
14 </iw:content>
15  </iw:iwidget>

In Listing 1 above:

  • Line 1: The declaration defines an iWidget instance with the identifier grants.
  • Line 2: Continues the declaration with GrantsWidgetClass as the name for a JavaScript object.
  • Line 3: Shows that the widget supports a view mode only, which means a Profiles user won't be able to change the displayable widget’s content.
  • Line 4: The widget's title is My Grant Awards.
  • Line 5: Specifies the iWidget resource section.
  • Lines 6 to 14: The iWidget content section.

The resource section binds the iWidget declaration with the source code file containing the implementation of the JavaScript object. The class name for this object is provided in line 2 of Listing 1. The instance of the GrantsWidgetClass object is responsible for the widget's DOM rendering. Implementation details of the object are covered in Dojo/JavaScript code.

The content section contains the source code that serves as an entry point for the My Grant Awards widget's DOM rendering. In lines 8 to 12 in Listing 1, the static HTML for the My Grant Awards widget consists of a single DIV element named grantsWidget. In line 10, the content of the element gets dynamically generated through the getGrantAwards() method call. This method is a member method of the GrantsWidgetClass JavaScript object.

The iWidget components that provide the overall management of the web page (layout, for example) are accessed by the iContext high-level object qualifier. The iScope() call returns the GrantsWidgetClass (line 2) object instance, which gets initialized prior to the loading of the iWidget.

Dojo/JavaScript code

The GrantsWidgetClass JavaScript object implementation is responsible for the My Grant Awards widget DOM rendering. Listing 2 shows the Dojo declarations in the grants.js file.

Listing 2. GrantWidgetClass Dojo declaration in grants.js
1 dojo.require("dojox.xml.DomParser");
2 dojo.provide("GrantsWidgetClass");
3 dojo.declare("GrantsWidgetClass", 
4 null, 
5 { 
6 getGrantAwards: function() {
7 var userName = profilesData.displayedUser.displayName;
8 retrieveGrantsXML(userName);
9 }
10 }
11 );

Line 1 in Listing 2 resolves the Dojox routine names that will be used for DOM parsing and retrieval. The rest of the code in Listing 2 declares the GrantsWidgetClass Dojo class, including its methods and variables. The GrantWidgetClass class has one method, getGrantAwards, which is called to fill in the contents of HTML DIV with the grantsWidget identifier, as shown in Listing 1. The getGrantAwards() method calls the retrieveGrantsXML JavaScript function with a parameter representing the name of the profile owner (whose profile is displayed by the Profiles application).

A high-level overview of the retrieveGrantsXML function is shown in Listing 3.

Listing 3. Overview of retrieveGrantsXML
1 var retrieveGrantsXML = function(authorName) {
2 /* ... */
3 var xhrArgs = {
4 url: "/pubApi/grants",
5 handleAs: "text",
6 preventCache: true,
7 content: {
8 investigator: authorName
9 },
10 load: function(data) {
11 /* ... */
12 var doc = dojox.xml.DomParser.parse(data,"text/xml");
13 var results = doc.getElementsByTagName("award");
14 /* ... */
15 },
16 error: function(error) { /* ...error handling code... */ }
17 };
18 var deferred = dojo.xhrGet(xhrArgs);
19 };

In Listing 3 above:

  • Line 18: The retrieveGrantsXML JavaScript function implements an asynchronous HTTP GET by calling the dojo.xhrGet routine.
  • Lines 3-17: Arguments for this call are initialized.
  • Line 4: During a GET call invocation, control is passed to a server side -- a servlet with a URL path.
  • Lines 7-9: Parameters passed to the servlet are listed in the content section.
  • Lines 10-15: The code responsible for the widget's content update resides in the load function.

    The function gets called as soon as the browser receives a response from the servlet. Response content is passed through the data variable, which is a parameter for the load function.

A typical response generated by the My Grant Awards servlet is in XML format. Listing 4 shows an example.

Listing 4. Typical response of My Grant Awards servlet
1 <grants-list faculty="Joel Francis Habener" GAManagerVersion="1.0">
2 <award>
3 <fiscal_year>2008</fiscal_year>
4 <opdiv>NIH</opdiv>
5 <award_number>R01DK030834</award_number>
7 <principal_investigator>JOEL F HABENER</principal_investigator>
8 </award>
9 </grants-list>

As soon as the servlet response data is parsed using the Dojo XML DOM parser (lines 12-13 in Listing 3), the results are displayed in an HTML table similar to the table in Figure 2.

My Keywords widget

The My Keywords widget lets users quickly learn about a profile owner's key research interests. It displays keywords that appear most frequently in the profile owner's publications, grant descriptions, and other web sources, such as PubMed. Unlike the My Grant Awards widget, the My Keywords widget has controls that let a profile owner customize the widget's appearance and the displayed content.

Any profile user can switch between list and cloud views. Figure 3 shows a list view.

Figure 3. My Keywords widget, list view
My Keywords widget, list view

Figure 4 shows the cloud view.

Figure 4. My Keywords widget, cloud view
My Keywords widget, cloud view

Using additional controls, a profile owner can customize the content displayed by the widget, as shown in Figure 5. For example, the owner can select multiple sources for keyword extraction, or prevent some keywords (also called stop words in Figure 5) from being displayed.

Figure 5. My Keywords widget, additional controls
My Keywords widget, additional controls

The widget cloud view in Figure 4 shows keywords for the Profiles user Alice if she is viewing her own profile. When another Profiles user, Bob, tries to observe Alice's profile, the My Keywords widget highlights Alice's keywords that match the keywords that Bob has in his own profile. Figure 6 shows Bob's view of Alice's profile, with their common keywords highlighted.

Figure 6. My Keywords widget, Cloud view with similar keywords
My Keywords widget, Cloud view with similar keywords

iWidget XML

The high-level structure of the My Keywords iWidget XML source code is identical to the source code for the My Grant Awards widget, but the implementation details differ significantly. The sample code in Listing 5 creates a string with a list of names of the sources used for keywords extraction. You can see the sources in Figure 5 under the “Extract keywords from” label.

Listing 5. Constructing the list of keywords sources
1 kwGetExtractableSources = function() {
2 str_extract_from = "";
3 if (dojo.byId("chkbox_1").checked) { 
4 str_extract_from += ",source_1";
5 }
6 if (dojo.byId("chkbox_2").checked) {
7 str_extract_from += ",source_2";
8 }
9 str_extract_from = str_extract_from.substring(1,str_extract_from.length);
10 if(str_extract_from=="") {
11 str_extract_from = "default_source"; 
12 }
13 return str_extract_from; 
14 }

The string is passed, along with other parameters, to the My Keywords servlet.

Similar to My Grant Awards implementation, the My Keywords widget has its own JavaScript object responsible for GUI rendering. One of the object's methods gets called from the My Keywords iWidget XML file, as shown in Listing 6. This method accepts the string representing the extractable sources list. The string is retrieved by calling the function shown in Listing 5.

Listing 6. Initial update of My Keywords widget internals
1 document.getElementById("kw_status").innerHTML += "Loading keywords...";
2 iContext.iScope().kwInitialUpdate (kwGetExtractableSources());

Listing 7 shows the code that handles clicks on the Update current view button at the bottom of Figure 5.

Listing 7. Handling “Update current view” button click
1 <script type="text/javascript"> 
2 kwProcessUpdateCall = function() {
3 str_extract_from = kwGetExtractableSources();
4 iContext.iScope().kwInterimUpdate(kwGetExtractableSources(),
5 kwCurrPage, kwCurrView);
6 }
7 </script>
8 <form name=stopWordsForm>
9 <textarea name=stopWordsText id=kw_stopwords_editable cols=25 rows=5>
10 </textarea>
12 </form>
13 <input type="button" class="lotusBtn lotusBtnSpecial" name="submit_all" 
14 value="Update current view" onClick=kwProcessUpdateCall();/>

Notice there are two different methods called:

The methods are two entry points to kick off the widget's GUI rendering. Rendering the widget GUI has more detail.

Role based authorization for widget controls

People viewing a Lotus Connections Profile are in one of two roles: profile owner or profile observer. A profile owner created the profile and can modify that profile. Profile observers can view but cannot modify the profile.

The My Grant Awards widget looks similar to both a profile owner and a profile observer. The My Keywords widget, however, appears differently when viewed by a profile owner versus a profile observer. Profile observers lack authorization to modify the content displayed by the My Keywords widget. The controls available to the profile owner are shown in Figure 5.

Role-based widget authorization is implemented in the Dojo onLoad function, which is called by Dojo upon completion of a widget's loading process. The onLoad function, shown in Listing 8, uses two variables:

  • pObserved - represents the user whose profile is currently observed.
  • pLoggedIn - represents the user currently logged in to the Profiles application.
Listing 8. Role based simple authorization in Dojo onLoad() function
1 onLoad: function () {
2 var pObserved = this.personObserved;
3 var pLoggedIn = this.personLoggedIn;
4 if(pObserved != null && pLoggedIn != null && pObserved == pLoggedIn) {
5 dojo.byId('kw_cust_expand').style.display = "";
6 }
7 }

Depending on the result of an alphanumerical comparison of the two variables, the HTML element with the identifier kw_cust_expand is either shown or remains hidden. The HTML element represents the Customize this view link element shown in Figures 3 and 4. Since the widget gets loaded only once (when a browser loads the Profiles page), there's no need to continuously maintain role authorization.

It is important to note that the kwInitialUpdate method (which is called by My Keywords widget initialization code in Listing 6) is called before the widget is loaded. The Dojo onLoad function is called after invocation of the kwInitialUpdate method, so kwInitialUpdate initializes the object variables personObserved and personLoggedIn used by the DojoonLoadfunction.

Rendering the widget GUI

Two entry points (methods) to kick off the widget's GUI rendering were discussed earlier (shown in Listing 6 and Listing 7):

  • kwInitialUpdate to update the widget's content on initial load.
  • kwInterimUpdate to update the widget's contents after the user clicks Update current view (see Figure 5).

The Initial update of the widget's content is with the kwUpdateContents function call, as shown on line 4 in Listing 9.

Listing 9. Initial and interim update method implementations for My Keywords widget
        1 kwInitialUpdate: function(extractableSources) { 
        2 /* initialization of personObserved and personLoggedIn */
3 /* ... */
4 kwUpdateContents(this,personObserved,0);
5 }
6 kwInterimUpdate: function(extractableSources, currPageId, currView) { 
7 /* ... */
8 kwUpdateStopWords(this, personLoggedIn,extractableSources,currPageId);
9 }

Listing 10 shows the implementation of the function above.

Listing 10. Asynchronous HTTP GET call implementation for My Keywords widget
1 var kwUpdateContents = function(kwClassInstance,investigatorName,currPage) {
2 var xhrArgs = {
3 url: "/termsfrequency_proxy/termsfrequency",
4 handleAs: "text",
5 preventCache: true,
6 content: {
7 investigator: investigatorName,
8 compare_with: kwClassInstance.personLoggedIn,
9 extract_from: termsSources, 
10 threshold: 2
11 }, 
12 load: function(data) {
13 /* ... */
14 kwClassInstance.xmlParsed = dojox.xml.DomParser.parse(data);
15 kwUpdateWidgetInternals(kwClassInstance,currPage);
16 /* ... */
17 },
18 error: function(error) {
19 /* error handling ... */
20 }
21 };
22 var deferred = dojo.xhrGet(xhrArgs);
23 };

In Listing 10, HTTP GET is called asynchronously using /termsfrequency_proxy/termsfrequency as the URL path, and using request parameters from content scope (lines 6-11). As soon as HTTP GET returns the data, the load function performs the GUI rendering by invoking the implementation encapsulated by the kwUpdateWidgetInternals function.

The kwInterimUpdate method calls the kwUpdateStopWords function, which (unlike kwUpdateContents) calls an asynchronous HTTP POST. As soon as the HTTP POST request is processed on the server side, control is returned back to the caller (kwUpdateStopWordsfunction), which calls kwUpdateContents. See lines 14 and 15 in Listing 11.

Listing 11. Asynchronous HTTP POST call implementation for My Keywords widget
1 var kwUpdateStopWords = 
2 function(kwClassInstance,userName,termsSources,currPage) {
3 var stopWordsEditable = dojo.byId("kw_stopwords_editable");
4 var stopWordsGiven = "";
5 if(stopWordsEditable.value != "Add your own stop words to here...") {
6 stopWordsGiven = stopWordsEditable.value; 
7 }
8 var xhrArgs = {
9 url: "/termsfrequency_proxy/termsfrequency",
10 postData: "updated_stopwords_list="+stopWordsGiven+"+
11 "&investigator="+username+"&terms_sources="+termsSources,
12 error: function(error) {/* ... error handling ... */}
13 };
14 var handler = dojo.xhrPost(xhrArgs);
15      handler.addCallback(kwUpdateContents(kwClassInstance,userName,currPage));
16 };

Using a Dojo Tag Cloud widget

The kwDisplayCloudView method is used to display user keywords as a cloud, as shown in Figures 4 and 6. The cloud is implemented using a Dojo Tag Cloud object that's created from scratch each time the My Keywords widget is refreshed.

The Dojo Tag Cloud works with the read only data store. Once, during the widget initialization, the data store gets filled with the following metadata: a list of keywords and their frequencies; and additional markup to be used to render the similar tag cloud. The My Keywords servlet response fills the data store with XML and JSON representations of keywords and their frequencies. The My Keywords widget uses XML in list mode and JSON in cloud mode.

Listing 12 shows the implementation of the logic responsible for rendering a Dojo Tag Cloud widget.

Listing 12. Dojo.TagCloud widget implementation
1 kwDisplayCloudView: function() {
2 var kwCloudDivName = "kw_cloud_placeholder";
3 var kwCloudRootName = "kw_cloud_root";
4 if(this.oCloud == null) {
5 this.jsonStore = 
6           new{data:this.termsJson,clearOnClose:true});
7 var kwCloudDiv = dojo.byId(kwCloudDivName);
8           this.oCloud = new myDojo.TagCloud({store: this.jsonStore},kwCloudDiv);
9 } else {
10 this.jsonStore.close();
11 this.jsonStore._jsonData = this.termsJson;
12 this.jsonStore.fetch();
13 this.oCloud.destroy();
14 kwCreateCloudDiv(kwCloudDivName, kwCloudRootName);
15 var kwCloudDiv = dojo.byId(kwCloudDivName);
16          this.oCloud = new myDojo.TagCloud({store: this.jsonStore},kwCloudDiv);
17 }
18 }
20 var kwCreateCloudDiv = function(divName, rootName) {
21 _kwCreateCloudDiv_impl('div', {id: divName, widgetid: ""}, rootName);
22 }
24 _kwCreateCloudDiv_impl = function(tag, attrs, ref, pos){
25 var n = dojo.doc.createElement(tag);
26 if(attrs) dojo.attr(n, attrs);
27 if(ref), ref, pos);
28 return n;
29 }

In Listing 12 above:

  • Lines 5 to 8: Handle initial dojo.TagCloud object creation.
  • Lines 10 to 16: Are responsible for clean-up of a previously created dojo.TagCloud object and the read-only data store bound with it.
  • Lines 2, 7, 8: Initial dojo.TagCloud object is attached to pre-created DOM element, and all subsequent recreations of dojo.TagCloud object are done by first destroying the DOM element.
  • Lines 14, 15, and 20 to 29: This DOM element is created from scratch, then a new dojo.TagCloud object is created inside this DOM element.


In this article, you learned the value of integrating IBM Lotus Connections and IBM Content Analytics so Connections users can share their research interests keywords and grant awards. The article covered the application architecture, and walked through the details of the My Keywords and My Grant Awards iWidgets. You explored the HTML and JavaScript implementation of the widgets using Dojo. Sample source code helped illustrate Profiles role based authorization. You also learned how to enable HTTP communication between widgets and Java Servlets.

Stay tuned for Part 4 of this series, which will focus on the servlet implementation and integration with Content Analytics.


Deploying additional widgets to the Profiles application

The path to XML files declaring the widgets discussed in this article is in the widgets-config.xml widget configuration file. To configure existing widgets or to make custom widgets available for use in Profiles, you modify settings in the widgets-config.xml file. See Configuring widgets in Profiles for details. This configuration file is used to customize Lotus Connections Profiles UI content.

Listing 13 shows an example of the My Grant Awards widget's declaration XML file, as a part of the My Grant Awards widget definition in the Profiles widget configuration file.

Listing 13. My Grant Awards widget definition in widgets-config.xml
<widgetDef defId="myGrantAwards" bundleRefId="extraBundle" 



Get products and technologies



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 IBM collaboration and social software on developerWorks

ArticleTitle=Smarter collaboration for the education industry using Lotus Connections, Part 3: Use Profiles to share research interests and grant awards