HowToUseUIGesturesCollectorInYourApp

Let's assume you have an application build on NetBeans Platform and you are interested in some statistics about your product. You have probably found a UIGesturesCollector project intended for this purpose in NetBeans IDE. This page will show you how to integrate this functionality into your own application.

Contents

How to start UI actions logging

On the IDE side, you will need one extra modules - 'uihandler' and a library 'lib.uihandler'. If the uihandler module is enabled it starts logging of UI events into uigestures file in <USERDIR>/var/log/ directory. The UI event is considered everything that is logged into "org.netbeans.ui" logger. Just a short sample here. For more details see java.util.logging package.

String UI_LOGGER_NAME = "org.netbeans.ui.mymodule";
LogRecord record = new LogRecord(Level.INFO, "MY_UI_ACTION_APPEARED"); 
record.setLoggerName(UI_LOGGER_NAME);
record.setParameters(new Object[] {
       "action param 1", "action param 2"
});
record.setResourceBundle(NbBundle.getBundle(MyClass.class));
Logger.getLogger(UI_LOGGER_NAME).log(record);

Uihandler module provides an API class Controller. Using this class you can manage the UI Gestures collector functionality. The most important is probably the submit method. Using this method you can submit UI gestures on demand. You can also use uihandler.interactive module that provides additional button into toolbar with submit on demand functionality.

todo screenshot with submit interactive

How to link the NetBeans Platform to the server

Now you know how to log your actions and you want to submit them to your server and not to NetBeans.org statistics server

The only thing you need to do is to set up the WELCOME_URL property in org.netbeans.modules.uihandler.Bundle to point to your website. The recommended way is to use branding. For debugging purpose it's easier to use org.netbeans.modules.uihandler.LoadURI property.

The provided the WELCOME_URL must point to your page that contains a XHTML page that is going to be shown while submitting data in an interactive mode. It also contains a form that is used to generate buttons on the submit page and an URL to page where the real data is submitted. Using this indirection you can easily switch different servers or even shutdown the service by editing the XHTML page. The XHTML page structure:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
   <title>Welcome to UI Gestures Collector</title>
</head>
<body>
<p>You can now submit data about the UI actions you did.</p>
<form action="http://your.server/analytics/upload.jsp" method="post">
   <input type="hidden" name="submit" value="&Submit Data"></input>
   <input type="hidden" name="auto-submit" value="&Automatic Submit"></input>
   <input type="hidden" name="view-data" value="&View Data" align="left" alt="&Hide Data"></input>
   <input type="hidden" name="exit" value="&Cancel"></input>
</form>
</body>
</html>

The document is easy to understand and I propose you to just play with it a bit to see how it works in the IDE. Just make sure the file you edit is valid XHTML. The action property of form tag contains the target server URL where you want to upload the data.

How to start UI Gestures server

Well, you have already configured logging in the IDE and you've set up the URL, where the data is going to be submitted. It's time to start your server and accept the data.

To get sources of the UI Gestures server you have to clone NetBeans main/misc Mercurial repository. If you need more information about Mercurial and NetBeans sources see HgNetBeansSources. Otherwise just running

hg clone http://hg.netbeans.org/main/misc
command should be enough. The UI Gestures server project is placed in misc/logger/uihandlerserver directory. You can open it in the IDE.

To build the project you can use Build action in project popup menu or just simple 'ant dist' command in uihandlerserver directory. During first build about 40 libraries will be downloaded so expect some network trafic and some time. After sucessfull build you can run the project using IDE or just 'ant run' command. You don't need to have any server installed because Tomcat will be downloaded and configured during the build process for you.

After successfull project deployment, you can verify the project is running by openning http://localhost:8888/ in your favorite browser.

Let's talk about what's going in there :). The base directory of Tomcat is configured to uihandlerserver/build/tomcat_base. You can see server logs at uihandlerserver/build/tomcat_base/logs to solve possible problems. As a data storage Derby DB is used in this localhost environment. It's data are stored at uihandlerserver/exceptionsDB directory. If you upload some files from NetBeans to this local server it will be stored at uihandlerserver/build/logs directory. So let's check it.

Data upload to localy deployed server

To submit data from NetBeans we will use uihandler.interactive module. Just build it (invoke 'ant' command in uihandler.interactive directory) and start NetBeans platform with system property to redirect data upload to your local server instance - invoke

<path_to_your_build_of_netbeans>/netbeans \
 -J-Dorg.netbeans.modules.uihandler.LoadURI=file:/...miscrepo/logger/uihandlerserver/redirect.xhtml

Invoke 'Submit UI Logs' button at toolbar. Small dialog will appear and you can see collected data, Submit data and let IDE to submit data automatically when ever 1000 logs is collected. Press Submit Data button. Now let's what's going on with our server. Go to uihandlerserver/build/logs directory. You will find new directory there and one file inside the structure. Refresh the page in browser where you have the analytics application - you will see that there is one log uploaded.

How to configure production environment

Now we have deployed the application to localhost with embedded Derby DB which is good for debugging, but it's not very good for production and thus let's make better configuration with MySQL DB with higher performance. See MySQL install guide to install MySQL DB. You will have to create new database and set up a user for MySQL. Look into MySQL documentation how to do it.

If you have already configured MySQL DB and you can connect to it, you will have to create a DB schema. The DB Schema is described as an SQL construction script createDB.sql placed at uihandler/db directory. If you use MySQL command line client, just run

mysql -u<username> -p <db_name> < uihandler/db/createDB.sql

command, set a password and the schema will be created. There will be about 30 tables created in total.

Now it's time to set up uihander server to connect the MySQL. First of all you will need to edit persistence.xml configuration file and set up the Persistence Unit. You can just modify existing 'ExceptionsHibernatePU' by setting correct MySQL URL, username and password. Then you can redeploy the project specifying non default persistence unit in an ant property:

ant run -Dpersistence.unit=ExceptionsHibernatePU

You will probably start server at different port than 8888 and you will store your data (uploaded logs) somewhere else then in build directory. Here is the set of properties you can use to set up these and other options:

  • analytics.dir - directory where to upload logs
  • persistence.unit - persistence unit that should be used for DB connection
  • tomcat.opts - additional tomcat options like additional memory. We use tomcat.opts="-Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<path_to_heapdumps_dir>" in our production environment
  • logging.level - you can set server logging level as (FINEST, FINE, INFO, WARNING, SEVERE); INFO is used by default
  • settings.dir - path to a setting directory; the setting directory contains additional setting files.
  • tomcat.port - port used by the server process (8888 as default)
  • tomcat.debug.port - port open for debugger

How to process UI Gestures data

We have already prepared our application to submit what ever we need and we can accept it where ever we need. The task now is how to process and visualize the data. To reach this goal you have to do to actions. Create a statistic and create a JSP page to visualize the data.

To create a statistic we have to extend an abstract class org.netbeans.server.uihandler.Statistics and implement its six abstract methods. Let's create a simple statistics that will just count how many times our action appeared.

// register MyActionStatistic as a service
@ServiceProvider(service=Statistics.class)
public class MyActionStatistic extends Statistics<Integer> {
   // the name of the statistics
   public static final String STATISTIC_NAME = "MyActionStatistic";
   public MyActionStatistic() {
       super(STATISTIC_NAME);
   }
   // create new empty data instance
   @Override
   protected Integer newData() { 
       return 0;
   }
   // process a log record
   @Override
   protected Integer process(LogRecord rec) { 
       if ("MY_UI_ACTION_APPEARED".equals(rec.getMessage())){
           return 1; // let's count only our actions
       }else{
           return 0;
       }
   }
   @Override
   protected Integer finishSessionUpload(String userId, int sessionNumber, boolean initialParse, Integer d) {
       // here we could filter all records from one user
       return d;
   }
   @Override
   protected Integer join(Integer one, Integer two) { 
       // join statistics of more records
       return one + two;
   }
   @Override
   protected void write(Preferences pref, Integer d) throws BackingStoreException {
       // store data into persistent preferences
       pref.putInt("value", d);
   }
   @Override
   protected Integer read(Preferences pref) throws BackingStoreException {
       //read data from persistent preferences
       return pref.getInt("value", 0);
   }
}

There is a detailed javadoc for all the methods and you can find many samples in already existing statistics. The statistic is ready to count data, but before running all the server let's test it first. Open the statistic in NetBeans editor and invoke Tools/Create JUnit Test. For the test we will need a log that we have already submitted to our server in previous section. Let's copy the file stored somewhere deeply in the directory structure of uihandlerserver/build/logs directory into directory of the test file and let's replace the test code with the following code.

public class MyActionStatisticTest extends DatabaseTestCase {
   public MyActionStatisticTest(String name) {
       super(name);
   }
   @Test
   public void testParsing() throws Exception {
       Object countObject = super.processLog(MyActionStatisticTest.class,
           "my_actions.log", MyActionStatistic.STATISTIC_NAME);
       assertNotNull(countObject);
       assertTrue(countObject instanceof Integer);
       Integer count = (Integer) countObject;
       // how many time the action was invoked
       assertEquals("Just one invocation in the session", 1, count.intValue());
   }
}

DatabaseTestCase is a base for your tests. It initializes whole infrastructure based again on Derby DB. It's protected method 'processLog(TestClass, logfile_name, statistic_name) will return you the data that your statistic has generated.

How to visualize UI Gestures data

Well we have already writen and tested simple statistics so let's go to create same charts and to visualize the data. The problem of our statistic is that it counts only one number and there is not much to visualize. Let's make our statistic little bit more useful. Now we count only the whole number of all our actions, we will add a count of all sessions and of all sessions where our action appeard. Then we will create a pie chart showing what is the percentage of users who used our action in thir session and how many did not. As a second chart we will create a bar chart showing the average number of usages in one session and the average number of usages in sessions with at least one usage (it will filter the "ignorants" of our action).

The implementation is quite straight-forward. We will change the type of statistic from Integer to a DataBean containing all required information and will update all abstract methods to count the data correctly. Also don't omit updating tests. Here you can find my implementation Media:My_action.zip.

Let's start with the visualization. First of all let's create a JSP page. We will use statistic tag library that provides 'useStatistic' tag. The 'useStatistic' tag injects the statistics data into the JSP page. To create chars we will use also statistic tag library and its pie and bar tags. See the sample code how the JSP page could look like.

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="/WEB-INF/statistics.tld" prefix="ui"%>
<ui:useStatistic name="MyActionStatistic"/>
<html>
   <head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
       <title>My Statistic</title>
   </head>
   <body>
       <h1>My Statistic</h1>
       <ui:pie
           collection="globalMyActionStatisticUsages"
           category="key"
           value="value"
           title="How many users used our action in their session?"
           resolution="600x200"
           />
   </body>
</html>

The 'useStatistic' tag injects the data that your statistic has created into the JSP page. In our case we don't need to preprocess the data first, because the pie chart tag accepts a collection and it doesn't know nothing about our DataBean. First of all we need to prepare a map of values. Let's add one more method to the DataBean. The method will prepare a map of fields all that we want to show in the chart.

public Map<String, Integer> getUsages(){
  Map<String, Integer> usages = new HashMap<String, Integer>();
  usages.put("action was used", countOfNonNullSessions);
  usages.put("action was not used", countOfAllSessions - countOfNonNullSessions);
  return usages;
}

To register this value into JSP page we need to overwrite a registerPageContext method of our statistic. See sample code.

@Override
protected void registerPageContext(PageContext page, String name, DataBean data) {
  page.setAttribute(name + "Usages", data.getUsages());
}

Now you can run the web server, submit some logs to it from the IDE and open the URL http://localhost:8888/analytics/<path_to_your_jsp_page>. You will see a chart showing your data. [Media:Mystatistic.png]

Let's talk about the name of the collection you can see, that we have used bit mystic name 'globalMyActionStatisticUsages'. The prefix of the name 'global' describes that we want to see the over all statistics. There is also a possibility of 'user' and 'last' prefixes. The last prefix contains only data counted for the last submitted log and the 'user' prefix contains all the data from the submitter. The middle part of the name 'MyActionStatistic' is the name of statistic that has counted the data and the suffix 'Usages' was added by registerPageContext method. We will create one more chart, so we will register one more collection and thus some suffix is needed to distinguish them.

Let's create the bar chart showing the average number of usages in one session and the average number of usages in sessions with at least one usage. Our DataBean should provide a data collection.

private Collection<ViewBean> getAvgData() {
 List<ViewBean> vb = new ArrayList<ViewBean>();
 vb.add(new ViewBean("AVG for all logs", actionsCount / countOfAllSessions));
 vb.add(new ViewBean("AVG for users", actionsCount / countOfNonNullSessions));
 return vb;
}
public static final class ViewBean {
 private final String name;
 private final Integer value;
 public ViewBean(String name, Integer value) {
   this.name = name;
   this.value = value;
 }
 public String getName() {
   return name;
 }
 public Integer getValue() {
   return value;
 }
}

We have to register the data in registerPageContext

@Override
protected void registerPageContext(PageContext page, String name, DataBean data) {
   page.setAttribute(name + "Usages", data.getUsages());
   page.setAttribute(name + "Avg", data.getAvgData());
}

And finally create a chart in JSP page:

<ui:bar
  collection="globalMyActionStatisticAvg"
  category="name"
  value="value"
  serie="name"
  stacked="true"
  title="What is the average count of action invocations?"
  resolution="300x400"
/>

How to enable Exceptions Reporter

ReportExceptionProject is another part of the UI Gestures Collector. Let's assume an idea that an exception thrown by the IDE is a type of UI Gesture. On the other side, while having an infrastructure how to connect users with developers it sound pretty natural to use it and get as much information about users problems as possible.

To enable Exceptions Reporter just add uihandler.exceptionreporter module into your application or use uihandler API class Controller do activate it from your code. After the activation new button Review and Report Problem will be injected into the Unexpected Exception dialog that appears after an exception in Platform. The process is than very similar to UI Gestures process. You have to set up the URL to a page that is going to be downloaded from web. The Bundle property for exception reports is called ERROR_URL. If you want get a dialog with requested description, username etc. instead of HTML code set alt="reportDialog" parametter to submit button.

The file could look like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
  <title>An error in the application appeared</title>
</head>
<body>
<p>You can now error data to us.</p>
<form action="http://your.server/analytics/upload.jsp" method="post">
  <input type="hidden" name="submit" value="&Submit Data" alt="reportDialog"></input>
  <input type="hidden" name="view-data" value="&View Data" align="left" alt="&Hide Data"></input>
  <input type="hidden" name="exit" value="&Cancel"></input>
</form>
</body>
</html>

You can now start your application, invoke some action that throws an exception and report it using the exception reporter tool. You will probably notice that the user authentication doesn't work as you would expect. The are two more things to be done for this.

First you have to implement the authentication servlet. The servlet should return simply 'true' or 'false' for a request authenticate?username=<name>&password=<passwd> and you should set CHECKING_SERVER_URL property in the IDE in the same way as you have done with WELCOME_URL and ERROR_URL. Of course you don't have to write the servlet from scratch. You can use already existing implementation org.netbeans.server.uihandler.Authenticate class and just add put your authetication method in there.

Second thing that you should do is to generate a private/public key pair, replace pubKey file in lib.uihandler module with your public key and place your private key into server settings directory(see settings.dir property) into privKey file. You can change the file name on web.xml file if you were interested in it. Since now the password will be submitted encrypted and not open through the internet.

How to configure Bugzilla Connector

TODO

How to configure JIRA Connector

TODO

How to add Slowness Detector functionality

Check this blog to get started: http://weblogs.java.net/blog/fvo/archive/2010/11/19/slowness-detection-netbeans-rcp-applications



Jindrich Sedek 1/6/2009
Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo