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 }