From 4d4ed84d142a65164c46a9ef3d72fac7be95ed24 Mon Sep 17 00:00:00 2001 From: Michael Wodniok Date: Tue, 31 Aug 2021 07:32:58 +0200 Subject: [PATCH 1/3] [icalendar] Fixes #11084: Different method for retrieving events Replaced retrieval of events for CommandTags by another, already implemented method, fixing wrong behaviour in case of moved or removed events. Also updated dependencies to get this binding resolvable again. Signed-Off-By: Michael Wodniok --- bundles/org.openhab.binding.icalendar/pom.xml | 6 +- .../internal/handler/ICalendarHandler.java | 10 ++- .../logic/BiweeklyPresentableCalendar.java | 79 +++++++------------ .../BiweeklyPresentableCalendarTest.java | 25 ++++++ .../src/test/resources/test-issue11084.ics | 56 +++++++++++++ 5 files changed, 121 insertions(+), 55 deletions(-) create mode 100644 bundles/org.openhab.binding.icalendar/src/test/resources/test-issue11084.ics diff --git a/bundles/org.openhab.binding.icalendar/pom.xml b/bundles/org.openhab.binding.icalendar/pom.xml index 0c12afd983a69..b8b4676ae6653 100644 --- a/bundles/org.openhab.binding.icalendar/pom.xml +++ b/bundles/org.openhab.binding.icalendar/pom.xml @@ -17,7 +17,7 @@ net.sf.biweekly biweekly - 0.6.4 + 0.6.6 compile @@ -36,13 +36,13 @@ com.fasterxml.jackson.core jackson-core - ${jackson.version} + 2.12.1 compile com.fasterxml.jackson.core jackson-annotations - ${jackson.version} + 2.12.1 compile diff --git a/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/handler/ICalendarHandler.java b/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/handler/ICalendarHandler.java index 8dbf05d4c4a58..407dbbb23c333 100644 --- a/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/handler/ICalendarHandler.java +++ b/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/handler/ICalendarHandler.java @@ -424,13 +424,19 @@ private void updateStates() { (lastUpdate != null ? new DateTimeType(lastUpdate.atZone(tzProvider.getTimeZone())) : UnDefType.UNDEF)); + logger.debug("from {} to {}", updateStatesLastCalledTime, now); // process all Command Tags in all Calendar Events which ENDED since updateStates was last called // the END Event tags must be processed before the BEGIN ones - executeEventCommands(calendar.getJustEndedEvents(updateStatesLastCalledTime, now), CommandTagType.END); + List justEnded = calendar.getJustEndedEvents(updateStatesLastCalledTime, now); + logger.debug("Count JE: {}", justEnded.size()); + executeEventCommands(justEnded, CommandTagType.END); // process all Command Tags in all Calendar Events which BEGAN since updateStates was last called // the END Event tags must be processed before the BEGIN ones - executeEventCommands(calendar.getJustBegunEvents(updateStatesLastCalledTime, now), CommandTagType.BEGIN); + + List justStarted = calendar.getJustBegunEvents(updateStatesLastCalledTime, now); + logger.debug("Count JS: {}", justStarted.size()); + executeEventCommands(justStarted, CommandTagType.BEGIN); // save time when updateStates was previously called // the purpose is to prevent repeat command execution of events that have already been executed diff --git a/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendar.java b/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendar.java index 61d2f9a25184d..d38e9e4454ef6 100644 --- a/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendar.java +++ b/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendar.java @@ -88,55 +88,14 @@ class BiweeklyPresentableCalendar extends AbstractPresentableCalendar { @Override public List getJustBegunEvents(Instant frameBegin, Instant frameEnd) { - final List eventList = new ArrayList<>(); - // process all the events in the iCalendar - for (final VEvent event : usedCalendar.getEvents()) { - // iterate over all begin dates - final DateIterator begDates = getRecurredEventDateIterator(event); - while (begDates.hasNext()) { - final Instant begInst = begDates.next().toInstant(); - if (begInst.isBefore(frameBegin)) { - continue; - } else if (begInst.isAfter(frameEnd)) { - break; - } - // fall through => means we are within the time frame - Duration duration = getEventLength(event); - if (duration == null) { - duration = Duration.ofMinutes(1); - } - eventList.add(new VEventWPeriod(event, begInst, begInst.plus(duration)).toEvent()); - break; - } - } - return eventList; + return this.getVEventWPeriodsBetween(frameBegin, frameEnd, 0).stream().map(e -> e.toEvent()) + .collect(Collectors.toList()); } @Override public List getJustEndedEvents(Instant frameBegin, Instant frameEnd) { - final List eventList = new ArrayList<>(); - // process all the events in the iCalendar - for (final VEvent event : usedCalendar.getEvents()) { - final Duration duration = getEventLength(event); - if (duration == null) { - continue; - } - // iterate over all begin dates - final DateIterator begDates = getRecurredEventDateIterator(event); - while (begDates.hasNext()) { - final Instant begInst = begDates.next().toInstant(); - final Instant endInst = begInst.plus(duration); - if (endInst.isBefore(frameBegin)) { - continue; - } else if (endInst.isAfter(frameEnd)) { - break; - } - // fall through => means we are within the time frame - eventList.add(new VEventWPeriod(event, begInst, endInst).toEvent()); - break; - } - } - return eventList; + return this.getVEventWPeriodsBetween(frameBegin, frameEnd, 0, true).stream().map(e -> e.toEvent()) + .collect(Collectors.toList()); } @Override @@ -247,6 +206,20 @@ public List getFilteredEventsBetween(Instant begin, Instant end, @Nullabl * @return All events which begin in the time frame. */ private List getVEventWPeriodsBetween(Instant frameBegin, Instant frameEnd, int maximumPerSeries) { + return this.getVEventWPeriodsBetween(frameBegin, frameEnd, maximumPerSeries, false); + } + + /** + * Finds events which begin in the given frame by end time and date + * + * @param frameBegin Begin of the frame where to search events. + * @param frameEnd End of the time frame where to search events. The Instant is inclusive when searchByEnd is true. + * @param maximumPerSeries Limit the results per series. Set to 0 for no limit. + * @param searchByEnd Whether to search by begin of the event or by end. + * @return All events which begin in the time frame. + */ + private List getVEventWPeriodsBetween(Instant frameBegin, Instant frameEnd, int maximumPerSeries, + boolean searchByEnd) { final List positiveEvents = new ArrayList<>(); final List negativeEvents = new ArrayList<>(); classifyEvents(positiveEvents, negativeEvents); @@ -254,16 +227,22 @@ private List getVEventWPeriodsBetween(Instant frameBegin, Instant final List eventList = new ArrayList<>(); for (final VEvent positiveEvent : positiveEvents) { final DateIterator positiveBeginDates = getRecurredEventDateIterator(positiveEvent); - positiveBeginDates.advanceTo(Date.from(frameBegin)); + Duration duration = getEventLength(positiveEvent); + if (duration == null) { + duration = Duration.ZERO; + } + positiveBeginDates.advanceTo(Date.from(frameBegin.minus(searchByEnd ? duration : Duration.ZERO))); int foundInSeries = 0; while (positiveBeginDates.hasNext()) { final Instant begInst = positiveBeginDates.next().toInstant(); - if (begInst.isAfter(frameEnd) || begInst.equals(frameEnd)) { + if ((!searchByEnd && (begInst.isAfter(frameEnd) || begInst.equals(frameEnd))) + || (searchByEnd && begInst.plus(duration).isAfter(frameEnd))) { break; } - Duration duration = getEventLength(positiveEvent); - if (duration == null) { - duration = Duration.ZERO; + // biweekly is not as precise as java.time. An exact check is required. + if ((!searchByEnd && begInst.isBefore(frameBegin)) + || (searchByEnd && begInst.plus(duration).isBefore(frameBegin))) { + continue; } final VEventWPeriod resultingVEWP = new VEventWPeriod(positiveEvent, begInst, begInst.plus(duration)); diff --git a/bundles/org.openhab.binding.icalendar/src/test/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendarTest.java b/bundles/org.openhab.binding.icalendar/src/test/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendarTest.java index 7c60c4fb68f34..c4857336c7daa 100644 --- a/bundles/org.openhab.binding.icalendar/src/test/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendarTest.java +++ b/bundles/org.openhab.binding.icalendar/src/test/java/org/openhab/binding/icalendar/internal/logic/BiweeklyPresentableCalendarTest.java @@ -49,6 +49,7 @@ public class BiweeklyPresentableCalendarTest { private AbstractPresentableCalendar calendar3; private AbstractPresentableCalendar calendar_issue9647; private AbstractPresentableCalendar calendar_issue10808; + private AbstractPresentableCalendar calendar_issue11084; @BeforeEach public void setUp() throws IOException, CalendarException { @@ -59,6 +60,8 @@ public void setUp() throws IOException, CalendarException { new FileInputStream("src/test/resources/test-issue9647.ics")); calendar_issue10808 = new BiweeklyPresentableCalendar( new FileInputStream("src/test/resources/test-issue10808.ics")); + calendar_issue11084 = new BiweeklyPresentableCalendar( + new FileInputStream("src/test/resources/test-issue11084.ics")); } /** @@ -132,6 +135,13 @@ public void testGetCurrentEvent() { Event currentEvent4 = calendar_issue10808.getCurrentEvent(Instant.parse("2021-06-05T17:18:05Z")); assertNotNull(currentEvent4); assertTrue("Test event 1".contentEquals(currentEvent4.title)); + + Event currentEvent5 = calendar_issue11084.getCurrentEvent(Instant.parse("2021-08-16T16:30:05Z")); + assertNull(currentEvent5); + + Event currentEvent6 = calendar_issue11084.getCurrentEvent(Instant.parse("2021-08-16T16:45:05Z")); + assertNotNull(currentEvent6); + assertTrue("TEST_REPEATING_EVENT_3".contentEquals(currentEvent6.title)); } /** @@ -563,6 +573,17 @@ public void testCommandTagCode() { cmd7 = cmdTags.get(7).getCommand(); assertNotNull(cmd7); assertEquals(DecimalType.class, cmd7.getClass()); + + // issue 11084: Command tags from moved events are also executed + List events2 = calendar_issue11084.getJustBegunEvents(Instant.parse("2021-08-16T16:29:55Z"), + Instant.parse("2021-08-16T17:00:05Z")); + assertEquals(1, events2.size()); + assertEquals(Instant.parse("2021-08-16T16:45:00Z"), events2.get(0).start); + + List events3 = calendar_issue11084.getJustEndedEvents(Instant.parse("2021-08-16T16:29:55Z"), + Instant.parse("2021-08-16T17:00:05Z")); + assertEquals(1, events3.size()); + assertEquals(Instant.parse("2021-08-16T17:00:00Z"), events3.get(0).end); } @SuppressWarnings("null") @@ -621,5 +642,9 @@ public void testGetFilteredEventsBetween() { LocalDate.parse("2021-01-04").atStartOfDay(ZoneId.systemDefault()).toInstant(), LocalDate.parse("2021-01-05").atStartOfDay(ZoneId.systemDefault()).toInstant(), null, 3); assertArrayEquals(expectedFilteredEvents8, realFilteredEvents8.toArray(new Event[] {})); + + List realFilteredEvents9 = calendar_issue11084.getFilteredEventsBetween( + Instant.parse("2021-08-16T16:45:00.123456Z"), Instant.parse("2021-08-16T16:46:00.768643Z"), null, 3); + assertEquals(0, realFilteredEvents9.size()); } } diff --git a/bundles/org.openhab.binding.icalendar/src/test/resources/test-issue11084.ics b/bundles/org.openhab.binding.icalendar/src/test/resources/test-issue11084.ics new file mode 100644 index 0000000000000..38c208b09ea05 --- /dev/null +++ b/bundles/org.openhab.binding.icalendar/src/test/resources/test-issue11084.ics @@ -0,0 +1,56 @@ +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:PUBLISH +X-WR-CALNAME:ohtest +X-WR-TIMEZONE:UTC +BEGIN:VTIMEZONE +TZID:Europe/Brussels +X-LIC-LOCATION:Europe/Brussels +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTART;TZID=Europe/Brussels:20210816T184500 +DTEND;TZID=Europe/Brussels:20210816T190000 +DTSTAMP:20210816T174418Z +UID:pseudo7346893o7r8328zheh@google.com +RECURRENCE-ID;TZID=Europe/Brussels:20210816T183000 +CREATED:20210816T161602Z +DESCRIPTION:BEGIN:E_Test_Cal:ON +LAST-MODIFIED:20210816T162009Z +LOCATION: +SEQUENCE:1 +STATUS:CONFIRMED +SUMMARY:TEST_REPEATING_EVENT_3 +TRANSP:OPAQUE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Brussels:20210816T183000 +DTEND;TZID=Europe/Brussels:20210816T184500 +RRULE:FREQ=DAILY +DTSTAMP:20210816T174418Z +UID:pseudo7346893o7r8328zheh@google.com +CREATED:20210816T161602Z +DESCRIPTION:BEGIN:E_Test_Cal:ON +LAST-MODIFIED:20210816T162009Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:TEST_REPEATING_EVENT_3 +TRANSP:OPAQUE +END:VEVENT +END:VCALENDAR From 377e696e83abcda06ddc88a331f1a7eb754c881a Mon Sep 17 00:00:00 2001 From: Michael Wodniok Date: Tue, 31 Aug 2021 08:00:45 +0200 Subject: [PATCH 2/3] [icalendar] Reduced dependencies, cleaned up debug output. Signed-off-by: Michael Wodniok --- bundles/org.openhab.binding.icalendar/pom.xml | 6 +++--- .../icalendar/internal/handler/ICalendarHandler.java | 10 ++-------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/bundles/org.openhab.binding.icalendar/pom.xml b/bundles/org.openhab.binding.icalendar/pom.xml index b8b4676ae6653..dba5c6e316966 100644 --- a/bundles/org.openhab.binding.icalendar/pom.xml +++ b/bundles/org.openhab.binding.icalendar/pom.xml @@ -22,7 +22,7 @@ com.fasterxml.jackson.core - * + jackson-databind @@ -39,12 +39,12 @@ 2.12.1 compile - + com.fasterxml.jackson.core jackson-databind diff --git a/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/handler/ICalendarHandler.java b/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/handler/ICalendarHandler.java index 407dbbb23c333..8dbf05d4c4a58 100644 --- a/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/handler/ICalendarHandler.java +++ b/bundles/org.openhab.binding.icalendar/src/main/java/org/openhab/binding/icalendar/internal/handler/ICalendarHandler.java @@ -424,19 +424,13 @@ private void updateStates() { (lastUpdate != null ? new DateTimeType(lastUpdate.atZone(tzProvider.getTimeZone())) : UnDefType.UNDEF)); - logger.debug("from {} to {}", updateStatesLastCalledTime, now); // process all Command Tags in all Calendar Events which ENDED since updateStates was last called // the END Event tags must be processed before the BEGIN ones - List justEnded = calendar.getJustEndedEvents(updateStatesLastCalledTime, now); - logger.debug("Count JE: {}", justEnded.size()); - executeEventCommands(justEnded, CommandTagType.END); + executeEventCommands(calendar.getJustEndedEvents(updateStatesLastCalledTime, now), CommandTagType.END); // process all Command Tags in all Calendar Events which BEGAN since updateStates was last called // the END Event tags must be processed before the BEGIN ones - - List justStarted = calendar.getJustBegunEvents(updateStatesLastCalledTime, now); - logger.debug("Count JS: {}", justStarted.size()); - executeEventCommands(justStarted, CommandTagType.BEGIN); + executeEventCommands(calendar.getJustBegunEvents(updateStatesLastCalledTime, now), CommandTagType.BEGIN); // save time when updateStates was previously called // the purpose is to prevent repeat command execution of events that have already been executed From bc3a39180121f81e8d14ec65ad49f60cf27e4126 Mon Sep 17 00:00:00 2001 From: Michael Wodniok Date: Thu, 9 Sep 2021 18:54:06 +0200 Subject: [PATCH 3/3] [icalendar] replaced jackson version by openhab variable Signed-off-by: Michael Wodniok --- bundles/org.openhab.binding.icalendar/pom.xml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/bundles/org.openhab.binding.icalendar/pom.xml b/bundles/org.openhab.binding.icalendar/pom.xml index dba5c6e316966..768f07224abf3 100644 --- a/bundles/org.openhab.binding.icalendar/pom.xml +++ b/bundles/org.openhab.binding.icalendar/pom.xml @@ -36,15 +36,9 @@ com.fasterxml.jackson.core jackson-core - 2.12.1 + ${jackson.version} compile - com.fasterxml.jackson.core jackson-databind