1 /* 2 * Copyright (C) 2011 The Libphonenumber Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.i18n.phonenumbers.prefixmapper; 18 19 import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; 20 21 import java.io.IOException; 22 import java.io.InputStream; 23 import java.io.ObjectInputStream; 24 import java.util.HashMap; 25 import java.util.Map; 26 import java.util.logging.Level; 27 import java.util.logging.Logger; 28 29 /** 30 * A helper class doing file handling and lookup of phone number prefix mappings. 31 * 32 * @author Shaopeng Jia 33 */ 34 public class PrefixFileReader { 35 private static final Logger LOGGER = Logger.getLogger(PrefixFileReader.class.getName()); 36 37 private final String phonePrefixDataDirectory; 38 // The mappingFileProvider knows for which combination of countryCallingCode and language a phone 39 // prefix mapping file is available in the file system, so that a file can be loaded when needed. 40 private MappingFileProvider mappingFileProvider = new MappingFileProvider(); 41 // A mapping from countryCallingCode_lang to the corresponding phone prefix map that has been 42 // loaded. 43 private Map<String, PhonePrefixMap> availablePhonePrefixMaps = 44 new HashMap<String, PhonePrefixMap>(); 45 46 public PrefixFileReader(String phonePrefixDataDirectory) { 47 this.phonePrefixDataDirectory = phonePrefixDataDirectory; 48 loadMappingFileProvider(); 49 } 50 51 private void loadMappingFileProvider() { 52 InputStream source = 53 PrefixFileReader.class.getResourceAsStream(phonePrefixDataDirectory + "config"); 54 ObjectInputStream in = null; 55 try { 56 in = new ObjectInputStream(source); 57 mappingFileProvider.readExternal(in); 58 } catch (IOException e) { 59 LOGGER.log(Level.WARNING, e.toString()); 60 } finally { 61 close(in); 62 } 63 } 64 65 private PhonePrefixMap getPhonePrefixDescriptions( 66 int prefixMapKey, String language, String script, String region) { 67 String fileName = mappingFileProvider.getFileName(prefixMapKey, language, script, region); 68 if (fileName.length() == 0) { 69 return null; 70 } 71 if (!availablePhonePrefixMaps.containsKey(fileName)) { 72 loadPhonePrefixMapFromFile(fileName); 73 } 74 return availablePhonePrefixMaps.get(fileName); 75 } 76 77 private void loadPhonePrefixMapFromFile(String fileName) { 78 InputStream source = 79 PrefixFileReader.class.getResourceAsStream(phonePrefixDataDirectory + fileName); 80 ObjectInputStream in = null; 81 try { 82 in = new ObjectInputStream(source); 83 PhonePrefixMap map = new PhonePrefixMap(); 84 map.readExternal(in); 85 availablePhonePrefixMaps.put(fileName, map); 86 } catch (IOException e) { 87 LOGGER.log(Level.WARNING, e.toString()); 88 } finally { 89 close(in); 90 } 91 } 92 93 private static void close(InputStream in) { 94 if (in != null) { 95 try { 96 in.close(); 97 } catch (IOException e) { 98 LOGGER.log(Level.WARNING, e.toString()); 99 } 100 } 101 } 102 103 /** 104 * Returns a text description in the given language for the given phone number. 105 * 106 * @param number the phone number for which we want to get a text description 107 * @param lang two-letter lowercase ISO language codes as defined by ISO 639-1 108 * @param script four-letter titlecase (the first letter is uppercase and the rest of the letters 109 * are lowercase) ISO script codes as defined in ISO 15924 110 * @param region two-letter uppercase ISO country codes as defined by ISO 3166-1 111 * @return a text description in the given language for the given phone number, or an empty 112 * string if a description is not available 113 */ 114 public String getDescriptionForNumber( 115 PhoneNumber number, String lang, String script, String region) { 116 int countryCallingCode = number.getCountryCode(); 117 // As the NANPA data is split into multiple files covering 3-digit areas, use a phone number 118 // prefix of 4 digits for NANPA instead, e.g. 1650. 119 int phonePrefix = (countryCallingCode != 1) ? 120 countryCallingCode : (1000 + (int) (number.getNationalNumber() / 10000000)); 121 PhonePrefixMap phonePrefixDescriptions = 122 getPhonePrefixDescriptions(phonePrefix, lang, script, region); 123 String description = (phonePrefixDescriptions != null) ? 124 phonePrefixDescriptions.lookup(number) : null; 125 // When a location is not available in the requested language, fall back to English. 126 if ((description == null || description.length() == 0) && mayFallBackToEnglish(lang)) { 127 PhonePrefixMap defaultMap = getPhonePrefixDescriptions(phonePrefix, "en", "", ""); 128 if (defaultMap == null) { 129 return ""; 130 } 131 description = defaultMap.lookup(number); 132 } 133 return description != null ? description : ""; 134 } 135 136 private boolean mayFallBackToEnglish(String lang) { 137 // Don't fall back to English if the requested language is among the following: 138 // - Chinese 139 // - Japanese 140 // - Korean 141 return !lang.equals("zh") && !lang.equals("ja") && !lang.equals("ko"); 142 } 143 } 144