001 package org.hackystat.dailyprojectdata.resource.devtime; 002 003 import java.io.StringWriter; 004 import java.util.logging.Logger; 005 006 import javax.xml.bind.JAXBContext; 007 import javax.xml.bind.Marshaller; 008 import javax.xml.datatype.XMLGregorianCalendar; 009 import javax.xml.parsers.DocumentBuilder; 010 import javax.xml.parsers.DocumentBuilderFactory; 011 import javax.xml.transform.Transformer; 012 import javax.xml.transform.TransformerFactory; 013 import javax.xml.transform.dom.DOMSource; 014 import javax.xml.transform.stream.StreamResult; 015 016 import org.hackystat.dailyprojectdata.resource.dailyprojectdata.DailyProjectDataResource; 017 import org.hackystat.dailyprojectdata.resource.devtime.jaxb.DevTimeDailyProjectData; 018 import org.hackystat.dailyprojectdata.resource.devtime.jaxb.MemberData; 019 import org.hackystat.sensorbase.client.SensorBaseClient; 020 import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorDataIndex; 021 import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorDataRef; 022 import org.hackystat.utilities.tstamp.Tstamp; 023 import org.restlet.Context; 024 import org.restlet.data.MediaType; 025 import org.restlet.data.Request; 026 import org.restlet.data.Response; 027 import org.restlet.resource.Representation; 028 import org.restlet.resource.Variant; 029 import org.w3c.dom.Document; 030 031 import static org.hackystat.dailyprojectdata.server.ServerProperties.SENSORBASE_FULLHOST_KEY; 032 033 /** 034 * Implements the Resource for processing GET {host}/devtime/{user}/{project}/{starttime} requests. 035 * Requires the authenticated user to be {user} or else the Admin user for the sensorbase 036 * connected to this service. 037 * @author Philip Johnson 038 */ 039 public class DevTimeResource extends DailyProjectDataResource { 040 041 /** 042 * The standard constructor. 043 * @param context The context. 044 * @param request The request object. 045 * @param response The response object. 046 */ 047 public DevTimeResource(Context context, Request request, Response response) { 048 super(context, request, response); 049 } 050 051 /** 052 * Returns an DevTimeDailyProjectData instance representing the DevTime associated with the 053 * Project data, or null if not authorized. 054 * Authenticated user must be the uriUser, or Admin, or project member. 055 * @param variant The representational variant requested. 056 * @return The representation. 057 */ 058 @Override 059 public Representation represent(Variant variant) { 060 Logger logger = this.server.getLogger(); 061 logger.fine("DevTime DPD: Starting"); 062 if (variant.getMediaType().equals(MediaType.TEXT_XML)) { 063 try { 064 // [1] get the SensorBaseClient for the user making this request. 065 SensorBaseClient client = super.getSensorBaseClient(); 066 // [2] Check the front side cache and return if the DPD is found and is OK to access. 067 String cachedDpd = this.server.getFrontSideCache().get(uriUser, project, uriString); 068 if ((cachedDpd != null) && client.inProject(uriUser, project)) { 069 return super.getStringRepresentation(cachedDpd); 070 } 071 // [2] get a SensorDataIndex of all DevEvent data for this Project on the requested day. 072 XMLGregorianCalendar startTime = Tstamp.makeTimestamp(this.timestamp); 073 XMLGregorianCalendar endTime = Tstamp.incrementDays(startTime, 1); 074 logger.fine("DevTime DPD: Requesting index: " + uriUser + " " + project); 075 SensorDataIndex index = client.getProjectSensorData(uriUser, project, startTime, endTime, 076 "DevEvent"); 077 logger.fine("DevTime DPD: Got index: " + index.getSensorDataRef().size() + " instances"); 078 // [3] update the DevTime counter. 079 MemberDevTimeCounter counter = new MemberDevTimeCounter(); 080 for (SensorDataRef ref : index.getSensorDataRef()) { 081 // Get the member and timestamp and update the MemberDevTimeCounter. 082 counter.addMemberDevEvent(ref.getOwner(), ref.getTimestamp()); 083 } 084 // [4] create and return the DevTimeDailyProjectData 085 DevTimeDailyProjectData devTime = new DevTimeDailyProjectData(); 086 // create the individual MemberData elements. 087 String sensorBaseHost = this.server.getServerProperties().get(SENSORBASE_FULLHOST_KEY); 088 for (String member : counter.getMembers()) { 089 MemberData memberData = new MemberData(); 090 memberData.setMemberUri(sensorBaseHost + "users/" + member); 091 memberData.setDevTime(counter.getMemberDevTime(member)); 092 devTime.getMemberData().add(memberData); 093 } 094 devTime.setOwner(uriUser); 095 devTime.setProject(project); 096 devTime.setUriPattern("**"); // we don't support UriPatterns yet. 097 devTime.setTotalDevTime(counter.getTotalDevTime()); 098 String xmlData = makeDevTime(devTime); 099 if (!Tstamp.isTodayOrLater(startTime)) { 100 this.server.getFrontSideCache().put(uriUser, project, uriString, xmlData); 101 } 102 logRequest("DevTime"); 103 return super.getStringRepresentation(xmlData); 104 } 105 catch (Exception e) { 106 setStatusError("Error creating DevTime DPD.", e); 107 return null; 108 } 109 } 110 return null; 111 } 112 113 /** 114 * Returns the passed SensorData instance as a String encoding of its XML representation. 115 * @param data The SensorData instance. 116 * @return The XML String representation. 117 * @throws Exception If problems occur during translation. 118 */ 119 private String makeDevTime (DevTimeDailyProjectData data) throws Exception { 120 JAXBContext devTimeJAXB = 121 (JAXBContext)this.server.getContext().getAttributes().get("DevTimeJAXB"); 122 Marshaller marshaller = devTimeJAXB.createMarshaller(); 123 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 124 dbf.setNamespaceAware(true); 125 DocumentBuilder documentBuilder = dbf.newDocumentBuilder(); 126 Document doc = documentBuilder.newDocument(); 127 marshaller.marshal(data, doc); 128 DOMSource domSource = new DOMSource(doc); 129 StringWriter writer = new StringWriter(); 130 StreamResult result = new StreamResult(writer); 131 TransformerFactory tf = TransformerFactory.newInstance(); 132 Transformer transformer = tf.newTransformer(); 133 transformer.transform(domSource, result); 134 return writer.toString(); 135 } 136 } 137