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