phonelib 0.4.9 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/README.rdoc +14 -3
  3. data/data/extended_data.dat +0 -0
  4. data/data/libphonenumber/README.md +5 -1
  5. data/data/libphonenumber/cpp/src/phonenumbers/lite_metadata.cc +10195 -10134
  6. data/data/libphonenumber/cpp/src/phonenumbers/metadata.cc +11081 -11017
  7. data/data/libphonenumber/cpp/src/phonenumbers/short_metadata.cc +1514 -1509
  8. data/data/libphonenumber/cpp/src/phonenumbers/shortnumberinfo.cc +22 -0
  9. data/data/libphonenumber/cpp/src/phonenumbers/shortnumberinfo.h +3 -0
  10. data/data/libphonenumber/cpp/src/phonenumbers/test_metadata.cc +128 -120
  11. data/data/libphonenumber/cpp/test/phonenumbers/shortnumberinfo_test.cc +13 -0
  12. data/data/libphonenumber/java/carrier/pom.xml +4 -4
  13. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/230_en +0 -0
  14. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/235_en +0 -0
  15. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/239_en +0 -0
  16. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/263_en +0 -0
  17. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/41_en +0 -0
  18. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/509_en +0 -0
  19. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/61_en +0 -0
  20. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/91_en +0 -0
  21. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/976_en +0 -0
  22. data/data/libphonenumber/java/carrier/src/com/google/i18n/phonenumbers/carrier/data/config +0 -0
  23. data/data/libphonenumber/java/demo/pom.xml +5 -5
  24. data/data/libphonenumber/java/geocoder/pom.xml +4 -4
  25. data/data/libphonenumber/java/geocoder/src/com/google/i18n/phonenumbers/geocoding/data/263_en +0 -0
  26. data/data/libphonenumber/java/geocoder/src/com/google/i18n/phonenumbers/geocoding/data/config +0 -0
  27. data/data/libphonenumber/java/geocoder/src/com/google/i18n/phonenumbers/timezones/data/map_data +0 -0
  28. data/data/libphonenumber/java/internal/prefixmapper/pom.xml +3 -3
  29. data/data/libphonenumber/java/libphonenumber/pom.xml +2 -2
  30. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/MetadataSource.java +38 -0
  31. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/MultiFileMetadataSourceImpl.java +155 -0
  32. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java +31 -109
  33. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/ShortNumberInfo.java +19 -0
  34. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_AR +0 -0
  35. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_AU +0 -0
  36. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BY +0 -0
  37. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CR +0 -0
  38. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_DZ +0 -0
  39. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_EH +0 -0
  40. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_ES +0 -0
  41. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_HK +0 -0
  42. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_HT +0 -0
  43. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_IN +0 -0
  44. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_JO +0 -0
  45. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_MN +0 -0
  46. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_MU +0 -0
  47. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_MX +0 -0
  48. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_PL +0 -0
  49. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_ST +0 -0
  50. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SZ +0 -0
  51. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_TD +0 -0
  52. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_TT +0 -0
  53. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_YT +0 -0
  54. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_ZW +0 -0
  55. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/ShortNumberMetadataProto_HK +0 -0
  56. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/ShortNumberMetadataProto_KR +0 -0
  57. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/ShortNumberMetadataProto_MX +0 -0
  58. data/data/libphonenumber/java/libphonenumber/src/com/google/i18n/phonenumbers/data/ShortNumberMetadataProto_ZW +0 -0
  59. data/data/libphonenumber/java/libphonenumber/test/com/google/i18n/phonenumbers/CountryCodeToRegionCodeMapForTesting.java +6 -2
  60. data/data/libphonenumber/java/libphonenumber/test/com/google/i18n/phonenumbers/MultiFileMetadataSourceImplTest.java +51 -0
  61. data/data/libphonenumber/java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java +0 -20
  62. data/data/libphonenumber/java/libphonenumber/test/com/google/i18n/phonenumbers/ShortNumberInfoTest.java +11 -0
  63. data/data/libphonenumber/java/libphonenumber/test/com/google/i18n/phonenumbers/TestMetadataTestCase.java +3 -2
  64. data/data/libphonenumber/java/libphonenumber/test/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProtoForTesting_SE +0 -0
  65. data/data/libphonenumber/java/pom.xml +1 -1
  66. data/data/libphonenumber/java/release_notes.txt +16 -0
  67. data/data/libphonenumber/javascript/i18n/phonenumbers/demo-compiled.js +135 -133
  68. data/data/libphonenumber/javascript/i18n/phonenumbers/metadata.js +54 -48
  69. data/data/libphonenumber/javascript/i18n/phonenumbers/metadatafortesting.js +14 -0
  70. data/data/libphonenumber/javascript/i18n/phonenumbers/metadatalite.js +54 -48
  71. data/data/libphonenumber/resources/PhoneNumberMetadata.xml +366 -256
  72. data/data/libphonenumber/resources/PhoneNumberMetadataForTesting.xml +4 -0
  73. data/data/libphonenumber/resources/ShortNumberMetadata.xml +52 -15
  74. data/data/libphonenumber/resources/carrier/en/230.txt +2 -0
  75. data/data/libphonenumber/resources/carrier/en/235.txt +1 -0
  76. data/data/libphonenumber/resources/carrier/en/239.txt +1 -0
  77. data/data/libphonenumber/resources/carrier/en/263.txt +1 -0
  78. data/data/libphonenumber/resources/carrier/en/41.txt +1 -1
  79. data/data/libphonenumber/resources/carrier/en/509.txt +24 -0
  80. data/data/libphonenumber/resources/carrier/en/61.txt +1 -0
  81. data/data/libphonenumber/resources/carrier/en/91.txt +1726 -830
  82. data/data/libphonenumber/resources/carrier/en/976.txt +18 -0
  83. data/data/libphonenumber/resources/geocoding/en/263.txt +40 -22
  84. data/data/libphonenumber/resources/timezones/map_data.txt +24 -11
  85. data/data/libphonenumber/tools/java/cpp-build/pom.xml +1 -1
  86. data/data/libphonenumber/tools/java/cpp-build/target/cpp-build-1.0-SNAPSHOT-jar-with-dependencies.jar +0 -0
  87. data/data/libphonenumber/tools/java/java-build/target/java-build-1.0-SNAPSHOT-jar-with-dependencies.jar +0 -0
  88. data/data/phone_data.dat +0 -0
  89. data/lib/phonelib.rb +1 -0
  90. data/lib/phonelib/core.rb +1 -0
  91. data/lib/phonelib/data_importer_helper.rb +1 -0
  92. data/lib/phonelib/phone.rb +61 -78
  93. data/lib/phonelib/phone_analyzer.rb +1 -1
  94. data/lib/phonelib/phone_extended_data.rb +68 -0
  95. data/lib/phonelib/version.rb +1 -1
  96. metadata +11 -2
@@ -3,14 +3,14 @@
3
3
  <modelVersion>4.0.0</modelVersion>
4
4
  <groupId>com.googlecode.libphonenumber</groupId>
5
5
  <artifactId>prefixmapper</artifactId>
6
- <version>2.25-SNAPSHOT</version>
6
+ <version>2.27-SNAPSHOT</version>
7
7
  <packaging>jar</packaging>
8
8
  <url>https://github.com/googlei18n/libphonenumber/</url>
9
9
 
10
10
  <parent>
11
11
  <groupId>com.googlecode.libphonenumber</groupId>
12
12
  <artifactId>libphonenumber-parent</artifactId>
13
- <version>7.0.9-SNAPSHOT</version>
13
+ <version>7.0.11-SNAPSHOT</version>
14
14
  <relativePath>../../pom.xml</relativePath>
15
15
  </parent>
16
16
 
@@ -29,7 +29,7 @@
29
29
  <dependency>
30
30
  <groupId>com.googlecode.libphonenumber</groupId>
31
31
  <artifactId>libphonenumber</artifactId>
32
- <version>7.0.9-SNAPSHOT</version>
32
+ <version>7.0.11-SNAPSHOT</version>
33
33
  </dependency>
34
34
  </dependencies>
35
35
 
@@ -3,14 +3,14 @@
3
3
  <modelVersion>4.0.0</modelVersion>
4
4
  <groupId>com.googlecode.libphonenumber</groupId>
5
5
  <artifactId>libphonenumber</artifactId>
6
- <version>7.0.9-SNAPSHOT</version>
6
+ <version>7.0.11-SNAPSHOT</version>
7
7
  <packaging>jar</packaging>
8
8
  <url>https://github.com/googlei18n/libphonenumber/</url>
9
9
 
10
10
  <parent>
11
11
  <groupId>com.googlecode.libphonenumber</groupId>
12
12
  <artifactId>libphonenumber-parent</artifactId>
13
- <version>7.0.9-SNAPSHOT</version>
13
+ <version>7.0.11-SNAPSHOT</version>
14
14
  </parent>
15
15
 
16
16
  <build>
@@ -0,0 +1,38 @@
1
+ /*
2
+ * Copyright (C) 2015 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;
18
+
19
+ import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
20
+
21
+ /**
22
+ * A source for phone metadata from resources.
23
+ */
24
+ interface MetadataSource {
25
+ /**
26
+ * Gets phone metadata for a region.
27
+ * @param regionCode the region code.
28
+ * @return the phone metadata for that region, or null if there is none.
29
+ */
30
+ PhoneMetadata getMetadataForRegion(String regionCode);
31
+
32
+ /**
33
+ * Gets phone metadata for a non-geographical region.
34
+ * @param countryCallingCode the country calling code.
35
+ * @return the phone metadata for that region, or null if there is none.
36
+ */
37
+ PhoneMetadata getMetadataForNonGeographicalRegion(int countryCallingCode);
38
+ }
@@ -0,0 +1,155 @@
1
+ /*
2
+ * Copyright (C) 2015 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;
18
+
19
+ import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
20
+ import com.google.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.List;
28
+ import java.util.Map;
29
+ import java.util.logging.Level;
30
+ import java.util.logging.Logger;
31
+
32
+ /**
33
+ * Implementation of {@link MetadataSource} that reads from multiple resource files.
34
+ */
35
+ final class MultiFileMetadataSourceImpl implements MetadataSource {
36
+
37
+ private static final Logger logger =
38
+ Logger.getLogger(MultiFileMetadataSourceImpl.class.getName());
39
+
40
+ private static final String META_DATA_FILE_PREFIX =
41
+ "/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto";
42
+
43
+ // A mapping from a region code to the PhoneMetadata for that region.
44
+ // Note: Synchronization, though only needed for the Android version of the library, is used in
45
+ // all versions for consistency.
46
+ private final Map<String, PhoneMetadata> regionToMetadataMap =
47
+ Collections.synchronizedMap(new HashMap<String, PhoneMetadata>());
48
+
49
+ // A mapping from a country calling code for a non-geographical entity to the PhoneMetadata for
50
+ // that country calling code. Examples of the country calling codes include 800 (International
51
+ // Toll Free Service) and 808 (International Shared Cost Service).
52
+ // Note: Synchronization, though only needed for the Android version of the library, is used in
53
+ // all versions for consistency.
54
+ private final Map<Integer, PhoneMetadata> countryCodeToNonGeographicalMetadataMap =
55
+ Collections.synchronizedMap(new HashMap<Integer, PhoneMetadata>());
56
+
57
+ // The prefix of the metadata files from which region data is loaded.
58
+ private final String currentFilePrefix;
59
+
60
+ // The metadata loader used to inject alternative metadata sources.
61
+ private final MetadataLoader metadataLoader;
62
+
63
+ // It is assumed that metadataLoader is not null.
64
+ public MultiFileMetadataSourceImpl(String currentFilePrefix, MetadataLoader metadataLoader) {
65
+ this.currentFilePrefix = currentFilePrefix;
66
+ this.metadataLoader = metadataLoader;
67
+ }
68
+
69
+ // It is assumed that metadataLoader is not null.
70
+ public MultiFileMetadataSourceImpl(MetadataLoader metadataLoader) {
71
+ this(META_DATA_FILE_PREFIX, metadataLoader);
72
+ }
73
+
74
+ @Override
75
+ public PhoneMetadata getMetadataForRegion(String regionCode) {
76
+ synchronized (regionToMetadataMap) {
77
+ if (!regionToMetadataMap.containsKey(regionCode)) {
78
+ // The regionCode here will be valid and won't be '001', so we don't need to worry about
79
+ // what to pass in for the country calling code.
80
+ loadMetadataFromFile(currentFilePrefix, regionCode, 0, metadataLoader);
81
+ }
82
+ }
83
+ return regionToMetadataMap.get(regionCode);
84
+ }
85
+
86
+ @Override
87
+ public PhoneMetadata getMetadataForNonGeographicalRegion(int countryCallingCode) {
88
+ synchronized (countryCodeToNonGeographicalMetadataMap) {
89
+ if (!countryCodeToNonGeographicalMetadataMap.containsKey(countryCallingCode)) {
90
+ loadMetadataFromFile(currentFilePrefix, PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY,
91
+ countryCallingCode, metadataLoader);
92
+ }
93
+ }
94
+ return countryCodeToNonGeographicalMetadataMap.get(countryCallingCode);
95
+ }
96
+
97
+ // @VisibleForTesting
98
+ void loadMetadataFromFile(String filePrefix, String regionCode, int countryCallingCode,
99
+ MetadataLoader metadataLoader) {
100
+ boolean isNonGeoRegion = PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY.equals(regionCode);
101
+ String fileName = filePrefix + "_" +
102
+ (isNonGeoRegion ? String.valueOf(countryCallingCode) : regionCode);
103
+ InputStream source = metadataLoader.loadMetadata(fileName);
104
+ if (source == null) {
105
+ logger.log(Level.SEVERE, "missing metadata: " + fileName);
106
+ throw new IllegalStateException("missing metadata: " + fileName);
107
+ }
108
+ ObjectInputStream in = null;
109
+ try {
110
+ in = new ObjectInputStream(source);
111
+ PhoneMetadataCollection metadataCollection = loadMetadataAndCloseInput(in);
112
+ List<PhoneMetadata> metadataList = metadataCollection.getMetadataList();
113
+ if (metadataList.isEmpty()) {
114
+ logger.log(Level.SEVERE, "empty metadata: " + fileName);
115
+ throw new IllegalStateException("empty metadata: " + fileName);
116
+ }
117
+ if (metadataList.size() > 1) {
118
+ logger.log(Level.WARNING, "invalid metadata (too many entries): " + fileName);
119
+ }
120
+ PhoneMetadata metadata = metadataList.get(0);
121
+ if (isNonGeoRegion) {
122
+ countryCodeToNonGeographicalMetadataMap.put(countryCallingCode, metadata);
123
+ } else {
124
+ regionToMetadataMap.put(regionCode, metadata);
125
+ }
126
+ } catch (IOException e) {
127
+ logger.log(Level.SEVERE, "cannot load/parse metadata: " + fileName, e);
128
+ throw new RuntimeException("cannot load/parse metadata: " + fileName, e);
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Loads the metadata protocol buffer from the given stream and closes the stream afterwards. Any
134
+ * exceptions that occur while reading the stream are propagated (though exceptions that occur
135
+ * when the stream is closed will be ignored).
136
+ *
137
+ * @param source the non-null stream from which metadata is to be read.
138
+ * @return the loaded metadata protocol buffer.
139
+ */
140
+ private static PhoneMetadataCollection loadMetadataAndCloseInput(ObjectInputStream source) {
141
+ PhoneMetadataCollection metadataCollection = new PhoneMetadataCollection();
142
+ try {
143
+ metadataCollection.readExternal(source);
144
+ } catch (IOException e) {
145
+ logger.log(Level.WARNING, "error reading input (ignored)", e);
146
+ } finally {
147
+ try {
148
+ source.close();
149
+ } catch (IOException e) {
150
+ logger.log(Level.WARNING, "error closing input stream (ignored)", e);
151
+ }
152
+ }
153
+ return metadataCollection;
154
+ }
155
+ }
@@ -18,15 +18,11 @@ package com.google.i18n.phonenumbers;
18
18
 
19
19
  import com.google.i18n.phonenumbers.Phonemetadata.NumberFormat;
20
20
  import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
21
- import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadataCollection;
22
21
  import com.google.i18n.phonenumbers.Phonemetadata.PhoneNumberDesc;
23
22
  import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
24
23
  import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource;
25
24
 
26
- import java.io.IOException;
27
25
  import java.io.InputStream;
28
- import java.io.ObjectInput;
29
- import java.io.ObjectInputStream;
30
26
  import java.util.ArrayList;
31
27
  import java.util.Arrays;
32
28
  import java.util.Collections;
@@ -78,9 +74,6 @@ public class PhoneNumberUtil {
78
74
  // input from overflowing the regular-expression engine.
79
75
  private static final int MAX_INPUT_STRING_LENGTH = 250;
80
76
 
81
- private static final String META_DATA_FILE_PREFIX =
82
- "/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto";
83
-
84
77
  // Region-code for the unknown region.
85
78
  private static final String UNKNOWN_REGION = "ZZ";
86
79
 
@@ -535,6 +528,9 @@ public class PhoneNumberUtil {
535
528
  abstract boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util);
536
529
  }
537
530
 
531
+ // A source of metadata for different regions.
532
+ private final MetadataSource metadataSource;
533
+
538
534
  // A mapping from a country calling code to the region codes which denote the region represented
539
535
  // by that country calling code. In the case of multiple regions sharing a calling code, such as
540
536
  // the NANPA regions, the one indicated with "isMainCountryForCode" in the metadata should be
@@ -546,20 +542,6 @@ public class PhoneNumberUtil {
546
542
  // We set the initial capacity of the HashSet to 35 to offer a load factor of roughly 0.75.
547
543
  private final Set<String> nanpaRegions = new HashSet<String>(35);
548
544
 
549
- // A mapping from a region code to the PhoneMetadata for that region.
550
- // Note: Synchronization, though only needed for the Android version of the library, is used in
551
- // all versions for consistency.
552
- private final Map<String, PhoneMetadata> regionToMetadataMap =
553
- Collections.synchronizedMap(new HashMap<String, PhoneMetadata>());
554
-
555
- // A mapping from a country calling code for a non-geographical entity to the PhoneMetadata for
556
- // that country calling code. Examples of the country calling codes include 800 (International
557
- // Toll Free Service) and 808 (International Shared Cost Service).
558
- // Note: Synchronization, though only needed for the Android version of the library, is used in
559
- // all versions for consistency.
560
- private final Map<Integer, PhoneMetadata> countryCodeToNonGeographicalMetadataMap =
561
- Collections.synchronizedMap(new HashMap<Integer, PhoneMetadata>());
562
-
563
545
  // A cache for frequently used region-specific regular expressions.
564
546
  // The initial capacity is set to 100 as this seems to be an optimal value for Android, based on
565
547
  // performance measurements.
@@ -574,19 +556,13 @@ public class PhoneNumberUtil {
574
556
  // currently contains < 12 elements so the default capacity of 16 (load factor=0.75) is fine.
575
557
  private final Set<Integer> countryCodesForNonGeographicalRegion = new HashSet<Integer>();
576
558
 
577
- // The prefix of the metadata files from which region data is loaded.
578
- private final String currentFilePrefix;
579
- // The metadata loader used to inject alternative metadata sources.
580
- private final MetadataLoader metadataLoader;
581
-
582
559
  /**
583
560
  * This class implements a singleton, the constructor is only visible to facilitate testing.
584
561
  */
585
562
  // @VisibleForTesting
586
- PhoneNumberUtil(String filePrefix, MetadataLoader metadataLoader,
563
+ PhoneNumberUtil(MetadataSource metadataSource,
587
564
  Map<Integer, List<String>> countryCallingCodeToRegionCodeMap) {
588
- this.currentFilePrefix = filePrefix;
589
- this.metadataLoader = metadataLoader;
565
+ this.metadataSource = metadataSource;
590
566
  this.countryCallingCodeToRegionCodeMap = countryCallingCodeToRegionCodeMap;
591
567
  for (Map.Entry<Integer, List<String>> entry : countryCallingCodeToRegionCodeMap.entrySet()) {
592
568
  List<String> regionCodes = entry.getValue();
@@ -610,65 +586,6 @@ public class PhoneNumberUtil {
610
586
  nanpaRegions.addAll(countryCallingCodeToRegionCodeMap.get(NANPA_COUNTRY_CODE));
611
587
  }
612
588
 
613
- // @VisibleForTesting
614
- void loadMetadataFromFile(String filePrefix, String regionCode, int countryCallingCode,
615
- MetadataLoader metadataLoader) {
616
- boolean isNonGeoRegion = REGION_CODE_FOR_NON_GEO_ENTITY.equals(regionCode);
617
- String fileName = filePrefix + "_" +
618
- (isNonGeoRegion ? String.valueOf(countryCallingCode) : regionCode);
619
- InputStream source = metadataLoader.loadMetadata(fileName);
620
- if (source == null) {
621
- logger.log(Level.SEVERE, "missing metadata: " + fileName);
622
- throw new IllegalStateException("missing metadata: " + fileName);
623
- }
624
- ObjectInputStream in = null;
625
- try {
626
- in = new ObjectInputStream(source);
627
- PhoneMetadataCollection metadataCollection = loadMetadataAndCloseInput(in);
628
- List<PhoneMetadata> metadataList = metadataCollection.getMetadataList();
629
- if (metadataList.isEmpty()) {
630
- logger.log(Level.SEVERE, "empty metadata: " + fileName);
631
- throw new IllegalStateException("empty metadata: " + fileName);
632
- }
633
- if (metadataList.size() > 1) {
634
- logger.log(Level.WARNING, "invalid metadata (too many entries): " + fileName);
635
- }
636
- PhoneMetadata metadata = metadataList.get(0);
637
- if (isNonGeoRegion) {
638
- countryCodeToNonGeographicalMetadataMap.put(countryCallingCode, metadata);
639
- } else {
640
- regionToMetadataMap.put(regionCode, metadata);
641
- }
642
- } catch (IOException e) {
643
- logger.log(Level.SEVERE, "cannot load/parse metadata: " + fileName, e);
644
- throw new RuntimeException("cannot load/parse metadata: " + fileName, e);
645
- }
646
- }
647
-
648
- /**
649
- * Loads the metadata protocol buffer from the given stream and closes the stream afterwards. Any
650
- * exceptions that occur while reading the stream are propagated (though exceptions that occur
651
- * when the stream is closed will be ignored).
652
- *
653
- * @param source the non-null stream from which metadata is to be read.
654
- * @return the loaded metadata protocol buffer.
655
- */
656
- private static PhoneMetadataCollection loadMetadataAndCloseInput(ObjectInputStream source) {
657
- PhoneMetadataCollection metadataCollection = new PhoneMetadataCollection();
658
- try {
659
- metadataCollection.readExternal(source);
660
- } catch (IOException e) {
661
- logger.log(Level.WARNING, "error reading input (ignored)", e);
662
- } finally {
663
- try {
664
- source.close();
665
- } catch (IOException e) {
666
- logger.log(Level.WARNING, "error closing input stream (ignored)", e);
667
- }
668
- }
669
- return metadataCollection;
670
- }
671
-
672
589
  /**
673
590
  * Attempts to extract a possible number from the string passed in. This currently strips all
674
591
  * leading characters that cannot be used to start a phone number. Characters that can be used to
@@ -1019,6 +936,26 @@ public class PhoneNumberUtil {
1019
936
  return instance;
1020
937
  }
1021
938
 
939
+ /**
940
+ * Create a new {@link PhoneNumberUtil} instance to carry out international phone number
941
+ * formatting, parsing, or validation. The instance is loaded with all metadata by
942
+ * using the metadataSource specified.
943
+ *
944
+ * This method should only be used in the rare case in which you want to manage your own
945
+ * metadata loading. Calling this method multiple times is very expensive, as each time
946
+ * a new instance is created from scratch. When in doubt, use {@link #getInstance}.
947
+ *
948
+ * @param metadataSource Customized metadata source. This should not be null.
949
+ * @return a PhoneNumberUtil instance
950
+ */
951
+ public static PhoneNumberUtil createInstance(MetadataSource metadataSource) {
952
+ if (metadataSource == null) {
953
+ throw new IllegalArgumentException("metadataSource could not be null.");
954
+ }
955
+ return new PhoneNumberUtil(metadataSource,
956
+ CountryCodeToRegionCodeMap.getCountryCodeToRegionCodeMap());
957
+ }
958
+
1022
959
  /**
1023
960
  * Create a new {@link PhoneNumberUtil} instance to carry out international phone number
1024
961
  * formatting, parsing, or validation. The instance is loaded with all metadata by
@@ -1028,16 +965,14 @@ public class PhoneNumberUtil {
1028
965
  * metadata loading. Calling this method multiple times is very expensive, as each time
1029
966
  * a new instance is created from scratch. When in doubt, use {@link #getInstance}.
1030
967
  *
1031
- * @param metadataLoader Customized metadata loader. If null, default metadata loader will
1032
- * be used. This should not be null.
968
+ * @param metadataLoader Customized metadata loader. This should not be null.
1033
969
  * @return a PhoneNumberUtil instance
1034
970
  */
1035
971
  public static PhoneNumberUtil createInstance(MetadataLoader metadataLoader) {
1036
972
  if (metadataLoader == null) {
1037
973
  throw new IllegalArgumentException("metadataLoader could not be null.");
1038
974
  }
1039
- return new PhoneNumberUtil(META_DATA_FILE_PREFIX, metadataLoader,
1040
- CountryCodeToRegionCodeMap.getCountryCodeToRegionCodeMap());
975
+ return createInstance(new MultiFileMetadataSourceImpl(metadataLoader));
1041
976
  }
1042
977
 
1043
978
  /**
@@ -2038,27 +1973,14 @@ public class PhoneNumberUtil {
2038
1973
  if (!isValidRegionCode(regionCode)) {
2039
1974
  return null;
2040
1975
  }
2041
- synchronized (regionToMetadataMap) {
2042
- if (!regionToMetadataMap.containsKey(regionCode)) {
2043
- // The regionCode here will be valid and won't be '001', so we don't need to worry about
2044
- // what to pass in for the country calling code.
2045
- loadMetadataFromFile(currentFilePrefix, regionCode, 0, metadataLoader);
2046
- }
2047
- }
2048
- return regionToMetadataMap.get(regionCode);
1976
+ return metadataSource.getMetadataForRegion(regionCode);
2049
1977
  }
2050
1978
 
2051
1979
  PhoneMetadata getMetadataForNonGeographicalRegion(int countryCallingCode) {
2052
- synchronized (countryCodeToNonGeographicalMetadataMap) {
2053
- if (!countryCallingCodeToRegionCodeMap.containsKey(countryCallingCode)) {
2054
- return null;
2055
- }
2056
- if (!countryCodeToNonGeographicalMetadataMap.containsKey(countryCallingCode)) {
2057
- loadMetadataFromFile(
2058
- currentFilePrefix, REGION_CODE_FOR_NON_GEO_ENTITY, countryCallingCode, metadataLoader);
2059
- }
1980
+ if (!countryCallingCodeToRegionCodeMap.containsKey(countryCallingCode)) {
1981
+ return null;
2060
1982
  }
2061
- return countryCodeToNonGeographicalMetadataMap.get(countryCallingCode);
1983
+ return metadataSource.getMetadataForNonGeographicalRegion(countryCallingCode);
2062
1984
  }
2063
1985
 
2064
1986
  boolean isNumberPossibleForDesc(String nationalNumber, PhoneNumberDesc numberDesc) {