From efca2709c961622563f7f29648c141566d42fa45 Mon Sep 17 00:00:00 2001 From: Alan Davis Date: Wed, 12 Feb 2014 01:16:36 +0000 Subject: [PATCH] Merged HEAD-BUG-FIX (4.3/Cloud) to HEAD (4.3/Cloud) 59252: Merged V4.2-BUG-FIX (4.2.1) to HEAD-BUG-FIX (Cloud/4.3) 59196: Merged DEV to V4.2-BUG-FIX (4.2.1) 58963 : MNT-10006: SPP: NPE occurs for recurrent event which occurs monthly/yearly on any weekday/weekend day - Support of day/weekday/weekend recurrence pattern was implemented - Unit tests are added. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@62116 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../calendar/CalendarRecurrenceHelper.java | 217 ++++- .../repo/calendar/CalendarHelpersTest.java | 819 +++++++++++++++++- .../CalendarRecurrenceHelperTest.java | 43 +- 3 files changed, 1036 insertions(+), 43 deletions(-) diff --git a/source/java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelper.java b/source/java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelper.java index 2ed8323cdb..7e7fe21a98 100644 --- a/source/java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelper.java +++ b/source/java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelper.java @@ -18,28 +18,14 @@ */ package org.alfresco.service.cmr.calendar; -import java.text.DateFormatSymbols; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - -import org.alfresco.repo.calendar.CalendarModel; -import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.namespace.QName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.extensions.surf.util.I18NUtil; +import java.text.DateFormatSymbols; +import java.text.SimpleDateFormat; +import java.util.*; + /** * This class provides helper functions for when working * with recurring {@link CalendarEntry} instances. @@ -189,21 +175,67 @@ public class CalendarRecurrenceHelper if (params.containsKey("BYDAY") && params.containsKey("BYSETPOS")) { int days = params.get("BYDAY").split(",").length; - if (days == 7) + + if (days == 7 && !"-1".equals(params.get("BYSETPOS"))) { // Make it normal params.put("BYMONTHDAY", params.get("BYSETPOS")); params.remove("BYDAY"); params.remove("BYSETPOS"); } + else + { + buildParams(params, days); + } } - } + } + // MNT-10006 fix. Added the support for recurrences rule "WEEKDAY", "WEEKEND DAY" + else if ("MONTHLY".equals(params.get("FREQ")) && + (params.containsKey("BYDAY") && params.containsKey("BYSETPOS"))) + { + int days = params.get("BYDAY").split(",").length; + buildParams(params, days); + } } return params; } - - - /** + + /** + * Builds correct params for recurrences 'weekday', 'weekend day' + * @param params the recurrence rule + * @param days the appropriate amount of days for recurrences 'day', 'weekday' weekend day' + */ + private static void buildParams(Map params, int days) + { + // building recurrence rule for recurrence pattern 'day' + if (days == 7) + { + // Make it normal + params.put("BYANYDAY", params.get("BYSETPOS")); + params.put("DAY", params.get("BYDAY")); + params.remove("BYDAY"); + params.remove("BYSETPOS"); + } + // building recurrence rule for recurrence pattern 'weekday' + else if (days == 5) + { + params.put("BYWEEKDAY", params.get("BYSETPOS")); + params.put("WEEKDAYS", params.get("BYDAY")); + params.remove("BYDAY"); + params.remove("BYSETPOS"); + } + // building recurrence rule for recurrence pattern 'weekend day' + else if (days == 2) + { + params.put("BYWEEKENDDAY", params.get("BYSETPOS")); + params.put("WEEKENDS", params.get("BYDAY")); + params.remove("BYDAY"); + params.remove("BYSETPOS"); + } + } + + + /** * For the given Calendar Entry, return its subsequent Recurrence on or after * the specified date, until the given limit. If it doesn't have any recurrences * on or after the start date (either no recurrence rules, or the last recurrence @@ -597,9 +629,138 @@ public class CalendarRecurrenceHelper toDayOfWeekInMonth(currentDate, dayOfWeek, instanceInMonth); } } + // MNT-10006 fix. Added the support for recurrences rule "WEEKDAY", "WEEKEND DAY" + if (params.get("BYWEEKDAY") != null || params.get("BYWEEKENDDAY") != null || params.get("BYANYDAY") != null) + { + buildWeekdayAndWeekEndRecurence(currentDate, dates, params, until, monthInterval); + } } - - protected static void buildYearlyRecurrences(Calendar currentDate, long duration, List dates, + + /** + * Build the recurrences for recurrence rules 'weekday', 'weekend day' + * @param currentDate the Calendar for current event + * @param dates Map for recurrence events dates + * @param params recurrence rules + * @param until date when the current event ends + */ + private static void buildWeekdayAndWeekEndRecurence(Calendar currentDate, List dates, Map params, Date until, int intervalInMonths) + { + String dayPosStr; + String dayWeekType; + + // founds which of the recurrence pattern is used "weekday" or "weekend day" + if (params.get("BYWEEKDAY") != null) + { + dayPosStr = params.get("BYWEEKDAY"); + dayWeekType = "WEEKDAYS"; + } + else if (params.get("BYWEEKENDDAY") != null) + { + dayPosStr = params.get("BYWEEKENDDAY"); + dayWeekType = "WEEKENDS"; + } + else + { + dayPosStr = params.get("BYANYDAY"); + dayWeekType = "DAY"; + } + + List daysOfWeek = getDaysOfWeek(params, dayWeekType); + + boolean isCurrentDateAfterUntil = false; + int firstMonthDay = 1; + + while (!isCurrentDateAfterUntil) + { + // Setting the current date to the first day of month + currentDate.set(Calendar.DAY_OF_MONTH, firstMonthDay); + if (currentDate.getTime().before(until)) + { + int currentDayOfWeek; + + // The sequence number for "BYSETPOS" parameter from recurrence rule for current date. + int dayCount = 0; + // week day position, e.q.: first, second. third, forth, last. If the weekday position is 'last' the weekDayPos + // value will less then '0' + int weekDayPos = Integer.parseInt(dayPosStr); + + if (weekDayPos > 0) + { + // Setting the current date to the first day of month + currentDate.set(Calendar.DAY_OF_MONTH, firstMonthDay); + // Walk forward from the first day of the month to the required day position according the recurrence + // rule, skipping the unnecessary days. F.ex, if we need only weekdays then weekends days should be skipped. + while (dayCount != weekDayPos) + { + currentDayOfWeek = currentDate.get(Calendar.DAY_OF_WEEK); + + if (daysOfWeek.contains(currentDayOfWeek)) + { + dayCount++; + } + + // If dayCount is not what we need go to the next day of the current month + if (dayCount != weekDayPos) + { + currentDate.add(Calendar.DAY_OF_MONTH, 1); + } + } + } + //when weekday position is 'last' + else + { + // Sets the last day of moth and retrieves the weekday number + currentDate.set(Calendar.DAY_OF_MONTH, currentDate.getActualMaximum(Calendar.DAY_OF_MONTH)); + currentDayOfWeek = currentDate.get(Calendar.DAY_OF_WEEK); + + // walk back from the last day of the month to last weekend day + while (!daysOfWeek.contains(currentDayOfWeek)) + { + currentDate.add(Calendar.DAY_OF_MONTH, -1); + currentDayOfWeek = currentDate.get(Calendar.DAY_OF_WEEK); + } + } + dates.add(currentDate.getTime()); + currentDate.add(Calendar.MONTH, intervalInMonths); + } + else + { + // The currentDate is after 'until' date. + isCurrentDateAfterUntil = true; + } + } + } + + /** + * Returns the sorted List of weekdays by numbers + * @param params recurrence rule + * @param dayWeekType "WEEKDAY" or "WEEKEND" day + */ + private static List getDaysOfWeek(Map params, String dayWeekType) + { + String[] weekDays = params.get(dayWeekType).split(","); + List daysOfWeek = new ArrayList<>(); + + for (String day : weekDays) + { + Integer dayNumber = DAY_NAMES_TO_CALENDAR_DAYS.get(day); + + if (dayNumber == null) + { + logger.warn("Invalid day " + day); + } + else + { + daysOfWeek.add(dayNumber); + } + } + + Collections.sort(daysOfWeek); + + return daysOfWeek; + } + + protected static void buildYearlyRecurrences(Calendar currentDate, long duration, List dates, Map params, Date onOrAfter, Date until, boolean firstOnly, int interval) { if (onOrAfter.before(currentDate.getTime())) @@ -666,6 +827,12 @@ public class CalendarRecurrenceHelper currentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); } } + // MNT-10006 fix. Added the support for recurrences rule "WEEKDAY", "WEEKEND DAY" + else if (null != params.get("BYWEEKDAY") || null != params.get("BYWEEKENDDAY") || null != params.get("BYANYDAY")) + { + int intervalInMonths = interval * 12; + buildWeekdayAndWeekEndRecurence(currentDate, dates, params, until, intervalInMonths); + } else { // eg the third Tuesday in February every year diff --git a/source/test-java/org/alfresco/repo/calendar/CalendarHelpersTest.java b/source/test-java/org/alfresco/repo/calendar/CalendarHelpersTest.java index 10a76540e9..cd1f1d66bd 100644 --- a/source/test-java/org/alfresco/repo/calendar/CalendarHelpersTest.java +++ b/source/test-java/org/alfresco/repo/calendar/CalendarHelpersTest.java @@ -18,27 +18,18 @@ */ package org.alfresco.repo.calendar; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertNotNull; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.SimpleTimeZone; -import java.util.TimeZone; - import org.alfresco.service.cmr.calendar.CalendarEntryDTO; import org.alfresco.service.cmr.calendar.CalendarRecurrenceHelper; import org.alfresco.service.cmr.calendar.CalendarService; import org.alfresco.service.cmr.calendar.CalendarTimezoneHelper; import org.junit.Test; +import java.text.SimpleDateFormat; +import java.util.*; + +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; + /** * Test cases for the helpers relating to the {@link CalendarService}, * but which don't need a full repo @@ -52,6 +43,7 @@ public class CalendarHelpersTest private final static long TWO_DAYS_MS = 2 * 24 * ONE_HOUR_MS; private static SimpleDateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd"); + private static SimpleDateFormat fullDayFmt = new SimpleDateFormat("EEEE"); /** * UTC+10, no daylight savings @@ -922,6 +914,803 @@ public class CalendarHelpersTest // TODO Add tests for this case, ALF-13287 } + + /** + * Testing the monthly recurrence rule for the first day of every first month + */ + @Test + public void monthlyRecurrenceByFirstDayOfEveryFirstMonth() + { + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Setting the recurrence rule fo the first day of every 1 month + // FREQ=MONTHLY;INTERVAL=1;BYDAY=SA,MO,TU,WE,TH,FR,SU;BYSETPOS=1 + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("INTERVAL", "1"); + params.put("BYDAY", "SA,MO,TU,WE,TH,FR,SU"); + params.put("BYSETPOS", "1"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals(null, paramsFixed.get("BYDAY")); + assertEquals(null, paramsFixed.get("BYSETPOS")); + assertEquals("1", paramsFixed.get("BYANYDAY")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2013,12, 30); + //Until the 1st of April + Date until = date(2014, 4, 1); + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildMonthlyRecurrences(currentDate, dates, params, onOrAfter, until, false, interval); + assertEquals(3, dates.size()); + assertEquals("2014-01-01", dateFmt.format(dates.get(0))); + assertEquals("2014-02-01", dateFmt.format(dates.get(1))); + assertEquals("2014-03-01", dateFmt.format(dates.get(2))); + } + + /** + * Testing the monthly recurrence rule for the first weekday of every first month + */ + @Test + public void monthlyRecurrenceByFirstWeekdayEveryFirstMonth() + { + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Setting the recurrence rule fo the first weekday of every 1 month + // FREQ=MONTHLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=1 + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("INTERVAL", "1"); + params.put("BYDAY", "MO,TU,WE,TH,FR"); + params.put("BYSETPOS", "1"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals(null, paramsFixed.get("BYDAY")); + assertEquals(null, paramsFixed.get("BYSETPOS")); + assertEquals("1", paramsFixed.get("BYWEEKDAY")); + assertEquals("MO,TU,WE,TH,FR", paramsFixed.get("WEEKDAYS")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2013,12, 30); + //Until the 1st of April + Date until = date(2014, 4, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildMonthlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + assertEquals(3, dates.size()); + assertEquals("2014-01-01", dateFmt.format(dates.get(0))); + assertEquals("2014-02-03", dateFmt.format(dates.get(1))); + assertEquals("2014-03-03", dateFmt.format(dates.get(2))); + } + + /** + * Testing the monthly recurrence rule for the first day of every first month + */ + @Test + public void monthlyRecurrenceByFirstWeekendDayEveryFirstMonth() + { + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Setting the recurrence rule fo the last day of every 1 month + // FREQ=MONTHLY;INTERVAL=1;BYDAY=SA,SU;BYSETPOS=1 + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("INTERVAL", "1"); + params.put("BYDAY", "SA,SU"); + params.put("BYSETPOS", "1"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals(null, paramsFixed.get("BYDAY")); + assertEquals(null, paramsFixed.get("BYSETPOS")); + assertEquals("1", paramsFixed.get("BYWEEKENDDAY")); + assertEquals("SA,SU", paramsFixed.get("WEEKENDS")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2013,12, 30); + //Until the 1st of April + Date until = date(2014, 4, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildMonthlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + assertEquals(3, dates.size()); + assertEquals("2014-01-04", dateFmt.format(dates.get(0))); + assertEquals("2014-02-01", dateFmt.format(dates.get(1))); + assertEquals("2014-03-01", dateFmt.format(dates.get(2))); + } + + /** + * Testing the monthly recurrence rule for the second day of every first month + */ + @Test + public void monthlyRecurrenceBySecondDayOfEveryFirstMonth() + { + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Setting the recurrence rule fo the second day of every 1 month + // FREQ=MONTHLY;INTERVAL=1;BYDAY=SA,MO,TU,WE,TH,FR,SU;BYSETPOS=-1 + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("INTERVAL", "1"); + params.put("BYDAY", "SA,MO,TU,WE,TH,FR,SU"); + params.put("BYSETPOS", "2"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals(null, paramsFixed.get("BYDAY")); + assertEquals(null, paramsFixed.get("BYSETPOS")); + assertEquals("2", paramsFixed.get("BYANYDAY")); + assertEquals("SA,MO,TU,WE,TH,FR,SU", paramsFixed.get("DAY")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2014,1, 1); + //Until the 1st of April + Date until = date(2014, 4, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildMonthlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + assertEquals(3, dates.size()); + assertEquals("2014-01-02", dateFmt.format(dates.get(0))); + assertEquals("2014-02-02", dateFmt.format(dates.get(1))); + assertEquals("2014-03-02", dateFmt.format(dates.get(2))); + } + + /** + * Testing the monthly recurrence rule for the second weekday of every first month + */ + @Test + public void monthlyRecurrenceBySecondWeekdayOfEveryFirstMonth() + { + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Setting the recurrence rule fo the second weekday of every 1 month + // FREQ=MONTHLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1 + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("INTERVAL", "1"); + params.put("BYDAY", "MO,TU,WE,TH,FR"); + params.put("BYSETPOS", "2"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals(null, paramsFixed.get("BYDAY")); + assertEquals(null, paramsFixed.get("BYSETPOS")); + assertEquals("2", paramsFixed.get("BYWEEKDAY")); + assertEquals("MO,TU,WE,TH,FR", paramsFixed.get("WEEKDAYS")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2014,1, 1); + //Until the 1st of April + Date until = date(2014, 4, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildMonthlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + + assertEquals(3, dates.size()); + + assertEquals("2014-01-02", dateFmt.format(dates.get(0))); + assertEquals("Thursday", fullDayFmt.format(dates.get(0))); + + assertEquals("2014-02-04", dateFmt.format(dates.get(1))); + assertEquals("Tuesday", fullDayFmt.format(dates.get(1))); + + assertEquals("2014-03-04", dateFmt.format(dates.get(2))); + assertEquals("Tuesday", fullDayFmt.format(dates.get(2))); + } + + /** + * Testing the monthly recurrence rule for the second weekend day of every first month + */ + @Test + public void monthlyRecurrenceBySecondWeekendDayOfEveryFirstMonth() + { + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Setting the recurrence rule fo the second weekday of every 1 month + // FREQ=MONTHLY;INTERVAL=1;BYDAY=SU,SA;BYSETPOS=-1 + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("INTERVAL", "1"); + params.put("BYDAY", "SU,SA"); + params.put("BYSETPOS", "2"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals(null, paramsFixed.get("BYDAY")); + assertEquals(null, paramsFixed.get("BYSETPOS")); + assertEquals("2", paramsFixed.get("BYWEEKENDDAY")); + assertEquals("SU,SA", paramsFixed.get("WEEKENDS")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2014,1, 1); + //Until the 1st of April + Date until = date(2014, 4, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildMonthlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + + assertEquals(3, dates.size()); + + assertEquals("2014-01-05", dateFmt.format(dates.get(0))); + assertEquals("Sunday", fullDayFmt.format(dates.get(0))); + + assertEquals("2014-02-02", dateFmt.format(dates.get(1))); + assertEquals("Sunday", fullDayFmt.format(dates.get(1))); + + assertEquals("2014-03-02", dateFmt.format(dates.get(2))); + assertEquals("Sunday", fullDayFmt.format(dates.get(2))); + } + + /** + * Testing the monthly recurrence rule for the last day of every first month + */ + @Test + public void monthlyRecurrenceByLastDayOfEveryFirstMonth() + { + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Setting the recurrence rule fo the last day of every 1 month + // FREQ=MONTHLY;INTERVAL=1;BYDAY=SA,MO,TU,WE,TH,FR,SU;BYSETPOS=-1 + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("INTERVAL", "1"); + params.put("BYDAY", "SU,MO,TU,WE,TH,FR,SA"); + params.put("BYSETPOS", "-1"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals(null, paramsFixed.get("BYDAY")); + assertEquals(null, paramsFixed.get("BYSETPOS")); + assertEquals("-1", paramsFixed.get("BYANYDAY")); + assertEquals("SU,MO,TU,WE,TH,FR,SA", paramsFixed.get("DAY")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2014,1, 1); + //Until the 4th of April + Date until = date(2014, 4, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildMonthlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + assertEquals(3, dates.size()); + assertEquals("2014-01-31", dateFmt.format(dates.get(0))); + assertEquals("2014-02-28", dateFmt.format(dates.get(1))); + assertEquals("2014-03-31", dateFmt.format(dates.get(2))); + } + + /** + * Testing the monthly recurrence rule for the last weekday of every first month + */ + @Test + public void monthlyRecurrenceByLastWeekdayOfEveryFirstMonth() + { + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Setting the recurrence rule fo the last day of every 1 month + // FREQ=MONTHLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1 + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("INTERVAL", "1"); + params.put("BYDAY", "MO,TU,WE,TH,FR"); + params.put("BYSETPOS", "-1"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals(null, paramsFixed.get("BYDAY")); + assertEquals(null, paramsFixed.get("BYSETPOS")); + assertEquals("-1", paramsFixed.get("BYWEEKDAY")); + assertEquals("MO,TU,WE,TH,FR", paramsFixed.get("WEEKDAYS")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2014,1, 1); + //Until the 4th of April + Date until = date(2014, 4, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildMonthlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + assertEquals(3, dates.size()); + assertEquals("2014-01-31", dateFmt.format(dates.get(0))); + assertEquals("2014-02-28", dateFmt.format(dates.get(1))); + assertEquals("2014-03-31", dateFmt.format(dates.get(2))); + } + + /** + * Testing the monthly recurrence rule for the last weekend day of every first month + */ + @Test + public void monthlyRecurrenceByLastWeekendDayOfEveryFirstMonth() + { + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Setting the recurrence rule fo the last day of every 1 month + // FREQ=MONTHLY;INTERVAL=1;BYDAY=SU,SA;BYSETPOS=-1 + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("INTERVAL", "1"); + params.put("BYDAY", "SU,SA"); + params.put("BYSETPOS", "-1"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals(null, paramsFixed.get("BYDAY")); + assertEquals(null, paramsFixed.get("BYSETPOS")); + assertEquals("-1", paramsFixed.get("BYWEEKENDDAY")); + assertEquals("SU,SA", paramsFixed.get("WEEKENDS")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2014,1, 1); + //Until the 4th of April + Date until = date(2014, 4, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildMonthlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + assertEquals(3, dates.size()); + assertEquals("2014-01-26", dateFmt.format(dates.get(0))); + assertEquals("2014-02-23", dateFmt.format(dates.get(1))); + assertEquals("2014-03-30", dateFmt.format(dates.get(2))); + } + + /** + * Testing the yearly recurrence rule for the first day of every January + */ + @Test + public void yearlyRecurrenceByFirstDayMonth() + { + // Setting the yearly recurrence rule fo the first day of every January + //FREQ=MONTHLY;BYDAY=SU,MO,TU,WE,TH,FR,SA;BYMONTH=1;BYSETPOS=1;INTERVAL=12 + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Recurrecne rule + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("BYDAY", "SU,MO,TU,WE,TH,FR,SA"); + params.put("BYMONTH", "1"); + params.put("BYSETPOS", "1"); + params.put("INTERVAL", "12"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals("YEARLY", paramsFixed.get("FREQ")); + assertEquals("1", paramsFixed.get("BYMONTHDAY")); + assertEquals("1", paramsFixed.get("INTERVAL")); + assertEquals("1", paramsFixed.get("BYMONTH")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2014,1, 1); + //Until the 4th of April + Date until = date(2018, 1, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildYearlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + + assertEquals(4, dates.size()); + assertEquals("2014-01-01", dateFmt.format(dates.get(0))); + assertEquals("2015-01-01", dateFmt.format(dates.get(1))); + assertEquals("2016-01-01", dateFmt.format(dates.get(2))); + assertEquals("2017-01-01", dateFmt.format(dates.get(3))); + + } + + /** + * Testing the yearly recurrence rule for the first weekday day of every January + */ + @Test + public void yearlyRecurrenceByFirstWeekdayMonth() + { + // Setting the yearly recurrence rule fo the first weekday of every January + //FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYMONTH=1;BYSETPOS=1;INTERVAL=12 + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Recurrecne rule + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("BYDAY", "MO,TU,WE,TH,FR"); + params.put("BYMONTH", "1"); + params.put("BYSETPOS", "1"); + params.put("INTERVAL", "12"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals("YEARLY", paramsFixed.get("FREQ")); + assertEquals("1", paramsFixed.get("BYWEEKDAY")); + assertEquals("1", paramsFixed.get("INTERVAL")); + assertEquals("1", paramsFixed.get("BYMONTH")); + assertEquals("MO,TU,WE,TH,FR", paramsFixed.get("WEEKDAYS")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2014,1, 1); + //Until the 4th of April + Date until = date(2018, 1, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildYearlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + + assertEquals(4, dates.size()); + assertEquals("2014-01-01", dateFmt.format(dates.get(0))); + assertEquals("2015-01-01", dateFmt.format(dates.get(1))); + assertEquals("2016-01-01", dateFmt.format(dates.get(2))); + assertEquals("2017-01-02", dateFmt.format(dates.get(3))); + + } + + /** + * Testing the yearly recurrence rule for the first weekend day of every January + */ + @Test + public void yearlyRecurrenceByFirstWeekendDayMonth() + { + // Setting the yearly recurrence rule fo the first weekend day of every January + //FREQ=MONTHLY;BYDAY=SU,SA;BYMONTH=1;BYSETPOS=1;INTERVAL=12 + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Recurrecne rule + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("BYDAY", "SU,SA"); + params.put("BYMONTH", "1"); + params.put("BYSETPOS", "1"); + params.put("INTERVAL", "12"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals("YEARLY", paramsFixed.get("FREQ")); + assertEquals("1", paramsFixed.get("BYWEEKENDDAY")); + assertEquals("1", paramsFixed.get("INTERVAL")); + assertEquals("1", paramsFixed.get("BYMONTH")); + assertEquals("SU,SA", paramsFixed.get("WEEKENDS")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2014,1, 1); + //Until the 4th of April + Date until = date(2018, 1, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildYearlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + + assertEquals(4, dates.size()); + assertEquals("2014-01-04", dateFmt.format(dates.get(0))); + assertEquals("2015-01-03", dateFmt.format(dates.get(1))); + assertEquals("2016-01-02", dateFmt.format(dates.get(2))); + assertEquals("2017-01-01", dateFmt.format(dates.get(3))); + + } + + /** + * Testing the yearly recurrence rule for the second weekday of every January + */ + @Test + public void yearlyRecurrenceBySecondWeekdayMonth() + { + // Setting the yearly recurrence rule fo the second weekend day of every January + //FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYMONTH=1;BYSETPOS=2;INTERVAL=12 + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Recurrecne rule + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("BYDAY", "MO,TU,WE,TH,FR"); + params.put("BYMONTH", "1"); + params.put("BYSETPOS", "2"); + params.put("INTERVAL", "12"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals("YEARLY", paramsFixed.get("FREQ")); + assertEquals("2", paramsFixed.get("BYWEEKDAY")); + assertEquals("1", paramsFixed.get("INTERVAL")); + assertEquals("1", paramsFixed.get("BYMONTH")); + assertEquals("MO,TU,WE,TH,FR", paramsFixed.get("WEEKDAYS")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2014,1, 1); + //Until the 4th of April + Date until = date(2018, 1, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildYearlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + + assertEquals(4, dates.size()); + assertEquals("2014-01-02", dateFmt.format(dates.get(0))); + assertEquals("Thursday", fullDayFmt.format(dates.get(0))); + + assertEquals("2015-01-02", dateFmt.format(dates.get(1))); + assertEquals("Friday", fullDayFmt.format(dates.get(1))); + + assertEquals("2016-01-04", dateFmt.format(dates.get(2))); + assertEquals("Monday", fullDayFmt.format(dates.get(2))); + + assertEquals("2017-01-03", dateFmt.format(dates.get(3))); + assertEquals("Tuesday", fullDayFmt.format(dates.get(3))); + } + + /** + * Testing the yearly recurrence rule for the second weekend day of every January + */ + @Test + public void yearlyRecurrenceBySecondWeekendDayMonth() + { + // Setting the yearly recurrence rule fo the second weekend day of every January + //FREQ=MONTHLY;BYDAY=SU,SA;BYMONTH=1;BYSETPOS=2;INTERVAL=12 + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Recurrecne rule + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("BYDAY", "SU,SA"); + params.put("BYMONTH", "1"); + params.put("BYSETPOS", "2"); + params.put("INTERVAL", "12"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals("YEARLY", paramsFixed.get("FREQ")); + assertEquals("2", paramsFixed.get("BYWEEKENDDAY")); + assertEquals("1", paramsFixed.get("INTERVAL")); + assertEquals("1", paramsFixed.get("BYMONTH")); + assertEquals("SU,SA", paramsFixed.get("WEEKENDS")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2014,1, 1); + //Until the 4th of April + Date until = date(2018, 1, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildYearlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + + assertEquals(4, dates.size()); + assertEquals("2014-01-05", dateFmt.format(dates.get(0))); + assertEquals("Sunday", fullDayFmt.format(dates.get(0))); + + assertEquals("2015-01-04", dateFmt.format(dates.get(1))); + assertEquals("Sunday", fullDayFmt.format(dates.get(1))); + + assertEquals("2016-01-03", dateFmt.format(dates.get(2))); + assertEquals("Sunday", fullDayFmt.format(dates.get(2))); + + assertEquals("2017-01-07", dateFmt.format(dates.get(3))); + assertEquals("Saturday", fullDayFmt.format(dates.get(3))); + } + + /** + * Testing the yearly recurrence rule for the last day of every January + */ + @Test + public void yearlyRecurrenceByLastDayMonth() + { + // Setting the yearly recurrence rule fo the last day of every January + //FREQ=MONTHLY;BYDAY=SU,MO,TU,WE,TH,FR,SA;BYMONTH=1;BYSETPOS=-1;INTERVAL=12 + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Recurrecne rule + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("BYDAY", "SU,MO,TU,WE,TH,FR,SA"); + params.put("BYMONTH", "1"); + params.put("BYSETPOS", "-1"); + params.put("INTERVAL", "12"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals("YEARLY", paramsFixed.get("FREQ")); + assertEquals("-1", paramsFixed.get("BYANYDAY")); + assertEquals("1", paramsFixed.get("INTERVAL")); + assertEquals("1", paramsFixed.get("BYMONTH")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2014,1, 1); + //Until the 4th of April + Date until = date(2018, 1, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildYearlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + + assertEquals(4, dates.size()); + assertEquals("2014-01-31", dateFmt.format(dates.get(0))); + assertEquals("2015-01-31", dateFmt.format(dates.get(1))); + assertEquals("2016-01-31", dateFmt.format(dates.get(2))); + assertEquals("2017-01-31", dateFmt.format(dates.get(3))); + + } + + /** + * Testing the yearly recurrence rule for the last weekday of every January + */ + @Test + public void yearlyRecurrenceByLastWeekdayMonth() + { + // Setting the yearly recurrence rule fo the last weekday of every January + //FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYMONTH=1;BYSETPOS=-1;INTERVAL=12 + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Recurrecne rule + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("BYDAY", "MO,TU,WE,TH,FR"); + params.put("BYMONTH", "1"); + params.put("BYSETPOS", "-1"); + params.put("INTERVAL", "12"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals("YEARLY", paramsFixed.get("FREQ")); + assertEquals("-1", paramsFixed.get("BYWEEKDAY")); + assertEquals("1", paramsFixed.get("INTERVAL")); + assertEquals("1", paramsFixed.get("BYMONTH")); + assertEquals("MO,TU,WE,TH,FR", paramsFixed.get("WEEKDAYS")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2014,1, 1); + //Until the 4th of April + Date until = date(2018, 1, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildYearlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + + assertEquals(4, dates.size()); + assertEquals("2014-01-31", dateFmt.format(dates.get(0))); + assertEquals("Friday", fullDayFmt.format(dates.get(0))); + + assertEquals("2015-01-30", dateFmt.format(dates.get(1))); + assertEquals("Friday", fullDayFmt.format(dates.get(1))); + + assertEquals("2016-01-29", dateFmt.format(dates.get(2))); + assertEquals("Friday", fullDayFmt.format(dates.get(2))); + + assertEquals("2017-01-31", dateFmt.format(dates.get(3))); + assertEquals("Tuesday", fullDayFmt.format(dates.get(3))); + } + + /** + * Testing the yearly recurrence rule for the last weekend day of every January + */ + @Test + public void yearlyRecurrenceByLastWeekendDayMonth() + { + // Setting the yearly recurrence rule fo the last weekday of every January + //FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYMONTH=1;BYSETPOS=-1;INTERVAL=12 + List dates = new ArrayList<>(); + Calendar currentDate = Calendar.getInstance(); + + // Recurrecne rule + Map params = new HashMap<>(); + params.put("FREQ", "MONTHLY"); + params.put("BYDAY", "SU,SA"); + params.put("BYMONTH", "1"); + params.put("BYSETPOS", "-1"); + params.put("INTERVAL", "12"); + + Map paramsFixed = RecurrenceHelper.fixOutlookRecurrenceQuirks(params); + assertEquals("YEARLY", paramsFixed.get("FREQ")); + assertEquals("-1", paramsFixed.get("BYWEEKENDDAY")); + assertEquals("1", paramsFixed.get("INTERVAL")); + assertEquals("1", paramsFixed.get("BYMONTH")); + assertEquals("SU,SA", paramsFixed.get("WEEKENDS")); + + dates.clear(); + currentDate.set(2014, Calendar.JANUARY, 1, 10, 30); + + // on or after the 30 of December + Date onOrAfter = date(2014,1, 1); + //Until the 4th of April + Date until = date(2018, 1, 1); + boolean firstOnly = false; + int interval = Integer.parseInt(paramsFixed.get("INTERVAL")); + + assertEquals(1, interval); + + RecurrenceHelper.buildYearlyRecurrences(currentDate, dates, params, onOrAfter, until, firstOnly, interval); + + assertEquals(4, dates.size()); + assertEquals("2014-01-26", dateFmt.format(dates.get(0))); + assertEquals("Sunday", fullDayFmt.format(dates.get(0))); + + assertEquals("2015-01-31", dateFmt.format(dates.get(1))); + assertEquals("Saturday", fullDayFmt.format(dates.get(1))); + + assertEquals("2016-01-31", dateFmt.format(dates.get(2))); + assertEquals("Sunday", fullDayFmt.format(dates.get(2))); + + assertEquals("2017-01-29", dateFmt.format(dates.get(3))); + assertEquals("Sunday", fullDayFmt.format(dates.get(3))); + } + /** * eg every 21st of February diff --git a/source/test-java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelperTest.java b/source/test-java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelperTest.java index d0925a5756..c3b905c27f 100644 --- a/source/test-java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelperTest.java +++ b/source/test-java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelperTest.java @@ -18,12 +18,13 @@ */ package org.alfresco.service.cmr.calendar; -import static org.junit.Assert.*; +import org.junit.Test; import java.util.HashMap; import java.util.Map; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; /** * Tests for the {@link CalendarRecurrenceHelper} class. @@ -69,7 +70,43 @@ public class CalendarRecurrenceHelperTest // Double check we're not just comparing in with itself. assertNotSame(in, out); } - + + // MNT-10006 fix. Validates the patterns 'weekday', 'weekend day', 'day' + @Test + public void fixOutLookRecurrenceQuirks_weekdayRecurrenceRule() + { + Map recurrenceRule = Params.fromKVPs("FREQ=MONTHLY", "BYDAY=MO,TU,WE,TH,FR", "INTERVAL=1", "BYSETPOS=1"); + Map fixedRecurrenceRule = CalendarRecurrenceHelper.fixOutlookRecurrenceQuirks(Params.fromMap(recurrenceRule)); + + assertEquals(null, fixedRecurrenceRule.get("BYDAY")); + assertEquals(null, fixedRecurrenceRule.get("BYSETPOS")); + assertEquals("1", fixedRecurrenceRule.get("BYWEEKDAY")); + assertEquals("MO,TU,WE,TH,FR", fixedRecurrenceRule.get("WEEKDAYS")); + } + + @Test + public void fixOutLookRecurrenceQuirks_weekendDayRecurrenceRule() + { + Map recurrenceRule = Params.fromKVPs("FREQ=MONTHLY", "BYDAY=SU,SA", "INTERVAL=1", "BYSETPOS=1"); + Map fixedRecurrenceRule = CalendarRecurrenceHelper.fixOutlookRecurrenceQuirks(Params.fromMap(recurrenceRule)); + + assertEquals(null, fixedRecurrenceRule.get("BYDAY")); + assertEquals(null, fixedRecurrenceRule.get("BYSETPOS")); + assertEquals("1", fixedRecurrenceRule.get("BYWEEKENDDAY")); + assertEquals("SU,SA", fixedRecurrenceRule.get("WEEKENDS")); + } + + @Test + public void fixOutLookRecurrenceQuirks_dayRecurrenceRule() + { + Map recurrenceRule = Params.fromKVPs("FREQ=MONTHLY", "BYDAY=SU,MO,TU,WE,TH,FR,SA", "INTERVAL=1", "BYSETPOS=1"); + Map fixedRecurrenceRule = CalendarRecurrenceHelper.fixOutlookRecurrenceQuirks(Params.fromMap(recurrenceRule)); + + assertEquals("1", fixedRecurrenceRule.get("BYANYDAY")); + assertEquals(null, fixedRecurrenceRule.get("BYSETPOS")); + assertEquals(null, fixedRecurrenceRule.get("BYMONTHDAY")); + assertEquals("SU,MO,TU,WE,TH,FR,SA", fixedRecurrenceRule.get("DAY")); + } /** * Inner class just here to make the tests more readable.