DepositoryAverageValuesServer.java
/**
* 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;
}
}
}