DepositoryValueServer.java
/**
* DepositoryValueServerResource.java This file is part of WattDepot.
*
* Copyright (C) 2013 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.logging.Level;
import javax.xml.datatype.DatatypeConfigurationException;
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.Labels;
import org.wattdepot.common.domainmodel.InterpolatedValue;
import org.wattdepot.common.domainmodel.Sensor;
import org.wattdepot.common.domainmodel.SensorGroup;
import org.wattdepot.common.exception.IdNotFoundException;
import org.wattdepot.common.exception.MeasurementGapException;
import org.wattdepot.common.exception.MisMatchedOwnerException;
import org.wattdepot.common.exception.NoMeasurementException;
import org.wattdepot.common.util.DateConvert;
import org.wattdepot.server.ServerProperties;
/**
* DepositoryValueServerResource - ServerResouce that handles the GET
* /wattdepot/{org-id}/depository/{depository-id}/value/ response.
*
* @author Cam Moore
*
*/
public class DepositoryValueServer extends WattDepotServerResource {
private String depositoryId;
private String sensorId;
private String start;
private String end;
private String timestamp;
private String latest;
private String earliest;
private String gapSeconds;
private static DescriptiveStatistics averageGetTime = new DescriptiveStatistics();
/*
* (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.timestamp = getQuery().getValues(Labels.TIMESTAMP);
this.latest = getQuery().getValues(Labels.LATEST);
this.earliest = getQuery().getValues(Labels.EARLIEST);
this.orgId = getAttribute(Labels.ORGANIZATION_ID);
this.depositoryId = getAttribute(Labels.DEPOSITORY_ID);
this.gapSeconds = getQuery().getValues(Labels.GAP);
}
/**
* retrieve the depository value for a sensor.
*
* @return measured value.
*/
public InterpolatedValue doRetrieve() {
getLogger().log(
Level.INFO,
"GET /wattdepot/{" + orgId + "}/depository/{" + depositoryId + "}/value/?sensor={"
+ sensorId + "}&start={" + start + "}&end={" + end + "}×tamp={" + timestamp
+ "}&latest={" + latest + "}&earliest={" + earliest + "}&gap={" + gapSeconds + "}");
Long startTime = null;
if (depot.getServerProperties().get(ServerProperties.SERVER_TIMING_KEY)
.equals(ServerProperties.TRUE)) {
startTime = System.nanoTime();
}
if (isInRole(orgId)) {
try {
Depository deposit = depot.getDepository(depositoryId, orgId, true);
if (deposit != null) {
try {
depot.getSensor(sensorId, orgId, true);
InterpolatedValue val = calculateValue(sensorId, start, end, timestamp, earliest, latest);
if (depot.getServerProperties().get(ServerProperties.SERVER_TIMING_KEY)
.equals(ServerProperties.TRUE)) {
Long endTime = System.nanoTime();
Long diff = endTime - startTime;
averageGetTime.addValue(diff / 1E9);
getLogger().log(
Level.SEVERE,
"GET /wattdepot/{" + orgId + "}/depository/{" + depositoryId
+ "}/value/?sensor={" + sensorId + "}&start={" + start + "}&end={" + end
+ "}×tamp={" + timestamp + "}&latest={" + latest + "}&earliest={"
+ earliest + "}&gap={" + gapSeconds + "} took "
+ (diff / 1E9) + " seconds. Running average is " + averageGetTime.getMean());
}
return val;
}
catch (IdNotFoundException inf) {
try {
SensorGroup group = depot.getSensorGroup(sensorId, orgId, true);
InterpolatedValue val = null;
// this wont work for earliest or latest.
if (earliest != null) {
// find the last 'earliest' time
Date time = null;
for (String s : group.getSensors()) {
InterpolatedValue v = calculateValue(s, start, end, timestamp, earliest, latest);
if (time == null) {
time = v.getStart();
}
else if (time.before(v.getStart())) {
time = v.getStart();
}
}
// have the time get the value at time
for (String s : group.getSensors()) {
if (val == null) {
val = calculateValue(s, null, null, DateConvert.convertDate(time).toString(),
null, null);
}
else {
val.setValue(val.getValue()
+ calculateValue(s, null, null, DateConvert.convertDate(time).toString(),
null, null).getValue());
}
}
}
else if (latest != null) {
// find the first 'latest' time
Date time = null;
for (String s : group.getSensors()) {
InterpolatedValue v = calculateValue(s, start, end, timestamp, earliest, latest);
if (time == null) {
time = v.getEnd();
}
else if (time.after(v.getEnd())) {
time = v.getEnd();
}
}
// have the time get the value at time
for (String s : group.getSensors()) {
if (val == null) {
val = calculateValue(s, null, null, DateConvert.convertDate(time).toString(),
null, null);
}
else {
val.setValue(val.getValue()
+ calculateValue(s, null, null, DateConvert.convertDate(time).toString(),
null, null).getValue());
}
}
}
else {
for (String s : group.getSensors()) {
if (val == null) {
val = calculateValue(s, start, end, timestamp, earliest, latest);
}
else {
val.setValue(val.getValue()
+ calculateValue(s, start, end, timestamp, earliest, latest).getValue());
}
}
}
if (depot.getServerProperties().get(ServerProperties.SERVER_TIMING_KEY)
.equals(ServerProperties.TRUE)) {
Long endTime = System.nanoTime();
getLogger().log(
Level.SEVERE,
"GET /wattdepot/{" + orgId + "}/depository/{" + depositoryId
+ "}/value/?sensor={" + sensorId + "}&start={" + start + "}&end={" + end
+ "}×tamp={" + timestamp + "}&latest={" + latest + "}&earliest={"
+ earliest + "}&gap={" + gapSeconds + "} took "
+ ((endTime - startTime) / 1E9) + " seconds.");
}
return val;
}
catch (IdNotFoundException inf1) {
setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "Could not find sensor " + sensorId);
}
}
}
else {
setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "Could not find depository " + depositoryId);
}
}
catch (MisMatchedOwnerException e) {
setStatus(Status.CLIENT_ERROR_BAD_REQUEST, e.getMessage());
}
catch (NoMeasurementException e1) {
setStatus(Status.SERVER_ERROR_INTERNAL, e1.getMessage());
}
catch (NumberFormatException e) {
setStatus(Status.SERVER_ERROR_INTERNAL, e.getMessage());
}
catch (MeasurementGapException e) {
setStatus(Status.CLIENT_ERROR_BAD_REQUEST, e.getMessage());
}
catch (ParseException e) {
setStatus(Status.SERVER_ERROR_INTERNAL, e.getMessage());
}
catch (DatatypeConfigurationException e) {
setStatus(Status.SERVER_ERROR_INTERNAL, e.getMessage());
}
catch (IdNotFoundException e) {
setStatus(Status.CLIENT_ERROR_BAD_REQUEST, e.getMessage());
}
return null;
}
else {
setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Bad credentials.");
return null;
}
}
/**
* @param sensorId the Sensor's id.
* @param start The start time. Optional, must have end if not null.
* @param end The end time. Optional, must exist if start not null.
* @param timestamp The time of the value. Optional, must be null if start or
* end.
* @param earliest if not null will get earliest value. Optional, must be null
* if start or end or latest or timestamp.
* @param latest if not null will get latest value. Optional, must be null if
* start or end or earliest or timestamp.
* @return The interpolated value for the sensorId and time(s).
* @throws IdNotFoundException if sensorId is not defined.
* @throws MisMatchedOwnerException if sensorId is not in orgId.
* @throws NoMeasurementException if there aren't measurements around the
* time(s).
* @throws ParseException if the times are not valid Date strings.
* @throws DatatypeConfigurationException if there is a server problem.
* @throws NumberFormatException if there is a problem.
* @throws MeasurementGapException if the measurements are too far apart.
*/
private InterpolatedValue calculateValue(String sensorId, String start, String end,
String timestamp, String earliest, String latest) throws IdNotFoundException,
MisMatchedOwnerException, NoMeasurementException, ParseException,
DatatypeConfigurationException, NumberFormatException, MeasurementGapException {
Depository deposit = depot.getDepository(depositoryId, orgId, true);
Sensor sensor = depot.getSensor(sensorId, orgId, true);
Double value = null;
Date startDate = null;
Date endDate = null;
Date time = null;
InterpolatedValue val = null;
if (earliest != null) {
val = depot.getEarliestMeasuredValue(depositoryId, orgId, sensorId, true);
val.addDefinedSensor(sensorId);
val.addReportingSensor(sensorId);
return val;
}
else if (latest != null) {
val = depot.getLatestMeasuredValue(depositoryId, orgId, sensorId, true);
val.addDefinedSensor(sensorId);
val.addReportingSensor(sensorId);
return val;
}
else if (timestamp != null) {
time = DateConvert.parseCalStringToDate(timestamp);
if (gapSeconds != null) {
value = depot.getValue(depositoryId, orgId, sensor.getId(), time,
Long.parseLong(gapSeconds), true);
}
else {
value = depot.getValue(depositoryId, orgId, sensor.getId(), time, true);
}
val = new InterpolatedValue(sensorId, value, deposit.getMeasurementType(), time);
}
else if (start != null && end != null) {
startDate = DateConvert.parseCalStringToDate(start);
endDate = DateConvert.parseCalStringToDate(end);
if (gapSeconds != null) {
value = depot.getValue(depositoryId, orgId, sensor.getId(), startDate, endDate,
Long.parseLong(gapSeconds), true);
}
else {
value = depot.getValue(depositoryId, orgId, sensor.getId(), startDate, endDate, true);
}
val = new InterpolatedValue(sensorId, value, deposit.getMeasurementType(), startDate, endDate);
}
if (val != null) {
val.addDefinedSensor(sensorId);
if (value != null) {
val.addReportingSensor(sensorId);
}
}
return val;
}
}