package com.flaremicro.visualforecast.datamart; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Calendar; import java.util.Locale; import java.util.concurrent.TimeUnit; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import com.flaremicro.util.Util; import com.flaremicro.visualforecast.forecast.DayForecast; import com.flaremicro.visualforecast.forecast.ForecastDetails; import com.flaremicro.visualforecast.forecast.TownForecast; import com.flaremicro.visualforecast.forecast.ValueCheck; public class ForecastProcessor implements Runnable { private final TownInfo[] towns; private ForecastDetails mostRecentForecast = null; private boolean running = false; private Thread self; private DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); private DatamartTranslation dmt = new DatamartTranslation(); public ForecastProcessor(TownInfo[] towns) { this.towns = towns; try { dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); } catch (ParserConfigurationException e) { e.printStackTrace(); } } public void stringToOffset(String dayString) { } public int getDayIndex(String dayString) { dayString = dayString.trim(); if (dayString.equalsIgnoreCase("today") || dayString.equalsIgnoreCase("tonight")) return 0; dayString = dayString.toLowerCase().replace("night", "").trim(); Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); for (int i = 1; i < 8; i++) { calendar.add(Calendar.HOUR, 24); if (calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.US).equalsIgnoreCase(dayString)) return i; } return -1; } public void processForecasts() { ForecastDetails forecastDetails = new ForecastDetails(); ArrayList townForecasts = new ArrayList(); for (TownInfo townInfo : towns) { DayForecast[] dayForecasts = new DayForecast[8]; InputStream is = null; try { URL url = new URL("https://dd.weather.gc.ca/citypage_weather/xml/BC/" + townInfo.code + "_e.xml"); DocumentBuilder db = dbf.newDocumentBuilder(); is = url.openStream(); Document doc = db.parse(is); NodeList nodeList = doc.getElementsByTagName("forecast"); for (int i = 0; i < nodeList.getLength(); i++) { if (nodeList.item(1).getNodeType() == Node.ELEMENT_NODE) { Element node = (Element) nodeList.item(i); int dayIndex = getDayIndex(XMLUtils.getStringFromTagAttribute(node, "period", "textForecastName")); Element abbForecast = XMLUtils.getFistElement(node, "abbreviatedForecast"); int iconIndex = XMLUtils.getIntFromTag(abbForecast, "iconCode", 0); String textForecast = XMLUtils.getStringFromTag(abbForecast, "textSummary"); WeatherLines lines = dmt.weatherName(textForecast); byte icon = dmt.icon(iconIndex); byte lo = ValueCheck.NO_DATA_BYTE; byte hi = ValueCheck.NO_DATA_BYTE; Element element = XMLUtils.getFistElement(node, "temperatures"); NodeList temps = element.getElementsByTagName("temperature"); for (int j = 0; j < temps.getLength(); j++) { Node n = temps.item(j); try { byte val = Byte.parseByte(n.getTextContent().trim()); if(XMLUtils.getStringFromAttribute(n, "class").trim().equalsIgnoreCase("high")) { hi = val; } else if(XMLUtils.getStringFromAttribute(n, "class").trim().equalsIgnoreCase("low")) { lo = val; } } catch (NumberFormatException ex) { } } if (dayIndex >= 0 && dayIndex <= 7) { if (dayForecasts[dayIndex] != null) { if (lo != ValueCheck.NO_DATA_BYTE && dayForecasts[dayIndex].loTemp == ValueCheck.NO_DATA_BYTE) { dayForecasts[dayIndex].loTemp = lo; } if (hi != ValueCheck.NO_DATA_BYTE && dayForecasts[dayIndex].hiTemp == ValueCheck.NO_DATA_BYTE) { dayForecasts[dayIndex].hiTemp = hi; } } else { dayForecasts[dayIndex] = new DayForecast(hi, lo, icon, lines.line1, lines.line2, ValueCheck.NO_DATA_FLOAT); } } } } } catch (IOException e) { e.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } finally { Util.cleanClose(is); } for (int i = 0; i < dayForecasts.length; i++) { if (dayForecasts[i] == null) { dayForecasts[i] = new DayForecast(); } } townForecasts.add(new TownForecast(townInfo.townName + ", " + townInfo.province, dayForecasts)); } forecastDetails.setTownForecast(townForecasts.toArray(new TownForecast[0])); setMostRecentForecast(forecastDetails); } public void end() { running = false; self.interrupt(); } public ForecastDetails getMostRecentForecast() { synchronized (this) { return mostRecentForecast; } } private void setMostRecentForecast(ForecastDetails forecast) { synchronized (this) { mostRecentForecast = forecast; } } @Override public void run() { self = Thread.currentThread(); while (running) { try { Thread.sleep(TimeUnit.MILLISECONDS.convert(1, TimeUnit.HOURS)); processForecasts(); } catch (InterruptedException e) { e.printStackTrace(); } } } }