Initial Commit

This commit is contained in:
Flare Microsystems
2024-03-07 14:15:34 -08:00
commit 37c506249a
12 changed files with 669 additions and 0 deletions

7
.classpath Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="src" path="/VisualForecast 1000"/>
<classpathentry kind="output" path="bin"/>
</classpath>

26
.gitignore vendored Normal file
View File

@@ -0,0 +1,26 @@
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
#Compiled binary directory
bin/
# Package Files #
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
*.dat

13
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,13 @@
# You can override the included template(s) by including variable overrides
# SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
# Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings
# Dependency Scanning customization: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings
# Container Scanning customization: https://docs.gitlab.com/ee/user/application_security/container_scanning/#customizing-the-container-scanning-settings
# Note that environment variables can be set in several places
# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence
stages:
- test
sast:
stage: test
include:
- template: Security/SAST.gitlab-ci.yml

17
.project Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>CanadaDatamartProvider</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6

View File

@@ -0,0 +1,92 @@
package com.flaremicro.visualforecast.datamart;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import com.flaremicro.util.Util;
import com.flaremicro.visualforecast.PropertyManager;
import com.flaremicro.visualforecast.api.ForecastProvider;
import com.flaremicro.visualforecast.forecast.ForecastDetails;
public class CanadaDatamartProvider extends ForecastProvider {
boolean ready = false;
PropertyManager propertyManager;
ForecastProcessor forecastProcessor;
ArrayList<TownInfo> towns = new ArrayList<TownInfo>();
@Override
public void init() {
propertyManager = super.getOwnPropertyManager();
String byCode = propertyManager.getString("towns-by-code", "").toLowerCase();
String byNameAndProvince = propertyManager.getString("towns-by-name-and-province", "").toLowerCase();
if(byCode.isEmpty() && byNameAndProvince.isEmpty())
{
ready = true;
return;
}
BufferedReader bufferedReader = null;
try
{
HashSet<String> byCodes = new HashSet<String>(Arrays.asList(byCode.split(",")));
HashSet<String> byNameAndProvinces = new HashSet<String>(Arrays.asList(byNameAndProvince.split(";")));
URL url = new URL("https://dd.weather.gc.ca/citypage_weather/docs/site_list_towns_en.csv");
bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()));
String line;
int skip = 2;
while ((line = bufferedReader.readLine()) != null)
{
if (skip > 0)
{
skip--;
continue;
}
String[] data = line.trim().split(",");
if (byCodes.contains(data[0].toLowerCase()) || byNameAndProvinces.contains(data[1].toLowerCase() + "," + data[2].toLowerCase()))
{
String code = data[0].trim();
String town = data[1].trim();
String province = data[2].trim();
float latitude = Float.parseFloat(data[3].trim().substring(0, data[3].length()-1));
float longitude = Float.parseFloat(data[4].trim().substring(0, data[4].length()-1));
towns.add(new TownInfo(code, town, province, latitude, longitude));
}
}
}
catch (IOException e)
{
e.printStackTrace();
ready = true;
}
finally
{
Util.cleanClose(bufferedReader);
}
forecastProcessor = new ForecastProcessor(towns.toArray(new TownInfo[0]));
forecastProcessor.processForecasts();
ready = true;
}
@Override
public ForecastDetails getForecast() {
return forecastProcessor.getMostRecentForecast();
}
@Override
public boolean isForecastReady() {
return ready;
}
@Override
public void deinit() {
propertyManager.store();
}
}

View File

@@ -0,0 +1,117 @@
package com.flaremicro.visualforecast.datamart;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import com.flaremicro.util.Util;
import com.flaremicro.visualforecast.icons.IconProvider;
public class DatamartTranslation {
private HashMap<Integer, Byte> iconTranslation = new HashMap<Integer, Byte>();
private HashMap<String, WeatherLines> stringTranslation = new HashMap<String, WeatherLines>();
public DatamartTranslation() {
iconTranslation.put(0, IconProvider.SUN.id);
iconTranslation.put(1, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(2, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(3, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(4, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(5, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(6, IconProvider.SCATTERD_SHOWERS.id);
iconTranslation.put(7, IconProvider.RAIN_SNOW.id);
iconTranslation.put(8, IconProvider.SNOW.id);
iconTranslation.put(9, IconProvider.RAIN_STORM.id);
iconTranslation.put(10, IconProvider.CLOUD.id);
iconTranslation.put(11, IconProvider.INVALID.id);
iconTranslation.put(12, IconProvider.RAIN_LIGHT.id);
iconTranslation.put(13, IconProvider.RAIN_HEAVY.id);
iconTranslation.put(14, IconProvider.FREEZING_RAIN.id);
iconTranslation.put(15, IconProvider.SCATTERD_SHOWERS.id);
iconTranslation.put(16, IconProvider.SNOW.id);
iconTranslation.put(17, IconProvider.SNOW.id);
iconTranslation.put(18, IconProvider.BLIZZARD.id);
iconTranslation.put(19, IconProvider.RAIN_STORM.id);
iconTranslation.put(20, IconProvider.INVALID.id);
iconTranslation.put(21, IconProvider.INVALID.id);
iconTranslation.put(22, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(23, IconProvider.FOG.id);
iconTranslation.put(24, IconProvider.FOG.id);
iconTranslation.put(25, IconProvider.INVALID.id);
iconTranslation.put(26, IconProvider.INVALID.id);
iconTranslation.put(27, IconProvider.HAIL.id);
iconTranslation.put(28, IconProvider.RAIN_LIGHTEST.id);
iconTranslation.put(29, IconProvider.INVALID.id);
iconTranslation.put(30, IconProvider.SUN.id); //MOON
iconTranslation.put(31, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(32, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(33, IconProvider.CLOUD.id);
iconTranslation.put(34, IconProvider.CLOUDY_CLOUDY.id);
iconTranslation.put(35, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(36, IconProvider.SCATTERD_SHOWERS.id);
iconTranslation.put(37, IconProvider.RAIN_LIGHT.id);
iconTranslation.put(38, IconProvider.SNOW.id);
iconTranslation.put(39, IconProvider.LIGHTNING_STORM.id);
iconTranslation.put(40, IconProvider.SNOW.id);
iconTranslation.put(41, IconProvider.INVALID.id);
iconTranslation.put(42, IconProvider.INVALID.id);
iconTranslation.put(43, IconProvider.INVALID.id); //WIND
iconTranslation.put(44, IconProvider.INVALID.id); //SMOKE
BufferedReader reader = null;
try
{
reader = new BufferedReader(new InputStreamReader(this.getClass().getResourceAsStream("/translation.csv")));
String line;
while((line = reader.readLine()) != null)
{
String[] info = line.split(",");
if(info.length == 2)
{
stringTranslation.put(info[0].toLowerCase(), new WeatherLines(info[1], ""));
}
else if(info.length == 3)
{
stringTranslation.put(info[0].toLowerCase(), new WeatherLines(info[1], info[2]));
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
Util.cleanClose(reader);
}
}
public byte icon(int icon) {
if(!iconTranslation.containsKey(icon))
return IconProvider.INVALID.id;
return iconTranslation.get(icon);
}
public WeatherLines weatherName(String desc) {
WeatherLines lines = stringTranslation.get(desc.toLowerCase());
if(lines == null)
{
System.out.println("FAILED:"+desc.toLowerCase());
return new WeatherLines("TRANSLAT.", "FAILURE");
}
else return lines;
}
}
class WeatherLines {
public final String line1;
public final String line2;
public WeatherLines(String line1, String line2) {
this.line1 = line1;
this.line2 = line2;
}
}

View File

@@ -0,0 +1,213 @@
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<TownForecast> townForecasts = new ArrayList<TownForecast>();
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();
}
}
}
}

View File

@@ -0,0 +1,17 @@
package com.flaremicro.visualforecast.datamart;
public class TownInfo {
public final String code;
public final String townName;
public final String province;
public final float northLat;
public final float westLong;
public TownInfo(String code, String townName, String province, float northLat, float westLong) {
this.code = code;
this.townName = townName;
this.province = province;
this.northLat = northLat;
this.westLong = westLong;
}
}

View File

@@ -0,0 +1,56 @@
package com.flaremicro.visualforecast.datamart;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class XMLUtils {
public static String getStringFromTag(Element parent, String tag) {
NodeList l = parent.getElementsByTagName(tag);
if (l.getLength() > 0)
return l.item(0).getTextContent();
return null;
}
public static String getStringFromTagAttribute(Element parent, String tag, String attribute) {
NodeList l = parent.getElementsByTagName(tag);
if (l.getLength() > 0)
{
Node attrib = l.item(0).getAttributes().getNamedItem(attribute);
if(attrib != null)
return attrib.getTextContent();
}
return null;
}
public static String getStringFromAttribute(Node n, String attribute) {
Node attrib = n.getAttributes().getNamedItem(attribute);
if(attrib != null)
return attrib.getTextContent();
return null;
}
public static Element getFistElement(Element parent, String tag) {
NodeList l = parent.getElementsByTagName(tag);
for (int i = 0; i < l.getLength(); i++)
{
if (l.item(i).getNodeType() == Node.ELEMENT_NODE)
return (Element) l.item(i);
}
return null;
}
public static Integer getIntFromTag(Element abbForecast, String tag, Integer fallback) {
String content = getStringFromTag(abbForecast, tag);
try
{
return Integer.parseInt(content);
}
catch (NumberFormatException ex)
{
}
return fallback;
}
}

1
src/provider.properties Normal file
View File

@@ -0,0 +1 @@
main-class=com.flaremicro.visualforecast.datamart.CanadaDatamartProvider

99
src/translation.csv Normal file
View File

@@ -0,0 +1,99 @@
Mainly sunny,Mainly,Sunny
Mainly cloudy,Mainly, Cloudy
Sunny,Sunny,
A few clouds,Few,Clouds
A mix of sun and cloud,Partly,Cloudy
Cloudy periods,Cloudy,Periods
Sunny with cloudy periods,Cloudy,Periods
Cloudy with sunny periods,Sunny,Periods
Increasing cloudiness,Increasing,Clouds
Clearing,Clearing,
Clear,Sun,
Chance of showers,Chance,Showers
A few showers,Few,Showers
Chance of drizzle or rain,Chance,Drizzle
A few flurries or rain showers,Flurries/,Showers
Chance of flurries or rain showers,Flurries/,Showers
Chance of rain showers or flurries,Flurries/,Showers
A few flurries,Flurries,
Chance of flurries,Chance,Flurries
A few wet flurries,Wet,Flurries
Chance of showers at times heavy or thundershowers,Scattered,T'Storms
Chance of showers at times heavy or thunderstorms,Scattered,T'Storms
Chance of thundershowers,Thunder,Storms
Chance of thunderstorms,Thunder,Storms
Chance of showers or thundershowers,Thunder,Storms
Chance of showers or thunderstorms,Thunder,Storms
A few flurries or thundershowers,Thunder,Storms
Cloudy,Cloudy,
Overcast,Overcast,
Showers,Showers,
Chance of showers,Chance,Showers
Periods of rain,Scattered,Rain
Mostly Cloudy,Mostly,Cloudy
Rain at times heavy,Heavy,Rain
A few showers or drizzle,Drizzle
Rain,Rain
Chance of freezing rain,Chance,Ice Rain
Freezing rain,Freezing,Rain
Chance of freezing rain or rain,Chance,Ice Rain,
Chance of rain or freezing rain,Chance,Ice Rain,
A few rain showers or flurries,Scattered,Flurries
Periods of rain or snow,Rain or,Snow
A few rain showers or wet flurries,Rain or,Flurries
Snow mixed with rain,Rain,Snow
Chance of snow mixed with freezing rain,Rain,Snow
Wet snow or rain,Wet,Snow
Flurries,Flurries,
Light snow,Light,Snow
Wet flurries,Wet,Flurries
Wet snow,Wet,Snow
Snow at times heavy,Heavy,Snow
Periods of snow,Scattered,Snow
Snow,Snow,
Chance of snow,Chance,Snow
Snow squalls,Snow,Squalls
Local snow squalls,Snow,Squalls
Blizzard,Blizzard,
Near blizzard,Near,Blizzard
Snow and blizzard,Blizzard,
Snow at times heavy and blowing snow,Blowing,Snow
A few showers or thundershowers,Thunder,Showers
A few showers or thunderstorms,Thunder,Storms
Showers or thundershowers,Thunder,Showers
Showers or thunderstorms,Thunder,Storms
Rain or thunderstorms,Thunder,Storms
Rain or thundershowers,Thunder,Showers
Chance of thunderstorms and possible hail,Hail,T'Storms
Thunderstorms and possible hail,Hail,T'Storms
A mix of sun and cloud,Partly,Cloudy
Haze,Haze,
Fog,Fog,
Fog Patches,Patchy,Fog
Fog dissipating,Fog
Fog developing,Fog
Ice fog,Ice,Fog
Ice fog developing,Ice,Fog
Ice fog dissipating,Ice,Fog
A few flurries mixed with ice pellets,Sleet,Flurries
Ice pellet,Sleet
Ice pellet mixed with freezing rain,Sleet,Rain
Ice pellet mixed with snow,Sleet,Snow
Ice pellet or snow,Sleet,Snow
Possibility of drizzle mixed with freezing drizzle,Ice,Drizzle
Drizzle,Drizzle
Freezing drizzle,Freezing,Drizzle
Possibility of drizzle,Drizzle
Drizzle or freezing drizzle,Freezing,Drizzle
Not available,MISSING,DATA
Chance of drizzle or rain,Chance,Rain
A few flurries or showers,Flurries/,Showers
Chance of snow or rain,Chance,Snow
A few flurries,Scattered,Flurries
Chance of light snow,Light,Snow
A few wet flurries,Wet,Flurries
Chance of showers at times heavy or thunderstorms,Thunder,Storms
Chance of thunderstorms,Thunder,Storms
Snow and blowing snow,Blowing,Snow
Windy,Windy
Smoke,Smoke
Can't render this file because it has a wrong number of fields in line 35.