Coverage Report - de.jollyday.parser.AbstractHolidayParser
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractHolidayParser
81%
36/44
73%
38/52
4,429
 
 1  
 /**
 2  
  * Copyright 2010 Sven Diedrichsen
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an
 12  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 13  
  * express or implied. See the License for the specific language
 14  
  * governing permissions and limitations under the License.
 15  
  */
 16  
 package de.jollyday.parser;
 17  
 
 18  
 import de.jollyday.config.*;
 19  
 import de.jollyday.util.CalendarUtil;
 20  
 import de.jollyday.util.XMLUtil;
 21  
 
 22  
 import java.time.DayOfWeek;
 23  
 import java.time.LocalDate;
 24  
 
 25  
 /**
 26  
  * The abstract base class for all HolidayParser implementations.
 27  
  *
 28  
  * @author Sven Diedrichsen
 29  
  */
 30  90
 public abstract class AbstractHolidayParser implements HolidayParser {
 31  
 
 32  
         private static final String EVERY_YEAR = "EVERY_YEAR";
 33  
         private static final String ODD_YEARS = "ODD_YEARS";
 34  
         private static final String EVEN_YEARS = "EVEN_YEARS";
 35  
         private static final String TWO_YEARS = "2_YEARS";
 36  
         private static final String THREE_YEARS = "3_YEARS";
 37  
         private static final String FOUR_YEARS = "4_YEARS";
 38  
         private static final String FIVE_YEARS = "5_YEARS";
 39  
         private static final String SIX_YEARS = "6_YEARS";
 40  
 
 41  
         /**
 42  
          * Calendar utility class.
 43  
          */
 44  90
         protected CalendarUtil calendarUtil = new CalendarUtil();
 45  
         /**
 46  
          * XML utility class.
 47  
          */
 48  90
         protected XMLUtil xmlUtil = new XMLUtil();
 49  
 
 50  
         /**
 51  
          * Evaluates if the provided <code>Holiday</code> instance is valid for the
 52  
          * provided year.
 53  
          *
 54  
          * @param <T> a {@link Holiday} subclass
 55  
          * @param h
 56  
          *            The holiday configuration entry to validate
 57  
          * @param year
 58  
          *            The year to validate against.
 59  
          * @return is valid for the year.
 60  
          */
 61  
         protected <T extends Holiday> boolean isValid(T h, int year) {
 62  2966
                 return isValidInYear(h, year) && isValidForCycle(h, year);
 63  
         }
 64  
 
 65  
         /**
 66  
          * Checks cyclic holidays and checks if the requested year is hit within the
 67  
          * cycles.
 68  
          *
 69  
          * @param h Holiday to be valid in cycle
 70  
          * @param year the year for the holiday to be valid in
 71  
          * @return is valid
 72  
          */
 73  
         private <T extends Holiday> boolean isValidForCycle(T h, int year) {
 74  2827
                 if (h.getEvery() != null) {
 75  2827
                         if (!EVERY_YEAR.equals(h.getEvery())) {
 76  5
                                 if (ODD_YEARS.equals(h.getEvery())) {
 77  0
                                         return year % 2 != 0;
 78  5
                                 } else if (EVEN_YEARS.equals(h.getEvery())) {
 79  1
                                         return year % 2 == 0;
 80  
                                 } else {
 81  4
                                         if (h.getValidFrom() != null) {
 82  
                                                 int cycleYears;
 83  4
                                                 if (TWO_YEARS.equalsIgnoreCase(h.getEvery())) {
 84  2
                                                         cycleYears = 2;
 85  2
                                                 } else if (THREE_YEARS.equalsIgnoreCase(h.getEvery())) {
 86  2
                                                         cycleYears = 3;
 87  0
                                                 } else if (FOUR_YEARS.equalsIgnoreCase(h.getEvery())) {
 88  0
                                                         cycleYears = 4;
 89  0
                                                 } else if (FIVE_YEARS.equalsIgnoreCase(h.getEvery())) {
 90  0
                                                         cycleYears = 5;
 91  0
                                                 } else if (SIX_YEARS.equalsIgnoreCase(h.getEvery())) {
 92  0
                                                         cycleYears = 6;
 93  
                                                 } else {
 94  0
                                                         throw new IllegalArgumentException("Cannot handle unknown cycle type '" + h.getEvery()
 95  
                                                                         + "'.");
 96  
                                                 }
 97  4
                                                 return (year - h.getValidFrom()) % cycleYears == 0;
 98  
                                         }
 99  
                                 }
 100  
                         }
 101  
                 }
 102  2822
                 return true;
 103  
         }
 104  
 
 105  
         /**
 106  
          * Checks whether the holiday is within the valid date range.
 107  
          *
 108  
          * @param h the holiday to check for validity
 109  
          * @param year the year to check the holiday to be valid in
 110  
          * @return the holiday is valid
 111  
          */
 112  
         private <T extends Holiday> boolean isValidInYear(T h, int year) {
 113  2966
                 return (h.getValidFrom() == null || h.getValidFrom() <= year)
 114  2960
                                 && (h.getValidTo() == null || h.getValidTo() >= year);
 115  
         }
 116  
 
 117  
         /**
 118  
          * Moves a date if there are any moving conditions for this holiday and any
 119  
          * of them fit.
 120  
          *
 121  
          * @param fm
 122  
          *            a {@link de.jollyday.config.MoveableHoliday} object.
 123  
          * @param fixed
 124  
          *            a {@link LocalDate} object.
 125  
          * @return the moved date
 126  
          */
 127  
         protected LocalDate moveDate(MoveableHoliday fm, LocalDate fixed) {
 128  2397
                 for (MovingCondition mc : fm.getMovingCondition()) {
 129  76
                         if (shallBeMoved(fixed, mc)) {
 130  40
                                 fixed = moveDate(mc, fixed);
 131  40
                                 break;
 132  
                         }
 133  36
                 }
 134  2397
                 return fixed;
 135  
         }
 136  
 
 137  
         /**
 138  
          * Determines if the provided date shall be substituted.
 139  
          *
 140  
          * @param fixed
 141  
          *            a {@link LocalDate} object.
 142  
          * @param mc
 143  
          *            a {@link de.jollyday.config.MovingCondition} object.
 144  
          * @return a boolean.
 145  
          */
 146  
         protected boolean shallBeMoved(LocalDate fixed, MovingCondition mc) {
 147  76
                 return fixed.getDayOfWeek() == xmlUtil.getWeekday(mc.getSubstitute());
 148  
         }
 149  
 
 150  
         /**
 151  
          * Moves the date using the FixedMoving information
 152  
          *
 153  
          * @param mc the moving condition
 154  
          * @param fixed the date to move
 155  
          * @return the eventually moved date
 156  
          */
 157  
         private LocalDate moveDate(MovingCondition mc, LocalDate fixed) {
 158  40
                 DayOfWeek weekday = xmlUtil.getWeekday(mc.getWeekday());
 159  40
                 int direction = (mc.getWith() == With.NEXT ? 1 : -1);
 160  109
                 while (fixed.getDayOfWeek() != weekday) {
 161  69
                         fixed = fixed.plusDays(direction);
 162  
                 }
 163  40
                 return fixed;
 164  
         }
 165  
 
 166  
         /**
 167  
          * <p>
 168  
          * getEasterSunday.
 169  
          * </p>
 170  
          *
 171  
          * @param year
 172  
          *            a int.
 173  
          * @param ct
 174  
          *            a {@link de.jollyday.config.ChronologyType} object.
 175  
          * @return a {@link LocalDate} object.
 176  
          */
 177  
         protected LocalDate getEasterSunday(int year, ChronologyType ct) {
 178  
                 LocalDate easterSunday;
 179  323
                 if (ct == ChronologyType.JULIAN) {
 180  3
                         easterSunday = calendarUtil.getJulianEasterSunday(year);
 181  320
                 } else if (ct == ChronologyType.GREGORIAN) {
 182  8
                         easterSunday = calendarUtil.getGregorianEasterSunday(year);
 183  
                 } else {
 184  312
                         easterSunday = calendarUtil.getEasterSunday(year);
 185  
                 }
 186  323
                 return easterSunday;
 187  
         }
 188  
 
 189  
 }