Update generated .pb.js files with proper generated proto2 descriptor APIs
[platform/upstream/libphonenumber.git] / tools / java / java-build / src / com / google / i18n / phonenumbers / BuildMetadataJsonFromXml.java
1 /*
2  * Copyright (C) 2010 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.NumberFormat;
20 import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
21 import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadataCollection;
22 import com.google.i18n.phonenumbers.Phonemetadata.PhoneNumberDesc;
23
24 import java.io.BufferedWriter;
25 import java.io.FileWriter;
26 import java.io.IOException;
27 import java.util.Formatter;
28 import java.util.List;
29 import java.util.Map;
30
31 /**
32  * Tool to convert phone number metadata from the XML format to JSON format.
33  *
34  * @author Nikolaos Trogkanis
35  */
36 public class BuildMetadataJsonFromXml extends Command {
37   private static final String NAMESPACE = "i18n.phonenumbers.metadata";
38
39   private static final String HELP_MESSAGE =
40       "Usage:\n" +
41       "BuildMetadataJsonFromXml <inputFile> <outputFile> [<liteBuild>]\n" +
42       "\n" +
43       "where:\n" +
44       "  inputFile    The input file containing phone number metadata in XML format.\n" +
45       "  outputFile   The output file to contain phone number metadata in JSON format.\n" +
46       "  liteBuild    Whether to generate the lite-version of the metadata (default:\n" +
47       "               false). When set to true certain metadata will be omitted.\n" +
48       "               At this moment, example numbers information is omitted.\n" +
49       "\n" +
50       "Example command line invocation:\n" +
51       "BuildMetadataJsonFromXml PhoneNumberMetadata.xml metadatalite.js true\n";
52
53   private static final String FILE_OVERVIEW =
54       "/**\n" +
55       " * @fileoverview Generated metadata for file\n" +
56       " * %s\n" +
57       " * @author Nikolaos Trogkanis\n" +
58       " */\n\n";
59
60   private static final String COUNTRY_CODE_TO_REGION_CODE_MAP_COMMENT =
61       "/**\n" +
62       " * A mapping from a country calling code to the region codes which denote the\n" +
63       " * region represented by that country calling code. In the case of multiple\n" +
64       " * countries sharing a calling code, such as the NANPA regions, the one\n" +
65       " * indicated with \"isMainCountryForCode\" in the metadata should be first.\n" +
66       " * @type {!Object.<number, Array.<string>>}\n" +
67       " */\n";
68
69   private static final String COUNTRY_TO_METADATA_COMMENT =
70       "/**\n" +
71       " * A mapping from a region code to the PhoneMetadata for that region.\n" +
72       " * @type {!Object.<string, Array>}\n" +
73       " */\n";
74
75   private static final int COPYRIGHT_YEAR = 2010;
76
77   @Override
78   public String getCommandName() {
79     return "BuildMetadataJsonFromXml";
80   }
81
82   @Override
83   public boolean start() {
84     String[] args = getArgs();
85
86     if (args.length != 3 && args.length != 4) {
87       System.err.println(HELP_MESSAGE);
88       return false;
89     }
90     String inputFile = args[1];
91     String outputFile = args[2];
92     boolean liteBuild = args.length > 3 && args[3].equals("true");
93
94     try {
95       PhoneMetadataCollection metadataCollection =
96           BuildMetadataFromXml.buildPhoneMetadataCollection(inputFile, liteBuild);
97       Map<Integer, List<String>> countryCodeToRegionCodeMap =
98           BuildMetadataFromXml.buildCountryCodeToRegionCodeMap(metadataCollection);
99
100       BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile));
101
102       CopyrightNotice.writeTo(writer, COPYRIGHT_YEAR, true);
103       Formatter formatter = new Formatter(writer);
104       formatter.format(FILE_OVERVIEW, inputFile);
105
106       writer.write("goog.provide('" + NAMESPACE + "');\n\n");
107
108       writer.write(COUNTRY_CODE_TO_REGION_CODE_MAP_COMMENT);
109       writer.write(NAMESPACE + ".countryCodeToRegionCodeMap = ");
110       writeCountryCodeToRegionCodeMap(countryCodeToRegionCodeMap, writer);
111       writer.write(";\n\n");
112
113       writer.write(COUNTRY_TO_METADATA_COMMENT);
114       writer.write(NAMESPACE + ".countryToMetadata = ");
115       writeCountryToMetadataMap(metadataCollection, writer);
116       writer.write(";\n");
117
118       writer.flush();
119       writer.close();
120       formatter.close();
121     } catch (Exception e) {
122       e.printStackTrace();
123       return false;
124     }
125     return true;
126   }
127
128   // Writes a PhoneMetadataCollection in JSON format.
129   private static void writeCountryToMetadataMap(PhoneMetadataCollection metadataCollection,
130                                                 BufferedWriter writer) throws IOException {
131     writer.write("{\n");
132     boolean isFirstTimeInLoop = true;
133     for (PhoneMetadata metadata : metadataCollection.getMetadataList()) {
134       if (isFirstTimeInLoop) {
135         isFirstTimeInLoop = false;
136       } else {
137         writer.write(",");
138       }
139       String key = metadata.getId();
140       // For non-geographical country calling codes (e.g. +800), use the country calling codes
141       // instead of the region code as key in the map.
142       if (key.equals("001")) {
143         key = Integer.toString(metadata.getCountryCode());
144       }
145       JSArrayBuilder jsArrayBuilder = new JSArrayBuilder();
146       toJsArray(metadata, jsArrayBuilder);
147       writer.write("\"");
148       writer.write(key);
149       writer.write("\":");
150       writer.write(jsArrayBuilder.toString());
151     }
152     writer.write("}");
153   }
154
155   // Writes a Map<Integer, List<String>> in JSON format.
156   private static void writeCountryCodeToRegionCodeMap(
157       Map<Integer, List<String>> countryCodeToRegionCodeMap,
158       BufferedWriter writer) throws IOException {
159     writer.write("{\n");
160     boolean isFirstTimeInLoop = true;
161     for (Map.Entry<Integer, List<String>> entry : countryCodeToRegionCodeMap.entrySet()) {
162       if (isFirstTimeInLoop) {
163         isFirstTimeInLoop = false;
164       } else {
165         writer.write(",");
166       }
167       writer.write(Integer.toString(entry.getKey()));
168       writer.write(":");
169       JSArrayBuilder jsArrayBuilder = new JSArrayBuilder();
170       jsArrayBuilder.beginArray();
171       jsArrayBuilder.appendIterator(entry.getValue().iterator());
172       jsArrayBuilder.endArray();
173       writer.write(jsArrayBuilder.toString());
174     }
175     writer.write("}");
176   }
177
178   // Converts NumberFormat to JSArray.
179   private static void toJsArray(NumberFormat format, JSArrayBuilder jsArrayBuilder) {
180     jsArrayBuilder.beginArray();
181
182     // missing 0
183     jsArrayBuilder.append(null);
184     // required string pattern = 1;
185     jsArrayBuilder.append(format.getPattern());
186     // required string format = 2;
187     jsArrayBuilder.append(format.getFormat());
188     // repeated string leading_digits_pattern = 3;
189     int leadingDigitsPatternSize = format.leadingDigitsPatternSize();
190     if (leadingDigitsPatternSize > 0) {
191       jsArrayBuilder.beginArray();
192       for (int i = 0; i < leadingDigitsPatternSize; i++) {
193         jsArrayBuilder.append(format.getLeadingDigitsPattern(i));
194       }
195       jsArrayBuilder.endArray();
196     } else {
197       jsArrayBuilder.append(null);
198     }
199     // optional string national_prefix_formatting_rule = 4;
200     if (format.hasNationalPrefixFormattingRule()) {
201       jsArrayBuilder.append(format.getNationalPrefixFormattingRule());
202     } else {
203       jsArrayBuilder.append(null);
204     }
205     // optional string domestic_carrier_code_formatting_rule = 5;
206     if (format.hasDomesticCarrierCodeFormattingRule()) {
207       jsArrayBuilder.append(format.getDomesticCarrierCodeFormattingRule());
208     } else {
209       jsArrayBuilder.append(null);
210     }
211     // optional bool national_prefix_optional_when_formatting = 6;
212     if (format.hasNationalPrefixOptionalWhenFormatting()) {
213       jsArrayBuilder.append(format.isNationalPrefixOptionalWhenFormatting());
214     } else {
215       jsArrayBuilder.append(null);
216     }
217
218     jsArrayBuilder.endArray();
219   }
220
221   // Converts PhoneNumberDesc to JSArray.
222   private static void toJsArray(PhoneNumberDesc desc, JSArrayBuilder jsArrayBuilder) {
223     if (desc == null) {
224       // Some descriptions are optional; in these cases we just append null and return if they are
225       // absent.
226       jsArrayBuilder.append(null);
227       return;
228     }
229     jsArrayBuilder.beginArray();
230
231     // missing 0
232     jsArrayBuilder.append(null);
233     // missing 1
234     jsArrayBuilder.append(null);
235     // optional string national_number_pattern = 2;
236     if (desc.hasNationalNumberPattern()) {
237       jsArrayBuilder.append(desc.getNationalNumberPattern());
238     } else {
239       jsArrayBuilder.append(null);
240     }
241     // optional string possible_number_pattern = 3;
242     if (desc.hasPossibleNumberPattern()) {
243       jsArrayBuilder.append(desc.getPossibleNumberPattern());
244     } else {
245       jsArrayBuilder.append(null);
246     }
247     // missing 4
248     jsArrayBuilder.append(null);
249     // missing 5
250     jsArrayBuilder.append(null);
251     // optional string example_number = 6;
252     if (desc.hasExampleNumber()) {
253       jsArrayBuilder.append(desc.getExampleNumber());
254     } else {
255       jsArrayBuilder.append(null);
256     }
257
258     jsArrayBuilder.endArray();
259   }
260
261   // Converts PhoneMetadata to JSArray.
262   private static void toJsArray(PhoneMetadata metadata, JSArrayBuilder jsArrayBuilder) {
263     jsArrayBuilder.beginArray();
264
265     // missing 0
266     jsArrayBuilder.append(null);
267     // optional PhoneNumberDesc general_desc = 1;
268     toJsArray(metadata.getGeneralDesc(), jsArrayBuilder);
269     // optional PhoneNumberDesc fixed_line = 2;
270     toJsArray(metadata.getFixedLine(), jsArrayBuilder);
271     // optional PhoneNumberDesc mobile = 3;
272     toJsArray(metadata.getMobile(), jsArrayBuilder);
273     // optional PhoneNumberDesc toll_free = 4;
274     toJsArray(metadata.getTollFree(), jsArrayBuilder);
275     // optional PhoneNumberDesc premium_rate = 5;
276     toJsArray(metadata.getPremiumRate(), jsArrayBuilder);
277     // optional PhoneNumberDesc shared_cost = 6;
278     toJsArray(metadata.getSharedCost(), jsArrayBuilder);
279     // optional PhoneNumberDesc personal_number = 7;
280     toJsArray(metadata.getPersonalNumber(), jsArrayBuilder);
281     // optional PhoneNumberDesc voip = 8;
282     toJsArray(metadata.getVoip(), jsArrayBuilder);
283     // required string id = 9;
284     jsArrayBuilder.append(metadata.getId());
285     // optional int32 country_code = 10;
286     if (metadata.hasCountryCode()) {
287       jsArrayBuilder.append(metadata.getCountryCode());
288     } else {
289       jsArrayBuilder.append(null);
290     }
291     // optional string international_prefix = 11;
292     if (metadata.hasInternationalPrefix()) {
293       jsArrayBuilder.append(metadata.getInternationalPrefix());
294     } else {
295       jsArrayBuilder.append(null);
296     }
297
298     // optional string national_prefix = 12;
299     if (metadata.hasNationalPrefix()) {
300       jsArrayBuilder.append(metadata.getNationalPrefix());
301     } else {
302       jsArrayBuilder.append(null);
303     }
304     // optional string preferred_extn_prefix = 13;
305     if (metadata.hasPreferredExtnPrefix()) {
306       jsArrayBuilder.append(metadata.getPreferredExtnPrefix());
307     } else {
308       jsArrayBuilder.append(null);
309     }
310     // missing 14
311     jsArrayBuilder.append(null);
312     // optional string national_prefix_for_parsing = 15;
313     if (metadata.hasNationalPrefixForParsing()) {
314       jsArrayBuilder.append(metadata.getNationalPrefixForParsing());
315     } else {
316       jsArrayBuilder.append(null);
317     }
318     // optional string national_prefix_transform_rule = 16;
319     if (metadata.hasNationalPrefixTransformRule()) {
320       jsArrayBuilder.append(metadata.getNationalPrefixTransformRule());
321     } else {
322       jsArrayBuilder.append(null);
323     }
324     // optional string preferred_international_prefix = 17;
325     if (metadata.hasPreferredInternationalPrefix()) {
326       jsArrayBuilder.append(metadata.getPreferredInternationalPrefix());
327     } else {
328       jsArrayBuilder.append(null);
329     }
330     // optional bool same_mobile_and_fixed_line_pattern = 18 [default=false];
331     if (metadata.isSameMobileAndFixedLinePattern()) {
332       jsArrayBuilder.append(1);
333     } else {
334       jsArrayBuilder.append(null);
335     }
336     // repeated NumberFormat number_format = 19;
337     int numberFormatSize = metadata.numberFormatSize();
338     if (numberFormatSize > 0) {
339       jsArrayBuilder.beginArray();
340       for (int i = 0; i < numberFormatSize; i++) {
341         toJsArray(metadata.getNumberFormat(i), jsArrayBuilder);
342       }
343       jsArrayBuilder.endArray();
344     } else {
345       jsArrayBuilder.append(null);
346     }
347     // repeated NumberFormat intl_number_format = 20;
348     int intlNumberFormatSize = metadata.intlNumberFormatSize();
349     if (intlNumberFormatSize > 0) {
350       jsArrayBuilder.beginArray();
351       for (int i = 0; i < intlNumberFormatSize; i++) {
352         toJsArray(metadata.getIntlNumberFormat(i), jsArrayBuilder);
353       }
354       jsArrayBuilder.endArray();
355     } else {
356       jsArrayBuilder.append(null);
357     }
358     // optional PhoneNumberDesc pager = 21;
359     toJsArray(metadata.getPager(), jsArrayBuilder);
360     // optional bool main_country_for_code = 22 [default=false];
361     if (metadata.isMainCountryForCode()) {
362       jsArrayBuilder.append(1);
363     } else {
364       jsArrayBuilder.append(null);
365     }
366     // optional string leading_digits = 23;
367     if (metadata.hasLeadingDigits()) {
368       jsArrayBuilder.append(metadata.getLeadingDigits());
369     } else {
370       jsArrayBuilder.append(null);
371     }
372     // optional PhoneNumberDesc no_international_dialling = 24;
373     toJsArray(metadata.getNoInternationalDialling(), jsArrayBuilder);
374     // optional PhoneNumberDesc uan = 25;
375     toJsArray(metadata.getUan(), jsArrayBuilder);
376     // optional bool leading_zero_possible = 26 [default=false];
377     if (metadata.isLeadingZeroPossible()) {
378       jsArrayBuilder.append(1);
379     } else {
380       jsArrayBuilder.append(null);
381     }
382     // optional PhoneNumberDesc emergency = 27;
383     toJsArray(metadata.getEmergency(), jsArrayBuilder);
384     // optional PhoneNumberDesc voicemail = 28;
385     toJsArray(metadata.getVoicemail(), jsArrayBuilder);
386     // Fields 29-31 are omitted due to space increase.
387     // optional PhoneNumberDesc short_code = 29;
388     // optional PhoneNumberDesc standard_rate = 30;
389     // optional PhoneNumberDesc carrier_specific = 31;
390     // optional bool mobile_number_portable_region = 32 [default=false];
391     // Omit since the JS API doesn't expose this data.
392     // Note: Need to add null for each of the above fields when a subsequent
393     // field is being populated.
394
395     jsArrayBuilder.endArray();
396   }
397 }