/** * DepositoryAverageValuesServer.java This file is part of WattDepot. * * Copyright (C) 2014 Cam Moore * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.wattdepot.server.http.api; import java.text.ParseException; import java.util.Date; import java.util.List; import java.util.logging.Level; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.XMLGregorianCalendar; import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics; import org.restlet.data.Status; import org.restlet.resource.ResourceException; import org.wattdepot.common.domainmodel.Depository; import org.wattdepot.common.domainmodel.InterpolatedValue; import org.wattdepot.common.domainmodel.Labels; import org.wattdepot.common.domainmodel.InterpolatedValueList; import org.wattdepot.common.domainmodel.Sensor; import org.wattdepot.common.domainmodel.SensorGroup; import org.wattdepot.common.exception.IdNotFoundException; import org.wattdepot.common.exception.MisMatchedOwnerException; import org.wattdepot.common.exception.NoMeasurementException; import org.wattdepot.common.util.DateConvert; import org.wattdepot.common.util.tstamp.Tstamp; /** * DepositoryAverageValuesServer - Base class for handling HTTP API * ("/wattdepot/{org-id}/depository/{depository-id}/values/average/"). * * @author Cam Moore * */ public class DepositoryAverageValuesServer extends WattDepotServerResource { private String depositoryId; private String sensorId; /** The start of the range. */ private String start; /** The end of the range. */ private String end; /** The interval to calculate the average over. */ private String interval; private String dataType; /* * (non-Javadoc) * * @see org.restlet.resource.Resource#doInit() */ @Override protected void doInit() throws ResourceException { super.doInit(); this.sensorId = getQuery().getValues(Labels.SENSOR); this.start = getQuery().getValues(Labels.START); this.end = getQuery().getValues(Labels.END); this.depositoryId = getAttribute(Labels.DEPOSITORY_ID); this.interval = getQuery().getValues(Labels.INTERVAL); this.dataType = getQuery().getValues(Labels.VALUE_TYPE); } /** * retrieve the depository measurement list for a sensor. * * @return measurement list. */ public InterpolatedValueList doRetrieve() { getLogger().log( Level.INFO, "GET /wattdepot/{" + orgId + "}/" + Labels.DEPOSITORY + "/{" + depositoryId + "}/" + Labels.VALUES + "/" + Labels.AVERAGE + "/?" + Labels.SENSOR + "={" + sensorId + "}&" + Labels.START + "={" + start + "}&" + Labels.END + "={" + end + "}&" + Labels.INTERVAL + "={" + interval + "}&" + Labels.VALUE_TYPE + "={" + dataType + "}"); if (isInRole(orgId)) { if (start != null && end != null && interval != null) { InterpolatedValueList ret = new InterpolatedValueList(); try { Depository depository = depot.getDepository(depositoryId, orgId, true); XMLGregorianCalendar startRange = DateConvert.parseCalString(start); XMLGregorianCalendar endRange = DateConvert.parseCalString(end); int intervalMinutes = Integer.parseInt(interval); List<XMLGregorianCalendar> rangeList = Tstamp.getTimestampList(startRange, endRange, intervalMinutes); if (rangeList != null) { for (int i = 1; i < rangeList.size(); i++) { Date valueDate = DateConvert.convertXMLCal(rangeList.get(i)); XMLGregorianCalendar startInterval = rangeList.get(i - 1); XMLGregorianCalendar endInterval = rangeList.get(i); List<XMLGregorianCalendar> intervalList = Tstamp.getNTimestampList(24, startInterval, endInterval); DescriptiveStatistics stats = new DescriptiveStatistics(); Date previous = null; InterpolatedValue interpolatedValue = new InterpolatedValue(sensorId, 0.0, depository.getMeasurementType(), valueDate); for (int j = 0; j < intervalList.size(); j++) { Date timestamp = DateConvert.convertXMLCal(intervalList.get(j)); Double value = null; if ("point".equals(dataType)) { value = getValue(depositoryId, orgId, sensorId, timestamp, interpolatedValue); } else { if (previous != null) { value = getValue(depositoryId, orgId, sensorId, previous, timestamp, interpolatedValue); } previous = timestamp; } if (value != null) { stats.addValue(value); } } if (!Double.isNaN(stats.getMean())) { interpolatedValue.setValue(stats.getMean()); ret.getInterpolatedValues().add(interpolatedValue); } } } } catch (IdNotFoundException e) { setStatus(Status.CLIENT_ERROR_BAD_REQUEST, e.getMessage()); return null; } catch (ParseException e) { setStatus(Status.SERVER_ERROR_INTERNAL, e.getMessage()); return null; } catch (DatatypeConfigurationException e) { setStatus(Status.SERVER_ERROR_INTERNAL, e.getMessage()); return null; } return ret; } else { setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "Missing start and/or end times or interval."); return null; } } else { setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "Bad credentials."); return null; } } /** * @param depositoryId The depository. * @param orgId The organization. * @param sensorId The sensor. * @param timestamp When to get the value. * @param interpolatedValue the interpolated value used to update definedSensors and reportingSensors. * @return The value. */ private Double getValue(String depositoryId, String orgId, String sensorId, Date timestamp, InterpolatedValue interpolatedValue) { try { Sensor sensor = depot.getSensor(sensorId, orgId, false); Double value = 0.0; if (sensor != null) { // just get sensor value interpolatedValue.addDefinedSensor(sensorId); try { value = depot.getValue(depositoryId, orgId, sensor.getId(), timestamp, true); interpolatedValue.addReportingSensor(sensorId); } catch (NoMeasurementException e) { return null; } } else { // check for sensor group SensorGroup group = depot.getSensorGroup(sensorId, orgId, false); if (group != null) { for (String s : group.getSensors()) { try { interpolatedValue.addDefinedSensor(s); value += depot.getValue(depositoryId, orgId, s, timestamp, true); interpolatedValue.addReportingSensor(s); } catch (NoMeasurementException e) { // NOPMD // add 0 to value so do nothing. } } } } return value; } catch (MisMatchedOwnerException e) { return null; } catch (IdNotFoundException e) { return null; } } /** * @param depositoryId The depository. * @param orgId The organization. * @param sensorId The sensor. * @param start The start of the interval. * @param end The end of the interval. * @param interpolatedValue the value used to update the defined and reporting sensors. * @return The value. */ private Double getValue(String depositoryId, String orgId, String sensorId, Date start, Date end, InterpolatedValue interpolatedValue) { try { Sensor sensor = depot.getSensor(sensorId, orgId, false); Double value = 0.0; if (sensor != null) { // just get sensor value interpolatedValue.addDefinedSensor(sensorId); try { value = depot.getValue(depositoryId, orgId, sensor.getId(), start, end, true); interpolatedValue.addReportingSensor(sensorId); } catch (NoMeasurementException e) { return null; } } else { // check for sensor group SensorGroup group = depot.getSensorGroup(sensorId, orgId, false); if (group != null) { for (String s : group.getSensors()) { interpolatedValue.addDefinedSensor(s); try { value += depot.getValue(depositoryId, orgId, s, start, end, true); interpolatedValue.addReportingSensor(s); } catch (NoMeasurementException e) { // NOPMD // add 0 to value so do nothing. } } } } return value; } catch (MisMatchedOwnerException e) { return null; } catch (IdNotFoundException e) { return null; } } }