001    package org.hackystat.sensorbase.resource.projects;
002    
003    import javax.xml.datatype.XMLGregorianCalendar;
004    
005    import org.hackystat.sensorbase.resource.sensorbase.SensorBaseResource;
006    import org.hackystat.utilities.tstamp.Tstamp;
007    import org.restlet.Context;
008    import org.restlet.data.MediaType;
009    import org.restlet.data.Request;
010    import org.restlet.data.Response;
011    import org.restlet.resource.Representation;
012    import org.restlet.resource.Variant;
013    
014    /**
015     * The resource for processing GET host/projects/{user}/{projectname}/sensordata.
016     * Returns an index to the SensorData resources associated with this  Project.
017     * This includes all of the SensorData from all members that matches the UriPattern.
018     * Note that this could be quite large if you do not also specify a start and end time.
019     * 
020     * @author Philip Johnson
021     */
022    public class UserProjectSensorDataResource extends SensorBaseResource {
023      
024      /** An optional query parameter. */
025      private String startTime;
026      /** An optional query string parameter. */
027      private String endTime;
028      /** An optional query parameter. */
029      private String sdt;
030      /** An optional query parameter. */
031      private String startIndex;
032      /** An optional query parameter. */
033      private String maxInstances;
034      /** An optional tool parameter. */
035      private String tool;
036    
037      
038      /**
039       * Provides the following representational variants: TEXT_XML.
040       * @param context The context.
041       * @param request The request object.
042       * @param response The response object.
043       */
044      public UserProjectSensorDataResource(Context context, Request request, Response response) {
045        super(context, request, response);
046        this.startTime = (String) request.getAttributes().get("startTime");
047        this.endTime = (String) request.getAttributes().get("endTime");
048        this.sdt = (String) request.getAttributes().get("sdt");
049        this.startIndex = (String) request.getAttributes().get("startIndex");
050        this.maxInstances = (String) request.getAttributes().get("maxInstances");
051        this.tool = (String) request.getAttributes().get("tool");
052      }
053      
054      /**
055       * Returns a SensorDataIndex of all SensorData associated with this Project.  This
056       * includes all SensorData from all Members in this project over the 
057       * (optional) specified time period  for the (optional) SDT and (optional) tool that match 
058       * at least one of the UriPatterns in the project definition.
059       * 
060       * Returns an error condition if:
061       * <ul>
062       * <li> The user does not exist.
063       * <li> The authenticated user is not the uriUser or the Admin or a member of the project or
064       * a spectator of the project.
065       * <li> The Project Resource named by the User and Project does not exist.
066       * <li> startTime or endTime is not an XMLGregorianCalendar string.
067       * <li> One or the other but not both of startTime and endTime is provided.
068       * <li> endTime is earlier than startTime.
069       * </ul>
070       * 
071       * @param variant The representational variant requested.
072       * @return The representation. 
073       */
074      @Override
075      public Representation represent(Variant variant) {
076        if (!validateUriUserIsUser() ||
077            !validateUriProjectName() ||
078            !validateProjectViewer()) {
079          return null;
080        }
081        
082        // If startTime is provided, then both startTime and endTime must be XMLGregorianCalendars,
083        // and startTime must be <= endTime.
084        XMLGregorianCalendar startTimeXml = null;
085        XMLGregorianCalendar endTimeXml = null;
086        if (this.startTime != null) {
087          try {
088            startTimeXml = Tstamp.makeTimestamp(this.startTime);
089            endTimeXml = Tstamp.makeTimestamp(this.endTime);
090          }
091          catch (Exception e) {
092            setStatusMiscError("startTime (or endTime) is not supplied and/or is not a timestamp");
093            return null;
094          }
095          // We have a start and end time. Make sure startTime is not greater than endTime.
096          if (Tstamp.greaterThan(startTimeXml, endTimeXml)) {
097            setStatusMiscError("startTime cannot be greater than endTime.");
098            return null;
099          }
100          // Make sure that startTime is not less than project.startTime.
101          if (!ProjectUtils.isValidStartTime(project, startTimeXml)) {
102            setStatusMiscError(String.format("%s cannot be less than project start time of %s", 
103                startTimeXml, project.getStartTime()));
104            return null;
105          }
106          // And that endTime is not past the project endTime (if there is a project endTime).
107          if ((project.getEndTime() != null) && 
108              (!ProjectUtils.isValidEndTime(project, endTimeXml))) {
109            setStatusMiscError(String.format("%s cannot be greater than project end time of %s", 
110                endTimeXml, project.getEndTime()));
111            return null;
112          }
113        }
114        int startIndexInt = 0;
115        int maxInstancesInt = 0;
116        // Must supply both startIndex and maxInstances if either are supplied, and
117        // startIndex and maxInstances must be non-negative integers.
118        if (this.startIndex != null) {
119          try {
120            startIndexInt = Integer.parseInt(this.startIndex);
121            maxInstancesInt = Integer.parseInt(this.maxInstances);
122            if ((startIndexInt < 0) || (maxInstancesInt <= 0)) {
123              setStatusMiscError("both startIndex & maxInstances must be non-negative.");
124              return null;
125            }
126          }
127          catch (Exception e) {
128            setStatusMiscError("startIndex (or maxInstances) is not supplied or is not an integer.");
129            return null;
130          }
131        }
132    
133        if (variant.getMediaType().equals(MediaType.TEXT_XML)) {
134          try {
135            if (startTime == null) {
136              // Return all sensor data for this project if no query parameters.
137              String data = super.projectManager.getProjectSensorDataIndex(this.user, project);
138              return SensorBaseResource.getStringRepresentation(data);
139            }
140            if (tool != null) {
141              // Return the tool's sensor data starting at startTime and ending with endTime.
142              String data = super.projectManager.getProjectSensorDataIndex(this.user, project,
143                  startTimeXml, endTimeXml, this.sdt, this.tool);
144              return SensorBaseResource.getStringRepresentation(data);
145              
146            }
147            if (startIndex == null) {
148              // Return all sensor data starting at startTime and ending with endTime.
149              String data = super.projectManager.getProjectSensorDataIndex(this.user, project,
150                  startTimeXml, endTimeXml, this.sdt);
151              return SensorBaseResource.getStringRepresentation(data);
152            }
153            else {
154              // Return the data for startIndex and maxInstances. 
155              String data = super.projectManager.getProjectSensorDataIndex(this.user, project,
156                  startTimeXml, endTimeXml, startIndexInt, maxInstancesInt);
157              return SensorBaseResource.getStringRepresentation(data);
158              
159            }
160          }
161          catch (Exception e) {
162            setStatusInternalError(e);
163          }
164        }
165        return null;
166      }
167    }