diff --git a/src/main/java/de/jollyday/AbstractI18nObject.java b/src/main/java/de/jollyday/AbstractI18nObject.java new file mode 100644 index 00000000..f4a0f1c9 --- /dev/null +++ b/src/main/java/de/jollyday/AbstractI18nObject.java @@ -0,0 +1,93 @@ +/** + * Copyright 2019 Sven Diedrichsen + * + * 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. + */ +package de.jollyday; + +import java.util.Locale; + +import de.jollyday.util.ResourceUtil; + +/** + * Represents a localizable object. + * + * @author Christoph Weitkamp + * @version $Id: $ + */ +public abstract class AbstractI18nObject { + /** + * The calculated hashcode cached for performance. + */ + protected int hashCode = 0; + /** + * The properties key to retrieve the description with. + */ + protected final String propertiesKey; + + /** + * Utility for accessing resources. + */ + private final ResourceUtil resourceUtil = new ResourceUtil(); + + /** + * Constructs a country using the provided ISO code to retrieve the + * description with. + * + * @param propertiesKey + * a {@link java.lang.String} object. + */ + public AbstractI18nObject(String propertiesKey) { + super(); + this.propertiesKey = propertiesKey; + } + + /** + *

+ * Getter for the propertiesKey. + *

+ * + * @return the country properties key + */ + public String getPropertiesKey() { + return propertiesKey; + } + + /** + * The description read with the default locale. + * + * @return Description for this object + */ + public String getDescription() { + return resourceUtil.getHolidayDescription(Locale.getDefault(), propertiesKey); + } + + /** + * The description read with the provided locale. + * + * @param locale + * a {@link java.util.Locale} object. + * @return Description for this object + */ + public String getDescription(Locale locale) { + return resourceUtil.getHolidayDescription(locale, propertiesKey); + } + + @Override + public String toString() { + return propertiesKey + " (" + getDescription() + ")"; + } + + @Override + public abstract int hashCode(); +} diff --git a/src/main/java/de/jollyday/City.java b/src/main/java/de/jollyday/City.java new file mode 100644 index 00000000..1cde11d1 --- /dev/null +++ b/src/main/java/de/jollyday/City.java @@ -0,0 +1,126 @@ +/** + * Copyright 2019 Sven Diedrichsen + * + * 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. + */ +package de.jollyday; + +/** + * Represents a city and contains the city code and a localized description. + * + * @author Christoph Weitkamp + * @version $Id: $ + */ +public final class City extends AbstractI18nObject implements Comparable { + /** + * The ISO code to retrieve the description with. + */ + private final String isoCode; + /** + * The region code to retrieve the description with. + */ + private final String regionCode; + /** + * The city code to retrieve the description with. + */ + private final String code; + + /** + * Constructs a city using the provided code to retrieve the description + * with. + * + * @param isoCode + * a {@link java.lang.String} object. + * @param regionCode + * a {@link java.lang.String} object. + * @param code + * a {@link java.lang.String} object. + */ + public City(String isoCode, String regionCode, String code) { + super(isoCode + "." + regionCode + "." + code); + this.isoCode = isoCode; + this.regionCode = regionCode; + this.code = code; + } + + /** + *

+ * Getter for the field isoCode. + *

+ * + * @return the ISO code + */ + public String getISOCode() { + return isoCode; + } + + /** + *

+ * Getter for the field regionCode. + *

+ * + * @return the region code + */ + public String getRegionCode() { + return regionCode; + } + + /** + *

+ * Getter for the field code. + *

+ * + * @return the city code + */ + public String getCode() { + return code; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof City) { + City other = (City) obj; + return isoCode.equals(other.isoCode) && regionCode.equals(other.regionCode) && code.equals(other.code); + } + return false; + } + + @Override + public int hashCode() { + if (hashCode == 0) { + int hash = 1; + hash = hash * 31 + isoCode.hashCode(); + hash = hash * 31 + regionCode.hashCode(); + hash = hash * 31 + code.hashCode(); + hashCode = hash; + } + return hashCode; + } + + /** + * Compares this city to another city. + * + * The comparison is primarily based on the city code. + * + * @param other + * the other city to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public int compareTo(City other) { + return code.compareTo(other.code); + } +} diff --git a/src/main/java/de/jollyday/Country.java b/src/main/java/de/jollyday/Country.java new file mode 100644 index 00000000..fc30901a --- /dev/null +++ b/src/main/java/de/jollyday/Country.java @@ -0,0 +1,116 @@ +/** + * Copyright 2019 Sven Diedrichsen + * + * 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. + */ +package de.jollyday; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * Represents a country. It contains the ISO code, a localized description and a + * list of regions. + * + * @author Christoph Weitkamp + * @version $Id: $ + */ +public final class Country extends AbstractI18nObject implements Comparable { + /** + * The ISO code to retrieve the description with. + */ + private final String isoCode; + /** + * A list of regions inside this country + */ + private final Set regions = new HashSet<>(0); + + /** + * Constructs a country using the provided ISO code to retrieve the + * description with. + * + * @param isoCode + * a {@link java.lang.String} object. + */ + public Country(String isoCode) { + super(isoCode); + this.isoCode = isoCode; + } + + /** + *

+ * Getter for the field isoCode. + *

+ * + * @return the ISO code + */ + public String getISOCode() { + return isoCode; + } + + /** + * Adds a {@link Region} to this country. + * + * @param region + * a {@link Region} object. + */ + public void addRegion(Region region) { + regions.add(region); + } + + /** + * The {@link Region}s of this country. + * + * @return an unmodifiable set of {@link Region}s of this country + */ + public Set getRegions() { + return Collections.unmodifiableSet(regions); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Country) { + Country other = (Country) obj; + return isoCode.equals(other.isoCode) && regions.equals(other.regions); + } + return false; + } + + @Override + public int hashCode() { + if (hashCode == 0) { + int hash = 1; + hash = hash * 31 + isoCode.hashCode(); + hashCode = hash; + } + return hashCode; + } + + /** + * Compares this country to another country. + * + * The comparison is primarily based on the ISO code. + * + * @param other + * the other country to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public int compareTo(Country other) { + return isoCode.compareTo(other.isoCode); + } +} diff --git a/src/main/java/de/jollyday/Holiday.java b/src/main/java/de/jollyday/Holiday.java index 047355c2..72f89fb6 100644 --- a/src/main/java/de/jollyday/Holiday.java +++ b/src/main/java/de/jollyday/Holiday.java @@ -15,40 +15,24 @@ */ package de.jollyday; -import de.jollyday.util.ResourceUtil; - import java.time.LocalDate; -import java.util.Locale; /** - * Represents the holiday and contains the actual date and an localized + * Represents the holiday and contains the actual date and a localized * description. * * @author Sven Diedrichsen * @version $Id: $ */ -public final class Holiday implements Comparable { - /** - * The calculated hashcode cached for performance. - */ - private int hashCode = 0; +public final class Holiday extends AbstractI18nObject implements Comparable { /** * The date the holiday occurs. */ private final LocalDate date; - /** - * The properties key to retrieve the description with. - */ - private final String propertiesKey; - /** * The type of holiday. e.g. official holiday or not. - * */ - private final HolidayType type; - /** - * Utility for accessing resources. */ - private final ResourceUtil resourceUtil = new ResourceUtil(); + private final HolidayType type; /** * Constructs a holiday for a date using the provided properties key to @@ -62,10 +46,9 @@ public final class Holiday implements Comparable { * a {@link de.jollyday.HolidayType} object. */ public Holiday(LocalDate date, String propertiesKey, HolidayType type) { - super(); - this.type = type; + super(propertiesKey == null ? "" : propertiesKey); this.date = date; - this.propertiesKey = propertiesKey == null ? "" : propertiesKey; + this.type = type; } /** @@ -79,37 +62,6 @@ public LocalDate getDate() { return date; } - /** - *

- * Getter for the field propertiesKey. - *

- * - * @return the holidays properties key - */ - public String getPropertiesKey() { - return propertiesKey; - } - - /** - * The description read with the default locale. - * - * @return Description for this holiday - */ - public String getDescription() { - return resourceUtil.getHolidayDescription(Locale.getDefault(), getPropertiesKey()); - } - - /** - * The description read with the provided locale. - * - * @param locale - * a {@link java.util.Locale} object. - * @return Description for this holiday - */ - public String getDescription(Locale locale) { - return resourceUtil.getHolidayDescription(locale, getPropertiesKey()); - } - @Override public boolean equals(Object obj) { if (obj == this) { @@ -117,8 +69,7 @@ public boolean equals(Object obj) { } if (obj instanceof Holiday) { Holiday other = (Holiday) obj; - return other.date.equals(this.date) && other.propertiesKey.equals(this.propertiesKey) - && type.equals(other.type); + return date.equals(other.date) && propertiesKey.equals(other.propertiesKey) && type.equals(other.type); } return false; } @@ -152,13 +103,15 @@ public HolidayType getType() { /** * Compares this holiday to another holiday. * - * The comparison is primarily based on the date, from earliest to latest by using the LocalDate comparator. + * The comparison is primarily based on the date, from earliest to latest by + * using the LocalDate comparator. * - * @param other the other holiday to compare to, not null + * @param other + * the other holiday to compare to, not null * @return the comparator value, negative if less, positive if greater */ @Override public int compareTo(Holiday other) { - return this.getDate().compareTo(other.getDate()); + return date.compareTo(other.date); } } diff --git a/src/main/java/de/jollyday/Region.java b/src/main/java/de/jollyday/Region.java new file mode 100644 index 00000000..ed5c9a88 --- /dev/null +++ b/src/main/java/de/jollyday/Region.java @@ -0,0 +1,135 @@ +/** + * Copyright 2019 Sven Diedrichsen + * + * 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. + */ +package de.jollyday; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * Represents a region. It contains the region code, a localized description and + * a list of cities. + * + * @author Christoph Weitkamp + * @version $Id: $ + */ +public final class Region extends AbstractI18nObject implements Comparable { + /** + * The ISO code to retrieve the description with. + */ + private final String isoCode; + /** + * The code to retrieve the description with. + */ + private final String code; + /** + * A list of cities inside this region + */ + private final Set cities = new HashSet<>(0); + + /** + * Constructs a region using the provided code to retrieve the description + * with. + * + * @param isoCode + * a {@link java.lang.String} object. + * @param code + * a {@link java.lang.String} object. + */ + public Region(String isoCode, String code) { + super(isoCode + "." + code); + this.isoCode = isoCode; + this.code = code; + } + + /** + *

+ * Getter for the field isoCode. + *

+ * + * @return the ISO code + */ + public String getISOCode() { + return isoCode; + } + + /** + *

+ * Getter for the field code. + *

+ * + * @return the region code + */ + public String getCode() { + return code; + } + + /** + * Adds a {@link City} to this region. + * + * @param city + * a {@link City} object. + */ + public void addCity(City city) { + cities.add(city); + } + + /** + * The {@link City Cities} of this region. + * + * @return an unmodifiable set of {@link City Cities} of this region + */ + public Set getCities() { + return Collections.unmodifiableSet(cities); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Region) { + Region other = (Region) obj; + return isoCode.equals(other.isoCode) && code.equals(other.code) && cities.equals(other.cities); + } + return false; + } + + @Override + public int hashCode() { + if (hashCode == 0) { + int hash = 1; + hash = hash * 31 + isoCode.hashCode(); + hash = hash * 31 + code.hashCode(); + hashCode = hash; + } + return hashCode; + } + + /** + * Compares this region to another region. + * + * The comparison is primarily based on the region code. + * + * @param other + * the other region to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public int compareTo(Region other) { + return code.compareTo(other.code); + } +} diff --git a/src/main/java/de/jollyday/util/ResourceUtil.java b/src/main/java/de/jollyday/util/ResourceUtil.java index d22910e7..39fd9f7d 100644 --- a/src/main/java/de/jollyday/util/ResourceUtil.java +++ b/src/main/java/de/jollyday/util/ResourceUtil.java @@ -16,9 +16,19 @@ package de.jollyday.util; import java.net.URL; -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import de.jollyday.City; +import de.jollyday.Country; +import de.jollyday.Region; + /** *

* ResourceUtil class. @@ -32,6 +42,9 @@ public class ResourceUtil { * Property prefix for country descriptions. */ private static final String COUNTRY_PROPERTY_PREFIX = "country.description"; + private static final int COUNTRY_INDEX = 2; + private static final int REGION_INDEX = 3; + private static final int CITY_INDEX = 4; /** * Property prefix for holiday descriptions. */ @@ -66,7 +79,8 @@ public class ResourceUtil { * The description read with the default locale. * * @return holiday description using default locale. - * @param key a {@link java.lang.String} object. + * @param key + * a {@link java.lang.String} object. */ public String getHolidayDescription(String key) { return getHolidayDescription(Locale.getDefault(), key); @@ -75,9 +89,11 @@ public String getHolidayDescription(String key) { /** * The description read with the provided locale. * - * @param locale a {@link java.util.Locale} object. + * @param locale + * a {@link java.util.Locale} object. * @return holiday description using the provided locale. - * @param key a {@link java.lang.String} object. + * @param key + * a {@link java.lang.String} object. */ public String getHolidayDescription(Locale locale, String key) { return getDescription(HOLIDAY_PROPERTY_PREFIX + "." + key, getHolidayDescriptions(locale)); @@ -89,7 +105,8 @@ public String getHolidayDescription(Locale locale, String key) { *

* * @return the description - * @param key a {@link java.lang.String} object. + * @param key + * a {@link java.lang.String} object. */ public String getCountryDescription(String key) { return getCountryDescription(Locale.getDefault(), key); @@ -98,8 +115,10 @@ public String getCountryDescription(String key) { /** * Returns the hierarchies description text from the resource bundle. * - * @param l Locale to return the description text for. - * @param key a {@link java.lang.String} object. + * @param l + * Locale to return the description text for. + * @param key + * a {@link java.lang.String} object. * @return Description text */ public String getCountryDescription(Locale l, String key) { @@ -119,19 +138,93 @@ public Set getISOCodes() { ResourceBundle countryDescriptions = getCountryDescriptions(Locale.getDefault()); for (String property : Collections.list(countryDescriptions.getKeys())) { String[] split = property.split("\\."); - if (split.length > 2) { - codes.add(split[2].toLowerCase()); + if (split.length > COUNTRY_INDEX) { + codes.add(split[COUNTRY_INDEX].toLowerCase()); } } return codes; } + /** + * TODO + * + * @return + */ + public Set getCountries() { + Set contries = new HashSet<>(); + ResourceBundle countryDescriptions = getCountryDescriptions(Locale.getDefault()); + for (String property : Collections.list(countryDescriptions.getKeys())) { + String[] split = property.split("\\."); + if (split.length > COUNTRY_INDEX) { + contries.add(new Country(split[COUNTRY_INDEX].toLowerCase())); + } + } + return contries; + } + + /** + * TODO + * + * @return + */ + public Map> getRegions(String isoCode) { + Map> regions = new HashMap<>(); + ResourceBundle countryDescriptions = getCountryDescriptions(Locale.getDefault()); + for (String property : Collections.list(countryDescriptions.getKeys())) { + String[] split = property.split("\\."); + if (split.length > REGION_INDEX) { + String countryCode = split[COUNTRY_INDEX].toLowerCase(); + if (isoCode.equals(countryCode)) { + Region region = new Region(countryCode, split[REGION_INDEX].toLowerCase()); + if (regions.containsKey(region.getISOCode())) { + regions.get(region.getISOCode()).add(region); + } else { + Set internalRegions = new HashSet<>(); + internalRegions.add(region); + regions.put(region.getISOCode(), internalRegions); + } + } + } + } + return regions; + } + + /** + * TODO + * + * @return + */ + public Map> getCitys(String regionCode) { + Map> cities = new HashMap<>(); + ResourceBundle countryDescriptions = getCountryDescriptions(Locale.getDefault()); + for (String property : Collections.list(countryDescriptions.getKeys())) { + String[] split = property.split("\\."); + if (split.length > CITY_INDEX) { + String internalRegionCode = split[REGION_INDEX].toLowerCase(); + if (regionCode.equals(internalRegionCode)) { + City city = new City(split[COUNTRY_INDEX].toLowerCase(), internalRegionCode, + split[CITY_INDEX].toLowerCase()); + if (cities.containsKey(city.getRegionCode())) { + cities.get(city.getRegionCode()).add(city); + } else { + Set internalCities = new HashSet<>(); + internalCities.add(city); + cities.put(city.getRegionCode(), internalCities); + } + } + } + } + return cities; + } + /** * Returns the description from the resource bundle if the key is contained. * It will return 'undefined' otherwise. * - * @param key the key to get the description from - * @param bundle the bundle to get the description + * @param key + * the key to get the description from + * @param bundle + * the bundle to get the description * @return description the description behind the key */ private String getDescription(String key, final ResourceBundle bundle) { @@ -145,7 +238,8 @@ private String getDescription(String key, final ResourceBundle bundle) { * Returns the eventually cached ResourceBundle for the holiday * descriptions. * - * @param l Locale to retrieve the descriptions for. + * @param l + * Locale to retrieve the descriptions for. * @return ResourceBundle containing the descriptions for the locale. */ private ResourceBundle getHolidayDescriptions(Locale l) { @@ -156,7 +250,8 @@ private ResourceBundle getHolidayDescriptions(Locale l) { * Returns the eventually cached ResourceBundle for the holiday * descriptions. * - * @param l Locale to retrieve the descriptions for. + * @param l + * Locale to retrieve the descriptions for. * @return ResourceBundle containing the descriptions for the locale. */ private ResourceBundle getCountryDescriptions(Locale l) { @@ -166,7 +261,8 @@ private ResourceBundle getCountryDescriptions(Locale l) { /** * Returns the eventually cached ResourceBundle for the descriptions. * - * @param l Locale to retrieve the descriptions for. + * @param l + * Locale to retrieve the descriptions for. * @return ResourceBundle containing the descriptions for the locale. */ private ResourceBundle getResourceBundle(Locale l, Map resourceCache, String filePrefix) { @@ -180,7 +276,8 @@ private ResourceBundle getResourceBundle(Locale l, Map r /** * Returns the resource by URL. * - * @param resourceName the name/path of the resource to load + * @param resourceName + * the name/path of the resource to load * @return the URL to the resource */ public URL getResource(String resourceName) { @@ -188,7 +285,7 @@ public URL getResource(String resourceName) { URL resource = classLoadingUtil.getClassloader().getResource(resourceName); return resource == null ? this.getClass().getClassLoader().getResource(resourceName) : resource; } catch (Exception e) { - throw new IllegalStateException("Cannot load resource: " + resourceName, e); + throw new IllegalStateException("Cannot load resource: " + resourceName, e); } }