001 package org.hackystat.telemetry.service.resource.telemetry; 002 003 import java.util.Date; 004 import java.util.List; 005 import java.util.Map; 006 007 import org.hackystat.dailyprojectdata.client.DailyProjectDataClient; 008 import org.hackystat.sensorbase.client.SensorBaseClient; 009 import org.hackystat.telemetry.analyzer.configuration.TelemetryDefinitionManager; 010 import org.hackystat.telemetry.analyzer.configuration.TelemetryDefinitionManagerFactory; 011 import org.hackystat.telemetry.analyzer.configuration.jaxb.TelemetryDefinition; 012 import org.hackystat.telemetry.service.server.Server; 013 import org.hackystat.telemetry.service.server.ServerProperties; 014 import org.restlet.Context; 015 import org.restlet.data.CharacterSet; 016 import org.restlet.data.Language; 017 import org.restlet.data.MediaType; 018 import org.restlet.data.Request; 019 import org.restlet.data.Response; 020 import org.restlet.data.Status; 021 import org.restlet.resource.Representation; 022 import org.restlet.resource.Resource; 023 import org.restlet.resource.StringRepresentation; 024 import org.restlet.resource.Variant; 025 026 import static org.hackystat.telemetry.service.server.Authenticator.AUTHENTICATOR_DPD_CLIENTS_KEY; 027 import static 028 org.hackystat.telemetry.service.server.Authenticator.AUTHENTICATOR_SENSORBASE_CLIENTS_KEY; 029 import static org.hackystat.telemetry.service.server.ServerProperties.DAILYPROJECTDATA_FULLHOST_KEY; 030 import static org.hackystat.telemetry.service.server.ServerProperties.SENSORBASE_FULLHOST_KEY; 031 032 /** 033 * An abstract superclass for all Telemetry resources that supplies common 034 * initialization processing. 035 * This includes: 036 * <ul> 037 * <li> Extracting the authenticated user identifier (when authentication available) 038 * <li> Extracting the URI elements and parameters. 039 * <li> Declares that the TEXT/XML representational variant is supported. 040 * </ul> 041 * 042 * @author Philip Johnson 043 * 044 */ 045 public abstract class TelemetryResource extends Resource { 046 047 /** To be retrieved from the URL as the 'email' template parameter, or null. */ 048 protected String uriUser = null; 049 050 /** To be retrieved from the URL as the 'project' template parameter, or null. */ 051 protected String projectName = null; 052 053 /** To be retrieved from the URL as the 'chart' template parameter, or null. */ 054 protected String chart = null; 055 056 /** To be retrieved from the URL as the 'granularity' template parameter, or null. */ 057 protected String granularity = null; 058 059 /** To be retrieved from the URL as the 'start' template parameter, or null. */ 060 protected String start = null; 061 062 /** To be retrieved from the URL as the 'end' template parameter, or null. */ 063 protected String end = null; 064 065 /** To be retrieved from the URL as the 'params' template parameter, or null. */ 066 protected String params = null; 067 068 /** The authenticated user, retrieved from the ChallengeResponse, or null. */ 069 protected String authUser = null; 070 071 /** This server (telemetry). */ 072 protected Server telemetryServer; 073 074 /** The sensorbase host (for authentication). */ 075 protected String sensorBaseHost; 076 077 /** The dailyprojectdata host (for analysis). */ 078 protected String dpdHost; 079 080 /** The standard error message returned from invalid authentication. */ 081 protected String badAuth = "User is not admin and authenticated user does not not match URI user"; 082 083 /** Records the time at which each HTTP request was initiated. */ 084 protected long requestStartTime = new Date().getTime(); 085 086 /** 087 * Provides the following representational variants: TEXT_XML. 088 * @param context The context. 089 * @param request The request object. 090 * @param response The response object. 091 */ 092 public TelemetryResource(Context context, Request request, Response response) { 093 super(context, request, response); 094 if (request.getChallengeResponse() != null) { 095 this.authUser = request.getChallengeResponse().getIdentifier(); 096 } 097 this.telemetryServer = (Server)getContext().getAttributes().get("TelemetryServer"); 098 ServerProperties properties = this.telemetryServer.getServerProperties(); 099 this.dpdHost = properties.get(DAILYPROJECTDATA_FULLHOST_KEY); 100 this.sensorBaseHost = properties.get(SENSORBASE_FULLHOST_KEY); 101 this.chart = (String) request.getAttributes().get("chart"); 102 this.uriUser = (String) request.getAttributes().get("email"); 103 this.projectName = (String) request.getAttributes().get("project"); 104 this.granularity = (String) request.getAttributes().get("granularity"); 105 this.start = (String) request.getAttributes().get("start"); 106 this.end = (String) request.getAttributes().get("end"); 107 this.params = (String) request.getAttributes().get("params"); 108 getVariants().clear(); // copied from BookmarksResource.java, not sure why needed. 109 getVariants().add(new Variant(MediaType.TEXT_XML)); 110 } 111 112 /** 113 * The Restlet getRepresentation method which must be overridden by all concrete Resources. 114 * @param variant The variant requested. 115 * @return The Representation. 116 */ 117 @Override 118 public abstract Representation represent(Variant variant); 119 120 /** 121 * Creates and returns a new Restlet StringRepresentation built from xmlData. 122 * The xmlData will be prefixed with a processing instruction indicating UTF-8 and version 1.0. 123 * @param xmlData The xml data as a string. 124 * @return A StringRepresentation of that xmldata. 125 */ 126 public StringRepresentation getStringRepresentation(String xmlData) { 127 return new StringRepresentation(xmlData, MediaType.TEXT_XML, Language.ALL, CharacterSet.UTF_8); 128 } 129 130 /** 131 * Returns a DailyProjectDataClient instance associated with the User in this request. 132 * @return The DailyProjectDataClient instance. 133 */ 134 @SuppressWarnings("unchecked") 135 public DailyProjectDataClient getDailyProjectDataClient() { 136 Map<String, DailyProjectDataClient> userClientMap = 137 (Map<String, DailyProjectDataClient>)this.telemetryServer.getContext().getAttributes() 138 .get(AUTHENTICATOR_DPD_CLIENTS_KEY); 139 return userClientMap.get(this.authUser); 140 } 141 142 /** 143 * Returns a SensorBaseClient instance associated with the User in this request. 144 * @return The SensorBaseClient instance. 145 */ 146 @SuppressWarnings("unchecked") 147 public SensorBaseClient getSensorBaseClient() { 148 Map<String, SensorBaseClient> userClientMap = 149 (Map<String, SensorBaseClient>)this.telemetryServer.getContext().getAttributes() 150 .get(AUTHENTICATOR_SENSORBASE_CLIENTS_KEY); 151 return userClientMap.get(this.authUser); 152 } 153 154 /** 155 * Returns a list of TelemetryDefinition instances corresponding to all definitions in 156 * telemetry.definitions.xml. 157 * @return A List of TelemetryDefinition instances. 158 */ 159 public List<TelemetryDefinition> getTelemetryDefinitions() { 160 TelemetryDefinitionManager manager = 161 TelemetryDefinitionManagerFactory.getGlobalPersistentInstance(); 162 return manager.getDefinitions(); 163 } 164 165 /** 166 * Generates a log message indicating the type of request, the elapsed time required, 167 * the user who requested the data, and the day. 168 */ 169 protected void logRequest() { 170 long elapsed = new Date().getTime() - requestStartTime; 171 String msg = elapsed + " ms: " + this.chart + " " + uriUser + " " + this.projectName; 172 telemetryServer.getLogger().info(msg); 173 } 174 175 /** 176 * Generates a log message indicating the command. 177 * @param command The command (typically cache). 178 */ 179 protected void logRequest(String command) { 180 long elapsed = new Date().getTime() - requestStartTime; 181 String msg = elapsed + " ms: " + command; 182 telemetryServer.getLogger().info(msg); 183 } 184 185 /** 186 * Helper function that removes any newline characters from the supplied string and 187 * replaces them with a blank line. 188 * @param msg The msg whose newlines are to be removed. 189 * @return The string without newlines. 190 */ 191 private String removeNewLines(String msg) { 192 return msg.replace(System.getProperty("line.separator"), " "); 193 } 194 195 /** 196 * Called when an error resulting from an exception is caught during processing. 197 * @param msg A description of the error. 198 * @param e A chained exception. 199 */ 200 protected void setStatusError (String msg, Exception e) { 201 String responseMsg = String.format("%s:%n Request: %s %s%n Caused by: %s", 202 msg, 203 this.getRequest().getMethod().getName(), 204 this.getRequest().getResourceRef().toString(), 205 e.getMessage()); 206 this.getLogger().info(responseMsg); 207 getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST, removeNewLines(responseMsg)); 208 } 209 210 /** 211 * Called when an error occurs during processing. 212 * @param msg A description of the error. 213 */ 214 protected void setStatusError (String msg) { 215 String responseMsg = String.format("%s:%n Request: %s %s", 216 msg, 217 this.getRequest().getMethod().getName(), 218 this.getRequest().getResourceRef().toString()); 219 this.getLogger().info(responseMsg); 220 getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST, removeNewLines(responseMsg)); 221 } 222 223 /** 224 * Called when an internal error occurs during processing. 225 * @param msg A description of the error. 226 */ 227 protected void setStatusInternalError (String msg) { 228 String responseMsg = String.format("%s:%n Request: %s %s", 229 msg, 230 this.getRequest().getMethod().getName(), 231 this.getRequest().getResourceRef().toString()); 232 this.getLogger().info(responseMsg); 233 getResponse().setStatus(Status.SERVER_ERROR_INTERNAL, removeNewLines(responseMsg)); 234 } 235 236 237 238 }