001 package org.hackystat.dailyprojectdata.resource.coverage; 002 003 import java.io.StringWriter; 004 import java.util.List; 005 import java.util.logging.Logger; 006 007 import javax.xml.bind.JAXBContext; 008 import javax.xml.bind.Marshaller; 009 import javax.xml.datatype.XMLGregorianCalendar; 010 import javax.xml.parsers.DocumentBuilder; 011 import javax.xml.parsers.DocumentBuilderFactory; 012 import javax.xml.transform.Transformer; 013 import javax.xml.transform.TransformerFactory; 014 import javax.xml.transform.dom.DOMSource; 015 import javax.xml.transform.stream.StreamResult; 016 017 import org.hackystat.dailyprojectdata.resource.coverage.jaxb.ConstructData; 018 import org.hackystat.dailyprojectdata.resource.coverage.jaxb.CoverageDailyProjectData; 019 import org.hackystat.dailyprojectdata.resource.dailyprojectdata.DailyProjectDataResource; 020 import org.hackystat.sensorbase.client.SensorBaseClient; 021 import org.hackystat.sensorbase.resource.sensordata.jaxb.Property; 022 import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorData; 023 import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorDataIndex; 024 import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorDataRef; 025 import org.hackystat.utilities.tstamp.Tstamp; 026 import org.restlet.Context; 027 import org.restlet.data.MediaType; 028 import org.restlet.data.Request; 029 import org.restlet.data.Response; 030 import org.restlet.resource.Representation; 031 import org.restlet.resource.Variant; 032 import org.w3c.dom.Document; 033 034 /** 035 * Implements the Resource for processing GET 036 * {host}/coverage/{user}/{project}/{timestamp}/{type} requests. 037 * 038 * Authenticated user must be the uriUser, or Admin, or project member. 039 * 040 * @author jsakuda 041 * @author austen 042 */ 043 public class CoverageResource extends DailyProjectDataResource { 044 private final String granularity; 045 046 /** 047 * The standard constructor. 048 * 049 * @param context The context. 050 * @param request The request object. 051 * @param response The response object. 052 */ 053 public CoverageResource(Context context, Request request, Response response) { 054 super(context, request, response); 055 this.granularity = (String) request.getAttributes().get("granularity"); 056 } 057 058 /** 059 * Returns an CoverageDailyProjectData instance representing the Coverage 060 * associated with the Project data for the given day and granularity. 061 * @param variant The representational variant requested. 062 * @return The representation. 063 */ 064 @Override 065 public Representation represent(Variant variant) { 066 Logger logger = this.server.getLogger(); 067 logger.fine("Coverage DPD: Starting"); 068 if (variant.getMediaType().equals(MediaType.TEXT_XML)) { 069 try { 070 // [1] get the SensorBaseClient for the user making this request. 071 SensorBaseClient client = super.getSensorBaseClient(); 072 // [2] Check the front side cache and return if the DPD is found and is OK to access. 073 String cachedDpd = this.server.getFrontSideCache().get(uriUser, project, uriString); 074 if ((cachedDpd != null) && client.inProject(uriUser, project)) { 075 return super.getStringRepresentation(cachedDpd); 076 } 077 // [2] Get the latest snapshot of Coverage data for this Project on the requested day. 078 XMLGregorianCalendar startTime = Tstamp.makeTimestamp(this.timestamp); 079 XMLGregorianCalendar endTime = Tstamp.incrementDays(startTime, 1); 080 logger.fine("Coverage DPD: Requesting index: " + uriUser + " " + project); 081 SensorDataIndex snapshot = 082 client.getProjectSensorDataSnapshot(this.uriUser, this.project, startTime, endTime, 083 "Coverage"); 084 logger.fine("Coverage DPD: Got index: " + snapshot.getSensorDataRef().size() 085 + " instances"); 086 // [3] Create the Coverage DPD. 087 CoverageDailyProjectData coverageData = new CoverageDailyProjectData(); 088 coverageData.setProject(this.project); 089 coverageData.setStartTime(startTime); 090 coverageData.setGranularity(this.granularity); 091 092 // [4] If data, then add ConstructData instances for required granularity. 093 if (!snapshot.getSensorDataRef().isEmpty()) { 094 logger.fine("There is data to process"); 095 // Add a ConstructData instance if this sensor data contains the appropriate granularity. 096 for (SensorDataRef ref : snapshot.getSensorDataRef()) { 097 SensorData data = client.getSensorData(ref); 098 logger.fine ("Sensor Data: " + data); 099 coverageData.setOwner(data.getOwner()); 100 coverageData.setTool(data.getTool()); 101 String coveredKey = this.granularity.toLowerCase() + "_Covered"; 102 String uncoveredKey = this.granularity.toLowerCase() + "_Uncovered"; 103 logger.fine("Covered: " + coveredKey + " " + this.getProperty(data, coveredKey)); 104 logger.fine("Uncovered: " + uncoveredKey + " " + this.getProperty(data, coveredKey)); 105 Integer covered = this.getCoverageValue(data, coveredKey); 106 Integer uncovered = this.getCoverageValue(data, uncoveredKey); 107 logger.fine("Covered num: " + covered); 108 logger.fine("Uncovered num: " + uncovered); 109 if ((covered != null) && (uncovered != null)) { //NOPMD 110 ConstructData construct = new ConstructData(); 111 construct.setName(data.getResource()); 112 construct.setNumCovered(covered); 113 construct.setNumUncovered(uncovered); 114 coverageData.getConstructData().add(construct); 115 } 116 } 117 } 118 logger.fine("Coverage DPD: Finished processing instances."); 119 // Now return the CoverageDPD instance. 120 String xmlData = this.makeCoverage(coverageData); 121 if (!Tstamp.isTodayOrLater(startTime)) { 122 this.server.getFrontSideCache().put(uriUser, project, uriString, xmlData); 123 } 124 logRequest("Coverage", this.granularity); 125 return super.getStringRepresentation(xmlData); 126 } 127 catch (Exception e) { 128 setStatusError("Error creating Coverage DPD.", e); 129 return null; 130 } 131 } 132 return null; 133 } 134 135 /** 136 * Returns the passed SensorData instance as a String encoding of its XML 137 * representation. 138 * 139 * @param data The SensorData instance. 140 * @return The XML String representation. 141 * @throws Exception If problems occur during translation. 142 */ 143 private String makeCoverage(CoverageDailyProjectData data) throws Exception { 144 JAXBContext codeIssueJAXB = (JAXBContext) this.server.getContext().getAttributes().get( 145 "CoverageJAXB"); 146 Marshaller marshaller = codeIssueJAXB.createMarshaller(); 147 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 148 dbf.setNamespaceAware(true); 149 DocumentBuilder documentBuilder = dbf.newDocumentBuilder(); 150 Document doc = documentBuilder.newDocument(); 151 marshaller.marshal(data, doc); 152 DOMSource domSource = new DOMSource(doc); 153 StringWriter writer = new StringWriter(); 154 StreamResult result = new StreamResult(writer); 155 TransformerFactory tf = TransformerFactory.newInstance(); 156 Transformer transformer = tf.newTransformer(); 157 transformer.transform(domSource, result); 158 return writer.toString(); 159 } 160 161 /** 162 * Returns the string value associated with the specified property key. If no 163 * property with that key exists, null is returned. 164 * @param data The sensor data instance whose property list will be searched. 165 * @param key the property key to search for. 166 * @return The property value with the specified key or null. 167 */ 168 private String getProperty(SensorData data, String key) { 169 List<Property> propertyList = data.getProperties().getProperty(); 170 for (Property property : propertyList) { 171 if (key.equals(property.getKey())) { 172 return property.getValue(); 173 } 174 } 175 return null; 176 } 177 178 /** 179 * Returns the Coverage value at the given Granularity, or null if not present or not 180 * parsable to an Integer. 181 * @param data The SensorData instance to inspect for the given granularity. 182 * @param granularityKey One of line_Covered, line_Uncovered, method_Covered, etc. 183 * @return The coverage integer, or null if not found. 184 */ 185 private Integer getCoverageValue(SensorData data, String granularityKey) { 186 String prop = getProperty(data, granularityKey); 187 Double coverageNum = null; 188 try { 189 coverageNum = Double.parseDouble(prop); 190 } 191 catch (Exception e) { //NOPMD 192 // Don't do anything, ok to drop through. 193 } 194 return ((coverageNum == null) ? null : coverageNum.intValue()); 195 } 196 }