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