IBM Lotus Quickr usage statistics: Measuring the success of team collaboration

IBM® Lotus® Quickr® 8.5 for IBM WebSphere® Portal introduces server- and place-level statistics. Administrators can monitor the use of the system through an administrative web user interface. Statistics for Lotus Quickr places can also be obtained by calling REST services on the \adminqcs context root. These services provide both server-wide and place-specific statistics.

Jim Antill (antillji@ie.ibm.com), Software Developer, IBM

Jim Antill is a Software Developer working on social and team collaboration software. Jim contributed to the Lotus Quickr 8.5 release, mainly working on the Member Management aspects of the product. You can reach him at ANTILLJI@ie.ibm.com.



Nan Shi (nanshi@cn.ibm.com), Advisory Software Engineer, IBM

Nan Shi is a Advisory Software Engineer working on social and team collaboration software. Nan has over 10 years of experience in IT solution consulting and software development. Nan has contributed to the Lotus Quickr Admin Console component as a technical leader and developer for Lotus Quickr 8.5. You can reach her at nanshi@cn.ibm.com.



Jon Brunn (jbrunn@us.ibm.com), Senior Software Engineer, IBM

Jon Brunn is a Senior Software Engineer working on social and team collaboration software. Jon has more than 10 years of experience with content management systems including IBM Content Manager and FileNet P8. Jon has contributed to Lotus Quickr, Lotus Connections, WebSphere Portal, Web Content Management, FileNet, and IBM Content Manager. You can reach him at jbrunn@us.ibm.com.


developerWorks Contributing author
        level

02 November 2010

Also available in Russian Portuguese

Editor's note: Know a lot about this topic? Want to share your expertise? Participate in the IBM Lotus software wiki program today.

Introduction

The place-specific statistics give us some useful information about a place including the number of documents in the place, number of documents modified today, number of library documents, and more. This information is useful to place owners and the server administrator. The statistics also need to be viewed using a simple user interface (UI) that is accessible from the theme and also exists in a downloadable CSV format that can be imported into a spreadsheet.

In this article you make these statistics more consumable for your place owners. You are going to do the following:

  • Develop a servlet to access Place Statistics feeds
  • Use Abdera to call the adminqcs feeds, build Atom feeds, and parse XML
  • Use the WebSphere Portal API to put together JSON feeds
  • Secure the new servlet
  • Write a Dojo widget to provide a simple UI and a means to download the CSV file
  • Integrate the widget with the Lotus Quickr theme

The resulting UI shows statistics about content, growth, and health of the place to the place owners in a consumable form.

All the necessary materials to deploy the Place Statistics widget are contained in the EAR file supplied with this article. The “Deployment” section of this article describes how to install this widget and make changes to the theme so that the new feature can be accessed.


Place Statistics servlet

We're going to start by building the servlet to obtain the place statistics data. The servlet makes use of the existing \adminqcs feed while adding the ability to output details in JSON format. Having a JSON formatted output improves the ease with which JavaScript components can use the feed output.

Figure 1 shows how the parts that make up the servlet work together. A request comes in, and data from the \adminqcs feed is obtained either in Atom or CSV formats, depending on the ultimate required format, using the FeedRetriever. The data is then passed to the FeedHandler, which causes the statistics data to be output in the right format, so if we want JSON format we get JSON coming out rather than Atom or CSV.

Figure 1. Place Statistics servlet
Place Statistics servlet

Authorization

Place statistics data can be obtained by any person in the manager role for the place or any person in a role that has the Manage Membership permission given to it.

No extra authorization is supplied by the Place Statistics servlet described in this article. The PlaceStatisticsRetriever class in the example code contains an authenticateAccess() method that can be used to perform additional authorization. If the method is implemented, then it throws a PlaceStatisticsAuthenticationException if the current user isn't allowed to view the statistics. The authenticateAccess() method is called before the place statistics are obtained.


Feed retriever: Consuming the Place Statistics feed

The existing \adminqcs Place Statistics feed provides details in either an Atom or CSV format. The Atom format is easy to parse using Java code and provides a structured view of place statistics. The CSV feed provides a feed that can be downloaded to a file from the browser but is hard to handle for any other purpose.

You need different code to retrieve each of these feeds because they are presented in different formats, the CSV is in a stream and the Atom is in an XML document. The behavior that you need is common so it can be expressed using an interface that each feed retriever that you create can implement. This interface is depicted in Listing 1.

Listing 1. #BaseFeedRetriever interface
package com.ibm.quickr.placestatistics.datahandler;
import javax.servlet.http.Cookie;
import com.ibm.quickr.placestatistics.exceptions.PlaceStatisticsException;
public interface BaseFeedRetriever {
	public Object getFeed(String feedUrl, Cookie[] cookies) 
	throws PlaceStatisticsException;
}

The getFeed() method takes as input the URL from which you want to get the feed (including any parameters such as from or to dates) and cookies that you need for authentication; the \adminqcs service uses the LTPA tokens (cookies) that WebSphere Portal uses for authentication.

You create classes extending this interface that provide their own implementation of the getFeed() method . To ensure that the correct feed reader implementation is used, you also create a factory class that provides the appropriate feed reader based on your eventual desired output format. In the case where the output required is CSV, the CSVFeedRetriever is used. In all other cases, the AtomFeedRetriever is used because the Atom document produced can then be parsed into other forms, such as JSON.

If other output types from the \adminqcs service become available, you can create a class to handle that feed type without affecting classes handling the Atom and CSV feeds.

Obtaining the Atom feed

The AtomFeedRetriever class is used to retrieve the Atom version of the Place Statistics feed.

Apache Abdera is used to make the HTTP request to the \adminqcs service. Abdera is also used to handle the returned data and a few other things in the project. An instance of the AbderaClient class and an instance of the RequestOptions class that you use to pass any options such as cookies across in the request are required.

One of the parameters in the getFeed method is an array of cookies. Some of the cookies on the original servlet request are the LTPA cookies that WebSphere Portal uses for authentication. An instance of the org.apache.abdera.protocol.client.RequestOptions class is created, and details from the cookies are set up. The cookies need to be defined as an array of strings, one string for each cookie, with each string taking the form:

name = value

You go through the cookies, form a string array with one element for each cookie, and then use this array to set up the RequestOptions object as shown in listing 2.

Listing 2. Setting up cookies for request
	RequestOptions options = new RequestOptions(true);
	// Put the cookies onto the request options.
	List<String> cookieStrings = new ArrayList<String>();;
			
	for (int i=0; i<cookies.length;i++) {
		String name = cookies[i].getName();
		String value = cookies[i].getValue();
		cookieStrings.add(name+"="+value);
	}

	options.setHeader("Cookie", (String[])cookieStrings.toArray
	(new String[cookieStrings.size()]));

The request itself is made using the get() method on the AbderaClient instance, passing in the URL for the request and the RequestOptions object that you set up. The response is an instance of Abdera's ClientResponse class containing details of the response status. for example, success or failure, and the data sent in the response. In this instance, assuming a successful response, the reply contains the Atom XML document. This document can be extracted using the getResponse() method on the ClientReponse instance. In the case of failure, an exception is raised and handled.

The obtained response is sent as the output from the feed retriever, ready to be used elsewhere.

Obtaining the CSV feed

Obtaining the CSV feed is similar to getting the Atom Place Statistics feed, the only real difference is how the output from the request is handled.

As before, you need to define the cookies in an attempt to aet up the RequestOptions object and then send the request off.

This time you get a CSV feed returned in the form of an InputStream, which needs to be read. A good option is to use a BufferedReader to read a bit of the stream at a time. Each bit that you read is appended to a StringBuffer object until there's nothing more to read. At that point, you can return the StringBuffer as the output from the retriever.


Outputting in the required format

Now that you have the Place Statistics data in either Atom or CSV format you need to form output that is sent to the caller of your servlet in the form that was originally asked for.

To keep things neat and flexible, you can use a separate class to handle each output format, each of these providing the functionality listed in table 1.

Table 1. Statistics data output class functions
Output functionDetailed description
Handle statistics feedTake the statistics feed and write it in the required format to the given output stream.
Provide content typeProvide a means for the content type of the output format to be retrieved. After a FeedHandler instance has been created, the content type for the feed can be obtained using this method.
Write exception outputOutput details of an exception in the given format. For example, if an exception occurs in processing the AtomHandler, it writes out exception details in an Atom format.

As the operations offered by the classes are the same, you can use an interface to define a contract that all of your classes implement. An example is shown in the BaseFeedHandler Interface in listing 3.

Listing 3. BaseFeedHandler interface
public interface BaseFeedHandler {
	// Method to produce feed for an exception.
	public Object produceExceptionFeed
	(Exception ex, PrintWriter writer, String feedId);
	public void handleStatsFeed(Object feed, PrintWriter writer) 
	throws PlaceStatisticsException;
	public String getContentType();
}

The type of the feed that is passed into the handleStatsFeed method depends on the type of feed to be output. For example, if you are handling an Atom feed, then the feed parameter is an Abdera feed, but it is a StringBuffer if you are handling a CSV feed.

AtomFeedHandler

The AtomFeedHandler outputs the Place Statistics feed in an Atom format. All that needs to be done is to take the Atom feed retrieved from the \adminqcs service and pass it out using the response for the servlet.

JSONFeedHandler

The JSONFeedHandler outputs the Place Statistics feed in a JSON format and requires a little more work. The feed expected by the handleStatsFeed function is the Atom feed produced by the adminqcs service.

The handler outputs a JSON structure that is capable of describing the statistics feed for a place; an example is:

{id : "statistics", fromDate : "2010-05-27", toDate : "2010-05-30",
title: "Lotus Quickr Admin Feed", items: [{"published", statistics:
[{key: "document_totalNum", value: 1}]}]}

The first part of the feed contains the feed ID, from and to dates that the feed is for, and the feed title. The items array follows, one item in the array corresponding to a single <entry> element in the Atom feed.

Each item has a published date, title, and a further array. This final array contains the statistics information for the place, with each item having a key and a value. The key identifies which statistic it is, for example, document_size, with the value indicating the value for that particular statistic.

You use Abdera to parse the Atom feed because Abdera gives you all that you need to parse a DOM either directly or by using Xpath queries. As you parse, you can build your JSON structure using the WebSphere Portal APIs that handle any special characters and encoding issues, giving you a little less to worry about.

Appendix 1 in this article shows a standard Atom feed for place statistics. With Abdera, parsing this feed into the JSON format is easy.

The list of entries in the Atom feed is first obtained, and these entries are then searched for the <statistics> element that contains the Place Statistics information. After this element has been found, the elements within this entry are iterated through with JSON pairs being formed for each statistic.

An instance of the JSONHandler class is created and a number of the methods on this instance are used to construct the JSON structure. Table 2 provides details of these methods.

Table 2. JSON handling methods provided by JSONHandler
API methodDescription
startJsonObjectStarts a JSON Object. Equivalent to typing an opening brace ({) into the structure.
jsonPair(key, value)Inserts a key-value pair into the structure:
fromDate : “2010-05-27”
startArray()Starts an array in the structure. Equivalent to entering an opening bracket ([).
startPair(pairkey)Starts a JSON pair with the key being passed in.
endPair()Ends a pair previously started with the startPair method.
endArray()Ends an array started with the startArray method. Effectively enters gthe closing bracket (]) into the structure.
endJsonObjectEnds a JSON Object started with the startJsonObject method. Effectively enters the closing brace (}) into the structure.

Producing exception feeds

Occasionally things go wrong, and the user needs to know about these cases.

Each of the FeedHandlers needs to be able to send details of exceptions that occurred in an appropriate format. For example, the Atom FeedHandler sends an Atom document containing details of the error, the JSON FeedHandler sends a JSON document, and so on. If you don't do that, then the JSON handling xhrGet used to get the Place Statistics feed might find itself being passed back an Atom exception report that it doesn't know what to do with.

The AtomFeedHandler uses Abdera to construct an Atom feed containing exception details. An instance of the FOMFactory class is used to generate a new feed with details of the exception being added into this instance. Finally, the whole thing is sent back to the caller. An example is shown in the listing to produce an Atom feed for an exception.

Listing 4. Example code to produce ATOM feed for an exception
public final Object produceExceptionFeed(Exception ex, 
PrintWriter writer, String feedId) {
    Feed feed = factory.newFeed();

    // Produce the feed header.
    this.produceFeedHeader(feed, MessageHelper.getMessageFromBundle
    ("statistics.feed.title"), feedId);

    // Add an entry in to show the error.
    Entry entry = factory.newEntry();
    entry.setTitle(MessageHelper.getMessageFromBundle
    ("statistics.feed.exceptiontitle"));
    entry.setContent(ex.getMessage());
    feed.insertEntry(entry);
		
    try {
      this.writeFeed(writer, feed);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return feed;
	}

The JSONFeedHandler outputs information about the exception in a JSON format. The WebSphere Portal API objects used to form JSON output that you've seen before are used to form the new structure. An instance of the com.ibm.portal.streaming.json.JSONHandler is used to create a document to which JSON pairs showing the exception are added as shown in listing 5.

Listing 5. Producing JSON feed for an exception
public Object produceExceptionFeed(Exception ex, PrintWriter writer, String id) {
		// TODO Auto-generated method stub
		JSONHandler json = null;
		try {
			json = this.getJSONHandler(writer);
			json.startDocument();
			json.startJSONObject();
			json.pair("id", PlaceStatisticsConstants.FEEDNAME);
			json.pair("name", PlaceStatisticsConstants.JSONERRORID);
			json.pair("message", ex.getMessage());
			json.endJSONObject();
			json.endDocument();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

Securing the servlet

Remember that the servlet needs details of the current user. And to work with these details, the servlet must be secured. An unsecured servlet can't get access to details of the current user.

The web.xml file for the servlet contains a <security-constraint> element that defines the security constraint, the HTTP methods that it applies to, and the roles that use the constraint. An example is shown in listing 6.

Listing 6. Securing the servlet in web.xml
 	<security-constraint id="SecurityConstraint_1">
      <web-resource-collection id="WebResourceCollection_1">
		<web-resource-name>Statistics Vault</web-resource-name>
		<url-pattern>/placestatistics</url-pattern>
		<http-method>GET</http-method>
	  </web-resource-collection>
		<auth-constraint id="AuthConstraint_1">
		<description>only for authenticated</description>
		<role-name>Authenticated</role-name>
      </auth-constraint>
	</security-constraint>
  <security-role id="SecurityRole_1">
	<description>All authenticated users</description>
	<role-name>Authenticated</role-name>
   </security-role>

Looking at the <security-constraint>/<web-resource-collection> section, the interesting parts are shown in table 3.

Table 3. Security constraint elements
Constraint elementDescription
<url-pattern>The URL that is having the security applied to it.
<http-method>Which HTTP methods the security is applied to. Leaving this element empty applies the security to all HTTP methods. As the PlaceStatistics servlet uses only the GET method, you apply security to GET operations.

The next step is to link the security roles that have access to the resource, and that link is done using the <auth-constraint> section. Next, you need to put specific users and groups into the roles that you defined during the application deployment. The EAR file is used to perform this task using XML contained in the application.xml file and ibm-application-bnd.xml files.

The application.xml file defines the EAR file, giving details of which WAR files are to be included. The context root of the application, for example, /lotus/PA_Place_Statistics, and details of the security roles used in the application are also provided. The ibm-application-bnd.xml file binds the security role to the appropriate users or groups, in this case the special All Authenticated Users group.

Both of these files are contained in the top-level META-INF directory in the EAR file that accompanies this article. The servlet is now secured and details of the currently logged-in user are available to it.


Place Statistics widget

To make full use of the Place Statistics servlet, you need to provide a means to:

  • View current statistics for a place using a UI
  • Download a CSV file containing the Place Statistics Information

You can do this download by using a JavaScript widget developed using Dojo 1.3.2, which is integrated into the Lotus Quickr theme. This widget is deployed as part of the EAR file supplied with this article and is placed in the directory:

wp_profile/installedApps/<node>/PA_Place_Statistics/js

Obtaining data

The techniques used to retrieve data for the UI and downloadable CSV file are different, with the UI able to use a straightforward Ajax call while the downloadable file is accessed using an <a> anchor tag.

Producing the widget UI

Producing the UI version of the widget is a two-step process. Step one is getting hold of the data by using an Ajax call to the Place Statistics servlet. The second step is to take the data and dynamically render a simple UI from it.

The getCurrentStats() function is used to retrieve the data as shown in listing 7.

Listing 7. JavaScript function to get the statistics feed
getCurrentStats: function() {
	var self = this;				
	var content = {"appid": this.placeId, "format": "json"};

	dojo.xhrGet({url: self.serverRoot + "/PA_Place_Statistics/placestatistics",
	 	content: content,
		handleAs: "json",
		load: function(response) { self._displayStats(response); },
		error: function(response,ioargs) {self._displayError(ioargs.xhr.status); }
			 });
			},

The ID of the place for which you want the statistics is held as an attribute on the widget. A JavaScript object is set up containing the “content” of the request; the content is the placeId and an indicator to say that you want a JSON structure returned.

The request to the Place Statistics servlet is then made, and the callbacks hooked into the load or error handlers are invoked as appropriate.

Assuming that the call is successful, the _displayStats() function is called. This step takes the items array declared in the JSON and uses it to dynamically build an HTML table showing the statistics details. An example is shown in listing 8.

Listing 8. Sample JavaScript code to display statistics
_displayStats: function(json) {
    dojo.byId(this.id + "_loading").style.display="none";

    // Go through each of the items. Each item represents a set of statistics.
    var self = this;

    var rangeString = this._labels["rangestring"] + " " + 
    json.fromDate + " - " + json.toDate;

    var statsHolder = dojo.create("div", {id: this.id + "_statsHolder", style: 
    {height: "260px", "overflow": "auto"}}, 				
    dojo.byId(this.id + "_statsdisplay"));
    dojo.create("h3",{},statsHolder).innerHTML = rangeString;

    // Start a table.
    var statTable = dojo.create("table", 
    {className: "lotusTable", border: "0", cellspacing: "0", 
      cellpadding: "0"}, statsHolder);
				
    if (json.items.length > 0) {
      var statsData = json.items[0].statistics;
				
      // Go through each of the statistics and create a row on the table.		
      dojo.forEach(statsData, function(stat) {
        var newRow = statTable.insertRow(0);
        var statDescCell = newRow.insertCell(0);
        statDescCell.innerHTML = self._labels[stat.key];
        var statValueCell = newRow.insertCell(1);
        statValueCell.innerHTML = stat.value;
      });
    }
},

Producing downloadable CSV

The Place Statistics widget also provides a link to obtain all the statistics for a place in a downloaded file supplied in CSV format. The link is constructed when the dialog is opened, the usual PlaceStatistics link being used with the parameters shown in table 4.

Table 4. Request parameters for obtaining CSV download
URL parameterDescription/contents
appidApplication ID
format“csv”
fromDateFirst date for which statistics are available
toDateLast date for which statistics are available

The from and to dates are obtained from the JSON structure returned as the response to the xhrGet call in the _getCurrentStats() function. As the URL is accessed by clicking the link (rather than through an xhrGet call), take care to encode each of the parameters. The response from the servlet has the content-type set to application/x-download so that the browser displays the Open/Save window.


Rendering the widget as a window

The Place Statistics widget is going to be presented as a window when it is accessed through a link. This access is done by styling the widget as a window and then including functions to show and hide the widget wrapped in a window.

First, you can look at the styling that affects how the window is displayed. This step involves putting a wrapping <div> around the widget and giving it the class lotusDialogBorder and max-width and width attributes. You also need a form element in there with classes of lotusDialog and lotusForm.

The piece of HTML code shown in listing 9 illustrates the window markup required.

Listing 9. HTML for the widget window
<div class="lotusDialogBorder" style="max-width:600px; width:600px;">
	<form id="${id}_PlaceStatsForm" 
	class="lotusDialog lotusForm" action="javascript:;">
	<h1>
		<a href="javascript:;" 
		class="lotusBtnImg lotusClose" title="Close Dialog" 
		  dojoAttachEvent="onclick: closeStatistics">"
		  <img src="${commonRes}/css/images/blank.gif"/>
		</a>Place Statistics
	</h1>"
	<div class="lotusDialogContent">
		<div>
		  Main part of widget markup goes in here.
		</div>
	</div>	
	<div class="lotusDialogFooter">
		  <input value="Close" class="lotusFormButton" 
		  dojoAttachEvent="onclick: closeStatistics"/>
	</form>
</div>

Add show/hide functions

When the Place Statistics link is clicked it displays the window. The window also needs to provide a way to close itself, which is done by using the closeStatistics() function bound to the close buttons by using dojoAttachEvent declarations as seen in listing 9. The show function must dynamically create a Dojo window object and put the PlaceStatistics content into it as shown in listing 10.

Listing 10. JavaScript function to show the window
….
popup: null,
postMixInProperties: function() {
	this.popup = new dijit.Dialog({});
}, …... 

show: function() {
		this.popup.attr("content",this.domNode);
		this.popup.show();
		this.getCurrentStats();
		},

An empty window is created in the postMixInProperties function. The show function then puts the top DOM node of the widget (this.domNode) into the window, shows it, and finally gets the place statistics.

The closeStatistics function is even simpler in that it invokes the hide method on the window to dismiss it from the display:

closeStatistics: function()
this.popup.hide();
}


Deployment

You have created the servlet, you've coded things to support authentication, output types, and more. The Dojo widget used to display the statistics to the user has also been coded. Now you've got to deploy it onto the server and add items into the theme to make the new feature accessible.

The following sections describe the full installation process and required changes to the theme.

Installing the servlet and widget using the EAR file

The EAR file that accompanies this article contains the servlet and the Dojo widget that is used to form a UI to the Place Statistics data. The EAR file can be installed on the Lotus Quickr server through the WebSphere Application Server administration console. Installing the EAR file puts the application in the /lotus/PA_Place_Statistics context root (defined in the application.xml file). After the EAR has been imported, the application needs to be started before either the servlet or the Dojo widget can be used.

If you look in the <server_root>\wp_profile\installedApps\<node> directory, you can see the PA_Place_Statistics directory.

Changing the theme

The only thing left to do now is to make some changes to the theme so that the user has a way to display the widget. You are going to incorporate the widget into Lotus Quickr so that it can be accessed using a link contained in the side navigation for the place, as shown in figure 2.

Figure 2. Side navigation showing new Place Statistics link
Side navigation showing new Place Statistics link

The following tasks need to be performed:

  • Update sideNav.jspf to provide access to the widget
  • Update js.jsp to load the Dojo widget

The two files we're going to change are both held in the application:
<server_root>\wp_profile\installedApps\<node>\QuickrThemeApp.ear

And the individual files under that directory are:
wp.theme.quickrtheme.war\themes\html\Quickr\js\js.jsp
wp.theme.quickrtheme.war\themes\html\Quickr\sideNav.jspf

Before you make any of the these changes, it's advisable to save copies of those theme files.

Load the widget in the js.jsp file

The js.jsp file needs to be amended to load the Place Statistics widget from the PA_Place_Statistics application. The js.jsp file is located at:
installedApps\QuickrThemeApp.ear\wp.theme.quickrtheme.war\themes\html\Quickr\js

You first need to register a module path so that Dojo knows where to get the statistics viewer. There are already a number of dojo.registerModulePath statements in the js.jsp file, and the following line can be added below these statements:
dojo.registerModulePath('com.ibm.quickr.statistics','/lotus/PA_Place_Statistics/js');

A <c:import> line then needs to be added to js.jsp file to load the Place Statistics widget. Add code like this:
<c:import url="/js/PlaceStatisticsViewer.js" context="/lotus/PA_Place_Statistics"/>

It should be noted that after this reference is put into the JSP file, the /lotus/PA_Place_Statistics application on the server must be started for the theme to work correctly.

Update sideNav.jspf to access the widget

You can now look at amending the sideNav.jspf file in the theme to include the link to launch the PlaceStatistics window. This file is at:
installedApps\QuickrThemeApp.ear\wp.theme.quickrtheme.war\themes\html\Quickr\sideNav.jspf.

Two main changes are required:

  • Some HTML markup to show the link
  • A new JavaScript function to open the widget

The sample sideNav.jspf file provided with this article contains examples of this code; these sections are marked with comments containing the text “PLACESTATS”. These pieces must be copied and pasted into your own copy of the sideNav.jspf file, rather than replacing the copy of the file on your server with the file contained in this article.

A new function to display the widget is placed at the bottom of the script. You need to pass the placeId, theme context root, and theme resource root into the function so that they can be passed into the widget.

The markup to show the link in the UI needs to be contained within a condition based on the isApplicationManager variable being set to true, so the link is displayed only if the current user is a manager. You also need to contain some code to obtain the theme context root and theme resource root. This task is done by using the code shown in listing 11.

Listing 11. JSP to show Place Statistics link in the Lotus Quickr theme
<c:if test="${isApplicationManager}">
	  <div>
	    <%
	      String themeContextRoot = theme.getContextRoot();
	      String themeResourceRoot = theme.getResourceRoot();
  	        %>    
	  <a href="javascript:;" onclick='showStatistics("<%=cdoGuid%>",
	    "<%=themeContextRoot%>","<%=themeResourceRoot%>")'>
	    Place Statistics</a>
	  </div>
</c:if >

The link to access the widget is defined as an <a> element. It includes an onclick event handler that calls the new function to show the widget, passing in the placeID, theme context root, and theme resource root.

Finally, you need to change the date stamp on the Default.jsp file for the theme changes to take effect. This file is located at:
installedApps\QuickrThemeApp.ear\wp.theme.quickrtheme.war\themes\html\Quickr\Default.jsp

One way to change the time stamp is to open the file in a text editor and save it.


What it looks like

After you've made the changes the new link is displayed below the left navigation menu as shown in figure 3.

Figure 3. Left navigation with Place Statistics added
Left navigation with Place Statistics added

Clicking the Place Statistics link displays a window that looks like the one shown in figure 4.

Figure 4. Place Statistics displayed in the web user interface to place managers
Place Statistics displayed in the web user interface to place managers

Clicking the Download Statistics link at the bottom of the window displays the usual browser download window, giving the default file name as placestatistics.csv. The file can either be saved or be opened using a program that accepts a CSV file as input, such as IBM Lotus Symphony™.


Using downloaded statistics

Now that you have a mechanism for place owners to download statistics about their places, they will be interested in exploring what statistics are available and what reports can be run.

Place owners can access place-level statistic data:

  • Total number of contents
  • Total size of contents (KB)
  • Total number of contents added today
  • Total number of contents updated today
  • Total number of web contents (blog post, wiki page, comment)
  • Total number of documents
  • Total number of web contents added today
  • Total number of web contents updated today
  • Total number of documents added today
  • Total number of documents updated today
  • Total number of blog posts
  • Total number of wiki pages
  • Total number of comments

Figure 5 shows a sample of downloaded place-level statistics in CSV file format.

Figure 5. Sample of comma-separated value (CSV) formatted statistics
Place level statistic data. Place Name: test1
,"Total number of contents","Total size of contents (KB)",
"Total number of contents added today", ......
2010-06-25,17443,1666,4640,2653,8896,8547,424,4881,4216,2430,1240,4371,2861
2010-06-26,17865,3198,8101,3065,11472,6393,4334,3291,3767,1663,1673,4977,488
2010-06-27,17529,4311,6957,4239,11471,6058,3002,4720,3955,1499,162,4389,3918
......
......

You can open the downloaded CSV file using Lotus Symphony Spreadsheets, Microsoft Excel, or your favorite spreadsheet application and create charts based on the statistics data. Figure 6 and 7 are two charts created based on “Total number of contents” and “Total size of contents (KB)” using Lotus Symphony Spreadsheets.

Figure 6. Example graph showing number of contents for places
Example graph showing number of contents for places
Figure 7. Graph showing total size of contents
Graph showing total size of contents

The CSV file containing the statistics data for these graphs is contained in Appendix 2 of this document.


Conclusion

This article shows how to use the Place Statistics services provided in Lotus Quickr 8.5 to present a UI showing the data and to provide the facility to export the statistics data into other applications.

Producing feeds of different formats using Abdera and the WebSphere Portal API has been demonstrated along with code showing how these feeds can be consumed.

The article also serves as an introduction to including Dojo widgets in the Lotus Quickr 8.5 theme. The technique of constructing a Dojo window and linking to an instance of this in the theme can be used in many different situations.


Appendix 1: Sample Atom feed

<feed xmlns:td="urn:ibm.com/td" xmlns="http://www.w3.org/2005/Atom">
  <id>urn:lsid:ibm.com:td:statistics</id>
  <title type="text">Lotus Quickr Admin Feed</title>
  <link href="/adminqcs/rest/statistics/feed" rel="self"></link>
  <link href="/adminqcs/rest/QuickrAdmin" rel="alternate"></link>
  <updated>2010-06-09T15:45:25.984Z</updated>
  <author>
    <name>Quickr Admin</name>
  </author>
  <td:total xmlns:td="urn:ibm.com/td">1</td:total>
  <td:statistic-range xmlns:td="urn:ibm.com/td" from="2010-05-07" 
  to="2010-06-08"></td:statistic-range>
  <entry xmlns:td="urn:ibm.com/td">
    <link rel="self"></link>
    <link rel="edit"></link>
    <id>1F_18M131M418NA60I2JCM5B51021</id>
    <title type="text">Place level statistic data. Place Name: Self Join Library</title>
    <published>2010-06-07T23:00:00.000Z</published>
    <updated>2010-06-07T23:00:00.000Z</updated>
    <td:statistics xmlns:td="urn:ibm.com/td">
      <td:property xmlns:td="urn:ibm.com/td" 
      key="document_totalNum">1</td:property>
      <td:property xmlns:td="urn:ibm.com/td" 
      key="document_size">1</td:property>
      <td:property xmlns:td="urn:ibm.com/td" 
      key="document_createdToday">0</td:property>
      <td:property xmlns:td="urn:ibm.com/td" 
      key="document_modifiedToday">0</td:property>
      <td:property xmlns:td="urn:ibm.com/td" 
      key="document_webdoc">0</td:property>
      <td:property xmlns:td="urn:ibm.com/td" 
      key="document_webdocCreatedToday">0</td:property>
      <td:property xmlns:td="urn:ibm.com/td" 
      key="document_webdocModifiedToday">0</td:property>
      <td:property xmlns:td="urn:ibm.com/td" 
      key="document_libdoc">1</td:property>
      <td:property xmlns:td="urn:ibm.com/td" 
      key="document_libdocCreatedToday">0</td:property>
      <td:property xmlns:td="urn:ibm.com/td" 
      key="document_libdocModifiedToday">0</td:property>
      <td:property xmlns:td="urn:ibm.com/td" 
      key="document_blog_totalNum">0</td:property>
      <td:property xmlns:td="urn:ibm.com/td" 
      key="document_wiki_totalNum">0</td:property>
      <td:property xmlns:td="urn:ibm.com/td" 
      key="document_comment_totalNum">0</td:property>
    </td:statistics>
  </entry>
</feed>

Appendix 2: CSV file for graphs

Place level statistic data. Place Name: test1
,"Total number of contents","Total size of contents (KB)","Total number of 
contents added today","Total number of contents updated today","Total 
number of web contents (blog post, wiki page, comment)","Total number 
of documents","Total number of web contents added today","Total number 
of web contents updated today","Total number of documents added 
today","Total number of documents updated today","Total number of blog 
posts","Total number of wiki pagess","Total number of comments"
2010-06-25,17443,1666,4640,2653,8896,8547,424,4881,4216,2430,1240,4371,2861
2010-06-26,17865,3198,8101,3065,11472,6393,4334,3291,3767,1663,1673,4977,488
2010-06-27,17529,4311,6957,4239,11471,6058,3002,4720,3955,1499,162,4389,3918
2010-06-28,14208,4323,5054,3620,10080,4128,2581,1121,2473,702,4201,746,2552
2010-06-29,12443,1301,3867,981,7597,4846,2371,2501,1496,749,217,2540,2469
2010-06-30,15494,2366,2938,1801,10809,4685,2701,2903,237,4286,4566,3290,252
2010-07-01,16620,4674,6849,627,8317,8303,2249,4931,4600,2813,3562,397,2109
2010-07-02,9927,1950,1054,3002,7314,2613,607,2125,447,4642,145,2428,4134
2010-07-03,8095,2436,3233,4363,3595,4500,1293,2074,1940,3416,93,20,2189
2010-07-04,19311,4066,3796,1185,14135,5176,3450,4040,346,1976,4446,2514,3725
2010-07-05,19913,2261,9272,3160,11316,8597,4403,1798,4869,1574,894,1877,4142
2010-07-06,12321,1792,5029,2556,8998,3323,3262,1967,1767,1133,3963,814,959
2010-07-07,16604,2194,5726,371,12048,4556,2828,4418,2898,1580,2932,2919,3369
2010-07-08,12897,2147,6183,2345,7288,5609,2505,703,3678,2593,2136,668,1979
2010-07-09,12351,3222,5878,38,8290,4061,4402,1953,1476,1439,488,3182,218
2010-07-10,12801,2088,7208,4206,7752,5049,2606,2225,4602,1547,3584,1414,148

Download

DescriptionNameSize
Code sampleplace.zip3.51MB

Resources

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


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Lotus
ArticleID=563116
ArticleTitle=IBM Lotus Quickr usage statistics: Measuring the success of team collaboration
publish-date=11022010