001 package org.hackystat.telemetry.analyzer.model; 002 003 import java.io.Serializable; 004 import java.util.ArrayList; 005 import java.util.Collections; 006 import java.util.Comparator; 007 import java.util.List; 008 import java.util.TreeMap; 009 010 import org.hackystat.utilities.time.period.TimePeriod; 011 012 /** 013 * Represents a single telemetry stream, which contains an ordered series of TelemetryDataPoint 014 * instances. 015 * 016 * @author (Cedric) Qin Zhang 017 */ 018 public class TelemetryStream { 019 020 private static final TelemetryDataPointTimePeriodComparator DATAPOINT_TIMEPERIOD_COMPARATOR 021 = new TelemetryDataPointTimePeriodComparator(); 022 023 private Object tag; 024 025 private TreeMap<TimePeriod, TelemetryDataPoint> dataPoints = 026 new TreeMap<TimePeriod, TelemetryDataPoint>(); 027 028 /** 029 * Constructs this instance. 030 * 031 * @param tag An object that helps to recognize this telemetry stream. Null is 032 * a valid value. 033 */ 034 public TelemetryStream(Object tag) { 035 this.tag = tag; 036 } 037 038 /** 039 * Gets the tag associated with this telemetry stream. 040 * 041 * @return The tag object. 042 */ 043 public Object getTag() { 044 return this.tag; 045 } 046 047 /** 048 * Sets the tag associated with this telemetry stream. 049 * 050 * @param tag The new tag value 051 */ 052 public void setTag(final Object tag) { 053 this.tag = tag; 054 } 055 056 /** 057 * Adds a data point to this telemetry stream. Note that the time period in 058 * all data points must be of the same type (either day, week, or month). 059 * Otherwise, an exception will be raised. 060 * 061 * @param dataPoint The data point to be added. 062 * 063 * @throws TelemetryDataModelException If the data for the time period already exists. 064 */ 065 public void addDataPoint(TelemetryDataPoint dataPoint) throws TelemetryDataModelException { 066 try { 067 TimePeriod period = dataPoint.getPeriod(); 068 if (this.dataPoints.containsKey(period)) { 069 throw new TelemetryDataModelException("Duplicated period: " + period.toString()); 070 } 071 this.dataPoints.put(period, dataPoint); 072 } 073 catch (ClassCastException ex) { 074 // this exception is raised when the types of time period in data points are different. 075 throw new 076 TelemetryDataModelException("All data points must have the same time period type.", ex); 077 } 078 } 079 080 /** 081 * Gets the value associated with the specified time period. Note that if this 082 * telemetry stream does not contain the data point associated the time 083 * period, an exception is raised. If a null is return, it means that this 084 * streams contains the data point, but the value in that data point is null. 085 * 086 * @param timePeriod The time period. 087 * @return The value. 088 * 089 * @throws TelemetryDataModelException If there is no value associated with the 090 * time period. 091 */ 092 public Number getDataPointValue(TimePeriod timePeriod) throws TelemetryDataModelException { 093 TelemetryDataPoint dataPoint = this.dataPoints.get(timePeriod); 094 if (dataPoint == null) { 095 throw new TelemetryDataModelException("No data for the period " + timePeriod.toString()); 096 } 097 return dataPoint.getValue(); 098 } 099 100 /** 101 * Gets a list of data points in this telemetry stream, ordered by time 102 * period. 103 * 104 * @return A collection of <code>TelemetryDataPoint</code> objects. 105 */ 106 public List<TelemetryDataPoint> getDataPoints() { 107 ArrayList<TelemetryDataPoint> list = 108 new ArrayList<TelemetryDataPoint>(this.dataPoints.values()); 109 Collections.sort(list, DATAPOINT_TIMEPERIOD_COMPARATOR); 110 return list; 111 } 112 113 /** 114 * Comparator for <code>TelemetryDataPoint</code> instances based on their 115 * time period property. 116 * 117 * @author (Cedric) Qin Zhang 118 */ 119 private static class TelemetryDataPointTimePeriodComparator 120 implements Serializable, Comparator<TelemetryDataPoint> { 121 122 private static final long serialVersionUID = 1L; 123 124 /** 125 * Compares two instances. 126 * 127 * @param o1 Data point 1. 128 * @param o2 Data point 2. 129 * 130 * @return 0 indicates they are equal, positive value indicates data point 1 131 * has later time stamp than data point 2, negative value indicates 132 * data point 1 has earlier time stamp than data point 2. 133 */ 134 public int compare(TelemetryDataPoint o1, TelemetryDataPoint o2) { 135 TimePeriod t1 = o1.getPeriod(); 136 TimePeriod t2 = o2.getPeriod(); 137 return t1.compareTo(t2); 138 } 139 } 140 }