1 /* 2 * Copyright (C) 2012 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.android.i18n.phonenumbers; 18 19 import com.android.i18n.phonenumbers.Phonemetadata.PhoneMetadata; 20 import com.android.i18n.phonenumbers.Phonemetadata.PhoneMetadataCollection; 21 22 import java.io.IOException; 23 import java.io.InputStream; 24 import java.io.ObjectInputStream; 25 import java.util.Collections; 26 import java.util.HashMap; 27 import java.util.Iterator; 28 import java.util.List; 29 import java.util.Map; 30 import java.util.Set; 31 import java.util.logging.Level; 32 import java.util.logging.Logger; 33 34 /** 35 * Class encapsulating loading of PhoneNumber Metadata information. Currently this is used only for 36 * additional data files such as PhoneNumberAlternateFormats, but in the future it is envisaged it 37 * would handle the main metadata file (PhoneNumberMetadata.xml) as well. 38 */ 39 class MetadataManager { 40 private static final String ALTERNATE_FORMATS_FILE_PREFIX = 41 "/com/android/i18n/phonenumbers/data/PhoneNumberAlternateFormatsProto"; 42 private static final String SHORT_NUMBER_METADATA_FILE_PREFIX = 43 "/com/android/i18n/phonenumbers/data/ShortNumberMetadataProto"; 44 45 private static final Logger LOGGER = Logger.getLogger(MetadataManager.class.getName()); 46 47 private static final Map<Integer, PhoneMetadata> callingCodeToAlternateFormatsMap = 48 Collections.synchronizedMap(new HashMap<Integer, PhoneMetadata>()); 49 private static final Map<String, PhoneMetadata> regionCodeToShortNumberMetadataMap = 50 Collections.synchronizedMap(new HashMap<String, PhoneMetadata>()); 51 52 // A set of which country calling codes there are alternate format data for. If the set has an 53 // entry for a code, then there should be data for that code linked into the resources. 54 private static final Set<Integer> countryCodeSet = 55 AlternateFormatsCountryCodeSet.getCountryCodeSet(); 56 57 // A set of which region codes there are short number data for. If the set has an entry for a 58 // code, then there should be data for that code linked into the resources. 59 private static final Set<String> regionCodeSet = ShortNumbersRegionCodeSet.getRegionCodeSet(); 60 MetadataManager()61 private MetadataManager() { 62 } 63 close(InputStream in)64 private static void close(InputStream in) { 65 if (in != null) { 66 try { 67 in.close(); 68 } catch (IOException e) { 69 LOGGER.log(Level.WARNING, e.toString()); 70 } 71 } 72 } 73 loadAlternateFormatsMetadataFromFile(int countryCallingCode)74 private static void loadAlternateFormatsMetadataFromFile(int countryCallingCode) { 75 InputStream source = PhoneNumberMatcher.class.getResourceAsStream( 76 ALTERNATE_FORMATS_FILE_PREFIX + "_" + countryCallingCode); 77 ObjectInputStream in = null; 78 try { 79 in = new ObjectInputStream(source); 80 PhoneMetadataCollection alternateFormats = new PhoneMetadataCollection(); 81 alternateFormats.readExternal(in); 82 for (PhoneMetadata metadata : alternateFormats.getMetadataList()) { 83 callingCodeToAlternateFormatsMap.put(metadata.getCountryCode(), metadata); 84 } 85 } catch (IOException e) { 86 LOGGER.log(Level.WARNING, e.toString()); 87 } finally { 88 close(in); 89 } 90 } 91 getAlternateFormatsForCountry(int countryCallingCode)92 static PhoneMetadata getAlternateFormatsForCountry(int countryCallingCode) { 93 if (!countryCodeSet.contains(countryCallingCode)) { 94 return null; 95 } 96 synchronized (callingCodeToAlternateFormatsMap) { 97 if (!callingCodeToAlternateFormatsMap.containsKey(countryCallingCode)) { 98 loadAlternateFormatsMetadataFromFile(countryCallingCode); 99 } 100 } 101 return callingCodeToAlternateFormatsMap.get(countryCallingCode); 102 } 103 loadShortNumberMetadataFromFile(String regionCode)104 private static void loadShortNumberMetadataFromFile(String regionCode) { 105 InputStream source = PhoneNumberMatcher.class.getResourceAsStream( 106 SHORT_NUMBER_METADATA_FILE_PREFIX + "_" + regionCode); 107 ObjectInputStream in = null; 108 try { 109 in = new ObjectInputStream(source); 110 PhoneMetadataCollection shortNumberMetadata = new PhoneMetadataCollection(); 111 shortNumberMetadata.readExternal(in); 112 for (PhoneMetadata metadata : shortNumberMetadata.getMetadataList()) { 113 regionCodeToShortNumberMetadataMap.put(regionCode, metadata); 114 } 115 } catch (IOException e) { 116 LOGGER.log(Level.WARNING, e.toString()); 117 } finally { 118 close(in); 119 } 120 } 121 122 // @VisibleForTesting getShortNumberMetadataSupportedRegions()123 static Set<String> getShortNumberMetadataSupportedRegions() { 124 return regionCodeSet; 125 } 126 getShortNumberMetadataForRegion(String regionCode)127 static PhoneMetadata getShortNumberMetadataForRegion(String regionCode) { 128 if (!regionCodeSet.contains(regionCode)) { 129 return null; 130 } 131 synchronized (regionCodeToShortNumberMetadataMap) { 132 if (!regionCodeToShortNumberMetadataMap.containsKey(regionCode)) { 133 loadShortNumberMetadataFromFile(regionCode); 134 } 135 } 136 return regionCodeToShortNumberMetadataMap.get(regionCode); 137 } 138 } 139