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.
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
- 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.xhrGetanddojo.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.
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
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.)
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=http://www.ibm.com/xmlns/prod/iWidget 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
GrantsWidgetClassas 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.
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
retrieveGrantsXMLJavaScript function implements an asynchronous HTTP GET by calling thedojo.xhrGetroutine. - 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
contentsection. - Lines 10-15: The code responsible for the widget's content update
resides in the
loadfunction.The function gets called as soon as the browser receives a response from the servlet. Response content is passed through the
datavariable, which is a parameter for theloadfunction.
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> 6 <award_title>GLUCAGON BIOSYNTHESIS AND METABOLISM</award_title> 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.
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
Figure 4 shows the cloud view.
Figure 4. 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
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
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
Dojo onLoad function.
Two entry points (methods) to kick off the widget's GUI rendering were discussed earlier (shown in Listing 6 and Listing 7):
kwInitialUpdateto update the widget's content on initial load.kwInterimUpdateto 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
(kwUpdateStopWords function),
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 };
|
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
dojo.data.ItemFileReadStore 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 dojo.data.ItemFileReadStore({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 }
19
20 var kwCreateCloudDiv = function(divName, rootName) {
21 _kwCreateCloudDiv_impl('div', {id: divName, widgetid: ""}, rootName);
22 }
23
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) dojo.place(n, ref, pos);
28 return n;
29 }
|
In Listing 12 above:
- Lines 5 to 8: Handle initial
dojo.TagCloudobject creation. - Lines 10 to 16: Are responsible for clean-up of a previously created
dojo.TagCloudobject and the read-only data store bound with it. - Lines 2, 7, 8: Initial
dojo.TagCloudobject is attached to pre-created DOM element, and all subsequent recreations ofdojo.TagCloudobject 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.TagCloudobject 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"
url="{context_root}/extra-widgets/grantsWidget.xml?version={version}"/>
|
Learn
- Read the previous parts in this series:
- Part 1: Integrate Lotus Connections with a RESTful web application
- Part 2: Optimize assignment of students to research projects: Use an IBM ILOG optimization model with data from a relational database
- IBM
Lotus Connections: Learn more about IBM Lotus Connections.
- IBM Lotus Connections Information Center: Access all of the
product documentation.
-
Lotus Connections Profiles: Read more about viewing
profiles.
-
Tag Cloud: Learn more
at Wikipedia.
-
diabetes: American
Diabetes Association online journal.
-
TAGGS: Tracking Accountability in US
Government Grants System. A central repository for grants awarded by the
twelve HHS Operating Divisions (OPDIVs).
-
IBM
Content Analytics Information Center: IBM text retrieval
and text analysis engine.
-
IBM iWidget Specification V1.0: Defines a simple component model
and explains how it can be extended to enhance
interoperability.
- Industries zone on
developerWorks: Get all the latest industry-specific technical
resources for developers.
- Industries library: See the developerWorks Industries library for
technical articles and tips, tutorials, standards, and IBM Redbooks.
- My
developerWorks: Personalize your developerWorks experience.
- developerWorks
technical events and webcasts: Stay current with technology in
these sessions.
- developerWorks on
Twitter: Join today to follow developerWorks tweets.
- developerWorks podcasts: Listen to interesting interviews and
discussions for software developers.
- developerWorks on-demand demos: Watch demos ranging from product
installation and setup for beginners to advanced functionality for
experienced developers.
Get products and technologies
- IBM product
evaluation versions: Download or explore
the online trials in the IBM SOA Sandbox and get your hands on
application development tools and middleware products from DB2®,
Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
- developerWorks blogs: Check out these blogs and get involved.

Ilya 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 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.




