package org.ff4j.strategy.time; /* * #%L * ff4j-core * %% * Copyright (C) 2013 - 2015 Ff4J * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; import org.ff4j.core.FeatureStore; import org.ff4j.core.FlippingExecutionContext; import org.ff4j.strategy.AbstractFlipStrategy; /** * Implemenetation of an office hour strategy. * * Expression { "monday":["08:00-12:00", "13:30-18:00"], "tuesday":[], "wednesday":[], "thursday":[],"friday":[],"saturday":[] } * * @author Cedrick Lunven (@clunven) */ public class OfficeHourStrategy extends AbstractFlipStrategy { /** Parsing date expression. */ private static final DateFormat SDF_DATE = new SimpleDateFormat("yyyy-MM-dd"); /** Constants. */ private static final String MONDAY = "monday"; /** Constants. */ private static final String TUESDAY = "tuesday"; /** Constants. */ private static final String WEDNESDAY = "wednesday"; /** Constants. */ private static final String THURSDAY = "thursday"; /** Constants. */ private static final String FRIDAY = "friday"; /** Constants. */ private static final String SATURDAY = "saturday"; /** Constants. */ private static final String SUNDAY = "sunday"; /** Constants. */ private static final String PUBLICHOLIDAY = "publicHolidays"; /** Constants. */ private static final String SPECIAL_OPENINGS = "specialOpenings"; /** Contacts. */ public static final String OVERRIDE_DATE = "overridedDate"; /** time table. */ private Map < Integer, List <HourInterval>> weekTimeTable = new HashMap<Integer, List<HourInterval>>(); /** openings. */ private Map < String, List < HourInterval>> specialTimeTable = new HashMap< String, List<HourInterval>>(); /** public holiday. */ private List < String > publicHolidays = new ArrayList<String>(); /** {@inheritDoc} */ @Override public void init(String featureName, Map<String, String> initParam) { super.init(featureName, initParam); // Update week timetable weekTimeTable.put(Calendar.MONDAY, parseIntervalsExpression(initParam.get(MONDAY))); weekTimeTable.put(Calendar.TUESDAY, parseIntervalsExpression(initParam.get(TUESDAY))); weekTimeTable.put(Calendar.WEDNESDAY, parseIntervalsExpression(initParam.get(WEDNESDAY))); weekTimeTable.put(Calendar.THURSDAY, parseIntervalsExpression(initParam.get(THURSDAY))); weekTimeTable.put(Calendar.FRIDAY, parseIntervalsExpression(initParam.get(FRIDAY))); weekTimeTable.put(Calendar.SATURDAY, parseIntervalsExpression(initParam.get(SATURDAY))); weekTimeTable.put(Calendar.SUNDAY, parseIntervalsExpression(initParam.get(SUNDAY))); // Update publiholidays if (initParam.containsKey(PUBLICHOLIDAY)) { String[] days = initParam.get(PUBLICHOLIDAY).split(","); for (String day : days) { try { Calendar c = Calendar.getInstance(); c.setTime(SDF_DATE.parse(day.trim())); c.set(Calendar.MILLISECOND, 0); c.set(Calendar.SECOND, 0); c.set(Calendar.MINUTE, 0); c.set(Calendar.HOUR_OF_DAY, 0); publicHolidays.add(SDF_DATE.format(c.getTime())); } catch (ParseException e) { throw new IllegalArgumentException("Invalid Syntax for <" + day + "> expected 'yyyy-MM-dd'", e); } } } // Update exclusive openings if (initParam.containsKey(SPECIAL_OPENINGS)) { String[] days = initParam.get(SPECIAL_OPENINGS).split(";"); for (String day : days) { String[] partDay = day.split("@"); if (partDay.length != 2) { throw new IllegalArgumentException("Invalid Syntax"); } // Check format at loading String dateExpression = partDay[1].trim(); try { SDF_DATE.parse(dateExpression); String inter = partDay[0].trim(); String extractIntervals = inter.substring(1, inter.length() -1); specialTimeTable.put(dateExpression, parseIntervalsExpression(extractIntervals)); } catch (ParseException e) { throw new IllegalArgumentException("Invalid Syntax for '" + dateExpression + "' expected 'yyyy-MM-dd'", e); } } } } /** * Parse Target expression. * * @param expression * target expression * @return * list of hour interval */ public List < HourInterval > parseIntervalsExpression(String expression) { // Always close List < HourInterval > lhi = new ArrayList<HourInterval>(); if (expression != null && !"".equals(expression)) { String[] chunks = expression.split(","); for (String chunk : chunks) { lhi.add(new HourInterval(chunk)); } } return lhi; } /** * Check if present time is at least in of the hour Interval. * * @param listOfHI * enable to list hour intervals * @return * if one of the interval matches */ public boolean matches(Calendar cal, List < HourInterval > listOfHI) { if (listOfHI == null) return false; int idx = 0; boolean found = false; while (!found && idx<listOfHI.size()) { found = listOfHI.get(idx).matches(cal); idx++; } return found; } /** {@inheritDoc} */ @Override public boolean evaluate(String featureName, FeatureStore store, FlippingExecutionContext executionContext) { // Check current date agains interval Calendar now = Calendar.getInstance(); if (executionContext != null && executionContext.containsKey(OVERRIDE_DATE)) { now = (Calendar) executionContext.getValue(OVERRIDE_DATE, false); } // Priority 1 : Special Opening String currentDate = SDF_DATE.format(now.getTime()); if (specialTimeTable.containsKey(currentDate)) { // Today is in special openings, apply return matches(now, specialTimeTable.get(currentDate)); } // Priority 2 : Public Holiday => CLOSED if (publicHolidays.contains(currentDate)) { return false; } // Default behavior, get current day, retrive intervals and check return matches(now, weekTimeTable.get(now.get(Calendar.DAY_OF_WEEK))); } }