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.commit.jaxb.CommitDailyProjectData;
007    import org.hackystat.dailyprojectdata.resource.commit.jaxb.MemberData;
008    import org.hackystat.sensorbase.resource.projects.jaxb.Project;
009    import org.hackystat.telemetry.analyzer.model.TelemetryDataPoint;
010    import org.hackystat.telemetry.analyzer.model.TelemetryStream;
011    import org.hackystat.telemetry.analyzer.model.TelemetryStreamCollection;
012    import org.hackystat.telemetry.analyzer.reducer.TelemetryReducer;
013    import org.hackystat.telemetry.analyzer.reducer.TelemetryReducerException;
014    import org.hackystat.telemetry.analyzer.reducer.util.IntervalUtility;
015    import org.hackystat.telemetry.service.server.ServerProperties;
016    import org.hackystat.utilities.time.interval.Interval;
017    import org.hackystat.utilities.time.period.Day;
018    import org.hackystat.utilities.tstamp.Tstamp;
019    
020    
021    /**
022     * Returns a single stream providing Commit counts.
023     * <p>
024     * Options:
025     * <ol>
026     * <li> member: The project member whose commit counts are to be returned, or "*" for all members.
027     * <li> isCumulative: True or false. Default is false.
028     * </ol>
029     * 
030     * @author Philip Johnson
031     */
032    public class CommitReducer implements TelemetryReducer { 
033     
034      /**
035       * Computes and returns the required telemetry streams object.
036       *
037       * @param project The project.
038       * @param dpdClient The DPD Client.
039       * @param interval The interval.
040       * @param options The optional parameters.
041       *
042       * @return Telemetry stream collection.
043       * @throws TelemetryReducerException If there is any error.
044       */
045      public TelemetryStreamCollection compute(Project project, DailyProjectDataClient dpdClient, 
046          Interval interval, String[] options) throws TelemetryReducerException {
047        String member = null;
048        boolean isCumulative = false;
049        //process options
050        if (options.length > 2) {
051          throw new TelemetryReducerException("Commit reducer takes 2 optional parameters.");
052        }
053        if (options.length >= 1) {
054          member = options[0];
055        }
056        
057        if (options.length >= 2) {
058          try {
059            isCumulative = Boolean.valueOf(options[1]);
060          }
061          catch (Exception e) {
062            throw new TelemetryReducerException("Illegal cumulative value.", e);
063          }
064        }
065        
066        // Find out the DailyProjectData host, throw error if not found.
067        String dpdHost = System.getProperty(ServerProperties.DAILYPROJECTDATA_FULLHOST_KEY);
068        if (dpdHost == null) {
069          throw new TelemetryReducerException("Null DPD host in CommitReducer");
070        }
071    
072        // now get the telemetry stream. 
073        try {
074          TelemetryStream telemetryStream = this.getStream(dpdClient, project, interval,  
075              member, isCumulative, null);
076          TelemetryStreamCollection streams = new TelemetryStreamCollection(null, project, interval);
077          streams.add(telemetryStream);
078          return streams;
079        } 
080        catch (Exception e) {
081          throw new TelemetryReducerException(e);
082        }
083      }
084    
085      /**
086       * Gets the telemetry stream.
087       * 
088       * @param dpdClient The DailyProjectData client we will contact for the data. 
089       * @param project The project.
090       * @param interval The interval.
091       * @param member The member, or "*" for all members.
092       * @param isCumulative True for cumulative measure.
093       * @param streamTagValue The tag for the generated telemetry stream.
094       * 
095       * @return The telemetry stream as required.
096       * 
097       * @throws Exception If there is any error.
098       */
099      TelemetryStream getStream(DailyProjectDataClient dpdClient, 
100          Project project, Interval interval,
101          String member, boolean isCumulative, Object streamTagValue) 
102            throws Exception {
103        TelemetryStream telemetryStream = new TelemetryStream(streamTagValue);
104        List<IntervalUtility.Period> periods = IntervalUtility.getPeriods(interval);
105        long cumulativeCommits = 0;
106        
107        for (IntervalUtility.Period period : periods) {
108          Long value = this.getData(dpdClient, project, period.getStartDay(), period.getEndDay(),
109              member);
110          
111          if (value != null) {
112            cumulativeCommits += value;
113          }
114          
115          if (isCumulative) {
116            telemetryStream.addDataPoint(new TelemetryDataPoint(period.getTimePeriod(), 
117                cumulativeCommits));        
118          }
119          else {
120            telemetryStream.addDataPoint(new TelemetryDataPoint(period.getTimePeriod(), value));
121          }
122        }
123        return telemetryStream;
124      }
125      
126      /**
127       * Returns a Commit value for the specified time interval, or null if no SensorData. 
128       * 
129       * @param dpdClient The DailyProjectData client we will use to get this data. 
130       * @param project The project.
131       * @param startDay The start day (inclusive).
132       * @param endDay The end day (inclusive).
133       * @param member The member email, or "*" for all members.
134       * @throws TelemetryReducerException If anything goes wrong.
135       *
136       * @return The UnitTest count, or null if there is no UnitTest SensorData for that time period. 
137       */
138      Long getData(DailyProjectDataClient dpdClient, Project project, Day startDay, Day endDay, 
139          String member) throws TelemetryReducerException {
140        long count = 0;
141        boolean hasData = false;
142        try {
143          // For each day in the interval... 
144          for (Day day = startDay; day.compareTo(endDay) <= 0; day = day.inc(1) ) {
145            // Get the DPD...
146            CommitDailyProjectData data = 
147              dpdClient.getCommit(project.getOwner(), project.getName(), Tstamp.makeTimestamp(day));
148            // Go through the DPD per-member data...
149            for (MemberData memberData : data.getMemberData()) {
150              if ((member == null) || "*".equals(member) || 
151                  (memberData.getMemberUri().endsWith(member))) {
152                hasData = true;
153                count += memberData.getCommits();
154              }
155            }
156          }
157        }
158        catch (Exception ex) {
159          throw new TelemetryReducerException(ex);
160        }
161    
162        //Return null if no data, the Commit counts otherwise. 
163        return (hasData) ? Long.valueOf(count) : null; 
164      }
165    
166    }