package com.cloudhopper.commons.locale; /* * #%L * ch-commons-locale * %% * Copyright (C) 2012 - 2013 Cloudhopper by Twitter * %% * 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.io.IOException; /** * The class needs to be able to receive and use a list or countries that * are in accordance with the ISO 3166 code lists. These may be * stored on a database, textfile or other storage mechanism. This class is * therefore designed in a way that does not hard-code country variables. * There should therefore be no need to sub-class this class for different * countries. The class is instead generic for all countries and can handle * and provide feedback to clients on field content. */ public final class Country implements Cloneable, Comparable { /** * Constructs a new Country from an ISO code and name. The code is * length checked (length =2). There is no other validation on the code * or name. A country name is "Nigeria", but the long name "Nigeria, Republic of" */ Country(String code, String name, String longName) throws IllegalArgumentException { this.name = name; this.longName = longName; if (code.length() != 2) { throw new IllegalArgumentException(CODE_LENGTH); } else { this.code = code; } } /** Return a copy of this object. */ @Override public Object clone() { Country country = null; try { country = (Country) super.clone(); if (country.code != null) { country.code = getCode(); //String is immutable no need to clone country.name = getName(); //String is immutable no need to clone country.longName = getLongName(); } } catch (CloneNotSupportedException e) { } // Won't happen return country; } /** Returns the country code string. If this is a valid ISO code it should * be comparable to another country code. */ public String getCode() { return code; } /** * Returns the name of a country such as "Nigeria". * @see #getLongName() */ public String getName() { return name; } /** * Returns the name of a country such as "Nigeria, Federal Republic Of". * @see #getName() */ public String getLongName() { return longName; } /** Compares two ISOCountry objects for ordering. * Returns the value <code>zero</code> if the two countries have equal * country codes. Returns a value less than <code>zero</code> if this * country code is before the country argument and a value greater than * <code>zero</code> if this country is after the country argument. Will * result in alphabetical sorting. */ public int compareTo(Country country) { String thisCode = this.getCode(); String otherCode = country.getCode(); return thisCode.compareTo(otherCode); } /** Compares this country to another Object. If the Object isan ISOCountry, * this function behaves like <code>compareTo(Date)</code>. Otherwise, * it throws a <code>ClassCastException</code>. */ public int compareTo(Object o) { return compareTo((Country) o); } /** * Tests if a country is equal to another one by 2 letter Country Code. */ @Override public boolean equals(Object o) { if (!(o instanceof Country)) return false; return (compareTo((Country)o) == 0); } @Override public int hashCode() { return this.code.hashCode(); } @Override public String toString() { return "Country [code=" + this.code + ", name=" + this.name + "]"; } /** A string that stipulates the code length. Used for error messages. */ private static final String CODE_LENGTH = "An ISO country code is two characters in length."; /** An ISO country code. Its length is validated in the constructor. */ private String code; /** An ISO country name. Not validated. */ private String longName; /** An ISO country short name (anything after a , is removed to a short name) */ private String name; // AF AFG 004 Afghanistan protected static Country parse(String line) throws IOException { try { int pos = line.indexOf(' '); if (pos < 0) throw new IOException("Invalid format, could not parse 2 char code"); String code2 = line.substring(0, pos); int pos2 = line.indexOf(' ', pos+1); if (pos2 < 0) throw new IOException("Invalid format, could not parse 3 char code"); String code3 = line.substring(pos+1, pos2); int pos3 = line.indexOf(' ', pos2+1); if (pos3 < 0) throw new IOException("Invalid format, could not parse 3 char digit code"); String num3 = line.substring(pos2+1, pos3); // rest of line is the long name String longName = line.substring(pos3+1).trim(); // was there a name? if (longName == null || longName.equals("")) { throw new IOException("Country name was null or empty"); } // parse long name into its short name (strip anything after the last comma) String name = longName; int pos4 = longName.lastIndexOf(','); if (pos4 > 0) { // strip out the final part such as ", Republic of" from something like "Nigeria, Republic Of" name = longName.substring(0, pos4); } // create the new country return new Country(code2, name, longName); } catch (Exception e) { throw new IOException("Failed while parsing country for line: " + line, e); } } }