/*
* (C) 2004 - Geotechnical Software Services
*
* This code 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 code 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 program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
package no.geosoft.cc.country;
import java.util.*;
import java.io.*;
/**
* A country management singelton module. Useful for presentation of
* sorted list of countries in GUI like in country combo boxes etc.
* <p>
* The country manager instantiate country objects for the countries
* listed in the <tt>countries.txt</tt> resource of this package. The file
* lists ISO codes and the official english names for countries of the world.
* The countries.txt file has the following layout:
*
* <pre>
* AF; AFGHANISTAN
* AL; ALBANIA
* DZ; ALGERIA
* AS; AMERICAN SAMOA
* AD; ANDORRA
* AO; ANGOLA
* :
* </pre>
*
* The country name is the defualt name used if a localized mapping is
* not found, or the client askes for countries independent of locale.
* <p>
* TODO: Connect to an online resource to pick country ISO codes.
* <p>
* For internal application usage, only ISO codes for countries should
* be used (i.e. for persistent storage store the ISO code rather than
* a country name).
* <p>
* In user interfaces, localized names should be used according
* to the locale of the application or preferred locale selected by the
* user. Localized names are maintained in resource bundles picked from
* property files with name <tt>Messages_xx_XX.properties</tt> where
* <tt>xx</tt> is the language specifier and <tt>XX</tt> is the country
* specifier. Provide localized country name mappings for all locales
* supported by the client application. The properties files should be
* located in the same package as the CountryManager. The properties
* files has the following format (Messages_en_US.properties):
*
* <pre>
* AF = Afghanistan
* AL = Albania
* DZ = Algeria
* AS = American Samoa
* AD = Andorra
* AO = Angola
* :
* </pre>
*
* <p>
* Typical usage:
* <pre>
* // Get a specific country
* Country country = CountryManager.getInstance().getCountry ("AF", french);
*
* // Get world countries localized to french (assuming
* // Messages_fr_FR.properties is available).
* Locale french = new Locale ("fr", "FR");
* Collection countries = CountryManager.getInstance.getCountries (french);
*
* // Put countries (sorted according to locale) in a combo box
* TreeSet sorted = new TreeSet (countries);
* JComboBox countriesCombo = new JComboBox (new Vector (sorted));
* </pre>
*
* @see <a href="http://www.iso.org">ISO standard</a>
*
* @author <a href="mailto:info@geosoft.no">GeoSoft</a>
*/
public class CountryManager
{
private static CountryManager instance_ = new CountryManager();
private HashMap countries_;
/**
* Create country manager.
* Private to prevent instantiation.
*/
private CountryManager()
{
countries_ = null;
}
/**
* Retur sole instance of this class.
*
* @return CountryManager singleton instance.
*/
public static CountryManager getInstance()
{
return instance_;
}
/**
* Return countries of the world (as specified in countries.txt) using
* the default (official ISO name) country names.
*
* @return Countries of the world.
*/
public Collection getCountries()
{
if (countries_ == null)
loadCountries();
return countries_.values();
}
/**
* Return countries of the world (as specified in countries.txt) with
* names according to the specified locale. The name mappings must be
* available in a Messages_xx_XX.properties file where xx and XX match
* the language and country of the specified locale respectively.
* <p>
* If the associated properties file is not found, the country names
* are set according to the default ISO standard.
*
* @param locale Locale to setting country names.
* @return Countries of the world.
*/
public Collection getCountries (Locale locale)
{
if (countries_ == null)
loadCountries();
String bundleName = getClass().getPackage().getName() + ".Messages";
ResourceBundle resourceBundle = ResourceBundle.getBundle (bundleName, locale);
Collection countries = countries_.values();
Collection sorted = new TreeSet();
for (Iterator i = countries.iterator(); i.hasNext(); ) {
Country country = (Country) i.next();
Country clone = new Country (country);
try {
String localizedName = resourceBundle.getString (country.getIsoCode());
clone.setName (localizedName);
}
catch (Exception exception) {
}
sorted.add (clone);
}
return sorted;
}
/**
* Get country for specified ISO code.
*
* @param isoCode ISO code of country to find.
* @return Requested country (with default ISO name) (or null if
* ISO code is unknown).
*/
public Country getCountry (String isoCode)
{
if (countries_ == null)
loadCountries();
return (Country) countries_.get (isoCode);
}
/**
* Get country for specified ISO code.
*
* @param isoCode ISO code of country to find.
* @param locale Locale to control name of requested country.
* @return Requested country (or null if ISO code is unknown).
*/
public Country getCountry (String isoCode, Locale locale)
{
if (countries_ == null)
loadCountries();
Country country = (Country) countries_.get (isoCode);
Country clone = null;
if (country != null) {
clone = new Country (country);
String bundleName = getClass().getPackage().getName() + ".Messages";
ResourceBundle resourceBundle = ResourceBundle.getBundle (bundleName, locale);
try {
String localizedName = resourceBundle.getString (country.getIsoCode());
clone.setName (localizedName);
}
catch (Exception exception) {
}
}
return clone;
}
/**
* Load all countries from countries.txt file.
*/
private void loadCountries()
{
countries_ = new HashMap();
String fileName = "countries.txt";
String packageName = getClass().getPackage().getName();
String packageLocation = packageName.replace ('.', '/');
String filePath = "/" + packageLocation + "/" + fileName;
InputStream stream = getClass().getResourceAsStream (filePath);
BufferedReader reader = new BufferedReader (new InputStreamReader (stream));
try {
String line = reader.readLine();
while (line != null) {
StringTokenizer tokenizer = new StringTokenizer (line, ";");
String isoCode = tokenizer.nextToken().trim();
String name = tokenizer.nextToken().trim();
Country country = new Country (isoCode);
country.setName (name);
countries_.put (isoCode, country);
line = reader.readLine();
}
}
catch (IOException exception) {
}
finally {
try {stream.close();} catch (Exception e) {}
}
}
/**
* Testing the class.
*
* @param args Not used.
*/
public static void main (String[] args)
{
Locale locale = new Locale ("no", "NO");
CountryManager countryManager = CountryManager.getInstance();
Collection countries = countryManager.getCountries (locale);
for (Iterator i = countries.iterator(); i.hasNext(); ) {
Country country = (Country) i.next();
System.out.println (country);
}
}
}