001 package org.hackystat.telemetry.analyzer.reducer; 002 003 import java.io.InputStream; 004 import java.util.Collection; 005 import java.util.Map; 006 import java.util.TreeMap; 007 import java.util.logging.Logger; 008 009 import javax.xml.bind.JAXBContext; 010 import javax.xml.bind.Unmarshaller; 011 012 import org.hackystat.telemetry.analyzer.model.TelemetryStreamCollection; 013 import org.hackystat.telemetry.analyzer.reducer.jaxb.ReducerDefinition; 014 import org.hackystat.telemetry.analyzer.reducer.jaxb.ReducerDefinitions; 015 import org.hackystat.dailyprojectdata.client.DailyProjectDataClient; 016 import org.hackystat.sensorbase.resource.projects.jaxb.Project; 017 import org.hackystat.utilities.logger.HackystatLogger; 018 import org.hackystat.utilities.stacktrace.StackTrace; 019 import org.hackystat.utilities.time.interval.Interval; 020 021 /** 022 * Provides a singleton manager for telemetry reducers. 023 * 024 * @author Qin ZHANG, Philip Johnson 025 */ 026 public class TelemetryReducerManager { 027 028 /** The singleton. */ 029 private static TelemetryReducerManager theInstance = new TelemetryReducerManager(); 030 /** Maps reducer names to a data structure with information about them. */ 031 private Map<String, TelemetryReducerInfo> reducerMap = 032 new TreeMap<String, TelemetryReducerInfo>(); 033 034 /** 035 * Gets the singleton instance of this class. 036 * 037 * @return An instance of this class. 038 */ 039 public static TelemetryReducerManager getInstance() { 040 return theInstance; 041 } 042 043 /** 044 * Finds and defines built-in telemetry reducer functions. 045 * If the reducer.definitions.xml file cannot be found, or the file specifies 046 * a class that cannot be instantiated, then logging messages will the displayed but no 047 * errors will be thrown. 048 */ 049 private TelemetryReducerManager() { 050 Logger logger = HackystatLogger.getLogger("org.hackystat.telemetry"); 051 ReducerDefinitions definitions = null; 052 try { 053 logger.info("Loading built-in telemetry reduction function definitions."); 054 //InputStream defStream = getClass().getResourceAsStream("impl/reducer.definitions.xml"); 055 InputStream defStream = 056 TelemetryReducerManager.class.getResourceAsStream("impl/reducer.definitions.xml"); 057 JAXBContext jaxbContext = JAXBContext 058 .newInstance(org.hackystat.telemetry.analyzer.reducer.jaxb.ObjectFactory.class); 059 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 060 definitions = (ReducerDefinitions) unmarshaller.unmarshal(defStream); 061 } 062 catch (Exception e) { 063 logger.severe("Could not find built-in telemetry reduction function definitions! " 064 + StackTrace.toString(e)); 065 return; 066 } 067 068 for (ReducerDefinition definition : definitions.getReducerDefinition()) { 069 String name = definition.getName(); 070 try { 071 logger.info("Defining built-in telemetry reduction function " + name); 072 Class<?> clazz = Class.forName(definition.getClassName()); 073 TelemetryReducer reducer = (TelemetryReducer) clazz.newInstance(); 074 TelemetryReducerInfo reducerInfo = new TelemetryReducerInfo(reducer, definition); 075 this.reducerMap.put(name, reducerInfo); 076 } 077 catch (Exception classEx) { 078 logger.severe("Unable to define " 079 + definition.getClassName() + ". Entry ignored. " + classEx.getMessage()); 080 continue; 081 } 082 } 083 } 084 085 086 /** 087 * Invokes the telemetry reducer to perform computations and generate a TelemetryStreamCollection. 088 * 089 * @param reducerName The name of the reducer to be invoked. 090 * @param project The project which defines the scope of metrics to be used in the computation. 091 * @param dpdClient The DPD Client. 092 * @param interval The time interval. 093 * @param parameters Parameters passed to reducer implementation. In case a reducer does not 094 * need any parameter, either null or an empty array may be passed. 095 * @return The resulting instance of <code>TelemetryStreamCollection</code>. 096 * @throws TelemetryReducerException If anything is wrong. 097 */ 098 public TelemetryStreamCollection compute(String reducerName, DailyProjectDataClient dpdClient, 099 Project project, Interval interval, String[] parameters) throws TelemetryReducerException { 100 TelemetryReducerInfo reducerInfo = this.reducerMap.get(reducerName); 101 if (reducerInfo == null) { 102 throw new TelemetryReducerException("Telemetry reducer " + reducerName + " not defined."); 103 } 104 return reducerInfo.getReducer().compute(project, dpdClient, interval, parameters); 105 } 106 107 /** 108 * Determines whether a particular telemetry reducer is defined. 109 * 110 * @param reducerName Telemetry reducer name. 111 * @return True if the specified telemetry reducer is defined. 112 */ 113 public boolean isReducer(String reducerName) { 114 return this.reducerMap.containsKey(reducerName); 115 } 116 117 /** 118 * Gets telemetry reducer information by name. 119 * 120 * @param reducerName The name of the reducer. 121 * @return The telemetry reducer information, or null if the reducer is not defined. 122 */ 123 public TelemetryReducerInfo getReducerInfo(String reducerName) { 124 return this.reducerMap.get(reducerName); 125 } 126 127 /** 128 * Returns information about all defined TelemetryReducers. 129 * 130 * @return A collection of <code>TelemetryReducerInfo</code> instances. 131 */ 132 public Collection<TelemetryReducerInfo> getAllReducerInfo() { 133 return this.reducerMap.values(); 134 } 135 }