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    }