View Javadoc
1   /*
2    * (c) Copyright 2006-2020 by rapiddweller GmbH & Volker Bergmann. All rights reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, is permitted under the terms of the
6    * GNU General Public License.
7    *
8    * For redistributing this software or a derivative work under a license other
9    * than the GPL-compatible Free Software License as defined by the Free
10   * Software Foundation or approved by OSI, you must first obtain a commercial
11   * license to this software product from rapiddweller GmbH & Volker Bergmann.
12   *
13   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14   * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
15   * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
16   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
17   * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24   * POSSIBILITY OF SUCH DAMAGE.
25   */
26  
27  package com.rapiddweller.domain.address;
28  
29  import com.rapiddweller.benerator.engine.DefaultBeneratorContext;
30  import com.rapiddweller.benerator.primitive.RandomVarLengthStringGenerator;
31  import com.rapiddweller.benerator.primitive.RegexStringGenerator;
32  import com.rapiddweller.benerator.util.RandomUtil;
33  import com.rapiddweller.common.Assert;
34  import com.rapiddweller.common.BeanUtil;
35  import com.rapiddweller.common.ConfigurationError;
36  import com.rapiddweller.common.Encodings;
37  import com.rapiddweller.common.IOUtil;
38  import com.rapiddweller.common.LocaleUtil;
39  import com.rapiddweller.common.StringUtil;
40  import com.rapiddweller.common.collection.OrderedNameMap;
41  import com.rapiddweller.format.DataContainer;
42  import com.rapiddweller.format.DataIterator;
43  import com.rapiddweller.format.csv.CSVLineIterator;
44  import com.rapiddweller.model.data.ComplexTypeDescriptor;
45  import com.rapiddweller.model.data.Entity;
46  import com.rapiddweller.platform.csv.CSVEntitySource;
47  import com.rapiddweller.platform.java.BeanDescriptorProvider;
48  import org.apache.logging.log4j.LogManager;
49  import org.apache.logging.log4j.Logger;
50  
51  import java.io.IOException;
52  import java.util.ArrayList;
53  import java.util.Collection;
54  import java.util.HashMap;
55  import java.util.List;
56  import java.util.Locale;
57  import java.util.Map;
58  
59  /**
60   * Represents a country and provides constants for most bigger countries.
61   * Country information is read from the file com/rapiddweller/domain/address/country.csv.<br/><br/>
62   * Created: 11.06.2006 08:15:37
63   *
64   * @author Volker Bergmann
65   * @since 0.1
66   */
67  public class Country {
68  
69    private static final Logger LOGGER = LogManager.getLogger(Country.class);
70    private static final String DEFAULT_PHONE_CODE = "[2-9][0-9][0-9]";
71    private static final String DEFAULT_MOBILE_PHONE_PATTERN =
72        "[1-9][0-9][0-9]";
73    private static final Map<String, Country> instances = new HashMap<>(250);
74    /**
75     * The constant GERMANY.
76     */
77    public static final Country GERMANY = getInstance("DE");
78    /**
79     * The constant AUSTRIA.
80     */
81    public static final Country AUSTRIA = getInstance("AT");
82    /**
83     * The constant SWITZERLAND.
84     */
85    public static final Country SWITZERLAND = getInstance("CH");
86    /**
87     * The constant LIECHTENSTEIN.
88     */
89    public static final Country LIECHTENSTEIN = getInstance("LI");
90    /**
91     * The constant BELGIUM.
92     */
93    // BeNeLux
94    public static final Country BELGIUM = getInstance("BE");
95    /**
96     * The constant NETHERLANDS.
97     */
98    public static final Country NETHERLANDS = getInstance("NL");
99    /**
100    * The constant LUXEMBURG.
101    */
102   public static final Country LUXEMBURG = getInstance("LU");
103   /**
104    * The constant DENMARK.
105    */
106   public static final Country DENMARK = getInstance("DK");
107   /**
108    * The constant FINLAND.
109    */
110   public static final Country FINLAND = getInstance("FI");
111   /**
112    * The constant IRELAND.
113    */
114   public static final Country IRELAND = getInstance("IE");
115   /**
116    * The constant ICELAND.
117    */
118   public static final Country ICELAND = getInstance("IS");
119   /**
120    * The constant NORWAY.
121    */
122   public static final Country NORWAY = getInstance("NO");
123   /**
124    * The constant SWEDEN.
125    */
126   public static final Country SWEDEN = getInstance("SE");
127   /**
128    * The constant UNITED_KINGDOM.
129    */
130   public static final Country UNITED_KINGDOM = getInstance("GB");
131   /**
132    * The constant GREAT_BRITAIN.
133    */
134   public static final Country GREAT_BRITAIN = getInstance("GB");
135   /**
136    * The constant ITALY.
137    */
138   public static final Country ITALY = getInstance("IT");
139   /**
140    * The constant SAN_MARINO.
141    */
142   public static final Country SAN_MARINO = getInstance("SM");
143   /**
144    * The constant MALTA.
145    */
146   public static final Country MALTA = getInstance("MT");
147   /**
148    * The constant FRANCE.
149    */
150   public static final Country FRANCE = getInstance("FR");
151   /**
152    * The constant MONACO.
153    */
154   public static final Country MONACO = getInstance("MC");
155   /**
156    * The constant ANDORRA.
157    */
158   public static final Country ANDORRA = getInstance("AD");
159   /**
160    * The constant SPAIN.
161    */
162   public static final Country SPAIN = getInstance("ES");
163   /**
164    * The constant PORTUGAL.
165    */
166   public static final Country PORTUGAL = getInstance("PT");
167   /**
168    * The constant GREECE.
169    */
170   public static final Country GREECE = getInstance("GR");
171   /**
172    * The constant CYPRUS.
173    */
174   public static final Country CYPRUS = getInstance("CY");
175   /**
176    * The constant TURKEY.
177    */
178   public static final Country TURKEY = getInstance("TR");
179   /**
180    * The constant ALBANIA.
181    */
182   public static final Country ALBANIA = getInstance("AL");
183   /**
184    * The constant BOSNIA_AND_HERZEGOVINA.
185    */
186   public static final Country BOSNIA_AND_HERZEGOVINA = getInstance("BA");
187   /**
188    * The constant BULGARIA.
189    */
190   public static final Country BULGARIA = getInstance("BG");
191   /**
192    * The constant BELARUS.
193    */
194   public static final Country BELARUS = getInstance("BY");
195   /**
196    * The constant CZECH_REPUBLIC.
197    */
198   public static final Country CZECH_REPUBLIC = getInstance("CZ");
199   /**
200    * The constant ESTONIA.
201    */
202   public static final Country ESTONIA = getInstance("EE");
203   /**
204    * The constant CROATIA.
205    */
206   public static final Country CROATIA = getInstance("HR");
207   /**
208    * The constant HUNGARY.
209    */
210   public static final Country HUNGARY = getInstance("HU");
211   /**
212    * The constant LITHUANIA.
213    */
214   public static final Country LITHUANIA = getInstance("LT");
215 
216   // java.lang.Object overrides --------------------------------------------------------------------------------------
217   /**
218    * The constant LATVIA.
219    */
220   public static final Country LATVIA = getInstance("LV");
221   /**
222    * The constant POLAND.
223    */
224   public static final Country POLAND = getInstance("PL");
225   /**
226    * The constant ROMANIA.
227    */
228   public static final Country ROMANIA = getInstance("RO");
229 
230   // constants -------------------------------------------------------------------------------------------------------
231   /**
232    * The constant RUSSIA.
233    */
234   public static final Country RUSSIA = getInstance("RU");
235   /**
236    * The constant SERBIA.
237    */
238   public static final Country SERBIA = getInstance("RS");
239   /**
240    * The constant SLOVENIA.
241    */
242   public static final Country SLOVENIA = getInstance("SI");
243   /**
244    * The constant SLOVAKIA.
245    */
246   public static final Country SLOVAKIA = getInstance("SK");
247   /**
248    * The constant UKRAINE.
249    */
250   public static final Country UKRAINE = getInstance("UA");
251   /**
252    * The constant UNITED_ARAB_EMIRATES.
253    */
254   public static final Country UNITED_ARAB_EMIRATES = getInstance("AE");
255   /**
256    * The constant AFGHANISTAN.
257    */
258   public static final Country AFGHANISTAN = getInstance("AF");
259   /**
260    * The constant BAHRAIN.
261    */
262   public static final Country BAHRAIN = getInstance("BH");
263   /**
264    * The constant ISRAEL.
265    */
266   public static final Country ISRAEL = getInstance("IL");
267   /**
268    * The constant IRAN.
269    */
270   public static final Country IRAN = getInstance("IR");
271   /**
272    * The constant IRAQ.
273    */
274   public static final Country IRAQ = getInstance("IQ");
275   /**
276    * The constant JORDAN.
277    */
278   public static final Country JORDAN = getInstance("JO");
279   /**
280    * The constant KAZAKHSTAN.
281    */
282   public static final Country KAZAKHSTAN = getInstance("KZ");
283   /**
284    * The constant PAKISTAN.
285    */
286   public static final Country PAKISTAN = getInstance("PK");
287   /**
288    * The constant QATAR.
289    */
290   public static final Country QATAR = getInstance("QA");
291   /**
292    * The constant SAUDI_ARABIA.
293    */
294   public static final Country SAUDI_ARABIA = getInstance("SA");
295   /**
296    * The constant ALGERIA.
297    */
298   public static final Country ALGERIA = getInstance("AL");
299   /**
300    * The constant EGYPT.
301    */
302   public static final Country EGYPT = getInstance("EG");
303   /**
304    * The constant GHANA.
305    */
306   public static final Country GHANA = getInstance("GH");
307   /**
308    * The constant KENYA.
309    */
310   public static final Country KENYA = getInstance("KE");
311   /**
312    * The constant SOUTH_AFRICA.
313    */
314   public static final Country SOUTH_AFRICA = getInstance("ZA");
315   /**
316    * The constant USA.
317    */
318   public static final Country USA = getInstance("US");
319   /**
320    * The constant US.
321    */
322   public static final Country US = USA;
323   /**
324    * The constant CANADA.
325    */
326   public static final Country CANADA = getInstance("CA");
327   /**
328    * The constant BAHAMAS.
329    */
330   public static final Country BAHAMAS = getInstance("BS");
331   /**
332    * The constant MEXICO.
333    */
334   public static final Country MEXICO = getInstance("MX");
335   /**
336    * The constant ARGENTINA.
337    */
338   public static final Country ARGENTINA = getInstance("AR");
339   /**
340    * The constant BRAZIL.
341    */
342   public static final Country BRAZIL = getInstance("BR");
343   /**
344    * The constant CHILE.
345    */
346   public static final Country CHILE = getInstance("CL");
347   /**
348    * The constant ECUADOR.
349    */
350   public static final Country ECUADOR = getInstance("EC");
351   /**
352    * The constant CHINA.
353    */
354   public static final Country CHINA = getInstance("CN");
355   /**
356    * The constant INDONESIA.
357    */
358   public static final Country INDONESIA = getInstance("ID");
359   /**
360    * The constant INDIA.
361    */
362   public static final Country INDIA = getInstance("IN");
363   /**
364    * The constant JAPAN.
365    */
366   public static final Country JAPAN = getInstance("JP");
367   /**
368    * The constant KOREA_PR.
369    */
370   public static final Country KOREA_PR = getInstance("KP");
371   /**
372    * The constant KOREA_R.
373    */
374   public static final Country KOREA_R = getInstance("KR");
375   /**
376    * The constant MALAYSIA.
377    */
378   public static final Country MALAYSIA = getInstance("MY");
379   /**
380    * The constant SINGAPORE.
381    */
382   public static final Country SINGAPORE = getInstance("SG");
383   /**
384    * The constant THAILAND.
385    */
386   public static final Country THAILAND = getInstance("TH");
387   /**
388    * The constant TAIWAN.
389    */
390   public static final Country TAIWAN = getInstance("TW");
391   /**
392    * The constant VIETNAM.
393    */
394   public static final Country VIETNAM = getInstance("VN");
395   /**
396    * The constant NEW_ZEALAND.
397    */
398   public static final Country NEW_ZEALAND = getInstance("NZ");
399   /**
400    * The constant AUSTRALIA.
401    */
402   public static final Country AUSTRALIA = getInstance("AU");
403   private static Country defaultCountry;
404 
405   static {
406     parseConfigFile();
407   }
408 
409   static {
410     defaultCountry =
411         Country.getInstance(LocaleUtil.getDefaultCountryCode());
412   }
413 
414   private final String isoCode;
415   private final String name;
416   private final String phoneCode;
417   private final boolean mobilePhoneCityRelated;
418   private final RegexStringGenerator mobilePrefixGenerator;
419   private final RandomVarLengthStringGenerator localNumberGenerator;
420   private final Locale countryLocale;
421   private final Locale defaultLanguageLocale;
422   private final int population;
423   private Map<String, State> states;
424   private CityGenerator cityGenerator;
425   private boolean citiesInitialized = false;
426 
427   private Country(String isoCode, String defaultLanguage, int population,
428                   String phoneCode, String mobileCodePattern,
429                   String name) {
430     this.isoCode = isoCode;
431     this.defaultLanguageLocale = LocaleUtil.getLocale(defaultLanguage);
432     this.phoneCode = phoneCode;
433     this.countryLocale =
434         new Locale(LocaleUtil.getLocale(defaultLanguage).getLanguage(),
435             isoCode);
436     this.mobilePhoneCityRelated = "BR".equalsIgnoreCase(isoCode); // TODO v1.0 make configuration generic
437     this.mobilePrefixGenerator = new RegexStringGenerator(mobileCodePattern);
438     this.mobilePrefixGenerator.init(null);
439     this.localNumberGenerator = new RandomVarLengthStringGenerator("\\d", 7);
440     this.localNumberGenerator.init(null);
441     this.name = (name != null ? name :
442         countryLocale.getDisplayCountry(Locale.US));
443     this.population = population;
444     importStates();
445     instances.put(isoCode, this);
446   }
447 
448   private static void mapProperty(String propertyName, Entity source,
449                                   State target, boolean required) {
450     String propertyValue = String.valueOf(source.get(propertyName));
451     if (required) {
452       Assert.notNull(propertyValue, propertyName);
453     }
454     BeanUtil.setPropertyValue(target, propertyName, propertyValue);
455   }
456 
457   /**
458    * Gets instances.
459    *
460    * @return the instances
461    */
462   public static Collection<Country> getInstances() {
463     return instances.values();
464   }
465 
466   /**
467    * Retrieves a country from the country configuration file.
468    *
469    * @param isoCode the ISO code of the country to retrieve
470    * @return if it is a predfined country, an instance with the configured data is returned, else one with the specified ISO code and default settings
471    * , e.g. phoneCode 'UNKNOWN'.
472    */
473   public static Country getInstance(String isoCode) {
474     return getInstance(isoCode, true);
475   }
476 
477   /**
478    * Retrieves a country from the country configuration file.
479    *
480    * @param isoCode the ISO code of the country to retrieve
481    * @param create  the create
482    * @return if it is a predfined country, an instance with the configured data is returned, else one with the specified ISO code and default settings
483    * , e.g. phoneCode 'UNKNOWN'.
484    */
485   public static Country getInstance(String isoCode, boolean create) {
486     Country country = instances.get(isoCode.toUpperCase());
487     if (country == null && create) {
488       country = new Country(isoCode, Locale.getDefault().getLanguage(),
489           1000000, DEFAULT_PHONE_CODE, DEFAULT_MOBILE_PHONE_PATTERN,
490           null);
491     }
492     return country;
493   }
494 
495   /**
496    * Has instance boolean.
497    *
498    * @param isoCode the iso code
499    * @return the boolean
500    */
501   public static boolean hasInstance(String isoCode) {
502     return (instances.get(isoCode.toUpperCase()) != null);
503   }
504 
505   /**
506    * Gets default.
507    *
508    * @return the default
509    */
510   public static Country getDefault() {
511     return Country.defaultCountry;
512   }
513 
514   /**
515    * Sets default.
516    *
517    * @param country the country
518    */
519   public static void setDefault(Country country) {
520     Country.defaultCountry = country;
521   }
522 
523   /**
524    * Gets fallback.
525    *
526    * @return the fallback
527    */
528   public static Country getFallback() {
529     return Country.US;
530   }
531 
532   private static void parseConfigFile() {
533     CSVLineIterator iterator = null;
534     try {
535       String fileName = "/com/rapiddweller/domain/address/country.csv";
536       iterator = new CSVLineIterator(fileName, ',', true);
537       LOGGER.debug("Parsing country setup file {}", fileName);
538       DataContainer<String[]> container = new DataContainer<>();
539       while ((container = iterator.next(container)) != null) {
540         String[] cells = container.getData();
541         String isoCode = cells[0];
542         String defaultLocale =
543             (cells.length > 1 && !StringUtil.isEmpty(cells[1]) ?
544                 cells[1].trim() : "en");
545         String phoneCode =
546             (cells.length > 2 && !StringUtil.isEmpty(cells[2]) ?
547                 cells[2].trim() : null);
548         String mobilCodePattern =
549             (cells.length > 3 && !StringUtil.isEmpty(cells[3]) ?
550                 cells[3].trim() : DEFAULT_MOBILE_PHONE_PATTERN);
551         String name = (cells.length > 4 ? cells[4].trim() : null);
552         int population =
553             (cells.length > 5 ? Integer.parseInt(cells[5].trim()) :
554                 1000000);
555         Country country =
556             new Country(isoCode, defaultLocale, population,
557                 phoneCode, mobilCodePattern, name);
558         LOGGER.debug("Parsed country {}", country);
559       }
560     } catch (IOException e) {
561       throw new ConfigurationError(
562           "Country definition file could not be processed. ", e);
563     } finally {
564       if (iterator != null) {
565         iterator.close();
566       }
567     }
568   }
569 
570   private void importStates() {
571     this.states = new OrderedNameMap<>();
572     String filename =
573         "/com/rapiddweller/domain/address/state_" + isoCode + ".csv";
574     if (!IOUtil.isURIAvailable(filename)) {
575       LOGGER.debug("No states defined for {}", this);
576       return;
577     }
578     ComplexTypeDescriptor stateDescriptor =
579         (ComplexTypeDescriptor) new BeanDescriptorProvider()
580             .getTypeDescriptor(State.class.getName());
581     CSVEntitySource source =
582         new CSVEntitySource(filename, stateDescriptor, Encodings.UTF_8);
583     source.setContext(new DefaultBeneratorContext());
584     DataIterator<Entity> iterator = source.iterator();
585     DataContainer<Entity> container = new DataContainer<>();
586     while ((container = iterator.next(container)) != null) {
587       Entity entity = container.getData();
588       Statedress/State.html#State">State state = new State();
589       mapProperty("id", entity, state, true);
590       mapProperty("name", entity, state, true);
591       mapProperty("defaultLanguage", entity, state, false);
592       state.setCountry(this);
593       addState(state);
594     }
595     IOUtil.close(iterator);
596   }
597 
598   /**
599    * Gets iso code.
600    *
601    * @return the iso code
602    */
603   public String getIsoCode() {
604     return isoCode;
605   }
606 
607   /**
608    * Returns the English name
609    *
610    * @return the name
611    */
612   public String getName() {
613     return name;
614   }
615 
616   /**
617    * Returns the name in the user's {@link Locale}
618    *
619    * @return the display name
620    */
621   public String getDisplayName() {
622     return countryLocale.getDisplayCountry(Locale.getDefault());
623   }
624 
625   /**
626    * Returns the name in the country's own {@link Locale}
627    *
628    * @return the local name
629    */
630   public String getLocalName() {
631     return countryLocale.getDisplayCountry(
632         new Locale(defaultLanguageLocale.getLanguage()));
633   }
634 
635   /**
636    * Gets default language locale.
637    *
638    * @return the default language locale
639    */
640   public Locale getDefaultLanguageLocale() {
641     return defaultLanguageLocale;
642   }
643 
644   /**
645    * Gets population.
646    *
647    * @return the population
648    */
649   public int getPopulation() {
650     return population;
651   }
652 
653   /**
654    * Gets phone code.
655    *
656    * @return the phone code
657    */
658   public String getPhoneCode() {
659     return phoneCode;
660   }
661 
662   /**
663    * Gets state.
664    *
665    * @param stateId the state id
666    * @return the state
667    */
668   public State getState(String stateId) {
669     return states.get(stateId);
670   }
671 
672   /**
673    * Gets states.
674    *
675    * @return the states
676    */
677   public Collection<State> getStates() {
678     return states.values();
679   }
680 
681   /**
682    * Add state.
683    *
684    * @param state the state
685    */
686   public void addState(State state) {
687     state.setCountry(this);
688     states.put(state.getId(), state);
689   }
690 
691   /**
692    * Is mobile phone city related boolean.
693    *
694    * @return the boolean
695    */
696   public boolean isMobilePhoneCityRelated() {
697     return mobilePhoneCityRelated;
698   }
699 
700   /**
701    * Gets cities.
702    *
703    * @return the cities
704    */
705   public List<City> getCities() {
706     List<City> cities = new ArrayList<>();
707     for (State state : states.values()) {
708       cities.addAll(state.getCities());
709     }
710     return cities;
711   }
712 
713   /**
714    * Generate city city.
715    *
716    * @return the city
717    */
718   public City generateCity() {
719     return getCityGenerator().generate();
720   }
721 
722   /**
723    * Generate phone number phone number.
724    *
725    * @return the phone number
726    */
727   public PhoneNumber generatePhoneNumber() {
728     if (RandomUtil.randomInt(0, 2) <
729         2) {
730       // generate land line numbers in 66% of the cases
731 
732       return generateLandlineNumber();
733     } else {
734       return generateMobileNumber();
735     }
736   }
737 
738   /**
739    * Generate landline number phone number.
740    *
741    * @return the phone number
742    */
743   public PhoneNumber generateLandlineNumber() {
744     return generateCity().generateLandlineNumber();
745   }
746 
747   /**
748    * Generate mobile number phone number.
749    *
750    * @return the phone number
751    */
752   public PhoneNumber generateMobileNumber() {
753     if (mobilePhoneCityRelated) {
754       return generateCity().generateMobileNumber();
755     } else {
756       return generateMobileNumber(null);
757     }
758   }
759 
760   /**
761    * Generate mobile number phone number.
762    *
763    * @param city the city
764    * @return the phone number
765    */
766   public PhoneNumber generateMobileNumber(City city) {
767     String localNumber = localNumberGenerator.generate();
768     String mobilePrefix = mobilePrefixGenerator.generate();
769     if (mobilePhoneCityRelated) {
770       return new PhoneNumber(phoneCode,
771           city != null ? city.getAreaCode() : null,
772           mobilePrefix +
773               localNumber.substring(mobilePrefix.length()));
774     } else {
775       return new PhoneNumber(phoneCode,
776           mobilePrefix,
777           localNumber);
778     }
779   }
780 
781   private CityGenerator getCityGenerator() {
782     if (cityGenerator == null) {
783       cityGenerator = new CityGenerator(this.getIsoCode());
784       cityGenerator.init(null);
785     }
786     return cityGenerator;
787   }
788 
789   // initialization --------------------------------------------------------------------------------------------------
790 
791   @Override
792   public String toString() {
793     return getName();
794   }
795 
796   @Override
797   public int hashCode() {
798     return isoCode.hashCode();
799   }
800 
801   @Override
802   public boolean equals(Object obj) {
803     if (this == obj) {
804       return true;
805     }
806     if (obj == null) {
807       return false;
808     }
809     if (getClass() != obj.getClass()) {
810       return false;
811     }
812     final Country../../../../com/rapiddweller/domain/address/Country.html#Country">Country other = (Country) obj;
813     return isoCode.equals(other.isoCode);
814   }
815 
816   /**
817    * Check cities.
818    */
819   void checkCities() {
820     if (!citiesInitialized) {
821       synchronized (this) {
822         if (!citiesInitialized) {
823           citiesInitialized = true;
824           CityManager.readCities(this);
825         }
826       }
827     }
828   }
829 
830 }