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);
}
}