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