001 package org.hackystat.sensor.ant.javancss; 002 003 import java.io.File; 004 import java.util.Date; 005 import java.util.HashMap; 006 import java.util.Map; 007 008 import javax.xml.bind.JAXBContext; 009 import javax.xml.bind.Unmarshaller; 010 import javax.xml.datatype.XMLGregorianCalendar; 011 012 import org.apache.tools.ant.BuildException; 013 import org.hackystat.sensor.ant.javancss.jaxb.Javancss; 014 import org.hackystat.sensor.ant.task.HackystatSensorTask; 015 import org.hackystat.utilities.tstamp.Tstamp; 016 017 /** 018 * Implements an Ant task that parses the XML files generated by JavaNCSS. The Ant Task sends the 019 * FileMetric data to a Hackystat server. 020 * 021 * @author Philip Johnson 022 */ 023 public class JavaNcssSensor extends HackystatSensorTask { 024 025 /** The name of this tool. */ 026 private static String tool = "JavaNCSS"; 027 028 /** Initialize a new instance of a JavaNcssSensor. */ 029 public JavaNcssSensor() { 030 super(tool); 031 } 032 033 /** 034 * Initialize a new instance of a JavaNcssSensor for testing purposes. 035 * 036 * @param host The SensorBase host URL. 037 * @param email The SensorBase email to use. 038 * @param password The SensorBase password to use. 039 */ 040 public JavaNcssSensor(String host, String email, String password) { 041 super(host, email, password, tool); 042 } 043 044 /** 045 * Parses the JavaNCSS XML file and sends the resulting FileMetric data to the SensorBase server. 046 * 047 * @throws BuildException If there is an error. 048 */ 049 @Override 050 public void executeInternal() throws BuildException { 051 this.setupSensorShell(); 052 int numberOfEntries = 0; 053 Date startTime = new Date(); 054 for (File dataFile : getDataFiles()) { 055 try { 056 verboseInfo("Processing JavaNCSS file: " + dataFile); 057 numberOfEntries += this.processJavaNcssXmlFile(dataFile); 058 } 059 catch (Exception e) { 060 signalError("Failure processing: " + dataFile, e); 061 } 062 } 063 // We've collected the data, now send it. 064 this.sendAndQuit(); 065 summaryInfo(startTime, "FileMetric", numberOfEntries); 066 } 067 068 /** 069 * Processes the JavaNCSS XML data file, generating sensor data. 070 * 071 * @param xmlFile The file containing the JavaNCSS data. 072 * @return The number of FileMetrics instances generated. 073 * @throws BuildException If problems occur. 074 */ 075 int processJavaNcssXmlFile(File xmlFile) throws BuildException { 076 // The start time for all entries will be approximated by the XML file's last mod time. 077 // Use the TstampSet to make it unique. 078 long startTime = xmlFile.lastModified(); 079 int count = 0; 080 try { 081 JAXBContext context = JAXBContext 082 .newInstance(org.hackystat.sensor.ant.javancss.jaxb.ObjectFactory.class); 083 Unmarshaller unmarshaller = context.createUnmarshaller(); 084 085 // JavaNCSS report. 086 Javancss javancss = (Javancss) unmarshaller.unmarshal(xmlFile); 087 // Construct the mapping from Java file paths to their CCN data. 088 CcnData ccnData = new CcnData(getSourceFiles(), javancss.getFunctions()); 089 090 for (File resource : ccnData.getFiles()) { 091 long tstamp = this.tstampSet.getUniqueTstamp(startTime); 092 XMLGregorianCalendar tstampXml = Tstamp.makeTimestamp(tstamp); 093 XMLGregorianCalendar runtimeXml = Tstamp.makeTimestamp(this.runtime); 094 // Create the sensor data instance key/value map. 095 Map<String, String> keyValMap = new HashMap<String, String>(); 096 // Required 097 keyValMap.put("Tool", "JavaNCSS"); 098 keyValMap.put("SensorDataType", "FileMetric"); 099 keyValMap.put("Runtime", runtimeXml.toString()); 100 keyValMap.put("Timestamp", tstampXml.toString()); 101 keyValMap.put("Resource", resource.getAbsolutePath()); 102 // Expected 103 keyValMap.put("TotalLines", String.valueOf(ccnData.getTotalLines(resource))); 104 // Optional, but of course the whole point of this sensor. 105 keyValMap.put("CyclomaticComplexityList", ccnData.getCcnData(resource)); 106 // add data to sensorshell 107 this.sensorShell.add(keyValMap); 108 count++; 109 } 110 return count; 111 } 112 catch (Exception e) { 113 throw new BuildException(errMsgPrefix + "Failure: " + e.getMessage(), e); 114 } 115 } 116 }