Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ephemeris] Evolutions of the Ephemeris module #1169

Merged
merged 5 commits into from
Nov 4, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package org.openhab.core.automation.internal.module.handler;

import java.time.ZonedDateTime;
import java.util.Map;

import org.eclipse.jdt.annotation.NonNullByDefault;
Expand Down Expand Up @@ -74,17 +75,18 @@ private static String getValidStringConfigParameter(String parameter, Configurat

@Override
public boolean isSatisfied(Map<String, Object> inputs) {
ZonedDateTime target = ZonedDateTime.now().plusDays(offset);
clinique marked this conversation as resolved.
Show resolved Hide resolved
switch (module.getTypeUID()) {
case HOLIDAY_MODULE_TYPE_ID:
return ephemerisManager.isBankHoliday(offset);
return ephemerisManager.isBankHoliday(target);
case WEEKEND_MODULE_TYPE_ID:
return ephemerisManager.isWeekend(offset);
return ephemerisManager.isWeekend(target);
case WEEKDAY_MODULE_TYPE_ID:
return !ephemerisManager.isWeekend(offset);
return !ephemerisManager.isWeekend(target);
case DAYSET_MODULE_TYPE_ID:
final String dayset = this.dayset;
if (dayset != null) {
return ephemerisManager.isInDayset(dayset, offset);
return ephemerisManager.isInDayset(dayset, target);
}
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.eclipse.smarthome.core.ephemeris;

import java.io.FileNotFoundException;
import java.time.ZonedDateTime;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand All @@ -27,57 +28,114 @@
public interface EphemerisManager {

/**
* Tests given day (related to today) status against configured weekend days
* Tests given day status against configured weekend days
*
* @param offset Today +/- offset days (+1 = tomorrow, -1 = yesterday)
* @param date observed day
* @return whether the day is on weekend
*/
boolean isWeekend(int offset);
boolean isWeekend(ZonedDateTime date);

/**
* Tests given day (related to today) status against configured dayset
* Tests given day status against configured dayset
*
* @param daysetName name of the requested dayset, without prefix
* @param offset Today +/- offset days (+1 = tomorrow, -1 = yesterday)
* @return whether the day is on weekend
* @param date observed day
* @return whether the day is in the dayset
*/
boolean isInDayset(String daysetName, int offset);
boolean isInDayset(String daysetName, ZonedDateTime date);

/**
* Tests given day status against official bank holidays
* Tests given day status
*
* @param offset Today +/- offset days (+1 = tomorrow, -1 = yesterday)
* @param date observed day
* @return whether the day is bank holiday or not
*/
boolean isBankHoliday(int offset);
boolean isBankHoliday(ZonedDateTime date);

/**
* Tests given day status against given userfile
*
* @param offset Today +/- offset days (+1 = tomorrow, -1 = yesterday)
* @param filename absolute or relative path to the file on local file system
* @param date observed day
* @param source :
* can be a String, absolute or relative path to the file on local file system
* can be an URL, bundle resource file containing holiday definitions
* @return whether the day is bank holiday or not
* @throws FileNotFoundException if given file does not exist
* @throws FileNotFoundException
*/
boolean isBankHoliday(int offset, String filename) throws FileNotFoundException;
boolean isBankHoliday(ZonedDateTime date, Object source) throws FileNotFoundException;
clinique marked this conversation as resolved.
Show resolved Hide resolved

/**
* Get given day bank holiday name
* Get given day name from given userfile
*
* @param offset Today +/- offset days (+1 = tomorrow, -1 = yesterday)
* @return name of the bank holiday or null if no bank holiday
* @param date observed day
* @return name of the day or null if no corresponding entry
*/
@Nullable
String getBankHolidayName(int offset);
String getBankHolidayName(ZonedDateTime date);

/**
* Get given day name from given userfile
*
* @param offset Today +/- offset days (+1 = tomorrow, -1 = yesterday)
* @param filename absolute or relative path to the file on local file system
* @param date observed day
* @param source :
* can be a String, absolute or relative path to the file on local file system
* can be an URL, bundle resource file containing holiday definitions
* @return name of the day or null if no corresponding entry
* @throws FileNotFoundException if given file does not exist
* @throws FileNotFoundException
*/
@Nullable
String getBankHolidayName(ZonedDateTime date, Object source) throws FileNotFoundException;

/**
* Gets the first next to come holiday in a 1 year time window
*
* @param startDate first day of the time window
* @return next coming holiday
*/
@Nullable
String getNextBankHoliday(ZonedDateTime startDate);

/**
* Gets the first next to come holiday in a 1 year time window
*
* @param startDate first day of the time window
* @param source :
* can be a String, absolute or relative path to the file on local file system
* can be an URL, bundle resource file containing holiday definitions
* @return next coming holiday
* @throws FileNotFoundException
*/
@Nullable
String getBankHolidayName(int offset, String filename) throws FileNotFoundException;
String getNextBankHoliday(ZonedDateTime startDate, Object source) throws FileNotFoundException;

/**
* Gets the localized holiday description
*
* @param holidayName code of searched holiday
* @return localized holiday description
*/
@Nullable
String getHolidayDescription(@Nullable String holiday);

/**
* Gets the number of days until searchedHoliday
*
* @param from first day of the time window
* @param searchedHoliday name of the searched holiday
* @return difference in days, -1 if not found
*/
long getDaysUntil(ZonedDateTime from, String searchedHoliday);

/**
* Gets the number of days until searchedHoliday in user file
*
* @param from first day of the time window
* @param searchedHoliday name of the searched holiday
* @param source :
* can be a String, absolute or relative path to the file on local file system
* can be an URL, bundle resource file containing holiday definitions
* @return difference in days, -1 if not found
* @throws FileNotFoundException
*/
long getDaysUntil(ZonedDateTime from, String searchedHoliday, Object source) throws FileNotFoundException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@
import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.time.format.TextStyle;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand All @@ -35,6 +37,7 @@
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand All @@ -57,6 +60,7 @@
import de.jollyday.HolidayManager;
import de.jollyday.ManagerParameter;
import de.jollyday.ManagerParameters;
import de.jollyday.util.ResourceUtil;

/**
* This service provides functionality around ephemeris services and is the central service to be used directly by
Expand Down Expand Up @@ -92,6 +96,10 @@ public class EphemerisManagerImpl implements EphemerisManager, ConfigOptionProvi
final Map<String, Set<DayOfWeek>> daysets = new HashMap<>();
private final Map<Object, HolidayManager> holidayManagers = new HashMap<>();
private final List<String> countryParameters = new ArrayList<>();
/**
* Utility for accessing resources.
*/
private final ResourceUtil resourceUtil = new ResourceUtil();

private final LocaleProvider localeProvider;

Expand Down Expand Up @@ -198,6 +206,18 @@ protected void modified(Map<String, Object> config) {
return null;
}

private URL getUrl(String filename) throws FileNotFoundException {
if (Files.exists(Paths.get(filename))) {
try {
return new URL("file:" + filename);
} catch (MalformedURLException e) {
throw new FileNotFoundException(e.getMessage());
}
} else {
throw new FileNotFoundException(filename);
}
}

private HolidayManager getHolidayManager(Object managerKey) {
return holidayManagers.computeIfAbsent(managerKey, key -> {
final ManagerParameter parameters = managerKey.getClass() == String.class
Expand All @@ -207,45 +227,63 @@ private HolidayManager getHolidayManager(Object managerKey) {
});
}

private Optional<Holiday> getHoliday(ZonedDateTime date) {
HolidayManager manager = getHolidayManager(country);
LocalDate localDate = date.toLocalDate();

Set<Holiday> holidays = manager.getHolidays(localDate, localDate, countryParameters.toArray(new String[0]));
return holidays.isEmpty() ? Optional.empty() : Optional.of(holidays.iterator().next());
private Object castSource(Object source) throws FileNotFoundException {
if (source.getClass() == String.class) {
return getUrl((String) source);
} else if (source.getClass() == URL.class) {
return source;
}
throw new FileNotFoundException("Source is not a valid file or URL");
}

private boolean isBankHoliday(ZonedDateTime date) {
Optional<Holiday> holiday = getHoliday(date);
return holiday.isPresent();
private List<Holiday> getHolidays(ZonedDateTime from, int span, HolidayManager holidayManager) {
LocalDate fromDate = from.toLocalDate();
LocalDate toDate = from.plusDays(span).toLocalDate();

Set<Holiday> days = holidayManager.getHolidays(fromDate, toDate, countryParameters.toArray(new String[0]));
List<Holiday> sortedHolidays = days.stream().sorted(Comparator.comparing(Holiday::getDate))
.collect(Collectors.toList());
return sortedHolidays;
}

@Override
public boolean isBankHoliday(int offset) {
return isBankHoliday(ZonedDateTime.now().plusDays(offset));
public long getDaysUntil(ZonedDateTime from, String searchedHoliday) {
List<Holiday> sortedHolidays = getHolidays(from, 366, getHolidayManager(country));
Optional<Holiday> result = sortedHolidays.stream()
.filter(holiday -> searchedHoliday.equalsIgnoreCase(holiday.getPropertiesKey())).findFirst();
return result.isPresent() ? from.toLocalDate().until(result.get().getDate(), ChronoUnit.DAYS) : -1;
}

@Override
public boolean isBankHoliday(int offset, String filename) throws FileNotFoundException {
Optional<String> holiday = getHolidayUserFile(ZonedDateTime.now().plusDays(offset), filename);
return holiday.isPresent();
public long getDaysUntil(ZonedDateTime from, String searchedHoliday, Object source) throws FileNotFoundException {
List<Holiday> sortedHolidays = getHolidays(from, 366, getHolidayManager(castSource(source)));
Optional<Holiday> result = sortedHolidays.stream()
.filter(holiday -> searchedHoliday.equalsIgnoreCase(holiday.getPropertiesKey())).findFirst();
return result.isPresent() ? from.toLocalDate().until(result.get().getDate(), ChronoUnit.DAYS) : -1;
}

private @Nullable String getFirstBankHolidayKey(ZonedDateTime from, int span, HolidayManager holidayManager) {
Optional<Holiday> holiday = getHolidays(from, span, holidayManager).stream().findFirst();
return holiday.map(p -> p.getPropertiesKey()).orElse(null);
}

@Override
public boolean isWeekend(int offset) {
return isWeekend(ZonedDateTime.now().plusDays(offset));
public boolean isBankHoliday(ZonedDateTime date) {
return !getHolidays(date, 0, getHolidayManager(country)).isEmpty();
}

private boolean isWeekend(ZonedDateTime date) {
return isInDayset(CONFIG_DAYSET_WEEKEND, date);
@Override
public boolean isBankHoliday(ZonedDateTime date, Object source) throws FileNotFoundException {
return !getHolidays(date, 0, getHolidayManager(castSource(source))).isEmpty();
}

@Override
public boolean isInDayset(String daysetName, int offset) {
return isInDayset(daysetName, ZonedDateTime.now().plusDays(offset));
public boolean isWeekend(ZonedDateTime date) {
return isInDayset(CONFIG_DAYSET_WEEKEND, date);
}

private boolean isInDayset(String daysetName, ZonedDateTime date) {
@Override
public boolean isInDayset(String daysetName, ZonedDateTime date) {
if (daysets.containsKey(daysetName)) {
DayOfWeek dow = date.getDayOfWeek();
return daysets.get(daysetName).contains(dow);
Expand All @@ -255,34 +293,24 @@ private boolean isInDayset(String daysetName, ZonedDateTime date) {
}
}

private String getBankHolidayName(ZonedDateTime date) {
Optional<Holiday> holiday = getHoliday(date);
return holiday.map(p -> p.getDescription(localeProvider.getLocale())).orElse(null);
@Override
public @Nullable String getBankHolidayName(ZonedDateTime date) {
return getFirstBankHolidayKey(date, 0, getHolidayManager(country));
}

@Override
public @Nullable String getBankHolidayName(int offset) {
return getBankHolidayName(ZonedDateTime.now().plusDays(offset));
public @Nullable String getBankHolidayName(ZonedDateTime date, Object source) throws FileNotFoundException {
return getFirstBankHolidayKey(date, 0, getHolidayManager(castSource(source)));
}

private Optional<String> getHolidayUserFile(ZonedDateTime date, String filename) throws FileNotFoundException {
if (Files.exists(Paths.get(filename))) {
try {
URL url = new URL("file:" + filename);
Set<Holiday> days = getHolidayManager(url).getHolidays(date.toLocalDate(), date.toLocalDate());
return days.isEmpty() ? Optional.empty() : Optional.of(days.iterator().next().getPropertiesKey());
} catch (MalformedURLException e) {
throw new FileNotFoundException(e.getMessage());
}
} else {
throw new FileNotFoundException();
}
@Override
public @Nullable String getNextBankHoliday(ZonedDateTime from) {
return getFirstBankHolidayKey(from, 365, getHolidayManager(country));
}

@Override
public @Nullable String getBankHolidayName(int offset, String filename) throws FileNotFoundException {
Optional<String> holiday = getHolidayUserFile(ZonedDateTime.now().plusDays(offset), filename);
return holiday.isPresent() ? holiday.get() : null;
public @Nullable String getNextBankHoliday(ZonedDateTime from, Object source) throws FileNotFoundException {
return getFirstBankHolidayKey(from, 365, getHolidayManager(castSource(source)));
}

private void addDayset(String setName, Iterable<?> values) {
Expand Down Expand Up @@ -359,4 +387,10 @@ private static String getValidPart(String part) {
throw new IllegalArgumentException("Unable to parse property - token is empty.");
}
}

@Override
public @Nullable String getHolidayDescription(@Nullable String holiday) {
return holiday != null ? resourceUtil.getHolidayDescription(localeProvider.getLocale(), holiday) : null;
}

}
Loading