Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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

  • Loading branch information...
commit 084d64ec2b0c8441f0f27952843cb9b85554a011 1 parent df1faf4
@jmurph jmurph authored
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; }
Please sign in to comment.
Something went wrong with that request. Please try again.