Welcome, guest! Login / Register - Why register?
Psst.. new poll here.
Psst.. new forums here.
Microsoft is blocking us again (TY IP Reputation!) so just use oauth login instead. :)

Paste

Pasted as Java by martintimell ( 7 years ago )
package se.zenon.gordon.rest.weatherforecast;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import se.zenon.gordon.config.ApplicationProperties;
import se.zenon.gordon.service.smhiopendata.IndexedLatLonPoint;
import se.zenon.gordon.service.smhiopendata.LatLonCircleArea;
import se.zenon.gordon.service.smhiopendata.LatLonPoint;
import se.zenon.gordon.service.smhiopendata.Parameter;
import se.zenon.gordon.service.smhiopendata.SmhiWeatherGridForecastService;
import se.zenon.gordon.service.smhiopendata.ValidTime;
import se.zenon.gordon.service.smhiopendata.WeatherGridForecast;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class SmhiWeatherGridForecastCache {

    private static final Logger LOG = Logger.getLogger(SmhiWeatherGridForecastCache.class);

    private static final int UPDATE_CHECK_INTERVAL = 5 * 60 * 1000;

    @Autowired
    private SmhiWeatherGridForecastService forecastService;

    @Autowired
        private ApplicationProperties applicationProperties;

    private List<DataUpdateListener> listeners = new ArrayList<>();

    private Date currentForecastReferenceTime;
    private ValidTime currentClosestValidTime;

    private GridLatLonPointQuadTree gridPointsQuadTree;

    private List<ValidTime> validTimes = new ArrayList<>();

    private Map<Parameter, WeatherGridForecast> parameterToForecastMap = new HashMap<>();

    public SmhiWeatherGridForecastCache() {
        // Empty by intention.
    }

    @Scheduled(fixedDelay = UPDATE_CHECK_INTERVAL)
    public void checkForServerUpdate() {
        if (forecastUpdateIsDisabled()) {
            LOG.info("Weather forecast provider update is disabled. No forecast will be updated. Exiting.");
            return;
        }

        LOG.info("Checking for weather forecast provider update.");
        final boolean initialUpdate = currentForecastReferenceTime == null;

        final Date providerForecastReferenceTime = forecastService.getForecastReferenceTime();
        final boolean providerReferenceTimeExist = providerForecastReferenceTime != null;
        final boolean referenceTimeChanged = initialUpdate || (providerReferenceTimeExist && providerForecastReferenceTime.after(currentForecastReferenceTime));

        final ValidTime closestValidTime = getClosestValidTime();
        final boolean closestValidTimeChanged = initialUpdate || !currentClosestValidTime.equals(closestValidTime);

        // Perform data update if reference time from provider is changed in respect to our last saved reference time stamp.
        if (initialUpdate || closestValidTimeChanged || referenceTimeChanged) {
            performWeatherUpdate(initialUpdate, providerForecastReferenceTime, referenceTimeChanged, closestValidTime, closestValidTimeChanged);
            LOG.info("Weather forecast update is done.");
        } else {
            LOG.info("No update of weather forecast necessary. Already loaded the latest forecast (issue time " + providerForecastReferenceTime + ").");
        }
    }

    private void performWeatherUpdate(final boolean initialUpdate, final Date providerForecastReferenceTime,
                                      final boolean referenceTimeChanged, final ValidTime closestValidTime,
                                      final boolean closestValidTimeChanged) {
        LOG.info("Updating weather forecast data due to" +
                (initialUpdate ? " [initial update]" : "") +
                (closestValidTimeChanged ? " [closest valid time changed]" : "") +
                (referenceTimeChanged ? " [reference time changed]" : "") +
                ".");
        currentForecastReferenceTime = providerForecastReferenceTime;
        currentClosestValidTime = closestValidTime;

        validTimes = forecastService.getValidTimes();

        final List<IndexedLatLonPoint> gridPoints = forecastService.getGridPoints();
        this.gridPointsQuadTree = new GridLatLonPointQuadTree(gridPoints);

        updateForecastFromProvider(Parameter.RELATIVE_HUMIDITY, closestValidTime);
        updateForecastFromProvider(Parameter.AIR_TEMPERATURE, closestValidTime);
        updateForecastFromProvider(Parameter.PRECIPITATION_AVERAGE, closestValidTime);
        updateForecastFromProvider(Parameter.THUNDERSTORM_PROBABILITY, closestValidTime);
        updateForecastFromProvider(Parameter.CLOUD_TOTAL, closestValidTime);

        notifyListeners(providerForecastReferenceTime);
    }

    private boolean forecastUpdateIsDisabled() {
        final Boolean forecastUpdateDisabled = applicationProperties.getForecstUpdateDisabled();
        if (forecastUpdateDisabled) {
            return true;
        }
        return false;
    }

    /**
     * @return time for when the current forecast is valid for.
     */
    public Date getCurrentForecastValidTime() {
        return currentClosestValidTime;
    }

    private void updateForecastFromProvider(final Parameter parameter, final ValidTime time) {
        final WeatherGridForecast weatherGridForecast = forecastService.getWeatherGridForecast(time, parameter);
        parameterToForecastMap.put(parameter, weatherGridForecast);

        final boolean dataExist = weatherGridForecast != null && weatherGridForecast.getValues() != null && weatherGridForecast.getValues().size() > 0;

        if (!dataExist) {
            LOG.error("No " + parameter + " forecast data/values at forecast valid time " + time.getSmhiIsoString() + " was loaded from provider.");
        }

        // Logging debug information for parameter forecast values
        if (LOG.isDebugEnabled() && dataExist) {
            final List<Double> values = weatherGridForecast.getValues();
            final int amountForecastValues = values.size();
            final Double minValue = getMinValue(parameter);
            final Double maxValue = getMaxValue(parameter);
            final String validTimeString = weatherGridForecast.getValidTime().getSmhiIsoString();

            LOG.debug("Read " + amountForecastValues + " " + weatherGridForecast.getParameter() + " values " +
                    "(forecast valid time " + validTimeString + ") from provider. " +
                    "Value range [" + minValue + " -- " + maxValue + "].");
        }
    }

    public Double getMinValue(final Parameter parameter) {
        Double minValue = null;
        final WeatherGridForecast weatherGridForecast = parameterToForecastMap.get(parameter);
        if (weatherGridForecast != null && weatherGridForecast.getValues() != null) {
            minValue = weatherGridForecast.getValues().parallelStream().min(Double::compare).get();
        }

        return minValue;
    }

    public Double getMaxValue(final Parameter parameter) {
        Double value = null;
        final WeatherGridForecast weatherGridForecast = parameterToForecastMap.get(parameter);
        if (weatherGridForecast != null && weatherGridForecast.getValues() != null) {
            value = weatherGridForecast.getValues().parallelStream().max(Double::compare).get();
        }

        return value;
    }

    private ValidTime getClosestValidTime() {
        return getClosestValidTime(new Date());
    }


    private ValidTime getClosestValidTime(final Date date) {
        ValidTime closestValidTime = null;

        if (validTimes.isEmpty()) {
            validTimes = forecastService.getValidTimes();
        }

        for (ValidTime validTime : validTimes) {
            final boolean noValidTimeSet = closestValidTime == null;

            if (noValidTimeSet || Math.abs(validTime.getTime() - date.getTime()) < Math.abs(closestValidTime.getTime() - date.getTime())) {
                closestValidTime = validTime;
            }
        }

        return closestValidTime;
    }


    GridLatLonPointQuadTree getGridPointsQuadTree() {
        if (gridPointsQuadTree == null) {
            gridPointsQuadTree = new GridLatLonPointQuadTree(forecastService.getGridPoints());
        }

        return gridPointsQuadTree;
    }

    public WeatherForecastGridLatLonPoint getForecastValue(final LatLonPoint point, final Parameter parameter) {
        final IndexedLatLonPoint closestPoint = getGridPointsQuadTree().getClosestGridPoint(point);

        if (closestPoint == null) {
            return null;
        }

        Double value = null;
        final WeatherGridForecast parameterForecast = parameterToForecastMap.get(parameter);
        if (parameterForecast != null) {
            final List<Double> parameterValues = parameterForecast.getValues();
            value = parameterValues.get(closestPoint.getIndex());
        }

        return new WeatherForecastGridLatLonPoint(point, getClosestValidTime(), parameter, value);
    }

    /**
     * Get largest value in circle area.
     *
     * @param area      area
     * @param parameter type of value
     * @return largest value
     */
    public Double getMaxForecastValue(final LatLonCircleArea area, final Parameter parameter) {
        final WeatherGridForecast parameterForecast = parameterToForecastMap.get(parameter);
        return parameterForecast.getPoints().parallelStream()
                .filter(area::isInArea)
                .map(indexedLatLonPoint -> parameterForecast.getValues().get(indexedLatLonPoint.getIndex()))
                .max(Double::compare)
                .orElse(getForecastValue(area.getCenterPoint(), parameter).getValue());
    }

    public LatLonBoundingBox getBoundingBox() {
        return getGridPointsQuadTree();
    }


    public void addUpdateListener(final DataUpdateListener listener) {
        listeners.add(listener);
    }


    public void removeUpdateListener(final DataUpdateListener listener) {
        listeners.remove(listener);
    }


    public void notifyListeners(final Date referenceTime) {
        for (DataUpdateListener listener : listeners) {
            listener.weatherForecastGridCacheDataUpdated(referenceTime);
        }
    }


    public static class WeatherForecastGridLatLonPoint extends LatLonPoint {
        private final LatLonPoint point;
        private final ValidTime validTime;
        private final Parameter parameter;
        private final Double value;

        public WeatherForecastGridLatLonPoint(final LatLonPoint point, final ValidTime validTime, final Parameter parameter, final Double value) {
            super(point.getLat(), point.getLon());
            this.point = point;
            this.validTime = validTime;
            this.parameter = parameter;
            this.value = value;
        }

        public LatLonPoint getPoint() {
            return point;
        }

        public ValidTime getValidTime() {
            return validTime;
        }

        public Parameter getParameter() {
            return parameter;
        }

        public Double getValue() {
            return value;
        }

        @Override
        public boolean equals(final Object o) {
            return super.equals(o);
        }

        @Override
        public int hashCode() {
            return super.hashCode();
        }
    }

    public interface DataUpdateListener {
        void weatherForecastGridCacheDataUpdated(final Date referenceTime);
    }
}

 

Revise this Paste

Your Name: Code Language: