001 package org.hackystat.dailyprojectdata.resource.issue; 002 003 import java.io.StringWriter; 004 import java.util.logging.Logger; 005 import javax.xml.bind.JAXBContext; 006 import javax.xml.bind.Marshaller; 007 import javax.xml.datatype.XMLGregorianCalendar; 008 import javax.xml.parsers.DocumentBuilder; 009 import javax.xml.parsers.DocumentBuilderFactory; 010 import javax.xml.transform.Transformer; 011 import javax.xml.transform.TransformerFactory; 012 import javax.xml.transform.dom.DOMSource; 013 import javax.xml.transform.stream.StreamResult; 014 import org.hackystat.dailyprojectdata.resource.dailyprojectdata.DailyProjectDataResource; 015 import org.hackystat.dailyprojectdata.resource.issue.jaxb.IssueDailyProjectData; 016 import org.hackystat.dailyprojectdata.resource.issue.jaxb.IssueData; 017 import org.hackystat.sensorbase.client.SensorBaseClient; 018 import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorDataIndex; 019 import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorDataRef; 020 import org.hackystat.utilities.tstamp.Tstamp; 021 import org.restlet.Context; 022 import org.restlet.data.MediaType; 023 import org.restlet.data.Request; 024 import org.restlet.data.Response; 025 import org.restlet.resource.Representation; 026 import org.restlet.resource.Variant; 027 import org.w3c.dom.Document; 028 029 /** 030 * Implements the Resource for processing GET {host}/issue/{user}/{project}/{starttime} requests. 031 * Requires the authenticated user to be {user} or else the Admin user for the sensorbase 032 * connected to this service. 033 * @author Shaoxuan Zhang 034 */ 035 public class IssueResource extends DailyProjectDataResource { 036 037 private String status; 038 039 /** 040 * The standard constructor. 041 * @param context The context. 042 * @param request The request object. 043 * @param response The response object. 044 */ 045 public IssueResource(Context context, Request request, Response response) { 046 super(context, request, response); 047 this.status = (String) request.getAttributes().get("Status"); 048 } 049 050 /** 051 * Returns an IssueDailyProjectData instance representing the Issue associated with the 052 * Project data, or null if not authorized. 053 * Authenticated user must be the uriUser, or Admin, or project member. 054 * @param variant The representational variant requested. 055 * @return The representation. 056 */ 057 @Override 058 public Representation represent(Variant variant) { 059 Logger logger = this.server.getLogger(); 060 logger.fine("Issue DPD: Starting"); 061 if (variant.getMediaType().equals(MediaType.TEXT_XML)) { 062 try { 063 // [1] get the SensorBaseClient for the user making this request. 064 SensorBaseClient client = super.getSensorBaseClient(); 065 // [2] Check the front side cache and return if the DPD is found and is OK to access. 066 String cachedDpd = this.server.getFrontSideCache().get(uriUser, project, uriString); 067 if ((cachedDpd != null) && client.inProject(uriUser, project)) { 068 return super.getStringRepresentation(cachedDpd); 069 } 070 // [2] get a SensorDataIndex of all Issue data for this Project on the requested day. 071 XMLGregorianCalendar startTime = Tstamp.makeTimestamp(this.timestamp); 072 XMLGregorianCalendar endTime = Tstamp.incrementDays(startTime, 1); 073 logger.fine("Issue DPD: Requesting index: " + uriUser + " " + project); 074 075 XMLGregorianCalendar projectStartTime = client.getProject(uriUser, project).getStartTime(); 076 077 SensorDataIndex index = client.getProjectSensorData(uriUser, project, projectStartTime, 078 endTime, "Issue"); 079 logger.fine("Issue DPD: Got index: " + index.getSensorDataRef().size() + " instances"); 080 // [3] prepare the IssueDailyProjectData 081 IssueDailyProjectData issueDpd = new IssueDailyProjectData(); 082 issueDpd.setOwner(uriUser); 083 issueDpd.setProject(project); 084 issueDpd.setStartTime(startTime); 085 // [4] parse Issue SensorData. 086 int openIssue = 0; 087 IssueDataParser parser = new IssueDataParser(this.server.getLogger()); 088 for (SensorDataRef ref : index.getSensorDataRef()) { 089 IssueData issueData = parser.getIssueDpd(client.getSensorData(ref), endTime); 090 boolean isOpen = parser.isOpenStatus(issueData.getStatus()); 091 boolean include = false; 092 if ((status == null) || (status.equalsIgnoreCase("all")) || 093 (status.equalsIgnoreCase("open") && isOpen) || 094 (status.equalsIgnoreCase("closed") && !isOpen) || 095 (status.equalsIgnoreCase(issueData.getStatus()))) { 096 include = true; 097 issueDpd.getIssueData().add(issueData); 098 } 099 if (include && isOpen) { 100 openIssue++; 101 } 102 } 103 // [5] finish the IssueDailyProjectData and send. 104 issueDpd.setOpenIssues(openIssue); 105 String xmlData = makeIssues(issueDpd); 106 if (!Tstamp.isTodayOrLater(startTime)) { 107 this.server.getFrontSideCache().put(uriUser, project, uriString, xmlData); 108 } 109 logRequest("Issue"); 110 return super.getStringRepresentation(xmlData); 111 } 112 catch (Exception e) { 113 setStatusError("Error creating Issue DPD.", e); 114 return null; 115 } 116 } 117 return null; 118 } 119 120 /** 121 * Returns the passed SensorData instance as a String encoding of its XML representation. 122 * @param data The SensorData instance. 123 * @return The XML String representation. 124 * @throws Exception If problems occur during translation. 125 */ 126 private String makeIssues (IssueDailyProjectData data) throws Exception { 127 JAXBContext devTimeJAXB = 128 (JAXBContext)this.server.getContext().getAttributes().get("IssueJAXB"); 129 Marshaller marshaller = devTimeJAXB.createMarshaller(); 130 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 131 dbf.setNamespaceAware(true); 132 DocumentBuilder documentBuilder = dbf.newDocumentBuilder(); 133 Document doc = documentBuilder.newDocument(); 134 marshaller.marshal(data, doc); 135 DOMSource domSource = new DOMSource(doc); 136 StringWriter writer = new StringWriter(); 137 StreamResult result = new StreamResult(writer); 138 TransformerFactory tf = TransformerFactory.newInstance(); 139 Transformer transformer = tf.newTransformer(); 140 transformer.transform(domSource, result); 141 return writer.toString(); 142 } 143 }