17.11. Sensors for servers

In most cases, you will be developing a sensor for a "single user" tool, such as an editor. In these cases, all of the sensor data should be associated with the user whose Hackystat host and user key is maintained in the sensor.properties file.

However, there is another class of tools, such as for configuration management (CVS, Subversion) or issue tracking (Bugzilla, Jira) in which the sensor data should be associated with multiple users. For example, in the case of a configuration management system, the sensor data for a commit should be associated with the user who committed the data, not the owner of the account who is running the configuration management tool.

To enable this behavior, Hackystat provides a special file called "usermaps.xml" that can be managed using HackyInstaller and Java classes that facilitate manipulation of this data. The UserMap provides a way of associating the account names for a particular server tool with the user keys for a Hackystat host. For details on how to manage the contents of the UserMaps.xml file using HackyInstaller, see Section 2.7, “Sensors for multi-user tools and the usermaps.xml file”.

When implementing a sensor for a multi-user tool, you must read in the usermaps.xml file (to obtain the mappings between your tool account names and the associated Hackystat user keys), then create a set of SensorShell instances, one for each user. For each instance of sensor data, you must determine the account name associated with the data, map it to the Hackystat user key, and then send it to the SensorShell instance associated with that Hackystat user.

For Java-based sensors, we have provided a set of Java classes that simplify this process. Example 17.31, “SensorShellMap initialization” shows an excerpt of code from the Bugzilla sensor illustrating the setup of one of these helper classes, called SensorShellMap.

Example 17.31. SensorShellMap initialization

 
String hackystatServer = new SensorProperties("Bugzilla").getHackystatHost();
this.sensorShellMap = new SensorShellMap(hackystatServer, "Bugzilla", "Issue");
if (this.defaultHackystatAccountKey != null) {
  this.defaultUserSensorShell = new SensorShell(new SensorProperties(hackystatServer, 
      this.defaultHackystatAccountKey), false, "Bugzilla");
  this.sensorShells.add(this.defaultUserSensorShell);
}

The SensorShellMap is provided with a Hackystat host, the name of the tool, and a string indicating the type of data being sent. It reads in the usermaps.xml file, finds the entries associated with the tool, and provides access to a SensorShell instance for each of the users indicated in the usermaps.xml file. In this code snippet, you can see how the SensorShellMap can be augmented with a "default" sensorshell to be used when sensor data is generated for an account that does not have a corresponding user key in the usermaps.xml file.

Example 17.32, “SensorShell retrieval” shows the getSensorShellBySvnAccountName method from the Bugzilla sensor, which illustrates how to obtain a SensorShell for a given Hackystat user given their Bugzilla account name.

Example 17.32. SensorShell retrieval

 
  private SensorShell getSensorShellBySvnAccountName(String bugzillaAccountName) {
    SensorShell shell = null;
    if (this.sensorShellMap.hasUserShell(bugzillaAccountName)) {
      try {
        shell = this.sensorShellMap.getUserShell(bugzillaAccountName);
      }
      catch (SensorShellMapException ex) {
        // this shouldn't typically happen since we're using hasUserShell.
        shell = this.defaultUserSensorShell;
      }
    }
    else {
      // bugzillaAccountName was not in the usermap, so we use the default shell if available.
      shell = this.defaultUserSensorShell;
    }
    // Shell can still be null if svnAccountName not in the mapping and there is no default user.
    if (shell != null) {
      this.sensorShells.add(shell);
    }
    // Return the shell to use or null if none was found.
    return shell;
  }  

This code is pretty straightforward; the complexities basically involve the corner cases where there is no mapping or no default user.

Once you have the SensorShell instance, you generate the sensor data in the normal way and send it off. For more details on this approach, it can be helpful to look at already implemented sensors using this code, including the Bugzilla, Jira, SVN, and CVS sensors.