refactor and bug fix
- Introduced sensor type specific aggregation logic in DataAggregationDeamon (sum/avg) - Renamed TimeConstants class to TimeUtility. - DataAggregationDeamon::getTimestampPeriodStart did not calculate days correctly. - Moved getTimestampPeriodStart to TimeUtility class. Former-commit-id: c3db0dba990f1091b249fcdd4b5c3e78999cd456
This commit is contained in:
parent
81b605d9be
commit
41d704ad73
7 changed files with 388 additions and 222 deletions
|
|
@ -23,7 +23,7 @@
|
||||||
<classpathentry kind="lib" path="lib/junit-4.12.jar"/>
|
<classpathentry kind="lib" path="lib/junit-4.12.jar"/>
|
||||||
<classpathentry kind="lib" path="lib/java-speech-api-master.jar"/>
|
<classpathentry kind="lib" path="lib/java-speech-api-master.jar"/>
|
||||||
<classpathentry kind="lib" path="lib/sphinx4-core.jar"/>
|
<classpathentry kind="lib" path="lib/sphinx4-core.jar"/>
|
||||||
<classpathentry kind="lib" path="lib/sqlite-jdbc-3.8.11.2.jar"/>
|
<classpathentry kind="lib" path="lib/sqlite-jdbc-3.8.11.2_HACKED_FOR_RPI.jar"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||||
<classpathentry combineaccessrules="false" kind="src" path="/zutil-java"/>
|
<classpathentry combineaccessrules="false" kind="src" path="/zutil-java"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
|
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,13 @@ import zutil.log.LogUtil;
|
||||||
public class DataAggregatorDaemon extends TimerTask implements HalDaemon {
|
public class DataAggregatorDaemon extends TimerTask implements HalDaemon {
|
||||||
private static final Logger logger = LogUtil.getLogger();
|
private static final Logger logger = LogUtil.getLogger();
|
||||||
|
|
||||||
|
private enum AggregationMethod{
|
||||||
|
SUM,
|
||||||
|
AVG
|
||||||
|
}
|
||||||
|
|
||||||
public void initiate(Timer timer){
|
public void initiate(Timer timer){
|
||||||
timer.schedule(this, 0, TimeConstants.FIVE_MINUTES_IN_MS);
|
timer.schedule(this, 0, TimeUtility.FIVE_MINUTES_IN_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -30,7 +35,7 @@ public class DataAggregatorDaemon extends TimerTask implements HalDaemon {
|
||||||
List<Sensor> sensorList = Sensor.getLocalSensors(HalContext.getDB());
|
List<Sensor> sensorList = Sensor.getLocalSensors(HalContext.getDB());
|
||||||
for(Sensor sensor : sensorList){
|
for(Sensor sensor : sensorList){
|
||||||
logger.fine("Aggregating sensor_id: " + sensor.getId());
|
logger.fine("Aggregating sensor_id: " + sensor.getId());
|
||||||
aggregateSensor(sensor.getId());
|
aggregateSensor(sensor);
|
||||||
}
|
}
|
||||||
logger.fine("Aggregation Done");
|
logger.fine("Aggregation Done");
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
|
|
@ -38,37 +43,70 @@ public class DataAggregatorDaemon extends TimerTask implements HalDaemon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void aggregateSensor(long sensorId) {
|
public void aggregateSensor(Sensor sensor) {
|
||||||
|
logger.fine("The sensor is of type: " + sensor.getType());
|
||||||
|
if(sensor.getType().equals("PowerMeter")){
|
||||||
|
logger.fine("aggregating raw data to five minute periods");
|
||||||
|
aggregateRawData(sensor.getId(), TimeUtility.FIVE_MINUTES_IN_MS, 5, AggregationMethod.SUM);
|
||||||
|
logger.fine("aggregating five minute periods into hour periods");
|
||||||
|
aggrigateAggregatedData(sensor.getId(), TimeUtility.FIVE_MINUTES_IN_MS, TimeUtility.HOUR_IN_MS, 12, AggregationMethod.SUM);
|
||||||
|
logger.fine("aggregating one hour periods into one day periods");
|
||||||
|
aggrigateAggregatedData(sensor.getId(), TimeUtility.HOUR_IN_MS, TimeUtility.DAY_IN_MS, 24, AggregationMethod.SUM);
|
||||||
|
}else{
|
||||||
|
logger.fine("The sensor type is not supported by the aggregation deamon. Ignoring");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aggregate data from the raw DB table to the aggregated table
|
||||||
|
* @param sensorId The sensor for to aggregate data
|
||||||
|
* @param toPeriodSizeInMs The period length in ms to aggregate to
|
||||||
|
*/
|
||||||
|
private void aggregateRawData(long sensorId, long toPeriodSizeInMs, int expectedSampleCount, AggregationMethod aggrMethod){
|
||||||
DBConnection db = HalContext.getDB();
|
DBConnection db = HalContext.getDB();
|
||||||
PreparedStatement stmt = null;
|
PreparedStatement stmt = null;
|
||||||
try {
|
try {
|
||||||
|
|
||||||
stmt = db.getPreparedStatement("SELECT MAX(timestamp_end) FROM sensor_data_aggr WHERE sensor_id == ?");
|
stmt = db.getPreparedStatement("SELECT MAX(timestamp_end) FROM sensor_data_aggr WHERE sensor_id == ?");
|
||||||
stmt.setLong(1, sensorId);
|
stmt.setLong(1, sensorId);
|
||||||
Long maxDBTimestamp = DBConnection.exec(stmt, new SimpleSQLResult<Long>());
|
Long maxDBTimestamp = DBConnection.exec(stmt, new SimpleSQLResult<Long>());
|
||||||
if(maxDBTimestamp == null)
|
if(maxDBTimestamp == null)
|
||||||
maxDBTimestamp = 0l;
|
maxDBTimestamp = 0l;
|
||||||
|
|
||||||
// 5 minute aggregation
|
long minPeriodTimestamp = TimeUtility.getTimestampPeriodStart(toPeriodSizeInMs, System.currentTimeMillis());
|
||||||
long minPeriodTimestamp = getTimestampPeriodStart(TimeConstants.FIVE_MINUTES_IN_MS, System.currentTimeMillis());
|
logger.fine("Calculating periods... (from:"+ maxDBTimestamp +", to:"+ minPeriodTimestamp +")");
|
||||||
logger.fine("Calculating 5 min periods... (from:"+ maxDBTimestamp +", to:"+ minPeriodTimestamp +")");
|
|
||||||
stmt = db.getPreparedStatement("SELECT *, 1 AS confidence, timestamp AS timestamp_start FROM sensor_data_raw"
|
stmt = db.getPreparedStatement("SELECT *, 1 AS confidence, timestamp AS timestamp_start FROM sensor_data_raw"
|
||||||
+" WHERE sensor_id == ? AND ? < timestamp AND timestamp < ? "
|
+" WHERE sensor_id == ? AND ? < timestamp AND timestamp < ? "
|
||||||
+" ORDER BY timestamp ASC");
|
+" ORDER BY timestamp ASC");
|
||||||
stmt.setLong(1, sensorId);
|
stmt.setLong(1, sensorId);
|
||||||
stmt.setLong(2, maxDBTimestamp);
|
stmt.setLong(2, maxDBTimestamp);
|
||||||
stmt.setLong(3, minPeriodTimestamp);
|
stmt.setLong(3, minPeriodTimestamp);
|
||||||
DBConnection.exec(stmt, new DataAggregator(sensorId, TimeConstants.FIVE_MINUTES_IN_MS, 5));
|
DBConnection.exec(stmt, new DataAggregator(sensorId, toPeriodSizeInMs, expectedSampleCount, aggrMethod));
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.log(Level.SEVERE, null, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-aggregate data from the aggregated DB table to itself
|
||||||
|
* @param sensorId The sensor for to aggregate data
|
||||||
|
* @param fromPeriodSizeInMs The period length in ms to aggregate from
|
||||||
|
* @param toPeriodSizeInMs The period length in ms to aggregate to
|
||||||
|
*/
|
||||||
|
private void aggrigateAggregatedData(long sensorId, long fromPeriodSizeInMs, long toPeriodSizeInMs, int expectedSampleCount, AggregationMethod aggrMethod){
|
||||||
|
DBConnection db = HalContext.getDB();
|
||||||
|
PreparedStatement stmt = null;
|
||||||
|
try {
|
||||||
|
|
||||||
// hour aggregation
|
|
||||||
stmt = db.getPreparedStatement("SELECT MAX(timestamp_end) FROM sensor_data_aggr"
|
stmt = db.getPreparedStatement("SELECT MAX(timestamp_end) FROM sensor_data_aggr"
|
||||||
+" WHERE sensor_id == ? AND timestamp_end-timestamp_start == ?");
|
+" WHERE sensor_id == ? AND timestamp_end-timestamp_start == ?");
|
||||||
stmt.setLong(1, sensorId);
|
stmt.setLong(1, sensorId);
|
||||||
stmt.setLong(2, TimeConstants.HOUR_IN_MS-1);
|
stmt.setLong(2, toPeriodSizeInMs-1);
|
||||||
maxDBTimestamp = DBConnection.exec(stmt, new SimpleSQLResult<Long>());
|
Long maxDBTimestamp = DBConnection.exec(stmt, new SimpleSQLResult<Long>());
|
||||||
if(maxDBTimestamp == null)
|
if(maxDBTimestamp == null)
|
||||||
maxDBTimestamp = 0l;
|
maxDBTimestamp = 0l;
|
||||||
long hourPeriodTimestamp = getTimestampPeriodStart(TimeConstants.HOUR_IN_MS, System.currentTimeMillis());
|
long hourPeriodTimestamp = TimeUtility.getTimestampPeriodStart(toPeriodSizeInMs, System.currentTimeMillis());
|
||||||
logger.fine("Calculating hour periods... (from:"+ maxDBTimestamp +", to:"+ hourPeriodTimestamp +")");
|
logger.fine("Calculating periods... (from:"+ maxDBTimestamp +", to:"+ hourPeriodTimestamp +")");
|
||||||
|
|
||||||
stmt = db.getPreparedStatement("SELECT * FROM sensor_data_aggr"
|
stmt = db.getPreparedStatement("SELECT * FROM sensor_data_aggr"
|
||||||
+" WHERE sensor_id == ? AND ? < timestamp_start AND timestamp_start < ? AND timestamp_end-timestamp_start == ?"
|
+" WHERE sensor_id == ? AND ? < timestamp_start AND timestamp_start < ? AND timestamp_end-timestamp_start == ?"
|
||||||
|
|
@ -76,68 +114,59 @@ public class DataAggregatorDaemon extends TimerTask implements HalDaemon {
|
||||||
stmt.setLong(1, sensorId);
|
stmt.setLong(1, sensorId);
|
||||||
stmt.setLong(2, maxDBTimestamp);
|
stmt.setLong(2, maxDBTimestamp);
|
||||||
stmt.setLong(3, hourPeriodTimestamp);
|
stmt.setLong(3, hourPeriodTimestamp);
|
||||||
stmt.setLong(4, TimeConstants.FIVE_MINUTES_IN_MS-1);
|
stmt.setLong(4, fromPeriodSizeInMs-1);
|
||||||
DBConnection.exec(stmt, new DataAggregator(sensorId, TimeConstants.HOUR_IN_MS, 12));
|
DBConnection.exec(stmt, new DataAggregator(sensorId, toPeriodSizeInMs, expectedSampleCount, aggrMethod));
|
||||||
|
|
||||||
// day aggregation
|
|
||||||
stmt = db.getPreparedStatement("SELECT MAX(timestamp_end) FROM sensor_data_aggr WHERE sensor_id == ? AND timestamp_end-timestamp_start == ?");
|
|
||||||
stmt.setLong(1, sensorId);
|
|
||||||
stmt.setLong(2, TimeConstants.DAY_IN_MS-1);
|
|
||||||
maxDBTimestamp = DBConnection.exec(stmt, new SimpleSQLResult<Long>());
|
|
||||||
if(maxDBTimestamp == null)
|
|
||||||
maxDBTimestamp = 0l;
|
|
||||||
long dayPeriodTimestamp = getTimestampPeriodStart(TimeConstants.DAY_IN_MS, System.currentTimeMillis());
|
|
||||||
logger.fine("Calculating day periods... (from:"+ maxDBTimestamp +", to:"+ dayPeriodTimestamp +")");
|
|
||||||
|
|
||||||
stmt = db.getPreparedStatement("SELECT * FROM sensor_data_aggr"
|
|
||||||
+" WHERE sensor_id == ? AND ? < timestamp_start AND timestamp_start < ? AND timestamp_end-timestamp_start == ?"
|
|
||||||
+" ORDER BY timestamp_start ASC");
|
|
||||||
stmt.setLong(1, sensorId);
|
|
||||||
stmt.setLong(2, maxDBTimestamp);
|
|
||||||
stmt.setLong(3, dayPeriodTimestamp);
|
|
||||||
stmt.setLong(4, TimeConstants.HOUR_IN_MS-1);
|
|
||||||
DBConnection.exec(stmt, new DataAggregator(sensorId, TimeConstants.DAY_IN_MS, 24));
|
|
||||||
|
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
logger.log(Level.SEVERE, null, e);
|
logger.log(Level.SEVERE, null, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal class for aggregating data to the aggregated DB table
|
||||||
|
*/
|
||||||
private class DataAggregator implements SQLResultHandler<Object>{
|
private class DataAggregator implements SQLResultHandler<Object>{
|
||||||
private long sensorId = -1;
|
private long sensorId = -1;
|
||||||
private long aggrTimeInMs = -1;
|
private long aggrTimeInMs = -1;
|
||||||
private int expectedSampleCount = -1;
|
private int expectedSampleCount = -1;
|
||||||
|
private AggregationMethod aggrMethod = null;
|
||||||
|
|
||||||
public DataAggregator(long sensorId, long aggrTimeInMs, int expectedSampleCount) {
|
public DataAggregator(long sensorId, long aggrTimeInMs, int expectedSampleCount, AggregationMethod aggrMethod) {
|
||||||
this.sensorId = sensorId;
|
this.sensorId = sensorId;
|
||||||
this.aggrTimeInMs = aggrTimeInMs;
|
this.aggrTimeInMs = aggrTimeInMs;
|
||||||
this.expectedSampleCount = expectedSampleCount;
|
this.expectedSampleCount = expectedSampleCount;
|
||||||
|
this.aggrMethod = aggrMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object handleQueryResult(Statement stmt, ResultSet result) throws SQLException {
|
public Object handleQueryResult(Statement stmt, ResultSet result) throws SQLException {
|
||||||
try{
|
try{
|
||||||
|
HalContext.getDB().getConnection().setAutoCommit(false);
|
||||||
|
|
||||||
long currentPeriodTimestamp = 0;
|
long currentPeriodTimestamp = 0;
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
float confidenceSum = 0;
|
float confidenceSum = 0;
|
||||||
int samples = 0;
|
int samples = 0;
|
||||||
long highestSequenceId = Sensor.getHighestSequenceId(sensorId);
|
long highestSequenceId = Sensor.getHighestSequenceId(sensorId);
|
||||||
HalContext.getDB().getConnection().setAutoCommit(false);
|
|
||||||
PreparedStatement preparedInsertStmt = HalContext.getDB().getPreparedStatement("INSERT INTO sensor_data_aggr(sensor_id, sequence_id, timestamp_start, timestamp_end, data, confidence) VALUES(?, ?, ?, ?, ?, ?)");
|
PreparedStatement preparedInsertStmt = HalContext.getDB().getPreparedStatement("INSERT INTO sensor_data_aggr(sensor_id, sequence_id, timestamp_start, timestamp_end, data, confidence) VALUES(?, ?, ?, ?, ?, ?)");
|
||||||
while(result.next()){
|
while(result.next()){
|
||||||
if(sensorId != result.getInt("sensor_id")){
|
if(sensorId != result.getInt("sensor_id")){
|
||||||
throw new IllegalArgumentException("found entry for aggregation for the wrong sensorId (expecting: "+sensorId+", but was: "+result.getInt("sensor_id")+")");
|
throw new IllegalArgumentException("found entry for aggregation for the wrong sensorId (expecting: "+sensorId+", but was: "+result.getInt("sensor_id")+")");
|
||||||
}
|
}
|
||||||
long timestamp = result.getLong("timestamp_start");
|
long timestamp = result.getLong("timestamp_start");
|
||||||
long periodTimestamp = getTimestampPeriodStart(this.aggrTimeInMs, timestamp);
|
long periodTimestamp = TimeUtility.getTimestampPeriodStart(this.aggrTimeInMs, timestamp);
|
||||||
if(currentPeriodTimestamp != 0 && periodTimestamp != currentPeriodTimestamp){
|
if(currentPeriodTimestamp != 0 && periodTimestamp != currentPeriodTimestamp){
|
||||||
float aggrConfidence = confidenceSum / (float)this.expectedSampleCount;
|
float aggrConfidence = confidenceSum / (float)this.expectedSampleCount;
|
||||||
logger.finer("Calculated day period: "+ currentPeriodTimestamp +" sum: "+ sum +" confidence: "+ aggrConfidence+ " samples: " + samples);
|
float data = -1;
|
||||||
|
switch(aggrMethod){
|
||||||
|
case SUM: data = sum; break;
|
||||||
|
case AVG: data = sum/samples; break;
|
||||||
|
}
|
||||||
|
logger.finer("Calculated day period: " + currentPeriodTimestamp + ", data: " + sum + ", confidence: " + aggrConfidence + ", samples: " + samples + ", aggrMethod: " + aggrMethod);
|
||||||
preparedInsertStmt.setInt(1, result.getInt("sensor_id"));
|
preparedInsertStmt.setInt(1, result.getInt("sensor_id"));
|
||||||
preparedInsertStmt.setLong(2, ++highestSequenceId);
|
preparedInsertStmt.setLong(2, ++highestSequenceId);
|
||||||
preparedInsertStmt.setLong(3, currentPeriodTimestamp);
|
preparedInsertStmt.setLong(3, currentPeriodTimestamp);
|
||||||
preparedInsertStmt.setLong(4, currentPeriodTimestamp + this.aggrTimeInMs - 1);
|
preparedInsertStmt.setLong(4, currentPeriodTimestamp + this.aggrTimeInMs - 1);
|
||||||
preparedInsertStmt.setInt(5, sum);
|
preparedInsertStmt.setInt(5, (int)data); //TODO: make data float in DB
|
||||||
preparedInsertStmt.setFloat(6, aggrConfidence);
|
preparedInsertStmt.setFloat(6, aggrConfidence);
|
||||||
preparedInsertStmt.addBatch();
|
preparedInsertStmt.addBatch();
|
||||||
|
|
||||||
|
|
@ -164,9 +193,4 @@ public class DataAggregatorDaemon extends TimerTask implements HalDaemon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long getTimestampPeriodStart(long periodLengthInMs, long timestamp){
|
|
||||||
long tmp = timestamp % periodLengthInMs;
|
|
||||||
return timestamp - tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ public class DataDeletionDaemon extends TimerTask implements HalDaemon {
|
||||||
private static final Logger logger = LogUtil.getLogger();
|
private static final Logger logger = LogUtil.getLogger();
|
||||||
|
|
||||||
public void initiate(Timer timer){
|
public void initiate(Timer timer){
|
||||||
timer.schedule(this, 5000, TimeConstants.FIVE_MINUTES_IN_MS);
|
timer.schedule(this, 5000, TimeUtility.FIVE_MINUTES_IN_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -48,7 +48,7 @@ public class DataDeletionDaemon extends TimerTask implements HalDaemon {
|
||||||
stmt = db.getPreparedStatement("SELECT MAX(timestamp_end) FROM sensor_data_aggr"
|
stmt = db.getPreparedStatement("SELECT MAX(timestamp_end) FROM sensor_data_aggr"
|
||||||
+" WHERE sensor_id == ? AND timestamp_end-timestamp_start == ?");
|
+" WHERE sensor_id == ? AND timestamp_end-timestamp_start == ?");
|
||||||
stmt.setLong(1, sensorId);
|
stmt.setLong(1, sensorId);
|
||||||
stmt.setLong(2, TimeConstants.HOUR_IN_MS-1);
|
stmt.setLong(2, TimeUtility.HOUR_IN_MS-1);
|
||||||
maxDBTimestamp = DBConnection.exec(stmt, new SimpleSQLResult<Long>());
|
maxDBTimestamp = DBConnection.exec(stmt, new SimpleSQLResult<Long>());
|
||||||
if(maxDBTimestamp == null)
|
if(maxDBTimestamp == null)
|
||||||
maxDBTimestamp = 0l;
|
maxDBTimestamp = 0l;
|
||||||
|
|
@ -60,15 +60,15 @@ public class DataDeletionDaemon extends TimerTask implements HalDaemon {
|
||||||
+ "AND timestamp_end < ?");
|
+ "AND timestamp_end < ?");
|
||||||
stmt.setLong(1, sensorId);
|
stmt.setLong(1, sensorId);
|
||||||
stmt.setLong(2, maxDBTimestamp);
|
stmt.setLong(2, maxDBTimestamp);
|
||||||
stmt.setLong(3, TimeConstants.FIVE_MINUTES_IN_MS-1);
|
stmt.setLong(3, TimeUtility.FIVE_MINUTES_IN_MS-1);
|
||||||
stmt.setLong(4, System.currentTimeMillis()-TimeConstants.DAY_IN_MS);
|
stmt.setLong(4, System.currentTimeMillis()-TimeUtility.DAY_IN_MS);
|
||||||
DBConnection.exec(stmt, new AggregateDataDeleter(sensorId));
|
DBConnection.exec(stmt, new AggregateDataDeleter(sensorId));
|
||||||
|
|
||||||
// delete too old 1 hour periods that already have been aggregated into days
|
// delete too old 1 hour periods that already have been aggregated into days
|
||||||
stmt = db.getPreparedStatement("SELECT MAX(timestamp_end) FROM sensor_data_aggr"
|
stmt = db.getPreparedStatement("SELECT MAX(timestamp_end) FROM sensor_data_aggr"
|
||||||
+" WHERE sensor_id == ? AND timestamp_end-timestamp_start == ?");
|
+" WHERE sensor_id == ? AND timestamp_end-timestamp_start == ?");
|
||||||
stmt.setLong(1, sensorId);
|
stmt.setLong(1, sensorId);
|
||||||
stmt.setLong(2, TimeConstants.DAY_IN_MS-1);
|
stmt.setLong(2, TimeUtility.DAY_IN_MS-1);
|
||||||
maxDBTimestamp = DBConnection.exec(stmt, new SimpleSQLResult<Long>());
|
maxDBTimestamp = DBConnection.exec(stmt, new SimpleSQLResult<Long>());
|
||||||
if(maxDBTimestamp == null)
|
if(maxDBTimestamp == null)
|
||||||
maxDBTimestamp = 0l;
|
maxDBTimestamp = 0l;
|
||||||
|
|
@ -80,8 +80,8 @@ public class DataDeletionDaemon extends TimerTask implements HalDaemon {
|
||||||
+ "AND timestamp_end < ?");
|
+ "AND timestamp_end < ?");
|
||||||
stmt.setLong(1, sensorId);
|
stmt.setLong(1, sensorId);
|
||||||
stmt.setLong(2, maxDBTimestamp);
|
stmt.setLong(2, maxDBTimestamp);
|
||||||
stmt.setLong(3, TimeConstants.HOUR_IN_MS-1);
|
stmt.setLong(3, TimeUtility.HOUR_IN_MS-1);
|
||||||
stmt.setLong(4, System.currentTimeMillis()-TimeConstants.SEVEN_DAYS_IN_MS);
|
stmt.setLong(4, System.currentTimeMillis()-TimeUtility.WEEK_IN_MS);
|
||||||
DBConnection.exec(stmt, new AggregateDataDeleter(sensorId));
|
DBConnection.exec(stmt, new AggregateDataDeleter(sensorId));
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
logger.log(Level.SEVERE, null, e);
|
logger.log(Level.SEVERE, null, e);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
package se.koc.hal.deamon;
|
|
||||||
|
|
||||||
public class TimeConstants {
|
|
||||||
public static final long FIVE_MINUTES_IN_MS = 5 * 60 * 1000;
|
|
||||||
public static final long HOUR_IN_MS = FIVE_MINUTES_IN_MS * 12;
|
|
||||||
public static final long DAY_IN_MS = HOUR_IN_MS * 24;
|
|
||||||
public static final long SEVEN_DAYS_IN_MS = DAY_IN_MS * 7;
|
|
||||||
}
|
|
||||||
77
src/se/koc/hal/deamon/TimeUtility.java
Normal file
77
src/se/koc/hal/deamon/TimeUtility.java
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
package se.koc.hal.deamon;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
public class TimeUtility {
|
||||||
|
public static final long SECOND_IN_MS = 1000;
|
||||||
|
public static final long MINUTES_IN_MS = SECOND_IN_MS * 60;
|
||||||
|
public static final long FIVE_MINUTES_IN_MS = MINUTES_IN_MS * 5;
|
||||||
|
public static final long HOUR_IN_MS = MINUTES_IN_MS * 60;
|
||||||
|
public static final long DAY_IN_MS = HOUR_IN_MS * 24;
|
||||||
|
public static final long WEEK_IN_MS = DAY_IN_MS * 7;
|
||||||
|
|
||||||
|
public static long getTimestampPeriodStart(long periodLengthInMs, long timestamp){
|
||||||
|
if(periodLengthInMs < DAY_IN_MS){
|
||||||
|
long tmp = timestamp % periodLengthInMs;
|
||||||
|
return timestamp - tmp;
|
||||||
|
}else{
|
||||||
|
long tmp = periodLengthInMs;
|
||||||
|
int milliseconds = (int) (tmp % SECOND_IN_MS);
|
||||||
|
tmp -= milliseconds * SECOND_IN_MS;
|
||||||
|
int seconds = (int) ((tmp % MINUTES_IN_MS) / SECOND_IN_MS);
|
||||||
|
tmp -= seconds * MINUTES_IN_MS;
|
||||||
|
int minutes = (int) ((tmp % HOUR_IN_MS) / MINUTES_IN_MS);
|
||||||
|
tmp -= minutes * HOUR_IN_MS;
|
||||||
|
int hours = (int) ((tmp % DAY_IN_MS) / HOUR_IN_MS);
|
||||||
|
tmp -= hours * DAY_IN_MS;
|
||||||
|
int days = (int) (tmp / DAY_IN_MS);
|
||||||
|
return getTimestampPeriodStart(days, hours, minutes, seconds, milliseconds, timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long getTimestampPeriodStart(int days, int hours, int minutes, int seconds, int milliseconds, long timestamp) {
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
cal.setTimeInMillis(timestamp);
|
||||||
|
boolean clear = false;
|
||||||
|
|
||||||
|
if(days > 0){
|
||||||
|
int currentDay = cal.get(Calendar.DAY_OF_YEAR);
|
||||||
|
cal.set(Calendar.DAY_OF_YEAR, (currentDay/days)*days);
|
||||||
|
clear = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hours > 0){
|
||||||
|
int currentHour = cal.get(Calendar.HOUR_OF_DAY);
|
||||||
|
cal.set(Calendar.HOUR_OF_DAY, (currentHour/hours)*hours);
|
||||||
|
clear = true;
|
||||||
|
}else if(clear){
|
||||||
|
cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(minutes > 0){
|
||||||
|
int currentMinute = cal.get(Calendar.MINUTE);
|
||||||
|
cal.set(Calendar.MINUTE, (currentMinute/minutes)*minutes);
|
||||||
|
clear = true;
|
||||||
|
}else if(clear){
|
||||||
|
cal.set(Calendar.MINUTE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(seconds > 0){
|
||||||
|
int currentSecond = cal.get(Calendar.SECOND);
|
||||||
|
cal.set(Calendar.SECOND, (currentSecond/seconds)*seconds);
|
||||||
|
clear = true;
|
||||||
|
}else if(clear){
|
||||||
|
cal.set(Calendar.SECOND, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(milliseconds > 0){
|
||||||
|
int currentMillisecond = cal.get(Calendar.MILLISECOND);
|
||||||
|
cal.set(Calendar.MILLISECOND, (currentMillisecond/milliseconds)*milliseconds);
|
||||||
|
}else if(clear){
|
||||||
|
cal.set(Calendar.MILLISECOND, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cal.getTimeInMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import se.koc.hal.HalContext;
|
import se.koc.hal.HalContext;
|
||||||
import se.koc.hal.deamon.TimeConstants;
|
import se.koc.hal.deamon.TimeUtility;
|
||||||
import zutil.db.DBConnection;
|
import zutil.db.DBConnection;
|
||||||
import zutil.db.SQLResultHandler;
|
import zutil.db.SQLResultHandler;
|
||||||
import zutil.io.file.FileUtil;
|
import zutil.io.file.FileUtil;
|
||||||
|
|
@ -35,15 +35,15 @@ public class PCOverviewHttpPage extends HalHttpPage {
|
||||||
+ " sensor_data_aggr.timestamp_end as timestamp_end,"
|
+ " sensor_data_aggr.timestamp_end as timestamp_end,"
|
||||||
+ " sensor_data_aggr.data as data,"
|
+ " sensor_data_aggr.data as data,"
|
||||||
+ " sensor_data_aggr.confidence as confidence,"
|
+ " sensor_data_aggr.confidence as confidence,"
|
||||||
+ TimeConstants.FIVE_MINUTES_IN_MS + " as period_length"
|
+ TimeUtility.FIVE_MINUTES_IN_MS + " as period_length"
|
||||||
+ " FROM sensor_data_aggr, user, sensor"
|
+ " FROM sensor_data_aggr, user, sensor"
|
||||||
+ " WHERE sensor.id = sensor_data_aggr.sensor_id"
|
+ " WHERE sensor.id = sensor_data_aggr.sensor_id"
|
||||||
+ " AND user.id = sensor.user_id"
|
+ " AND user.id = sensor.user_id"
|
||||||
+ " AND timestamp_end-timestamp_start == ?"
|
+ " AND timestamp_end-timestamp_start == ?"
|
||||||
+ " AND timestamp_start > ?"
|
+ " AND timestamp_start > ?"
|
||||||
+ " ORDER BY timestamp_start ASC");
|
+ " ORDER BY timestamp_start ASC");
|
||||||
stmt.setLong(1, TimeConstants.FIVE_MINUTES_IN_MS-1);
|
stmt.setLong(1, TimeUtility.FIVE_MINUTES_IN_MS-1);
|
||||||
stmt.setLong(2, (System.currentTimeMillis() - TimeConstants.DAY_IN_MS) );
|
stmt.setLong(2, (System.currentTimeMillis() - TimeUtility.DAY_IN_MS) );
|
||||||
ArrayList<PowerData> minDataList = DBConnection.exec(stmt , new SQLPowerDataBuilder());
|
ArrayList<PowerData> minDataList = DBConnection.exec(stmt , new SQLPowerDataBuilder());
|
||||||
|
|
||||||
stmt = db.getPreparedStatement(
|
stmt = db.getPreparedStatement(
|
||||||
|
|
@ -52,15 +52,15 @@ public class PCOverviewHttpPage extends HalHttpPage {
|
||||||
+ " sensor_data_aggr.timestamp_end as timestamp_end,"
|
+ " sensor_data_aggr.timestamp_end as timestamp_end,"
|
||||||
+ " sensor_data_aggr.data as data,"
|
+ " sensor_data_aggr.data as data,"
|
||||||
+ " sensor_data_aggr.confidence as confidence,"
|
+ " sensor_data_aggr.confidence as confidence,"
|
||||||
+ TimeConstants.HOUR_IN_MS + " as period_length"
|
+ TimeUtility.HOUR_IN_MS + " as period_length"
|
||||||
+ " FROM sensor_data_aggr, user, sensor"
|
+ " FROM sensor_data_aggr, user, sensor"
|
||||||
+ " WHERE sensor.id = sensor_data_aggr.sensor_id"
|
+ " WHERE sensor.id = sensor_data_aggr.sensor_id"
|
||||||
+ " AND user.id = sensor.user_id"
|
+ " AND user.id = sensor.user_id"
|
||||||
+ " AND timestamp_end-timestamp_start == ?"
|
+ " AND timestamp_end-timestamp_start == ?"
|
||||||
+ " AND timestamp_start > ?"
|
+ " AND timestamp_start > ?"
|
||||||
+ " ORDER BY timestamp_start ASC");
|
+ " ORDER BY timestamp_start ASC");
|
||||||
stmt.setLong(1, TimeConstants.HOUR_IN_MS-1);
|
stmt.setLong(1, TimeUtility.HOUR_IN_MS-1);
|
||||||
stmt.setLong(2, (System.currentTimeMillis() - 3*TimeConstants.DAY_IN_MS) );
|
stmt.setLong(2, (System.currentTimeMillis() - TimeUtility.WEEK_IN_MS) );
|
||||||
ArrayList<PowerData> hourDataList = DBConnection.exec(stmt, new SQLPowerDataBuilder());
|
ArrayList<PowerData> hourDataList = DBConnection.exec(stmt, new SQLPowerDataBuilder());
|
||||||
|
|
||||||
stmt = db.getPreparedStatement(
|
stmt = db.getPreparedStatement(
|
||||||
|
|
@ -69,13 +69,13 @@ public class PCOverviewHttpPage extends HalHttpPage {
|
||||||
+ " sensor_data_aggr.timestamp_end as timestamp_end,"
|
+ " sensor_data_aggr.timestamp_end as timestamp_end,"
|
||||||
+ " sensor_data_aggr.data as data,"
|
+ " sensor_data_aggr.data as data,"
|
||||||
+ " sensor_data_aggr.confidence as confidence,"
|
+ " sensor_data_aggr.confidence as confidence,"
|
||||||
+ TimeConstants.DAY_IN_MS + " as period_length"
|
+ TimeUtility.DAY_IN_MS + " as period_length"
|
||||||
+ " FROM sensor_data_aggr, user, sensor"
|
+ " FROM sensor_data_aggr, user, sensor"
|
||||||
+ " WHERE sensor.id = sensor_data_aggr.sensor_id"
|
+ " WHERE sensor.id = sensor_data_aggr.sensor_id"
|
||||||
+ " AND user.id = sensor.user_id"
|
+ " AND user.id = sensor.user_id"
|
||||||
+ " AND timestamp_end-timestamp_start == ?"
|
+ " AND timestamp_end-timestamp_start == ?"
|
||||||
+ " ORDER BY timestamp_start ASC");
|
+ " ORDER BY timestamp_start ASC");
|
||||||
stmt.setLong(1, TimeConstants.DAY_IN_MS-1);
|
stmt.setLong(1, TimeUtility.DAY_IN_MS-1);
|
||||||
ArrayList<PowerData> dayDataList = DBConnection.exec(stmt, new SQLPowerDataBuilder());
|
ArrayList<PowerData> dayDataList = DBConnection.exec(stmt, new SQLPowerDataBuilder());
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
73
test/se/koc/hal/deamon/TimeUtilityTest.java
Normal file
73
test/se/koc/hal/deamon/TimeUtilityTest.java
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
package se.koc.hal.deamon;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class TimeUtilityTest {
|
||||||
|
private long currentTime;
|
||||||
|
private Calendar referenceCalendar;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup(){
|
||||||
|
currentTime = System.currentTimeMillis();
|
||||||
|
referenceCalendar = Calendar.getInstance();
|
||||||
|
referenceCalendar.setTimeInMillis(currentTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDayStartForCurrentTime(){
|
||||||
|
long thisDayStartedAt = TimeUtility.getTimestampPeriodStart(TimeUtility.DAY_IN_MS, currentTime);
|
||||||
|
Calendar testCalendar = Calendar.getInstance();
|
||||||
|
testCalendar.setTimeInMillis(thisDayStartedAt);
|
||||||
|
|
||||||
|
assertEquals("millisecond is wrong", 0, testCalendar.get(Calendar.MILLISECOND));
|
||||||
|
assertEquals("second is wrong", 0, testCalendar.get(Calendar.SECOND));
|
||||||
|
assertEquals("minute is wrong", 0, testCalendar.get(Calendar.MINUTE));
|
||||||
|
assertEquals("hour is wrong", 0, testCalendar.get(Calendar.HOUR_OF_DAY));
|
||||||
|
assertEquals("day is wrong", referenceCalendar.get(Calendar.DAY_OF_YEAR), testCalendar.get(Calendar.DAY_OF_YEAR));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHourStartForCurrentTime(){
|
||||||
|
long thisDayStartedAt = TimeUtility.getTimestampPeriodStart(TimeUtility.HOUR_IN_MS, currentTime);
|
||||||
|
Calendar testCalendar = Calendar.getInstance();
|
||||||
|
testCalendar.setTimeInMillis(thisDayStartedAt);
|
||||||
|
|
||||||
|
assertEquals("millisecond is wrong", 0, testCalendar.get(Calendar.MILLISECOND));
|
||||||
|
assertEquals("second is wrong", 0, testCalendar.get(Calendar.SECOND));
|
||||||
|
assertEquals("minute is wrong", 0, testCalendar.get(Calendar.MINUTE));
|
||||||
|
assertEquals("hour is wrong", referenceCalendar.get(Calendar.HOUR_OF_DAY), testCalendar.get(Calendar.HOUR_OF_DAY));
|
||||||
|
assertEquals("day is wrong", referenceCalendar.get(Calendar.DAY_OF_YEAR), testCalendar.get(Calendar.DAY_OF_YEAR));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMinuteStartForCurrentTime(){
|
||||||
|
long thisDayStartedAt = TimeUtility.getTimestampPeriodStart(TimeUtility.MINUTES_IN_MS, currentTime);
|
||||||
|
Calendar testCalendar = Calendar.getInstance();
|
||||||
|
testCalendar.setTimeInMillis(thisDayStartedAt);
|
||||||
|
|
||||||
|
assertEquals("millisecond is wrong", 0, testCalendar.get(Calendar.MILLISECOND));
|
||||||
|
assertEquals("second is wrong", 0, testCalendar.get(Calendar.SECOND));
|
||||||
|
assertEquals("minute is wrong", referenceCalendar.get(Calendar.MINUTE), testCalendar.get(Calendar.MINUTE));
|
||||||
|
assertEquals("hour is wrong", referenceCalendar.get(Calendar.HOUR_OF_DAY), testCalendar.get(Calendar.HOUR_OF_DAY));
|
||||||
|
assertEquals("day is wrong", referenceCalendar.get(Calendar.DAY_OF_YEAR), testCalendar.get(Calendar.DAY_OF_YEAR));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSecondStartForCurrentTime(){
|
||||||
|
long thisDayStartedAt = TimeUtility.getTimestampPeriodStart(TimeUtility.SECOND_IN_MS, currentTime);
|
||||||
|
Calendar testCalendar = Calendar.getInstance();
|
||||||
|
testCalendar.setTimeInMillis(thisDayStartedAt);
|
||||||
|
|
||||||
|
assertEquals("millisecond is wrong", 0, testCalendar.get(Calendar.MILLISECOND));
|
||||||
|
assertEquals("second is wrong", referenceCalendar.get(Calendar.SECOND), testCalendar.get(Calendar.SECOND));
|
||||||
|
assertEquals("minute is wrong", referenceCalendar.get(Calendar.MINUTE), testCalendar.get(Calendar.MINUTE));
|
||||||
|
assertEquals("hour is wrong", referenceCalendar.get(Calendar.HOUR_OF_DAY), testCalendar.get(Calendar.HOUR_OF_DAY));
|
||||||
|
assertEquals("day is wrong", referenceCalendar.get(Calendar.DAY_OF_YEAR), testCalendar.get(Calendar.DAY_OF_YEAR));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue