Home | History | Annotate | Download | only in prefixmapper
      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 language  two or three-letter lowercase ISO language codes as defined by ISO 639. Note
    108    *     that where two different language codes exist (e.g. 'he' and 'iw' for Hebrew) we use the
    109    *     one that Java/Android canonicalized on ('iw' in this case).
    110    * @param script  four-letter titlecase (the first letter is uppercase and the rest of the letters
    111    *     are lowercase) ISO script code as defined in ISO 15924
    112    * @param region  two-letter uppercase ISO country code as defined by ISO 3166-1
    113    * @return  a text description in the given language for the given phone number, or an empty
    114    *     string if a description is not available
    115    */
    116   public String getDescriptionForNumber(
    117       PhoneNumber number, String language, String script, String region) {
    118     int countryCallingCode = number.getCountryCode();
    119     // As the NANPA data is split into multiple files covering 3-digit areas, use a phone number
    120     // prefix of 4 digits for NANPA instead, e.g. 1650.
    121     int phonePrefix = (countryCallingCode != 1)
    122         ? countryCallingCode : (1000 + (int) (number.getNationalNumber() / 10000000));
    123     PhonePrefixMap phonePrefixDescriptions =
    124         getPhonePrefixDescriptions(phonePrefix, language, script, region);
    125     String description = (phonePrefixDescriptions != null)
    126         ? phonePrefixDescriptions.lookup(number) : null;
    127     // When a location is not available in the requested language, fall back to English.
    128     if ((description == null || description.length() == 0) && mayFallBackToEnglish(language)) {
    129       PhonePrefixMap defaultMap = getPhonePrefixDescriptions(phonePrefix, "en", "", "");
    130       if (defaultMap == null) {
    131         return "";
    132       }
    133       description = defaultMap.lookup(number);
    134     }
    135     return description != null ? description : "";
    136   }
    137 
    138   private boolean mayFallBackToEnglish(String lang) {
    139     // Don't fall back to English if the requested language is among the following:
    140     // - Chinese
    141     // - Japanese
    142     // - Korean
    143     return !lang.equals("zh") && !lang.equals("ja") && !lang.equals("ko");
    144   }
    145 }
    146