org.starfishrespect.myconsumption.server.business.stats.StatisticsUpdater.java Source code

Java tutorial

Introduction

Here is the source code for org.starfishrespect.myconsumption.server.business.stats.StatisticsUpdater.java

Source

package org.starfishrespect.myconsumption.server.business.stats;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.starfishrespect.myconsumption.server.api.dto.Period;
import org.starfishrespect.myconsumption.server.business.entities.DayStat;
import org.starfishrespect.myconsumption.server.business.entities.PeriodStat;
import org.starfishrespect.myconsumption.server.business.entities.Sensor;
import org.starfishrespect.myconsumption.server.business.exceptions.DaoException;
import org.starfishrespect.myconsumption.server.business.repositories.DayStatRepository;
import org.starfishrespect.myconsumption.server.business.repositories.SensorRepository;
import org.starfishrespect.myconsumption.server.business.repositories.PeriodStatRepository;

import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * S23Y (2015). Licensed under the Apache License, Version 2.0.
 * Author: Thibaud Ledent
 * Tool that computes the statistics based on latest data. It also saves the statistics in the database.
 */
public class StatisticsUpdater {
    @Autowired
    private SensorRepository mSensorRepository;
    @Autowired
    private PeriodStatRepository mPeriodStatRepository;
    @Autowired
    private DayStatRepository mDayStatRepository;

    private final Logger mLogger = LoggerFactory.getLogger(StatisticsUpdater.class);

    public StatisticsUpdater(SensorRepository seRepo, PeriodStatRepository stRepo, DayStatRepository dStRepo) {
        this.mSensorRepository = seRepo;
        this.mPeriodStatRepository = stRepo;
        this.mDayStatRepository = dStRepo;
    }

    /**
     * Compute statistics for all sensors present in database
     * @return false if something goes wrong; true otherwise
     */
    public boolean computeAll() {
        List<Sensor> sensors = mSensorRepository.getAllSensors();
        boolean success = true;

        for (Sensor sensor : sensors) {
            System.out.println("Compute stats for sensor " + sensor.getId());

            try {
                computeStatsForSensor(sensor.getId(), StatUtils.getDateAtMidnight(new Date()));
            } catch (Exception e) {
                System.out.println("Error while computing stats for this sensor...");
                e.printStackTrace();
                success = false;
                continue;
            }

            System.out.println("Computing done.");
        }

        return success;
    }

    /**
     * Cycle through each period of a given sensor to compute its associated stats.
     *
     * @param id sensor id of the sensor
     * @param today today's date at midnight
     * @throws DaoException thrown if something goes wrong while communicating with the db
     */
    private void computeStatsForSensor(String id, Date today) throws DaoException {
        // Find latest DayStat available in db
        // Start by getting all stats sorted for this sensor id
        List<DayStat> dayStats = mDayStatRepository.findBySensorId(id);
        Collections.sort(dayStats, new DayStatComparator());

        Date dayDb;

        // If nothing has been found, the first day will be the first value of the sensor
        if (dayStats.size() == 0) {
            dayDb = mSensorRepository.getSensor(id).getFirstValue();
        } else {
            // else the first day will be the latest day found in db
            DayStat lastDayStat = dayStats.get(dayStats.size() - 1);
            dayDb = lastDayStat.getDay();
        }

        Calendar firstDay = StatUtils.date2Calendar(StatUtils.getDateAtMidnight(dayDb));
        Calendar last = StatUtils.date2Calendar(today);
        // Compute the stat for each day starting at first day
        Calendar currentDay = StatUtils.date2Calendar(firstDay.getTime());

        while (last.compareTo(currentDay) > 0) {
            computeStatForDay(id, StatUtils.calendar2TimeStamp(currentDay));
            currentDay.add(Calendar.DATE, 1);
        }

        // if the current day in db has already been processed, return
        if (!(firstDay.getTimeInMillis() < today.getTime()))
            return;

        // Update each period
        updatePeriod(id, firstDay.getTime());

    }

    /**
     * Update the stat for all periods of a given sensor from a specific date.
     * @param id id of the sensor to update
     * @param firstDay specific Date at which we start updating stats
     */
    private void updatePeriod(String id, Date firstDay) {
        List<DayStat> dayStats = mDayStatRepository.findBySensorId(id);
        Collections.sort(dayStats, new DayStatComparator());

        for (DayStat newDay : dayStats) {
            if (newDay.getDay().getTime() <= firstDay.getTime())
                continue;

            updateOrCreatePeriodStat(id, newDay, Period.DAY);
            updateOrCreatePeriodStat(id, newDay, Period.WEEK);
            updateOrCreatePeriodStat(id, newDay, Period.MONTH);
            updateOrCreatePeriodStat(id, newDay, Period.YEAR);
            updateOrCreatePeriodStat(id, newDay, Period.ALLTIME);
        }
    }

    /**
     * Update or create stats for a sensor at a given period by adding a DayStat.
     * @param id id of the sensor to update
     * @param dayStat DayStat to add to this period
     * @param period given Period
     */
    private void updateOrCreatePeriodStat(String id, DayStat dayStat, Period period) {
        List<PeriodStat> periodStats = mPeriodStatRepository.findBySensorIdAndPeriod(id, period);
        PeriodStat periodStat;

        if (periodStats == null || periodStats.size() == 0)
            periodStat = new PeriodStat(id, period);
        else
            periodStat = periodStats.get(0);

        // Update period stat
        periodStat.removeFirstDay();
        periodStat.addDayInList(dayStat);
        periodStat.recompute();

        mPeriodStatRepository.save(periodStat);
    }

    /**
     * Compute stat for a sensor and a given day.
     * @param id the String id of the sensor
     * @param currentDay the current day as an epoch timestamp (in seconds)
     */
    private void computeStatForDay(String id, int currentDay) {
        List<List<Integer>> values;
        try {
            values = mSensorRepository.getValues(id, currentDay, currentDay + 60 * 60 * 24);
        } catch (DaoException e) {
            mLogger.debug("No values found for day: " + StatUtils.timestamp2Date(currentDay));
            return;
        }
        Sensor sensor = mSensorRepository.getSensor(id);
        DayStatCreator creator = new DayStatCreator(sensor, currentDay, values);
        DayStat dayStat;
        try {
            dayStat = creator.createStat();
        } catch (Exception e) {
            mLogger.debug(e.toString());
            return;
        }

        if (dayStat == null) {
            mLogger.debug("DayStat null");
            return;
        }

        //removeExistingDayStats(id, StatUtils.timestamp2Date(currentDay));
        mDayStatRepository.save(dayStat);
    }

    /**
     * Remove DayStats in database corresponding to a given sensor id and date
     *
     * @param sensorId the sensor id
     * @param d        the date of the day
     */
    private void removeExistingDayStats(String sensorId, Date d) {
        List<DayStat> dayStats = mDayStatRepository.findBySensorIdAndDay(sensorId, d);

        for (DayStat dayStat : dayStats)
            mDayStatRepository.delete(dayStat);
    }

    /**
     * Remove PeriodStat in database corresponding to a given sensor id and period
     *
     * @param sensorId the sensor id
     * @param p       a Period
     */
    private void removeExistingStats(String sensorId, Period p) {
        List<PeriodStat> stats = mPeriodStatRepository.findBySensorIdAndPeriod(sensorId, p);

        for (PeriodStat stat : stats)
            mPeriodStatRepository.delete(stat);
    }
}