001    package org.hackystat.dailyprojectdata.resource.filemetric;
002    
003    import java.math.BigInteger;
004    import java.util.ArrayList;
005    import java.util.Iterator;
006    import java.util.List;
007    import javax.xml.datatype.XMLGregorianCalendar;
008    import org.hackystat.sensorbase.client.SensorBaseClient;
009    import org.hackystat.sensorbase.client.SensorBaseClientException;
010    import org.hackystat.sensorbase.resource.sensordata.jaxb.Property;
011    import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorData;
012    import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorDataRef;
013    import org.hackystat.utilities.time.period.Day;
014    import org.hackystat.utilities.tstamp.Tstamp;
015    
016    /**
017     * Provides a facility for counting the FileMetrics associated with a
018     * SensorData. It only counts the FileMetrics from the 'last' run of the same
019     * tool. This ensures that the FileMetric size is the latest snapshot of the
020     * Project's size.
021     * 
022     * The FileMetricCounter currently only looks at TotalLines.
023     * 
024     * @author Cam Moore
025     * 
026     */
027    public class FileMetricCounter {
028    
029      private String lastTool;
030      private XMLGregorianCalendar lastTime;
031      private List<SensorData> fileMetrics;
032      private SensorBaseClient sbClient;
033      private long totalLines;
034    
035      /**
036       * Constructs a FileMetricCounter.
037       * 
038       * @param client the SensorBaseClient to use to get the SensorData.
039       */
040      public FileMetricCounter(SensorBaseClient client) {
041        this.lastTool = "";
042        Day first = Day.getInstance(1000, 0, 1); // pick a very early Day
043        this.lastTime = Tstamp.makeTimestamp(first);
044        this.fileMetrics = new ArrayList<SensorData>();
045        this.sbClient = client;
046        this.totalLines = 0;
047      }
048    
049      /**
050       * Adds the SensorData to the list of FileMetrics if it is in the last run of the
051       * size counting tool.  Updates the total lines value.  If this sensor data represents
052       * a new run of a size counting tool then the total lines and list of file metrics is 
053       * reset.
054       * @param ref a SensorDataRef, the sensor data to add.
055       */
056      public void add(SensorDataRef ref) {
057        try {
058          SensorData data = sbClient.getSensorData(ref);
059          XMLGregorianCalendar refTime = data.getRuntime();
060          if (Tstamp.equal(lastTime, refTime)) {
061            data = sbClient.getSensorData(ref);
062            if (lastTool.equals(data.getTool())) {
063              // only add data from the same tool.
064              List<Property> props = data.getProperties().getProperty();
065              for (Iterator<Property> iter = props.iterator(); iter.hasNext();) {
066                Property prop = iter.next();
067                if (prop.getKey().equals("TotalLines")) {
068                  totalLines += Long.parseLong(prop.getValue());
069                }
070              }
071              fileMetrics.add(data);
072            }
073    
074          } 
075          else if (Tstamp.greaterThan(refTime, lastTime)) {
076            // newer time so replace everything
077            lastTime = refTime;
078            fileMetrics = new ArrayList<SensorData>();
079            totalLines = 0;
080            lastTool = data.getTool();
081            List<Property> props = data.getProperties().getProperty();
082            for (Iterator<Property> iter = props.iterator(); iter.hasNext();) {
083              Property prop = iter.next();
084              if (prop.getKey().equals("TotalLines")) {
085                totalLines += Long.parseLong(prop.getValue());
086              }
087            }
088            fileMetrics.add(data);
089          }
090        } 
091        catch (SensorBaseClientException e) {
092          lastTool = "";
093        }
094    
095      }
096    
097      /**
098       * @return The total lines as a BigInteger.
099       */
100      public BigInteger getTotalLines() {
101        return BigInteger.valueOf(totalLines);
102      }
103    
104      /**
105       * @return The individual FileMetrics SensorDataRefs.
106       */
107      public List<SensorData> getFileMetrics() {
108        return fileMetrics;
109      }
110    
111      /**
112       * @return The last time a size counting tool was run.
113       */
114      public XMLGregorianCalendar getLastTime() {
115        return lastTime;
116      }
117    
118      /**
119       * @param data a SensorData.
120       * @return The total lines in the given SensorData or 0 if the property "TotalLines"
121       * is undefined.
122       */
123      public BigInteger getTotalLines(SensorData data) {
124        long totalLines = 0;
125        List<Property> props = data.getProperties().getProperty();
126        for (Iterator<Property> iter = props.iterator(); iter.hasNext();) {
127          Property prop = iter.next();
128          if (prop.getKey().equals("TotalLines")) {
129            totalLines += Long.parseLong(prop.getValue());
130          }
131        }
132        return BigInteger.valueOf(totalLines);
133      }
134    }