001    package org.hackystat.telemetry.analyzer.reducer.impl;
002    
003    import java.util.List;
004    
005    import org.hackystat.dailyprojectdata.client.DailyProjectDataClient;
006    import org.hackystat.dailyprojectdata.resource.filemetric.jaxb.FileMetricDailyProjectData;
007    import org.hackystat.sensorbase.resource.projects.jaxb.Project;
008    import org.hackystat.telemetry.analyzer.model.TelemetryDataPoint;
009    import org.hackystat.telemetry.analyzer.model.TelemetryStream;
010    import org.hackystat.telemetry.analyzer.model.TelemetryStreamCollection;
011    import org.hackystat.telemetry.analyzer.reducer.TelemetryReducer;
012    import org.hackystat.telemetry.analyzer.reducer.TelemetryReducerException;
013    import org.hackystat.telemetry.analyzer.reducer.util.IntervalUtility;
014    import org.hackystat.telemetry.service.server.ServerProperties;
015    import org.hackystat.utilities.time.interval.Interval;
016    import org.hackystat.utilities.time.period.Day;
017    import org.hackystat.utilities.tstamp.Tstamp;
018    
019    
020    /**
021     * Returns a single stream providing FileMetric data.
022     * <p>
023     * Options:
024     * <ol>
025     * <li> sizemetric: A string indicating the size metric to return, such as "TotalLines".
026     * Default is 'TotalLines'.
027     * <li> tool: A string indicating the tool whose size data will be retrieved, such as "SCLC".
028     * Default is '*', indicating that any tool will do.
029     * </ol>
030     * 
031     * @author Philip Johnson, Cedric Zhang
032     */
033    public class FileMetricReducer implements TelemetryReducer { 
034     
035      /**
036       * Computes and returns the required telemetry streams object.
037       * 
038       * @param project The project.
039       * @param dpdClient The DPD Client.
040       * @param interval The interval.
041       * @param options The optional parameters.
042       * 
043       * @return Telemetry stream collection.
044       * @throws TelemetryReducerException If there is any error.
045       */
046      public TelemetryStreamCollection compute(Project project, DailyProjectDataClient dpdClient, 
047          Interval interval, String[] options) throws TelemetryReducerException {
048        String sizeMetric = null;
049        String tool = "*";
050        // process options
051        if (options.length > 2) {
052          throw new TelemetryReducerException("FileMetricReducer takes 1 optional parameter.");
053        }
054        if (options.length >= 1) {
055          sizeMetric = options[0];
056        }
057        if (options.length > 1) {
058          tool = options[1];
059        }
060    
061        // Find out the DailyProjectData host, throw error if not found.
062        String dpdHost = System.getProperty(ServerProperties.DAILYPROJECTDATA_FULLHOST_KEY);
063        if (dpdHost == null) {
064          throw new TelemetryReducerException("Null DPD host in FileMetricReducer.");
065        }
066    
067        // now get the telemetry stream.
068        try {
069          TelemetryStream telemetryStream = this.getStream(dpdClient, project, interval,   
070              sizeMetric, tool, null);
071          TelemetryStreamCollection streams = new TelemetryStreamCollection(null, project, interval);
072          streams.add(telemetryStream);
073          return streams;
074        } 
075        catch (Exception e) {
076          throw new TelemetryReducerException(e);
077        }
078      }
079    
080      /**
081       * Gets the telemetry stream.
082       * 
083       * @param dpdClient The DailyProjectData client we will contact for the data.
084       * @param project The project.
085       * @param interval The interval.
086       * @param sizeMetric The SizeMetric.
087       * @param tool The tool to get the size data from. 
088       * @param streamTagValue The tag for the generated telemetry stream.
089       * 
090       * @return The telemetry stream as required.
091       * 
092       * @throws Exception If there is any error.
093       */
094      TelemetryStream getStream(DailyProjectDataClient dpdClient, 
095          Project project, Interval interval, String sizeMetric, String tool, 
096          Object streamTagValue) 
097            throws Exception {
098        TelemetryStream telemetryStream = new TelemetryStream(streamTagValue);
099        List<IntervalUtility.Period> periods = IntervalUtility.getPeriods(interval);
100    
101        for (IntervalUtility.Period period : periods) {
102          Double value = this.getData(dpdClient, project, period.getStartDay(), period.getEndDay(),
103              sizeMetric, tool);
104          telemetryStream.addDataPoint(new TelemetryDataPoint(period.getTimePeriod(), value));
105        }
106        return telemetryStream;
107      }
108      
109      /**
110       * Returns a FileMetric value for the specified time interval and sizeMetric, or null 
111       * if no SensorData. 
112       * 
113       * We work backward through the time interval, and return the FileMetric value for the first day 
114       * in the interval for which FileMetric data exists.
115       * 
116       * @param dpdClient The DailyProjectData client we will use to get this data.
117       * @param project The project.
118       * @param startDay The start day (inclusive).
119       * @param endDay The end day (inclusive).
120       * @param sizeMetric The size metric.
121       * @param tool The tool name, or "*" if any tool will do. 
122       * @throws TelemetryReducerException If anything goes wrong.
123       * 
124       * @return The FileMetric value, or null if there is no SensorData for that time period.
125       */
126      Double getData(DailyProjectDataClient dpdClient, Project project, Day startDay, Day endDay, 
127          String sizeMetric, String tool) throws TelemetryReducerException {
128        try {
129          // Work backward through the interval, and return as soon as we get matching FileMetric info.
130          // We might want to make this smarter, and keep searching if we find FileMetric data but
131          // not containing the given sizeMetric.
132          for (Day day = endDay; day.compareTo(startDay) >= 0; day = day.inc(-1) ) {
133            // Get the DPD...
134            FileMetricDailyProjectData dpdData = 
135              dpdClient.getFileMetric(project.getOwner(), project.getName(), Tstamp.makeTimestamp(day),
136                  sizeMetric, ("*".equals(tool) ? null : tool));
137            // Return null right away if DPD is empty.
138            if ((dpdData.getFileData() == null) || dpdData.getFileData().isEmpty()) {
139              continue;
140            }
141            // Otherwise we have FileMetric data, so return the total field.
142            // Note that it can be null.
143            return dpdData.getTotal();
144          }
145        }
146        catch (Exception ex) {
147          throw new TelemetryReducerException(ex);
148        }
149        // Never found appropriate FileMetric data in this interval, so return null.
150        return null;
151      }
152    
153    }