Skip to content
Browse files

Changes to only read data from the weather service when we need to.

  • Loading branch information...
1 parent df1faf4 commit 084d64ec2b0c8441f0f27952843cb9b85554a011 @jmurph jmurph committed Nov 23, 2011
View
365 src/main/java/com/controlj/addon/weather/EquipmentHandler.java
@@ -25,7 +25,6 @@
import com.controlj.addon.weather.util.Logging;
import com.controlj.green.addonsupport.access.*;
import com.controlj.green.addonsupport.access.aspect.PresentValue;
-import com.controlj.green.addonsupport.access.util.Acceptors;
import com.controlj.green.addonsupport.access.value.FloatValue;
import com.controlj.green.addonsupport.access.value.InvalidValueException;
import org.jetbrains.annotations.NotNull;
@@ -39,200 +38,186 @@
* This class is responsible for inserting weather data into control programs. If the
* lookupString given in the constructor is not an equipment, other calls to this class
* will be ignored.
- *
+ * <p/>
* Only numeric field values are written into the field devices. String and Date type fields
* are ignored.
- *
+ * <p/>
* Control programs are written to using a "FieldAccess", so any changes get automatically
* downloaded to the field device.
*/
-public class EquipmentHandler
-{
- private static final Pattern WEATHER_STATION_PATTERN = Pattern.compile("ws_(.+)");
- private static final Pattern WEATHER_CONDITIONS_PATTERN = Pattern.compile("wc_(.+)");
- private static final Pattern WEATHER_FORECAST_PATTERN = Pattern.compile("wf(\\d+)_(.+)");
-
- private final SystemConnection systemConnection;
- private final Collection<PresentValue> presentValues;
-
- public EquipmentHandler(SystemConnection systemConn, final String lookupString) throws EquipmentWriteException
- {
- systemConnection = systemConn;
- if (Logging.is41)
- {
- // 4.1 doesn't support writing to equipment (the presentValue aspect does not correctly redirect
- // writes to the relinquish_default node). So, just set the presentValues to an empty list, effectively
- // bypassing the attempt to write data to the control programs.
- presentValues = Collections.emptyList();
- }
- else
- {
- try
- {
- presentValues = systemConnection.runReadAction(new ReadActionResult<Collection<PresentValue>>()
- {
- @Override public Collection<PresentValue> execute(@NotNull SystemAccess systemAccess) throws Exception
- {
- Location location = systemAccess.getTree(SystemTree.Geographic).resolve(lookupString);
- if (location.getType() == LocationType.Equipment)
- return location.find(PresentValue.class, Acceptors.acceptAll());
- else
- return Collections.emptyList();
- }
+public class EquipmentHandler {
+ private static final Pattern WEATHER_STATION_PATTERN = Pattern.compile("ws_(.+)");
+ private static final Pattern WEATHER_CONDITIONS_PATTERN = Pattern.compile("wc_(.+)");
+ private static final Pattern WEATHER_FORECAST_PATTERN = Pattern.compile("wf(\\d+)_(.+)");
+
+ private final SystemConnection systemConnection;
+ private final Collection<PresentValue> presentValues;
+
+ public EquipmentHandler(SystemConnection systemConn, String path) throws EquipmentWriteException {
+ systemConnection = systemConn;
+ if (Logging.is41) {
+ // 4.1 doesn't support writing to equipment (the presentValue aspect does not correctly redirect
+ // writes to the relinquish_default node). So, just set the presentValues to an empty list, effectively
+ // bypassing the attempt to write data to the control programs.
+ presentValues = Collections.emptyList();
+ } else {
+ try {
+ final String lookupString = "ABSPATH:1:" + path;
+ presentValues = systemConnection.runReadAction(new ReadActionResult<Collection<PresentValue>>() {
+ @Override
+ public Collection<PresentValue> execute(@NotNull SystemAccess systemAccess) throws Exception {
+ Location location = systemAccess.getTree(SystemTree.Geographic).resolve(lookupString);
+ if (location.getType() == LocationType.Equipment)
+ return location.find(PresentValue.class, new FieldReferenceAcceptor());
+ else
+ return Collections.emptyList();
+ }
+ });
+ } catch (Exception e) {
+ throw new EquipmentWriteException(e);
+ }
+ }
+ }
+
+ public boolean hasFieldsToWrite() { return !presentValues.isEmpty(); }
+
+ public void writeStationData(final StationSource stationSource) throws EquipmentWriteException {
+ if (!hasFieldsToWrite()) //short circuit if no data to update
+ return;
+
+ try {
+ systemConnection.runWriteAction(FieldAccessFactory.newFieldAccess(), "Updating weather station data", new WriteAction() {
+ @Override
+ public void execute(@NotNull WritableSystemAccess systemAccess) throws Exception {
+ for (PresentValue presentValue : presentValues) {
+ String referenceName = presentValue.getLocation().getReferenceName();
+ Float value = getValueIfStation(referenceName, stationSource);
+ if (value != null)
+ setValue(presentValue, value);
+ }
+ }
});
- }
- catch (Exception e)
- {
+ } catch (Exception e) {
throw new EquipmentWriteException(e);
- }
- }
- }
-
- public void writeStationData(final StationSource stationSource) throws EquipmentWriteException
- {
- if (presentValues.isEmpty()) //short circuit if no data to update
- return;
-
- try
- {
- systemConnection.runWriteAction(FieldAccessFactory.newFieldAccess(), "Updating weather station data", new WriteAction()
- {
- @Override public void execute(@NotNull WritableSystemAccess systemAccess) throws Exception
- {
- for (PresentValue presentValue : presentValues)
- {
- String referenceName = presentValue.getLocation().getReferenceName();
- Float value = getValueIfStation(referenceName, stationSource);
- if (value != null)
- setValue(presentValue, value);
- }
- }
- });
- }
- catch (Exception e)
- {
- throw new EquipmentWriteException(e);
- }
- }
-
- public void writeConditionsData(final ConditionsSource conditionsSource)throws EquipmentWriteException
- {
- if (presentValues.isEmpty()) //short circuit if no data to update
- return;
-
- try
- {
- systemConnection.runWriteAction(FieldAccessFactory.newFieldAccess(), "Updating current weather data", new WriteAction()
- {
- @Override public void execute(@NotNull WritableSystemAccess systemAccess) throws Exception
- {
- for (PresentValue presentValue : presentValues)
- {
- String referenceName = presentValue.getLocation().getReferenceName();
- Float value = getValueIfConditions(referenceName, conditionsSource);
- if (value != null)
- setValue(presentValue, value);
- }
- }
- });
- }
- catch (Exception e)
- {
- throw new EquipmentWriteException(e);
- }
- }
-
- public void writeForecastData(final ForecastSource[] forecastSources)throws EquipmentWriteException
- {
- if (presentValues.isEmpty()) //short circuit if no data to update
- return;
-
- try
- {
- systemConnection.runWriteAction(FieldAccessFactory.newFieldAccess(), "Updating weather forecast data", new WriteAction()
- {
- @Override public void execute(@NotNull WritableSystemAccess systemAccess) throws Exception
- {
- for (PresentValue presentValue : presentValues)
- {
- String referenceName = presentValue.getLocation().getReferenceName();
- Float value = getValueIfForecast(referenceName, forecastSources);
- if (value != null)
- setValue(presentValue, value);
- }
- }
- });
- }
- catch (Exception e)
- {
- throw new EquipmentWriteException(e);
- }
- }
-
- private Float getValueIfStation(String referenceName, StationSource stationSource)
- {
- Matcher matcher = WEATHER_STATION_PATTERN.matcher(referenceName);
- if (matcher.matches())
- {
- String fieldName = matcher.group(1);
- StationField field = StationField.find(fieldName);
- if (field != null)
- return sanitizeValue(field.getValue(stationSource), field.getType());
- }
- return null;
- }
-
- private Float getValueIfConditions(String referenceName, ConditionsSource conditionsSource)
- {
- Matcher matcher = WEATHER_CONDITIONS_PATTERN.matcher(referenceName);
- if (matcher.matches())
- {
- String fieldName = matcher.group(1);
- ConditionsField field = ConditionsField.find(fieldName);
- if (field != null)
- return sanitizeValue(field.getValue(conditionsSource), field.getType());
- }
- return null;
- }
-
- private Float getValueIfForecast(String referenceName, ForecastSource[] forecastSources)
- {
- Matcher matcher = WEATHER_FORECAST_PATTERN.matcher(referenceName);
- if (matcher.matches())
- {
- int day = Integer.parseInt(matcher.group(1));
- String fieldName = matcher.group(2);
- ForecastField field = ForecastField.find(fieldName);
- if (field != null && day < forecastSources.length)
- return sanitizeValue(field.getValue(forecastSources[day]), field.getType());
- }
- return null;
- }
-
- private Float sanitizeValue(Object value, FieldType type)
- {
- if (value == null)
- return null;
-
- switch(type)
- {
- case FloatType: return (Float)value;
- case IntegerType: return new Float((Integer)value);
- case StringType:
- case DateType: return null; // strings and dates don't get written to the field
- }
- return null; // if it's a type we don't recognize, ignore it
- }
-
- private void setValue(PresentValue pv, Float value)
- {
- try
- {
- ((FloatValue)pv.getValue()).set(value);
- }
- catch (InvalidValueException e)
- {
- Logging.println("Error writing weather data (" + value + ") into present value (" + pv.getLocation() + ')', e);
- }
- }
+ }
+ }
+
+ public void writeConditionsData(final ConditionsSource conditionsSource) throws EquipmentWriteException {
+ if (!hasFieldsToWrite()) //short circuit if no data to update
+ return;
+
+ try {
+ systemConnection.runWriteAction(FieldAccessFactory.newFieldAccess(), "Updating current weather data", new WriteAction() {
+ @Override
+ public void execute(@NotNull WritableSystemAccess systemAccess) throws Exception {
+ for (PresentValue presentValue : presentValues) {
+ String referenceName = presentValue.getLocation().getReferenceName();
+ Float value = getValueIfConditions(referenceName, conditionsSource);
+ if (value != null)
+ setValue(presentValue, value);
+ }
+ }
+ });
+ } catch (Exception e) {
+ throw new EquipmentWriteException(e);
+ }
+ }
+
+ public void writeForecastData(final ForecastSource[] forecastSources) throws EquipmentWriteException {
+ if (!hasFieldsToWrite()) //short circuit if no data to update
+ return;
+
+ try {
+ systemConnection.runWriteAction(FieldAccessFactory.newFieldAccess(), "Updating weather forecast data", new WriteAction() {
+ @Override
+ public void execute(@NotNull WritableSystemAccess systemAccess) throws Exception {
+ for (PresentValue presentValue : presentValues) {
+ String referenceName = presentValue.getLocation().getReferenceName();
+ Float value = getValueIfForecast(referenceName, forecastSources);
+ if (value != null)
+ setValue(presentValue, value);
+ }
+ }
+ });
+ } catch (Exception e) {
+ throw new EquipmentWriteException(e);
+ }
+ }
+
+ private Float getValueIfStation(String referenceName, StationSource stationSource) {
+ Matcher matcher = WEATHER_STATION_PATTERN.matcher(referenceName);
+ if (matcher.matches()) {
+ String fieldName = matcher.group(1);
+ StationField field = StationField.find(fieldName);
+ if (field != null)
+ return sanitizeValue(field.getValue(stationSource), field.getType());
+ }
+ return null;
+ }
+
+ private Float getValueIfConditions(String referenceName, ConditionsSource conditionsSource) {
+ Matcher matcher = WEATHER_CONDITIONS_PATTERN.matcher(referenceName);
+ if (matcher.matches()) {
+ String fieldName = matcher.group(1);
+ ConditionsField field = ConditionsField.find(fieldName);
+ if (field != null)
+ return sanitizeValue(field.getValue(conditionsSource), field.getType());
+ }
+ return null;
+ }
+
+ private Float getValueIfForecast(String referenceName, ForecastSource[] forecastSources) {
+ Matcher matcher = WEATHER_FORECAST_PATTERN.matcher(referenceName);
+ if (matcher.matches()) {
+ int day = Integer.parseInt(matcher.group(1));
+ String fieldName = matcher.group(2);
+ ForecastField field = ForecastField.find(fieldName);
+ if (field != null && day < forecastSources.length)
+ return sanitizeValue(field.getValue(forecastSources[day]), field.getType());
+ }
+ return null;
+ }
+
+ private Float sanitizeValue(Object value, FieldType type) {
+ if (value == null)
+ return null;
+
+ switch (type) {
+ case FloatType:
+ return (Float) value;
+ case IntegerType:
+ return new Float((Integer) value);
+ case StringType:
+ case DateType:
+ return null; // strings and dates don't get written to the field
+ }
+ return null; // if it's a type we don't recognize, ignore it
+ }
+
+ private void setValue(PresentValue pv, Float value) {
+ try {
+ ((FloatValue) pv.getValue()).set(value);
+ } catch (InvalidValueException e) {
+ Logging.println("Error writing weather data (" + value + ") into present value (" + pv.getLocation() + ')', e);
+ }
+ }
+
+ private static final class FieldReferenceAcceptor implements AspectAcceptor<PresentValue>
+ {
+ @Override
+ public boolean accept(@NotNull PresentValue presentValue) {
+ String referenceName = presentValue.getLocation().getReferenceName();
+ Matcher stationPatternMatcher = WEATHER_STATION_PATTERN.matcher(referenceName);
+ if (stationPatternMatcher.matches())
+ return true;
+ Matcher conditionsPatternMatcher = WEATHER_CONDITIONS_PATTERN.matcher(referenceName);
+ if (conditionsPatternMatcher.matches())
+ return true;
+ Matcher forecastPatternMatcher = WEATHER_FORECAST_PATTERN.matcher(referenceName);
+ if (forecastPatternMatcher.matches())
+ return true;
+
+ return false;
+ }
+ }
}
View
256 src/main/java/com/controlj/addon/weather/ScheduledWeatherLookup.java
@@ -24,10 +24,6 @@
import com.controlj.addon.weather.config.ConfigData;
import com.controlj.addon.weather.config.ConfigDataFactory;
import com.controlj.addon.weather.config.WeatherConfigEntry;
-import com.controlj.addon.weather.data.ForecastSource;
-import com.controlj.addon.weather.data.ConditionsSource;
-import com.controlj.addon.weather.service.WeatherService;
-import com.controlj.addon.weather.service.WeatherServiceException;
import com.controlj.addon.weather.util.Logging;
import javax.servlet.ServletContextEvent;
@@ -44,181 +40,83 @@
* pages. This class implements ServletContextListener so that it can be started up when the
* web server starts.
*/
-public class ScheduledWeatherLookup implements ServletContextListener
-{
- private static AtomicReference<ScheduledWeatherLookup> ref = new AtomicReference<ScheduledWeatherLookup>();
- private ScheduledExecutorService scheduledExecutorService;
- private ScheduledFuture<?> conditionsUpdateFuture;
- private ScheduledFuture<?> forecastsUpdateFuture;
-
- /**
- * Starts the scheduled update of weather information when the context starts.
- */
- @Override public synchronized void contextInitialized(ServletContextEvent sce)
- {
- ref.set(this);
- scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
- rescheduleUpdates(1);
- }
-
- /**
- * Stops the scheduled update of weather information when the context is destroyed. This happens when
- * the server is shutting down, or if this add-on is disabled.
- */
- @Override public synchronized void contextDestroyed(ServletContextEvent sce)
- {
- scheduledExecutorService.shutdownNow();
- }
-
- /**
- * Stops any running updates and reschedules them based on the current saved configuration data.
- * The updates have an initial delay as specified.
- */
- private synchronized void rescheduleUpdates(int initialDelay)
- {
- if (conditionsUpdateFuture != null)
- conditionsUpdateFuture.cancel(false);
- if (forecastsUpdateFuture != null)
- forecastsUpdateFuture.cancel(false);
-
- Logging.println("Starting scheduled update of weather information:");
-
- int conditionsRefresh = ConfigDataFactory.loadConfigData().getConditionsRefreshInMinutes();
- Logging.println(" current conditions updated at a fixed rate of every "+conditionsRefresh+" minutes");
- conditionsUpdateFuture = scheduledExecutorService.scheduleAtFixedRate(new ConditionsUpdate(), initialDelay*60, conditionsRefresh*60, TimeUnit.SECONDS);
-
- int forecastsRefresh = ConfigDataFactory.loadConfigData().getForecastsRefreshInMinutes();
- Logging.println(" forecasts updated at a fixed rate of every "+forecastsRefresh+" minutes");
- forecastsUpdateFuture = scheduledExecutorService.scheduleAtFixedRate(new ForecastsUpdate(), initialDelay*60, forecastsRefresh*60, TimeUnit.SECONDS);
- }
-
- /**
- * Stops any running updates and reschedules them based on the current saved configuration data. Used when
- * the UI changes the refresh rate.
- */
- public static void rescheduleUpdates()
- {
- ref.get().rescheduleUpdates(0);
- }
-
- /**
- * Reads weather conditions data from the WeatherService, inserts it into the associated control program
- * for the given entry (if any) and saves this data for later use by a view page.
- * @param configData the config data. Used to get the selected weather service.
- * @param entry the config entry for which this update is occurring.
- * @return the conditions data read from the weather service.
- * @throws WeatherServiceException if the data could not be read from the weather service.
- */
- public static ConditionsSource updateConditionsData(ConfigData configData, WeatherConfigEntry entry) throws WeatherServiceException
- {
- ConditionsSource conditionsSource = null;
- try
- {
- WeatherService weatherService = configData.getWeatherService();
- conditionsSource = weatherService.getConditionsSource(configData.getServiceConfigData(),
- entry.getStationSource(), entry.getServiceEntryData());
-
- String errorMessage = null;
- try
- {
- EquipmentHandler equipmentHandler = new EquipmentHandler(configData.getSystemConn(), "ABSPATH:1:"+entry.getCpPath());
- equipmentHandler.writeConditionsData(conditionsSource);
- }
- catch (EquipmentWriteException e)
- {
- Logging.println("Error writing current conditions to CP "+entry.getCpPath(), e);
- errorMessage = "Error writing data";
- }
-
- RuntimeInformation.getSingleton().updateConditionsData(entry, conditionsSource, errorMessage);
- return conditionsSource;
- }
- catch (WeatherServiceException e)
- {
- Logging.println("Error reading forecast data", e);
- RuntimeInformation.getSingleton().updateConditionsData(entry, null, "Error reading data");
- throw e;
- }
- }
-
- /**
- * Reads weather forecast data from the WeatherService, inserts it into the associated control program
- * for the given entry (if any) and saves this data for later use by a view page.
- * @param configData the config data. Used to get the selected weather service.
- * @param entry the config entry for which this update is occurring.
- * @return the forecast data read from the weather service.
- * @throws WeatherServiceException if the data could not be read from the weather service.
- */
- public static ForecastSource[] updateForecastsData(ConfigData configData, WeatherConfigEntry entry) throws WeatherServiceException
- {
- try
- {
- WeatherService weatherService = configData.getWeatherService();
- ForecastSource[] forecastSources = weatherService.getForecastSources(configData.getServiceConfigData(),
- entry.getStationSource(), entry.getServiceEntryData());
-
- String errorMessage = null;
- try
- {
- EquipmentHandler equipmentHandler = new EquipmentHandler(configData.getSystemConn(), "ABSPATH:1:"+entry.getCpPath());
- equipmentHandler.writeForecastData(forecastSources);
-
- // periodically push this just so that it's kept up to date in the module (in case the equipment is reset to definition
- // defaults or recreated or something)
- equipmentHandler.writeStationData(entry.getStationSource());
- }
- catch (EquipmentWriteException e)
- {
- Logging.println("Error writing forecast data to CP "+entry.getCpPath(), e);
- errorMessage = "Error writing data";
- }
-
- RuntimeInformation.getSingleton().updateForecastData(entry, forecastSources, errorMessage);
- return forecastSources;
- }
- catch (WeatherServiceException e)
- {
- Logging.println("Error reading forecast data", e);
- RuntimeInformation.getSingleton().updateForecastData(entry, null, "Error reading data");
- throw e;
- }
- }
-
- private static class ConditionsUpdate implements Runnable
- {
- @Override public void run()
- {
- ConfigData configData = ConfigDataFactory.loadConfigData();
- for (WeatherConfigEntry entry : configData.getList())
- {
- try
- {
- updateConditionsData(configData, entry);
- }
- catch (Exception e)
- {
- Logging.println("Error writing conditions data for entry "+entry, e);
- }
- }
- }
- }
-
- private static class ForecastsUpdate implements Runnable
- {
- @Override public void run()
- {
- ConfigData configData = ConfigDataFactory.loadConfigData();
- for (WeatherConfigEntry entry : configData.getList())
- {
- try
- {
- updateForecastsData(configData, entry);
+public class ScheduledWeatherLookup implements ServletContextListener {
+ private static final AtomicReference<ScheduledWeatherLookup> ref = new AtomicReference<ScheduledWeatherLookup>();
+ private ScheduledExecutorService scheduledExecutorService;
+ private ScheduledFuture<?> conditionsUpdateFuture;
+ private ScheduledFuture<?> forecastsUpdateFuture;
+
+ /**
+ * Starts the scheduled update of weather information when the context starts.
+ */
+ @Override public synchronized void contextInitialized(ServletContextEvent sce) {
+ ref.set(this);
+ scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
+ rescheduleUpdates(1);
+ }
+
+ /**
+ * Stops the scheduled update of weather information when the context is destroyed. This happens when
+ * the server is shutting down, or if this add-on is disabled.
+ */
+ @Override public synchronized void contextDestroyed(ServletContextEvent sce) {
+ scheduledExecutorService.shutdownNow();
+ }
+
+ public static void rescheduleUpdates() {
+ ref.get().rescheduleUpdates(1);
+ }
+
+ /**
+ * Stops any running updates and reschedules them based on the current saved configuration data.
+ * The updates have an initial delay as specified.
+ */
+ private synchronized void rescheduleUpdates(int initialDelay) {
+ if (conditionsUpdateFuture != null)
+ conditionsUpdateFuture.cancel(false);
+ if (forecastsUpdateFuture != null)
+ forecastsUpdateFuture.cancel(false);
+
+ Logging.println("Starting scheduled update of weather information:");
+
+ int conditionsRefresh = ConfigDataFactory.loadConfigData().getConditionsRefreshInMinutes();
+ Logging.println(" current conditions updated at a fixed rate of every " + conditionsRefresh + " minutes");
+ conditionsUpdateFuture = scheduledExecutorService.scheduleAtFixedRate(new ConditionsUpdate(), initialDelay * 60, conditionsRefresh * 60, TimeUnit.SECONDS);
+
+ int forecastsRefresh = ConfigDataFactory.loadConfigData().getForecastsRefreshInMinutes();
+ Logging.println(" forecasts updated at a fixed rate of every " + forecastsRefresh + " minutes");
+ forecastsUpdateFuture = scheduledExecutorService.scheduleAtFixedRate(new ForecastsUpdate(), initialDelay * 60, forecastsRefresh * 60, TimeUnit.SECONDS);
+ }
+
+ private static class ConditionsUpdate implements Runnable {
+ @Override public void run() {
+ ConfigData configData = ConfigDataFactory.loadConfigData();
+ WeatherLookup weatherLookup = new WeatherLookup(configData);
+ for (WeatherConfigEntry entry : configData.getList()) {
+ try {
+ EquipmentHandler handler = new EquipmentHandler(configData.getSystemConn(), entry.getCpPath());
+ if (handler.hasFieldsToWrite())
+ weatherLookup.lookupConditionsData(entry, true);
+ } catch (Exception e) {
+ Logging.println("Error writing conditions data for entry " + entry, e);
+ }
}
- catch (Exception e)
- {
- Logging.println("Error writing forecasts data for entry "+entry, e);
+ }
+ }
+
+ private static class ForecastsUpdate implements Runnable {
+ @Override public void run() {
+ ConfigData configData = ConfigDataFactory.loadConfigData();
+ WeatherLookup weatherLookup = new WeatherLookup(configData);
+ for (WeatherConfigEntry entry : configData.getList()) {
+ try {
+ EquipmentHandler handler = new EquipmentHandler(configData.getSystemConn(), entry.getCpPath());
+ if (handler.hasFieldsToWrite())
+ weatherLookup.lookupForecastsData(entry, true);
+ } catch (Exception e) {
+ Logging.println("Error writing forecasts data for entry " + entry, e);
+ }
}
- }
- }
- }
+ }
+ }
}
View
131 src/main/java/com/controlj/addon/weather/WeatherLookup.java
@@ -0,0 +1,131 @@
+/*=============================================================================
+ AUTOMATED LOGIC CORPORATION
+ Copyright (c) 1999 - 2011 All Rights Reserved
+ This document contains confidential/proprietary information.
+===============================================================================
+
+ @(#)WeatherLookup
+
+ Author(s) jmurph
+ $Log: $
+=============================================================================*/
+package com.controlj.addon.weather;
+
+import com.controlj.addon.weather.config.ConfigData;
+import com.controlj.addon.weather.config.WeatherConfigEntry;
+import com.controlj.addon.weather.data.ConditionsSource;
+import com.controlj.addon.weather.data.ForecastSource;
+import com.controlj.addon.weather.service.WeatherService;
+import com.controlj.addon.weather.service.WeatherServiceException;
+import com.controlj.addon.weather.util.Logging;
+
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+public class WeatherLookup {
+ private final ConfigData configData;
+
+ public WeatherLookup(ConfigData configData) {
+ this.configData = configData;
+ }
+
+ /**
+ * Reads weather conditions data from the WeatherService, inserts it into the associated control program
+ * for the given entry (if any) and saves this data for later use by a view page.
+ *
+ * @param entry the config entry for which this update is occurring.
+ * @param force if true, will lookup data even if the latest data has not yet expired.
+ * @return the conditions data read from the weather service.
+ * @throws WeatherServiceException if the data could not be read from the weather service.
+ */
+ public ConditionsSource lookupConditionsData(WeatherConfigEntry entry, boolean force) throws WeatherServiceException {
+ RuntimeInformation rti = RuntimeInformation.getSingleton();
+ if (!force) {
+ ConditionsSource conditionsData = rti.getLastConditionsData(entry);
+ if (conditionsData != null && conditionsData.getUpdateTime().after(getConditionDataExpirary()))
+ return conditionsData;
+ }
+
+ ConditionsSource conditionsSource = null;
+ try {
+ WeatherService weatherService = configData.getWeatherService();
+ Logging.println("Reading conditions data for "+entry.getCpPath());
+ conditionsSource = weatherService.getConditionsSource(configData.getServiceConfigData(),
+ entry.getStationSource(), entry.getServiceEntryData());
+
+ String errorMessage = null;
+ try {
+ EquipmentHandler equipmentHandler = new EquipmentHandler(configData.getSystemConn(), entry.getCpPath());
+ equipmentHandler.writeConditionsData(conditionsSource);
+ } catch (EquipmentWriteException e) {
+ Logging.println("Error writing current conditions to CP " + entry.getCpPath(), e);
+ errorMessage = "Error writing data";
+ }
+
+ RuntimeInformation.getSingleton().updateConditionsData(entry, conditionsSource, errorMessage);
+ return conditionsSource;
+ } catch (WeatherServiceException e) {
+ Logging.println("Error reading forecast data", e);
+ RuntimeInformation.getSingleton().updateConditionsData(entry, null, "Error reading data");
+ throw e;
+ }
+ }
+
+ /**
+ * Reads weather forecast data from the WeatherService, inserts it into the associated control program
+ * for the given entry (if any) and saves this data for later use by a view page.
+ *
+ * @param entry the config entry for which this update is occurring.
+ * @param force if true, will lookup data even if the latest data has not yet expired.
+ * @return the forecast data read from the weather service.
+ * @throws WeatherServiceException if the data could not be read from the weather service.
+ */
+ public ForecastSource[] lookupForecastsData(WeatherConfigEntry entry, boolean force) throws WeatherServiceException {
+ RuntimeInformation rti = RuntimeInformation.getSingleton();
+ if (!force) {
+ ForecastSource[] forecastData = rti.getLastForecastData(entry);
+ if (forecastData != null && forecastData[0].getUpdateTime().after(getForecastDataExpirary()))
+ return forecastData;
+ }
+
+ try {
+ WeatherService weatherService = configData.getWeatherService();
+ Logging.println("Reading forecast data for "+entry.getCpPath());
+ ForecastSource[] forecastSources = weatherService.getForecastSources(configData.getServiceConfigData(),
+ entry.getStationSource(), entry.getServiceEntryData());
+
+ String errorMessage = null;
+ try {
+ EquipmentHandler equipmentHandler = new EquipmentHandler(configData.getSystemConn(), entry.getCpPath());
+ equipmentHandler.writeForecastData(forecastSources);
+
+ // periodically push this just so that it's kept up to date in the module (in case the equipment is reset to definition
+ // defaults or recreated or something)
+ equipmentHandler.writeStationData(entry.getStationSource());
+ } catch (EquipmentWriteException e) {
+ Logging.println("Error writing forecast data to CP " + entry.getCpPath(), e);
+ errorMessage = "Error writing data";
+ }
+
+ RuntimeInformation.getSingleton().updateForecastData(entry, forecastSources, errorMessage);
+ return forecastSources;
+ } catch (WeatherServiceException e) {
+ Logging.println("Error reading forecast data", e);
+ RuntimeInformation.getSingleton().updateForecastData(entry, null, "Error reading data");
+ throw e;
+ }
+ }
+
+ private Date getConditionDataExpirary() {
+ return getDataExpirary(configData.getConditionsRefreshInMinutes());
+ }
+
+ private Date getForecastDataExpirary() {
+ return getDataExpirary(configData.getForecastsRefreshInMinutes());
+ }
+
+ private Date getDataExpirary(int refreshInMinutes) {
+ long refresh = TimeUnit.MILLISECONDS.convert(refreshInMinutes, TimeUnit.MINUTES);
+ return new Date(System.currentTimeMillis() - refresh);
+ }
+}
View
7 src/main/java/com/controlj/addon/weather/service/WeatherServiceUIBase.java
@@ -1,5 +1,6 @@
package com.controlj.addon.weather.service;
+import com.controlj.addon.weather.ScheduledWeatherLookup;
import com.controlj.addon.weather.config.ConfigData;
import com.controlj.addon.weather.util.Logging;
import com.controlj.addon.weather.util.ResponseWriter;
@@ -59,10 +60,12 @@ public static WeatherServices getSpecifiedService(HttpServletRequest req) {
public void updateConfiguration(ConfigData configData, ResponseWriter writer, HttpServletRequest req) {
String conditionRateString = req.getParameter("conditionrefresh");
String forecastRateString = req.getParameter("forecastrefresh");
+ boolean rescheduleUpdates = false;
if (conditionRateString != null) {
try {
configData.setConditionsRefreshInMinutes(Integer.parseInt(conditionRateString));
+ rescheduleUpdates = true;
} catch (NumberFormatException e) {
writer.addValidationError("conditionrefresh", "\"" + conditionRateString + "\" is not a valid number");
}
@@ -73,12 +76,16 @@ public void updateConfiguration(ConfigData configData, ResponseWriter writer, Ht
if (forecastRateString!= null) {
try {
configData.setForecastsRefreshInMinutes(Integer.parseInt(forecastRateString));
+ rescheduleUpdates = true;
} catch (NumberFormatException e) {
writer.addValidationError("forecastrefresh", "\"" + forecastRateString + "\" is not a valid number");
}
} else {
writer.addValidationError("forecastrefresh", "forecast rate not specified");
}
+
+ if (rescheduleUpdates)
+ ScheduledWeatherLookup.rescheduleUpdates();
}
@Override
View
7 src/main/java/com/controlj/addon/weather/servlets/AjaxController.java
@@ -23,6 +23,7 @@
package com.controlj.addon.weather.servlets;
import com.controlj.addon.weather.ScheduledWeatherLookup;
+import com.controlj.addon.weather.WeatherLookup;
import com.controlj.addon.weather.config.ConfigData;
import com.controlj.addon.weather.config.ConfigDataFactory;
import com.controlj.addon.weather.config.WeatherConfigEntry;
@@ -166,8 +167,10 @@ private void showData(ConfigData configData, ResponseWriter writer, HttpServletR
}
}
+ WeatherLookup weatherLookup = new WeatherLookup(configData);
+
// current conditions
- ConditionsSource conditionsSource = ScheduledWeatherLookup.updateConditionsData(configData, entry);
+ ConditionsSource conditionsSource = weatherLookup.lookupConditionsData(entry, true);
if (conditionsSource != null) {
for (ConditionsField field : ConditionsField.values()) {
if (field.isSupported(conditionsSource)) {
@@ -180,7 +183,7 @@ private void showData(ConfigData configData, ResponseWriter writer, HttpServletR
}
// forecast data
- ForecastSource[] forecastSources = ScheduledWeatherLookup.updateForecastsData(configData, entry);
+ ForecastSource[] forecastSources = weatherLookup.lookupForecastsData(entry, true);
if (forecastSources != null) {
writer.appendToArray(JSON_FORECAST_HEADERS, "Field");
for (int i=0; i<forecastSources.length; i++) {
View
14 src/main/java/com/controlj/addon/weather/servlets/PrimDeclaration.java
@@ -23,9 +23,8 @@
package com.controlj.addon.weather.servlets;
import com.controlj.addon.weather.EquipmentWriteException;
-import com.controlj.addon.weather.RuntimeInformation;
+import com.controlj.addon.weather.WeatherLookup;
import com.controlj.addon.weather.config.ConfigData;
-import com.controlj.addon.weather.config.ConfigDataFactory;
import com.controlj.addon.weather.config.WeatherConfigEntry;
import com.controlj.addon.weather.data.*;
import com.controlj.addon.weather.service.WeatherServiceException;
@@ -34,13 +33,10 @@
import org.apache.commons.lang.StringEscapeUtils;
import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.Date;
-import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -120,10 +116,10 @@ private static String getLocation(HttpServletRequest request) {
private void definePrimitives(final StringBuilder builder, ConfigData config, WeatherConfigEntry entry) throws EquipmentWriteException, WeatherServiceException {
- RuntimeInformation rti = RuntimeInformation.getSingleton();
- StationSource stationData = getStationSource(rti, config, entry);
- ConditionsSource conditionData = getConditionsSource(rti, config, entry);
- ForecastSource[] forecastSources = getForecastSources(rti, config, entry);
+ WeatherLookup weatherLookup = new WeatherLookup(config);
+ StationSource stationData = entry.getStationSource();
+ ConditionsSource conditionData = weatherLookup.lookupConditionsData(entry, false);
+ ForecastSource[] forecastSources = weatherLookup.lookupForecastsData(entry, false);
try {
iterateFields(conditionData, stationData, forecastSources, new FieldHandler() {
View
10 src/main/java/com/controlj/addon/weather/servlets/PrimUpdate.java
@@ -23,7 +23,7 @@
package com.controlj.addon.weather.servlets;
import com.controlj.addon.weather.EquipmentWriteException;
-import com.controlj.addon.weather.RuntimeInformation;
+import com.controlj.addon.weather.WeatherLookup;
import com.controlj.addon.weather.config.ConfigData;
import com.controlj.addon.weather.config.WeatherConfigEntry;
import com.controlj.addon.weather.data.ConditionsSource;
@@ -79,10 +79,10 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
}
private void updatePrimitives(final StringBuilder builder, ConfigData config, WeatherConfigEntry entry) throws EquipmentWriteException, WeatherServiceException {
- RuntimeInformation rti = RuntimeInformation.getSingleton();
- StationSource stationData = getStationSource(rti, config, entry);
- ConditionsSource conditionData = getConditionsSource(rti, config, entry);
- ForecastSource[] forecastSources = getForecastSources(rti, config, entry);
+ WeatherLookup weatherLookup = new WeatherLookup(config);
+ StationSource stationData = entry.getStationSource();
+ ConditionsSource conditionData = weatherLookup.lookupConditionsData(entry, false);
+ ForecastSource[] forecastSources = weatherLookup.lookupForecastsData(entry, false);
try {
iterateFields(conditionData, stationData, forecastSources, new FieldHandler() {
View
21 src/main/java/com/controlj/addon/weather/servlets/PrimitiveServletBase.java
@@ -25,6 +25,7 @@
import com.controlj.addon.weather.EquipmentWriteException;
import com.controlj.addon.weather.RuntimeInformation;
import com.controlj.addon.weather.ScheduledWeatherLookup;
+import com.controlj.addon.weather.WeatherLookup;
import com.controlj.addon.weather.config.ConfigData;
import com.controlj.addon.weather.config.ConfigDataFactory;
import com.controlj.addon.weather.config.WeatherConfigEntry;
@@ -42,26 +43,6 @@ protected ConfigData getConfigData() {
return ConfigDataFactory.loadConfigData();
}
- protected ConditionsSource getConditionsSource(RuntimeInformation rti, ConfigData config, WeatherConfigEntry entry) throws EquipmentWriteException, WeatherServiceException {
- ConditionsSource weatherData = rti.getLastConditionsData(entry);
- if (weatherData == null) {
- weatherData = ScheduledWeatherLookup.updateConditionsData(config, entry);
- }
- return weatherData;
- }
-
- protected StationSource getStationSource(RuntimeInformation rti, ConfigData config, WeatherConfigEntry entry) throws EquipmentWriteException, WeatherServiceException {
- return entry.getStationSource();
- }
-
- protected ForecastSource[] getForecastSources(RuntimeInformation rti, ConfigData config, WeatherConfigEntry entry) throws EquipmentWriteException, WeatherServiceException {
- ForecastSource[] forecastSources = rti.getLastForecastData(entry);
- if (forecastSources == null || forecastSources.length == 0) {
- forecastSources = ScheduledWeatherLookup.updateForecastsData(config, entry);
- }
- return forecastSources;
- }
-
protected void iterateFields(ConditionsSource conditionData, StationSource stationData, ForecastSource[] forecastSources, FieldHandler handler) throws EquipmentWriteException, WeatherServiceException {
FieldType fieldType;
View
2 src/main/webapp/index.html
@@ -30,7 +30,7 @@
<script type="text/javascript" src="js/weather.js"></script>
<style type="text/css">
body { font-family:sans-serif; color:black; }
- .configdata { background: #85b6de url("images/sunny_clouds_sky.jpg") no-repeat; }
+ .configdata { background: url("images/sunny_clouds_sky.jpg") no-repeat; }
a { color:black; }
td { padding-left:1em; text-align:left; }
th { padding-left:1em; text-align:left; }

0 comments on commit 084d64e

Please sign in to comment.
Something went wrong with that request. Please try again.