draft: continue cache
This commit is contained in:
parent
6d0e8f9786
commit
932e272cc5
@ -61,12 +61,20 @@ public class Main {
|
|||||||
OpenMeteo openMeteo = new OpenMeteo();
|
OpenMeteo openMeteo = new OpenMeteo();
|
||||||
OpenWeatherMap openWeatherMap = new OpenWeatherMap(OpenWMapKey);
|
OpenWeatherMap openWeatherMap = new OpenWeatherMap(OpenWMapKey);
|
||||||
WeatherDisplay display = new WeatherDisplayBasic();
|
WeatherDisplay display = new WeatherDisplayBasic();
|
||||||
|
WeatherDisplay display2 = new WeatherDisplayBasic();
|
||||||
|
WeatherDisplay display3 = new WeatherDisplayBasic();
|
||||||
|
|
||||||
|
display.addAPI(weatherAPI);
|
||||||
display.addAPI(weatherAPI);
|
display.addAPI(weatherAPI);
|
||||||
display.addAPI(openMeteo);
|
display.addAPI(openMeteo);
|
||||||
display.addAPI(openWeatherMap);
|
display.addAPI(openWeatherMap);
|
||||||
|
|
||||||
|
display2.addAPI(weatherAPI);
|
||||||
|
display3.addAPI(weatherAPI);
|
||||||
|
|
||||||
// weatherAPI can't fetch for more than 3 days with free plan
|
// weatherAPI can't fetch for more than 3 days with free plan
|
||||||
display.display(days, city);
|
display.display(days, city);
|
||||||
|
display2.display(days, city);
|
||||||
|
display3.display(days, city);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import eirb.pg203.WeatherData.Condition;
|
|||||||
public class OpenMeteo implements WeatherDataAPI {
|
public class OpenMeteo implements WeatherDataAPI {
|
||||||
private static final String forecastBaseURL = "https://api.open-meteo.com/v1/forecast";
|
private static final String forecastBaseURL = "https://api.open-meteo.com/v1/forecast";
|
||||||
private static final String dailyQuery = "weather_code,temperature_2m_max,temperature_2m_min,wind_speed_10m_max,wind_direction_10m_dominant";
|
private static final String dailyQuery = "weather_code,temperature_2m_max,temperature_2m_min,wind_speed_10m_max,wind_direction_10m_dominant";
|
||||||
|
private final WeatherDataCache cache = new WeatherDataCache();
|
||||||
|
|
||||||
// https://www.nodc.noaa.gov/archive/arc0021/0002199/1.1/data/0-data/HTML/WMO-CODE/WMO4677.HTM
|
// https://www.nodc.noaa.gov/archive/arc0021/0002199/1.1/data/0-data/HTML/WMO-CODE/WMO4677.HTM
|
||||||
private JSONObject fetchWeather(int days, City city) throws IOException {
|
private JSONObject fetchWeather(int days, City city) throws IOException {
|
||||||
@ -28,8 +29,7 @@ public class OpenMeteo implements WeatherDataAPI {
|
|||||||
)
|
)
|
||||||
).toURL();
|
).toURL();
|
||||||
|
|
||||||
JSONArray jsonArray = JSONFetcher.fetchArray(url);
|
return JSONFetcher.fetch(url);
|
||||||
return jsonArray.getJSONObject(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Condition getConditionFromCode(int WMOCode) {
|
private static Condition getConditionFromCode(int WMOCode) {
|
||||||
@ -44,7 +44,7 @@ public class OpenMeteo implements WeatherDataAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static WeatherData getWeatherDataFromForecast(JSONObject response, int day, String city) {
|
private static WeatherData getWeatherDataFromForecast(JSONObject response, int day, String cityName) {
|
||||||
JSONObject daily = response.getJSONObject("daily");
|
JSONObject daily = response.getJSONObject("daily");
|
||||||
float max_temp = daily.getJSONArray("temperature_2m_max").getFloat(day);
|
float max_temp = daily.getJSONArray("temperature_2m_max").getFloat(day);
|
||||||
float min_temp = daily.getJSONArray("temperature_2m_min").getFloat(day);
|
float min_temp = daily.getJSONArray("temperature_2m_min").getFloat(day);
|
||||||
@ -55,7 +55,7 @@ public class OpenMeteo implements WeatherDataAPI {
|
|||||||
int conditionCode = daily.getJSONArray("weather_code").getInt(day);
|
int conditionCode = daily.getJSONArray("weather_code").getInt(day);
|
||||||
|
|
||||||
return new WeatherData(
|
return new WeatherData(
|
||||||
new City(city),
|
new City(cityName),
|
||||||
Instant.now(),
|
Instant.now(),
|
||||||
temp_c,
|
temp_c,
|
||||||
windSpeed,
|
windSpeed,
|
||||||
@ -68,28 +68,33 @@ public class OpenMeteo implements WeatherDataAPI {
|
|||||||
* @param day Day, 0 ≤ day ≤ 14
|
* @param day Day, 0 ≤ day ≤ 14
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public WeatherData getTemperature(int day, String city) throws IOException {
|
public WeatherData getTemperature(int day, String cityName) throws IOException {
|
||||||
JSONObject result = fetchWeather(day + 1, new City(city));
|
JSONObject result = fetchWeather(day + 1, new City(cityName));
|
||||||
|
|
||||||
return getWeatherDataFromForecast(result, day, city);
|
return getWeatherDataFromForecast(result, day, cityName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WeatherData getTemperature(int day, int hour, String city) throws IOException{
|
public WeatherData getTemperature(int day, int hour, String cityName) throws IOException{
|
||||||
return getTemperature(day, city);
|
return getTemperature(day, cityName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ArrayList<WeatherData> getTemperatures(int days, String city) throws IOException {
|
public ArrayList<WeatherData> getTemperatures(int days, String cityName) throws IOException {
|
||||||
JSONObject result = fetchWeather(days, new City(city));
|
if (!this.cache.needsUpdate(cityName, days))
|
||||||
|
return this.cache.get(cityName, days);
|
||||||
|
|
||||||
|
JSONObject result = fetchWeather(days, new City(cityName));
|
||||||
ArrayList<WeatherData> weatherDatas = new ArrayList<>();
|
ArrayList<WeatherData> weatherDatas = new ArrayList<>();
|
||||||
|
|
||||||
for (int day = 0; day < days; ++day) {
|
for (int day = 0; day < days; ++day) {
|
||||||
weatherDatas.add(
|
weatherDatas.add(
|
||||||
getWeatherDataFromForecast(result, day, city)
|
getWeatherDataFromForecast(result, day, cityName)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.cache.set(cityName, days, weatherDatas, Instant.now());
|
||||||
|
|
||||||
return weatherDatas;
|
return weatherDatas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import eirb.pg203.WeatherData.Condition;
|
|||||||
public class OpenWeatherMap implements WeatherDataAPI {
|
public class OpenWeatherMap implements WeatherDataAPI {
|
||||||
private static final String forecastBaseURL = "https://api.openweathermap.org/data/2.5/forecast";
|
private static final String forecastBaseURL = "https://api.openweathermap.org/data/2.5/forecast";
|
||||||
private String APIKey;
|
private String APIKey;
|
||||||
|
private final WeatherDataCache cache = new WeatherDataCache();
|
||||||
|
|
||||||
OpenWeatherMap(String APIKey) {
|
OpenWeatherMap(String APIKey) {
|
||||||
this.APIKey = APIKey;
|
this.APIKey = APIKey;
|
||||||
@ -37,7 +38,7 @@ public class OpenWeatherMap implements WeatherDataAPI {
|
|||||||
return JSONFetcher.fetch(url);
|
return JSONFetcher.fetch(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static WeatherData getWeatherDataFromForecast(JSONObject response, int day, String city) {
|
private static WeatherData getWeatherDataFromForecast(JSONObject response, int day, String cityName) {
|
||||||
JSONArray list = response.getJSONArray("list");
|
JSONArray list = response.getJSONArray("list");
|
||||||
|
|
||||||
DayOfWeek targetedDay = Instant.now().plusSeconds(day * 24 * 3600).atZone(ZoneId.systemDefault()).getDayOfWeek();
|
DayOfWeek targetedDay = Instant.now().plusSeconds(day * 24 * 3600).atZone(ZoneId.systemDefault()).getDayOfWeek();
|
||||||
@ -85,7 +86,7 @@ public class OpenWeatherMap implements WeatherDataAPI {
|
|||||||
|
|
||||||
|
|
||||||
return new WeatherData(
|
return new WeatherData(
|
||||||
new City(city),
|
new City(cityName),
|
||||||
Instant.now().plusSeconds(day * 24 * 3600),
|
Instant.now().plusSeconds(day * 24 * 3600),
|
||||||
temp_c,
|
temp_c,
|
||||||
windSpeed,
|
windSpeed,
|
||||||
@ -98,29 +99,33 @@ public class OpenWeatherMap implements WeatherDataAPI {
|
|||||||
* @param day Day, 0 ≤ day ≤ 14
|
* @param day Day, 0 ≤ day ≤ 14
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public WeatherData getTemperature(int day, String city) throws IOException {
|
public WeatherData getTemperature(int day, String cityName) throws IOException {
|
||||||
JSONObject result = fetchWeather(day+1, new City(city));
|
JSONObject result = fetchWeather(day+1, new City(cityName));
|
||||||
|
|
||||||
return getWeatherDataFromForecast(result, day, city);
|
return getWeatherDataFromForecast(result, day, cityName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WeatherData getTemperature(int day, int hour, String city) throws IOException{
|
public WeatherData getTemperature(int day, int hour, String cityname) throws IOException{
|
||||||
return getTemperature(day, city);
|
return getTemperature(day, cityname);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ArrayList<WeatherData> getTemperatures(int days, String city) throws IOException {
|
public ArrayList<WeatherData> getTemperatures(int days, String cityName) throws IOException {
|
||||||
JSONObject result = fetchWeather(days, new City(city));
|
if (!this.cache.needsUpdate(cityName, days))
|
||||||
|
return this.cache.get(cityName, days);
|
||||||
|
|
||||||
|
JSONObject result = fetchWeather(days, new City(cityName));
|
||||||
ArrayList<WeatherData> weatherDatas = new ArrayList<>();
|
ArrayList<WeatherData> weatherDatas = new ArrayList<>();
|
||||||
|
|
||||||
for (int day = 0; day < days ; ++day) {
|
for (int day = 0; day < days ; ++day) {
|
||||||
weatherDatas.add(
|
weatherDatas.add(
|
||||||
getWeatherDataFromForecast(result, day, city)
|
getWeatherDataFromForecast(result, day, cityName)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.cache.set(cityName, days, weatherDatas, Instant.now());
|
||||||
|
|
||||||
return weatherDatas;
|
return weatherDatas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import java.util.ArrayList;
|
|||||||
public class WeatherAPI implements WeatherDataAPI{
|
public class WeatherAPI implements WeatherDataAPI{
|
||||||
private final String weatherAPIKey;
|
private final String weatherAPIKey;
|
||||||
private static final String forecastBaseURL = "https://api.weatherapi.com/v1/forecast.json";
|
private static final String forecastBaseURL = "https://api.weatherapi.com/v1/forecast.json";
|
||||||
|
private final WeatherDataCache cache = new WeatherDataCache();
|
||||||
|
|
||||||
WeatherAPI(String weatherAPIKey) {
|
WeatherAPI(String weatherAPIKey) {
|
||||||
this.weatherAPIKey = weatherAPIKey;
|
this.weatherAPIKey = weatherAPIKey;
|
||||||
@ -80,27 +81,32 @@ public class WeatherAPI implements WeatherDataAPI{
|
|||||||
* @param day Day, 0 ≤ day ≤ 14
|
* @param day Day, 0 ≤ day ≤ 14
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public WeatherData getTemperature(int day, String city) throws IOException {
|
public WeatherData getTemperature(int day, String cityName) throws IOException {
|
||||||
JSONObject result = fetchWeather(day+1, city);
|
JSONObject result = fetchWeather(day+1, cityName);
|
||||||
return getWeatherDataFromForecast(result, day, city);
|
return getWeatherDataFromForecast(result, day, cityName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WeatherData getTemperature(int day, int hour, String city) throws IOException{
|
public WeatherData getTemperature(int day, int hour, String cityName) throws IOException{
|
||||||
return getTemperature(day, city);
|
return getTemperature(day, cityName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ArrayList<WeatherData> getTemperatures(int days, String city) throws IOException {
|
public ArrayList<WeatherData> getTemperatures(int days, String cityName) throws IOException {
|
||||||
JSONObject result = fetchWeather(days, city);
|
if (!this.cache.needsUpdate(cityName, days))
|
||||||
|
return this.cache.get(cityName, days);
|
||||||
|
|
||||||
|
JSONObject result = fetchWeather(days, cityName);
|
||||||
ArrayList<WeatherData> weatherDatas = new ArrayList<>();
|
ArrayList<WeatherData> weatherDatas = new ArrayList<>();
|
||||||
|
|
||||||
for (int day = 0; day < days; ++day) {
|
for (int day = 0; day < days; ++day) {
|
||||||
weatherDatas.add(
|
weatherDatas.add(
|
||||||
getWeatherDataFromForecast(result, day, city)
|
getWeatherDataFromForecast(result, day, cityName)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.cache.set(cityName, days, weatherDatas, Instant.now());
|
||||||
|
|
||||||
return weatherDatas;
|
return weatherDatas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
src/main/java/eirb/pg203/WeatherCachedAPI.java
Normal file
10
src/main/java/eirb/pg203/WeatherCachedAPI.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package eirb.pg203;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
abstract class WeatherCachedAPI implements WeatherDataAPI {
|
||||||
|
private final WeatherDataCache cache = new WeatherDataCache();
|
||||||
|
|
||||||
|
public void loadCache(JSONObject cache)
|
||||||
|
|
||||||
|
}
|
@ -7,9 +7,7 @@ import org.json.JSONObject;
|
|||||||
|
|
||||||
import com.sun.net.httpserver.Authenticator.Retry;
|
import com.sun.net.httpserver.Authenticator.Retry;
|
||||||
|
|
||||||
import eirb.pg203.utils.JSONCachable;
|
class WeatherData {
|
||||||
|
|
||||||
class WeatherData implements JSONCachable {
|
|
||||||
enum Condition {
|
enum Condition {
|
||||||
SUNNY("☀️"),
|
SUNNY("☀️"),
|
||||||
PARTIAL("🌤"),
|
PARTIAL("🌤"),
|
||||||
@ -188,7 +186,6 @@ class WeatherData implements JSONCachable {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public JSONObject toJSON() {
|
public JSONObject toJSON() {
|
||||||
JSONObject jsonObject = new JSONObject();
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
|
||||||
@ -203,8 +200,7 @@ class WeatherData implements JSONCachable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static WeatherData fromJSON(JSONObject data) {
|
||||||
public JSONCachable fromJSON(JSONObject data) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
94
src/main/java/eirb/pg203/WeatherDataCache.java
Normal file
94
src/main/java/eirb/pg203/WeatherDataCache.java
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package eirb.pg203;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
public class WeatherDataCache {
|
||||||
|
static class CacheValue {
|
||||||
|
private ArrayList<WeatherData> value;
|
||||||
|
private Instant timestamp;
|
||||||
|
|
||||||
|
CacheValue(ArrayList<WeatherData> value, Instant timestamp) {
|
||||||
|
this.value = value;
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<WeatherData> getWeatherData() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instant getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Will parse CacheValues with { "api": apiName } from JSON
|
||||||
|
*/
|
||||||
|
JSONObject toJSON(String apiName, String cityName) {
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
JSONArray values = new JSONArray();
|
||||||
|
|
||||||
|
jsonObject.put("city", cityName);
|
||||||
|
jsonObject.put("api", apiName);
|
||||||
|
jsonObject.put("timestamp", this.timestamp.getEpochSecond());
|
||||||
|
|
||||||
|
for (int i = 0 ; i < this.value.size() ; ++i)
|
||||||
|
values.put(this.value.get(i));
|
||||||
|
|
||||||
|
jsonObject.put("value", values);
|
||||||
|
|
||||||
|
return jsonObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CacheValue fromJSON(JSONObject data) {
|
||||||
|
ArrayList<WeatherData> value = new ArrayList<>();
|
||||||
|
|
||||||
|
JSONArray values = data.getJSONArray("value");
|
||||||
|
for (int i = 0 ; i < values.length() ; ++i)
|
||||||
|
value.add(WeatherData.fromJSON(values.getJSONObject(i)));
|
||||||
|
|
||||||
|
Instant timestamp = Instant.ofEpochSecond(data.getLong("timestamp"));
|
||||||
|
|
||||||
|
return new CacheValue(value, timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashMap<String, CacheValue> cache = new HashMap<>();
|
||||||
|
private long cacheTTL = 3600; // Cache data Time To Live
|
||||||
|
|
||||||
|
public boolean has(String cityName, int days) {
|
||||||
|
CacheValue cacheValue = this.cache.get(cityName);
|
||||||
|
|
||||||
|
return cacheValue != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean needsUpdate(String cityName, int days) {
|
||||||
|
if (!has(cityName, days)) // if (cityName, days) isn't cached, needs udpate
|
||||||
|
return true;
|
||||||
|
|
||||||
|
CacheKey cacheKey = new CacheKey(cityName, days);
|
||||||
|
CacheValue cacheValue = this.cache.get(cacheKey);
|
||||||
|
|
||||||
|
long dt = Instant.now().getEpochSecond() - cacheValue.getTimestamp().getEpochSecond();
|
||||||
|
|
||||||
|
return dt > this.cacheTTL; // if older than TTL, needs update
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<WeatherData> get(String cityName, int days) {
|
||||||
|
CacheKey cacheKey = new CacheKey(cityName, days);
|
||||||
|
ArrayList<WeatherData> weatherData = this.cache.get(cacheKey).getWeatherData();
|
||||||
|
|
||||||
|
return weatherData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(String cityName, int days, ArrayList<WeatherData> value, Instant timestamp) {
|
||||||
|
CacheKey cacheKey = new CacheKey(cityName, days);
|
||||||
|
CacheValue cacheValue = new CacheValue(value, timestamp);
|
||||||
|
|
||||||
|
this.cache.put(cacheKey, cacheValue);
|
||||||
|
}
|
||||||
|
}
|
@ -97,10 +97,9 @@ class WeatherDisplayBasic implements WeatherDisplay {
|
|||||||
displayWeatherDatas(api.getAPIName(), weatherDataAPIArrayListHashMap.get(api), startColumnString, sourceColumnSize, dayColumnSize);
|
displayWeatherDatas(api.getAPIName(), weatherDataAPIArrayListHashMap.get(api), startColumnString, sourceColumnSize, dayColumnSize);
|
||||||
this.displaySeparatorLine(days, sourceColumnSize, dayColumnSizeSeparator);
|
this.displaySeparatorLine(days, sourceColumnSize, dayColumnSizeSeparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void display(int days, String city) {
|
public void display(int days, String city) {
|
||||||
HashMap<WeatherDataAPI, ArrayList<WeatherData>> weatherDatasMap = new HashMap<>();
|
HashMap<WeatherDataAPI, ArrayList<WeatherData>> weatherDatasMap = new HashMap<>();
|
||||||
|
|
||||||
for (WeatherDataAPI w: apis) {
|
for (WeatherDataAPI w: apis) {
|
||||||
@ -110,6 +109,7 @@ class WeatherDisplayBasic implements WeatherDisplay {
|
|||||||
System.err.println(e);
|
System.err.println(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.displayAllWeatherDatas(weatherDatasMap, days);
|
this.displayAllWeatherDatas(weatherDatasMap, days);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ public class JSONFetcher {
|
|||||||
result.append(line);
|
result.append(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
System.out.println(url);
|
||||||
|
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user