Java tutorial
/* LanguageTool, a natural language style checker * Copyright (C) 2018 Fabian Richter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 * USA */ package org.languagetool.rules; import org.apache.commons.lang3.StringUtils; import org.languagetool.AnalyzedTokenReadings; import org.languagetool.rules.patterns.RuleFilter; import java.util.Calendar; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Checks if a given date is in the future * Used for mismatch detection between verb tense and a given date * @since 4.3 */ public abstract class AbstractFutureDateFilter extends RuleFilter { private static final Pattern DAY_OF_MONTH_PATTERN = Pattern.compile("(\\d+).*"); /** * Implement so that "first" returns {@code 1}, second returns {@code 2} etc. * @param localizedDayOfMonth name of day of the month or abbreviation thereof */ protected int getDayOfMonth(String localizedDayOfMonth) { return 0; } /** * Implement so that January returns {@code 1}, February {@code 2} etc. * @param localizedMonth name of a month or abbreviation thereof */ protected abstract int getMonth(String localizedMonth); protected abstract Calendar getCalendar(); /** * @param args a map with values for {@code year}, {@code month}, {@code day} (day of month), {@code weekDay} */ @Override public RuleMatch acceptRuleMatch(RuleMatch match, Map<String, String> args, AnalyzedTokenReadings[] patternTokens) { Calendar dateFromDate = getDate(args); Calendar currentDate = getCalendar(); if (TestHackHelper.isJUnitTest()) { currentDate = new Calendar.Builder().setDate(2014, 0, 1).build(); } try { if (dateFromDate.after(currentDate)) { return match; } else { return null; } } catch (IllegalArgumentException ignore) { // happens with 'dates' like '32.8.2014' - those should be caught by a different rule return null; } } protected String getRequired(String key, Map<String, String> map) { String result = map.get(key); if (result == null) { throw new IllegalArgumentException("Missing key '" + key + "'"); } return result; } private Calendar getDate(Map<String, String> args) { int year = Integer.parseInt(getRequired("year", args)); int month = getMonthFromArguments(args); int dayOfMonth = getDayOfMonthFromArguments(args); Calendar calendar = getCalendar(); calendar.setLenient(false); // be strict about validity of dates //noinspection MagicConstant calendar.set(year, month, dayOfMonth, 0, 0, 0); return calendar; } private int getDayOfMonthFromArguments(Map<String, String> args) { String dayOfMonthString = getRequired("day", args); int dayOfMonth; Matcher matcherDayOfMonth = DAY_OF_MONTH_PATTERN.matcher(dayOfMonthString); if (matcherDayOfMonth.matches()) { // The day of the month is a number, possibly with a suffix such // as "22nd" for example. dayOfMonth = Integer.parseInt(matcherDayOfMonth.group(1)); } else { // In some languages, the day of the month can also be written with // letters rather than with digits, so parse localized numbers. dayOfMonth = getDayOfMonth(dayOfMonthString); } return dayOfMonth; } private int getMonthFromArguments(Map<String, String> args) { String monthStr = getRequired("month", args); int month; if (StringUtils.isNumeric(monthStr)) { month = Integer.parseInt(monthStr); } else { month = getMonth(monthStr); } return month - 1; } }