summaryrefslogtreecommitdiffstats
path: root/tools/java
diff options
context:
space:
mode:
authorlararennie@google.com <lararennie@google.com@ee073f10-1060-11df-b6a4-87a95322a99c>2011-06-16 10:51:07 +0000
committerlararennie@google.com <lararennie@google.com@ee073f10-1060-11df-b6a4-87a95322a99c>2011-06-16 10:51:07 +0000
commit64fb6ace3b6a981a5f26b0044e9e61ad94087858 (patch)
tree5e3099b8fbd8cda89f0b1f35f412c73787b60b56 /tools/java
parent9c34776764671274289777fb4e88d4138b814ba6 (diff)
downloadandroid_external_libphonenumbergoogle-64fb6ace3b6a981a5f26b0044e9e61ad94087858.tar.gz
android_external_libphonenumbergoogle-64fb6ace3b6a981a5f26b0044e9e61ad94087858.tar.bz2
android_external_libphonenumbergoogle-64fb6ace3b6a981a5f26b0044e9e61ad94087858.zip
TOOLS: Moving java generation code under tools. Patch contributed by philip.liard.
git-svn-id: http://libphonenumber.googlecode.com/svn/trunk@242 ee073f10-1060-11df-b6a4-87a95322a99c
Diffstat (limited to 'tools/java')
-rw-r--r--tools/java/common/src/com/google/i18n/phonenumbers/tools/BuildMetadataFromXml.java2
-rw-r--r--tools/java/java-build/src/com/google/i18n/phonenumbers/tools/BuildMetadataJsonFromXml.java357
-rw-r--r--tools/java/java-build/src/com/google/i18n/phonenumbers/tools/BuildMetadataProtoFromXml.java185
-rw-r--r--tools/java/java-build/src/com/google/i18n/phonenumbers/tools/EntryPoint.java35
-rw-r--r--tools/java/java-build/src/com/google/i18n/phonenumbers/tools/GenerateAreaCodeData.java299
-rw-r--r--tools/java/java-build/src/com/google/i18n/phonenumbers/tools/JSArrayBuilder.java135
-rw-r--r--tools/java/pom.xml1
7 files changed, 1013 insertions, 1 deletions
diff --git a/tools/java/common/src/com/google/i18n/phonenumbers/tools/BuildMetadataFromXml.java b/tools/java/common/src/com/google/i18n/phonenumbers/tools/BuildMetadataFromXml.java
index 3a8787c..3b19d73 100644
--- a/tools/java/common/src/com/google/i18n/phonenumbers/tools/BuildMetadataFromXml.java
+++ b/tools/java/common/src/com/google/i18n/phonenumbers/tools/BuildMetadataFromXml.java
@@ -70,7 +70,7 @@ public class BuildMetadataFromXml {
// Build a mapping from a country calling code to the region codes which denote the country/region
// represented by that country code. In the case of multiple countries sharing a calling code,
- // such as the NANPA countries, the one indicated with "isMainCountryForCode" in the metadata
+ // such as the NANPA countries, the one indicated with "getMainCountryForCode" in the metadata
// should be first.
public static Map<Integer, List<String>> buildCountryCodeToRegionCodeMap(
PhoneMetadataCollection metadataCollection) {
diff --git a/tools/java/java-build/src/com/google/i18n/phonenumbers/tools/BuildMetadataJsonFromXml.java b/tools/java/java-build/src/com/google/i18n/phonenumbers/tools/BuildMetadataJsonFromXml.java
new file mode 100644
index 0000000..a37fd3b
--- /dev/null
+++ b/tools/java/java-build/src/com/google/i18n/phonenumbers/tools/BuildMetadataJsonFromXml.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.i18n.phonenumbers.tools;
+
+import com.google.i18n.phonenumbers.Phonemetadata.NumberFormat;
+import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
+import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadataCollection;
+import com.google.i18n.phonenumbers.Phonemetadata.PhoneNumberDesc;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Tool to convert phone number metadata from the XML format to JSON format.
+ *
+ * @author Nikolaos Trogkanis
+ */
+public class BuildMetadataJsonFromXml extends Command {
+ private static final String NAMESPACE = "i18n.phonenumbers.metadata";
+
+ private static final String HELP_MESSAGE =
+ "Usage:\n" +
+ "BuildMetadataJsonFromXml <inputFile> <outputFile> [<liteBuild>]\n" +
+ "\n" +
+ "where:\n" +
+ " inputFile The input file containing phone number metadata in XML format.\n" +
+ " outputFile The output file to contain phone number metadata in JSON format.\n" +
+ " liteBuild Whether to generate the lite-version of the metadata (default:\n" +
+ " false). When set to true certain metadata will be omitted.\n" +
+ " At this moment, example numbers information is omitted.\n" +
+ "\n" +
+ "Example command line invocation:\n" +
+ "BuildMetadataJsonFromXml PhoneNumberMetadata.xml metadatalite.js true\n";
+
+ private static final String FILE_OVERVIEW =
+ "/**\n" +
+ " * @fileoverview Generated metadata for file\n" +
+ " * %s\n" +
+ " * @author Nikolaos Trogkanis\n" +
+ " */\n\n";
+
+ private static final String COUNTRY_CODE_TO_REGION_CODE_MAP_COMMENT =
+ "/**\n" +
+ " * A mapping from a country calling code to the region codes which denote the\n" +
+ " * region represented by that country calling code. In the case of multiple\n" +
+ " * countries sharing a calling code, such as the NANPA regions, the one\n" +
+ " * indicated with \"isMainCountryForCode\" in the metadata should be first.\n" +
+ " * @type {Object.<number, Array.<string>>}\n" +
+ " */\n";
+
+ private static final String COUNTRY_TO_METADATA_COMMENT =
+ "/**\n" +
+ " * A mapping from a region code to the PhoneMetadata for that region.\n" +
+ " * @type {Object.<string, Array>}\n" +
+ " */\n";
+
+ @Override
+ public String getCommandName() {
+ return "BuildMetadataJsonFromXml";
+ }
+
+ @Override
+ public boolean start() {
+ String[] args = getArgs();
+
+ if (args.length != 3 && args.length != 4) {
+ System.err.println(HELP_MESSAGE);
+ return false;
+ }
+ String inputFile = args[1];
+ String outputFile = args[2];
+ boolean liteBuild = args.length > 3 && args[3].equals("true");
+
+ try {
+ PhoneMetadataCollection metadataCollection =
+ BuildMetadataFromXml.buildPhoneMetadataCollection(inputFile, liteBuild);
+ Map<Integer, List<String>> countryCodeToRegionCodeMap =
+ BuildMetadataFromXml.buildCountryCodeToRegionCodeMap(metadataCollection);
+
+ BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile));
+
+ writer.write(CopyrightNotice.TEXT);
+ Formatter formatter = new Formatter(writer);
+ formatter.format(FILE_OVERVIEW, inputFile);
+
+ writer.write("goog.provide('" + NAMESPACE + "');\n\n");
+
+ writer.write(COUNTRY_CODE_TO_REGION_CODE_MAP_COMMENT);
+ writer.write(NAMESPACE + ".countryCodeToRegionCodeMap = ");
+ writeCountryCodeToRegionCodeMap(countryCodeToRegionCodeMap, writer);
+ writer.write(";\n\n");
+
+ writer.write(COUNTRY_TO_METADATA_COMMENT);
+ writer.write(NAMESPACE + ".countryToMetadata = ");
+ writeCountryToMetadataMap(metadataCollection, writer);
+ writer.write(";\n");
+
+ writer.flush();
+ writer.close();
+ } catch (Exception e) {
+ System.err.println(HELP_MESSAGE);
+ return false;
+ }
+ return true;
+ }
+
+ // Writes a PhoneMetadataCollection in JSON format.
+ private static void writeCountryToMetadataMap(PhoneMetadataCollection metadataCollection,
+ BufferedWriter writer) throws IOException {
+ writer.write("{\n");
+ boolean isFirstTimeInLoop = true;
+ for (PhoneMetadata metadata : metadataCollection.getMetadataList()) {
+ if (isFirstTimeInLoop) {
+ isFirstTimeInLoop = false;
+ } else {
+ writer.write(",");
+ }
+ String regionCode = metadata.getId();
+ JSArrayBuilder jsArrayBuilder = new JSArrayBuilder();
+ toJsArray(metadata, jsArrayBuilder);
+ writer.write("\"");
+ writer.write(regionCode);
+ writer.write("\":");
+ writer.write(jsArrayBuilder.toString());
+ }
+ writer.write("}");
+ }
+
+ // Writes a Map<Integer, List<String>> in JSON format.
+ private static void writeCountryCodeToRegionCodeMap(
+ Map<Integer, List<String>> countryCodeToRegionCodeMap,
+ BufferedWriter writer) throws IOException {
+ writer.write("{\n");
+ boolean isFirstTimeInLoop = true;
+ for (Map.Entry<Integer, List<String>> entry : countryCodeToRegionCodeMap.entrySet()) {
+ if (isFirstTimeInLoop) {
+ isFirstTimeInLoop = false;
+ } else {
+ writer.write(",");
+ }
+ writer.write(Integer.toString(entry.getKey()));
+ writer.write(":");
+ JSArrayBuilder jsArrayBuilder = new JSArrayBuilder();
+ jsArrayBuilder.beginArray();
+ jsArrayBuilder.appendIterator(entry.getValue().iterator());
+ jsArrayBuilder.endArray();
+ writer.write(jsArrayBuilder.toString());
+ }
+ writer.write("}");
+ }
+
+ // Converts NumberFormat to JSArray.
+ private static void toJsArray(NumberFormat format, JSArrayBuilder jsArrayBuilder) {
+ jsArrayBuilder.beginArray();
+
+ // missing 0
+ jsArrayBuilder.append(null);
+ // required string pattern = 1;
+ jsArrayBuilder.append(format.getPattern());
+ // required string format = 2;
+ jsArrayBuilder.append(format.getFormat());
+ // repeated string leading_digits_pattern = 3;
+ int leadingDigitsPatternSize = format.leadingDigitsPatternSize();
+ if (leadingDigitsPatternSize > 0) {
+ jsArrayBuilder.beginArray();
+ for (int i = 0; i < leadingDigitsPatternSize; i++) {
+ jsArrayBuilder.append(format.getLeadingDigitsPattern(i));
+ }
+ jsArrayBuilder.endArray();
+ } else {
+ jsArrayBuilder.append(null);
+ }
+ // optional string national_prefix_formatting_rule = 4;
+ if (format.hasNationalPrefixFormattingRule()) {
+ jsArrayBuilder.append(format.getNationalPrefixFormattingRule());
+ } else {
+ jsArrayBuilder.append(null);
+ }
+ // optional string domestic_carrier_code_formatting_rule = 5;
+ if (format.hasDomesticCarrierCodeFormattingRule()) {
+ jsArrayBuilder.append(format.getDomesticCarrierCodeFormattingRule());
+ } else {
+ jsArrayBuilder.append(null);
+ }
+
+ jsArrayBuilder.endArray();
+ }
+
+ // Converts PhoneNumberDesc to JSArray.
+ private static void toJsArray(PhoneNumberDesc desc, JSArrayBuilder jsArrayBuilder) {
+ jsArrayBuilder.beginArray();
+
+ // missing 0
+ jsArrayBuilder.append(null);
+ // missing 1
+ jsArrayBuilder.append(null);
+ // optional string national_number_pattern = 2;
+ if (desc.hasNationalNumberPattern()) {
+ jsArrayBuilder.append(desc.getNationalNumberPattern());
+ } else {
+ jsArrayBuilder.append(null);
+ }
+ // optional string possible_number_pattern = 3;
+ if (desc.hasPossibleNumberPattern()) {
+ jsArrayBuilder.append(desc.getPossibleNumberPattern());
+ } else {
+ jsArrayBuilder.append(null);
+ }
+ // missing 4
+ jsArrayBuilder.append(null);
+ // missing 5
+ jsArrayBuilder.append(null);
+ // optional string example_number = 6;
+ if (desc.hasExampleNumber()) {
+ jsArrayBuilder.append(desc.getExampleNumber());
+ } else {
+ jsArrayBuilder.append(null);
+ }
+
+ jsArrayBuilder.endArray();
+ }
+
+ // Converts PhoneMetadata to JSArray.
+ private static void toJsArray(PhoneMetadata metadata, JSArrayBuilder jsArrayBuilder) {
+ jsArrayBuilder.beginArray();
+
+ // missing 0
+ jsArrayBuilder.append(null);
+ // required PhoneNumberDesc general_desc = 1;
+ toJsArray(metadata.getGeneralDesc(), jsArrayBuilder);
+ // required PhoneNumberDesc fixed_line = 2;
+ toJsArray(metadata.getFixedLine(), jsArrayBuilder);
+ // required PhoneNumberDesc mobile = 3;
+ toJsArray(metadata.getMobile(), jsArrayBuilder);
+ // required PhoneNumberDesc toll_free = 4;
+ toJsArray(metadata.getTollFree(), jsArrayBuilder);
+ // required PhoneNumberDesc premium_rate = 5;
+ toJsArray(metadata.getPremiumRate(), jsArrayBuilder);
+ // required PhoneNumberDesc shared_cost = 6;
+ toJsArray(metadata.getSharedCost(), jsArrayBuilder);
+ // required PhoneNumberDesc personal_number = 7;
+ toJsArray(metadata.getPersonalNumber(), jsArrayBuilder);
+ // required PhoneNumberDesc voip = 8;
+ toJsArray(metadata.getVoip(), jsArrayBuilder);
+ // required string id = 9;
+ jsArrayBuilder.append(metadata.getId());
+ // required int32 country_code = 10;
+ jsArrayBuilder.append(metadata.getCountryCode());
+ // required string international_prefix = 11;
+ jsArrayBuilder.append(metadata.getInternationalPrefix());
+
+ // optional string national_prefix = 12;
+ if (metadata.hasNationalPrefix()) {
+ jsArrayBuilder.append(metadata.getNationalPrefix());
+ } else {
+ jsArrayBuilder.append(null);
+ }
+ // optional string preferred_extn_prefix = 13;
+ if (metadata.hasPreferredExtnPrefix()) {
+ jsArrayBuilder.append(metadata.getPreferredExtnPrefix());
+ } else {
+ jsArrayBuilder.append(null);
+ }
+ // missing 14
+ jsArrayBuilder.append(null);
+ // optional string national_prefix_for_parsing = 15;
+ if (metadata.hasNationalPrefixForParsing()) {
+ jsArrayBuilder.append(metadata.getNationalPrefixForParsing());
+ } else {
+ jsArrayBuilder.append(null);
+ }
+ // optional string national_prefix_transform_rule = 16;
+ if (metadata.hasNationalPrefixTransformRule()) {
+ jsArrayBuilder.append(metadata.getNationalPrefixTransformRule());
+ } else {
+ jsArrayBuilder.append(null);
+ }
+ // optional string preferred_international_prefix = 17;
+ if (metadata.hasPreferredInternationalPrefix()) {
+ jsArrayBuilder.append(metadata.getPreferredInternationalPrefix());
+ } else {
+ jsArrayBuilder.append(null);
+ }
+ // optional bool same_mobile_and_fixed_line_pattern = 18 [default=false];
+ if (metadata.getSameMobileAndFixedLinePattern()) {
+ jsArrayBuilder.append(1);
+ } else {
+ jsArrayBuilder.append(null);
+ }
+ // repeated NumberFormat number_format = 19;
+ int numberFormatSize = metadata.numberFormatSize();
+ if (numberFormatSize > 0) {
+ jsArrayBuilder.beginArray();
+ for (int i = 0; i < numberFormatSize; i++) {
+ toJsArray(metadata.getNumberFormat(i), jsArrayBuilder);
+ }
+ jsArrayBuilder.endArray();
+ } else {
+ jsArrayBuilder.append(null);
+ }
+ // repeated NumberFormat intl_number_format = 20;
+ int intlNumberFormatSize = metadata.intlNumberFormatSize();
+ if (intlNumberFormatSize > 0) {
+ jsArrayBuilder.beginArray();
+ for (int i = 0; i < intlNumberFormatSize; i++) {
+ toJsArray(metadata.getIntlNumberFormat(i), jsArrayBuilder);
+ }
+ jsArrayBuilder.endArray();
+ } else {
+ jsArrayBuilder.append(null);
+ }
+ // required PhoneNumberDesc pager = 21;
+ toJsArray(metadata.getPager(), jsArrayBuilder);
+ // optional bool main_country_for_code = 22 [default=false];
+ if (metadata.isMainCountryForCode()) {
+ jsArrayBuilder.append(1);
+ } else {
+ jsArrayBuilder.append(null);
+ }
+ // optional string leading_digits = 23;
+ if (metadata.hasLeadingDigits()) {
+ jsArrayBuilder.append(metadata.getLeadingDigits());
+ } else {
+ jsArrayBuilder.append(null);
+ }
+ // required PhoneNumberDesc no_international_dialling = 24;
+ toJsArray(metadata.getNoInternationalDialling(), jsArrayBuilder);
+ // required PhoneNumberDesc uan = 25;
+ toJsArray(metadata.getUan(), jsArrayBuilder);
+ // optional bool leading_zero_possible = 26 [default=false];
+ if (metadata.isLeadingZeroPossible()) {
+ jsArrayBuilder.append(1);
+ } else {
+ jsArrayBuilder.append(null);
+ }
+
+ jsArrayBuilder.endArray();
+ }
+}
diff --git a/tools/java/java-build/src/com/google/i18n/phonenumbers/tools/BuildMetadataProtoFromXml.java b/tools/java/java-build/src/com/google/i18n/phonenumbers/tools/BuildMetadataProtoFromXml.java
new file mode 100644
index 0000000..2e488c1
--- /dev/null
+++ b/tools/java/java-build/src/com/google/i18n/phonenumbers/tools/BuildMetadataProtoFromXml.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.i18n.phonenumbers.tools;
+
+import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
+import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadataCollection;
+
+import java.io.BufferedWriter;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Tool to convert phone number metadata from the XML format to protocol buffer format.
+ *
+ * @author Shaopeng Jia
+ */
+public class BuildMetadataProtoFromXml extends Command {
+ private static final String PACKAGE_NAME = "com/google/i18n/phonenumbers";
+ private static final String META_DATA_FILE_PREFIX =
+ "/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto";
+ private static final String TEST_META_DATA_FILE_PREFIX =
+ "/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProtoForTesting";
+ private static final String TEST_COUNTRY_CODE_TO_REGION_CODE_MAP_CLASS_NAME =
+ "CountryCodeToRegionCodeMapForTesting";
+ private static final String COUNTRY_CODE_TO_REGION_CODE_MAP_CLASS_NAME =
+ "CountryCodeToRegionCodeMap";
+
+ private static final String HELP_MESSAGE =
+ "Usage:\n" +
+ "BuildMetadataProtoFromXml <inputFile> <outputDir> <forTesting> [<liteBuild>]\n" +
+ "\n" +
+ "where:\n" +
+ " inputFile The input file containing phone number metadata in XML format.\n" +
+ " outputDir The output directory to store phone number metadata in proto\n" +
+ " format (one file per region) and the country code to region code\n" +
+ " mapping file.\n" +
+ " forTesting Flag whether to generate metadata for testing purposes or not.\n" +
+ " liteBuild Whether to generate the lite-version of the metadata (default:\n" +
+ " false). When set to true certain metadata will be omitted.\n" +
+ " At this moment, example numbers information is omitted.\n" +
+ "\n" +
+ "Metadata will be stored in:\n" +
+ " <outputDir>" + META_DATA_FILE_PREFIX + "_*\n" +
+ "Mapping file will be stored in:\n" +
+ " <outputDir>/" + PACKAGE_NAME + "/" +
+ COUNTRY_CODE_TO_REGION_CODE_MAP_CLASS_NAME + ".java\n" +
+ "\n" +
+ "Example command line invocation:\n" +
+ "BuildMetadataProtoFromXml PhoneNumberMetadata.xml src false false\n";
+
+ @Override
+ public String getCommandName() {
+ return "BuildMetadataProtoFromXml";
+ }
+
+ @Override
+ public boolean start() {
+ String[] args = getArgs();
+ if (args.length != 4 && args.length != 5) {
+ System.err.println(HELP_MESSAGE);
+ return false;
+ }
+ String inputFile = args[1];
+ String outputDir = args[2];
+ boolean forTesting = args[3].equals("true");
+ boolean liteBuild = args.length > 4 && args[4].equals("true");
+
+ String filePrefix;
+ if (forTesting) {
+ filePrefix = outputDir + TEST_META_DATA_FILE_PREFIX;
+ } else {
+ filePrefix = outputDir + META_DATA_FILE_PREFIX;
+ }
+
+ try {
+ PhoneMetadataCollection metadataCollection =
+ BuildMetadataFromXml.buildPhoneMetadataCollection(inputFile, liteBuild);
+
+ for (PhoneMetadata metadata : metadataCollection.getMetadataList()) {
+ String regionCode = metadata.getId();
+ PhoneMetadataCollection outMetadataCollection = new PhoneMetadataCollection();
+ outMetadataCollection.addMetadata(metadata);
+ FileOutputStream outputForRegion = new FileOutputStream(filePrefix + "_" + regionCode);
+ ObjectOutputStream out = new ObjectOutputStream(outputForRegion);
+ outMetadataCollection.writeExternal(out);
+ out.close();
+ }
+
+ Map<Integer, List<String>> countryCodeToRegionCodeMap =
+ BuildMetadataFromXml.buildCountryCodeToRegionCodeMap(metadataCollection);
+
+ writeCountryCallingCodeMappingToJavaFile(countryCodeToRegionCodeMap, outputDir, forTesting);
+ } catch (Exception e) {
+ System.err.println(HELP_MESSAGE);
+ return false;
+ }
+ return true;
+ }
+
+ private static final String MAPPING_IMPORTS =
+ "import java.util.ArrayList;\n" +
+ "import java.util.HashMap;\n" +
+ "import java.util.List;\n" +
+ "import java.util.Map;\n";
+ private static final String MAPPING_COMMENT =
+ " // A mapping from a country code to the region codes which denote the\n" +
+ " // country/region represented by that country code. In the case of multiple\n" +
+ " // countries sharing a calling code, such as the NANPA countries, the one\n" +
+ " // indicated with \"isMainCountryForCode\" in the metadata should be first.\n";
+ private static final double MAPPING_LOAD_FACTOR = 0.75;
+ private static final String MAPPING_COMMENT_2 =
+ " // The capacity is set to %d as there are %d different country codes,\n" +
+ " // and this offers a load factor of roughly " + MAPPING_LOAD_FACTOR + ".\n";
+
+ private static void writeCountryCallingCodeMappingToJavaFile(
+ Map<Integer, List<String>> countryCodeToRegionCodeMap,
+ String outputDir, boolean forTesting) throws IOException {
+ String mappingClassName;
+ if (forTesting) {
+ mappingClassName = TEST_COUNTRY_CODE_TO_REGION_CODE_MAP_CLASS_NAME;
+ } else {
+ mappingClassName = COUNTRY_CODE_TO_REGION_CODE_MAP_CLASS_NAME;
+ }
+ String mappingFile =
+ outputDir + "/" + PACKAGE_NAME.replaceAll("\\.", "/") + "/" + mappingClassName + ".java";
+ int capacity = (int) (countryCodeToRegionCodeMap.size() / MAPPING_LOAD_FACTOR);
+
+ BufferedWriter writer = new BufferedWriter(new FileWriter(mappingFile));
+
+ writer.write(CopyrightNotice.TEXT);
+ if (PACKAGE_NAME.length() > 0) {
+ writer.write("package " + PACKAGE_NAME + ";\n\n");
+ }
+ writer.write(MAPPING_IMPORTS);
+ writer.write("\n");
+ writer.write("public class " + mappingClassName + " {\n");
+ writer.write(MAPPING_COMMENT);
+ writer.write(" static Map<Integer, List<String>> getCountryCodeToRegionCodeMap() {\n");
+ Formatter formatter = new Formatter(writer);
+ formatter.format(MAPPING_COMMENT_2, capacity, countryCodeToRegionCodeMap.size());
+ writer.write(" Map<Integer, List<String>> countryCodeToRegionCodeMap =\n");
+ writer.write(" new HashMap<Integer, List<String>>(" + capacity + ");\n");
+ writer.write("\n");
+ writer.write(" ArrayList<String> listWithRegionCode;\n");
+ writer.write("\n");
+
+ for (Map.Entry<Integer, List<String>> entry : countryCodeToRegionCodeMap.entrySet()) {
+ int countryCallingCode = entry.getKey();
+ List<String> regionCodes = entry.getValue();
+ writer.write(" listWithRegionCode = new ArrayList<String>(" + regionCodes.size() + ");\n");
+ for (String regionCode : regionCodes) {
+ writer.write(" listWithRegionCode.add(\"" + regionCode + "\");\n");
+ }
+ writer.write(" countryCodeToRegionCodeMap.put(" + countryCallingCode +
+ ", listWithRegionCode);\n");
+ writer.write("\n");
+ }
+
+ writer.write(" return countryCodeToRegionCodeMap;\n");
+ writer.write(" }\n");
+ writer.write("}\n");
+
+ writer.flush();
+ writer.close();
+ }
+}
diff --git a/tools/java/java-build/src/com/google/i18n/phonenumbers/tools/EntryPoint.java b/tools/java/java-build/src/com/google/i18n/phonenumbers/tools/EntryPoint.java
new file mode 100644
index 0000000..cad9518
--- /dev/null
+++ b/tools/java/java-build/src/com/google/i18n/phonenumbers/tools/EntryPoint.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.i18n.phonenumbers.tools;
+
+/**
+ * Entry point class for Java and JavaScript build tools.
+ *
+ * @author Philippe Liard
+ */
+public class EntryPoint {
+
+ public static void main(String[] args) {
+ boolean status = new CommandDispatcher(args, new Command[] {
+ new BuildMetadataJsonFromXml(),
+ new BuildMetadataProtoFromXml(),
+ new GenerateAreaCodeData(),
+ }).start();
+
+ System.exit(status ? 0 : 1);
+ }
+}
diff --git a/tools/java/java-build/src/com/google/i18n/phonenumbers/tools/GenerateAreaCodeData.java b/tools/java/java-build/src/com/google/i18n/phonenumbers/tools/GenerateAreaCodeData.java
new file mode 100644
index 0000000..a21e212
--- /dev/null
+++ b/tools/java/java-build/src/com/google/i18n/phonenumbers/tools/GenerateAreaCodeData.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.i18n.phonenumbers.tools;
+
+import com.google.i18n.phonenumbers.geocoding.AreaCodeMap;
+import com.google.i18n.phonenumbers.geocoding.MappingFileProvider;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A utility that generates the binary serialization of the area code/location mappings from
+ * human-readable text files. It also generates a configuration file which contains information on
+ * data files available for use.
+ *
+ * <p> The text files must be located in sub-directories of the provided input path. For each input
+ * file inputPath/lang/countryCallingCode.txt the corresponding binary file is generated as
+ * outputPath/countryCallingCode_lang.
+ *
+ * @author Philippe Liard
+ */
+public class GenerateAreaCodeData extends Command {
+ // The path to the input directory containing the languages directories.
+ private final File inputPath;
+ // The path to the output directory.
+ private final File outputPath;
+ // Whether the data is generated for testing.
+ private final boolean forTesting;
+
+ private static final Logger LOGGER = Logger.getLogger(GenerateAreaCodeData.class.getName());
+
+ /**
+ * Empty constructor used by the EntryPoint class.
+ */
+ public GenerateAreaCodeData() {
+ inputPath = null;
+ outputPath = null;
+ forTesting = false;
+ }
+
+ public GenerateAreaCodeData(File inputPath, File outputPath, boolean forTesting)
+ throws IOException {
+ if (!inputPath.isDirectory()) {
+ throw new IOException("The provided input path does not exist: " +
+ inputPath.getAbsolutePath());
+ }
+ if (outputPath.exists()) {
+ if (!outputPath.isDirectory()) {
+ throw new IOException("Expected directory: " + outputPath.getAbsolutePath());
+ }
+ } else {
+ if (!outputPath.mkdirs()) {
+ throw new IOException("Could not create directory " + outputPath.getAbsolutePath());
+ }
+ }
+ this.inputPath = inputPath;
+ this.outputPath = outputPath;
+ this.forTesting = forTesting;
+ }
+
+ /**
+ * Closes the provided file and log any potential IOException.
+ */
+ private static void closeFile(Closeable closeable) {
+ if (closeable == null) {
+ return;
+ }
+ try {
+ closeable.close();
+ } catch (IOException e) {
+ LOGGER.log(Level.WARNING, e.getMessage());
+ }
+ }
+
+ /**
+ * Converts the text data read from the provided input stream to the Java binary serialization
+ * format. The resulting data is written to the provided output stream.
+ *
+ * @VisibleForTesting
+ */
+ static void convertData(InputStream input, OutputStream output) throws IOException {
+ SortedMap<Integer, String> areaCodeMapTemp = new TreeMap<Integer, String>();
+ BufferedReader bufferedReader =
+ new BufferedReader(new InputStreamReader(
+ new BufferedInputStream(input), Charset.forName("UTF-8")));
+ for (String line; (line = bufferedReader.readLine()) != null; ) {
+ line = line.trim();
+ if (line.length() == 0 || line.startsWith("#")) {
+ continue;
+ }
+ int indexOfPipe = line.indexOf('|');
+ if (indexOfPipe == -1) {
+ LOGGER.log(Level.WARNING, "Malformatted data: expected '|'");
+ continue;
+ }
+ String areaCode = line.substring(0, indexOfPipe);
+ if (indexOfPipe == line.length() - 1) {
+ LOGGER.log(Level.WARNING, "Missing location for area code " + areaCode);
+ continue;
+ }
+ String location = line.substring(indexOfPipe + 1);
+ areaCodeMapTemp.put(Integer.parseInt(areaCode), location);
+ }
+ // Build the corresponding area code map and serialize it to the binary format.
+ AreaCodeMap areaCodeMap = new AreaCodeMap();
+ areaCodeMap.readAreaCodeMap(areaCodeMapTemp);
+ ObjectOutputStream objectOutputStream = new ObjectOutputStream(output);
+ areaCodeMap.writeExternal(objectOutputStream);
+ objectOutputStream.flush();
+ }
+
+ private class Pair<A, B> {
+ public final A first;
+ public final B second;
+
+ public Pair(A first, B second) {
+ this.first = first;
+ this.second = second;
+ }
+ }
+
+ /**
+ * Creates the input country code text file/output binary file (named countryCode_language)
+ * mappings.
+ */
+ private List<Pair<File, File>> createInputOutputFileMappings() {
+ List<Pair<File, File>> mappings = new ArrayList<Pair<File, File>>();
+ File[] languageDirectories = inputPath.listFiles();
+
+ for (File languageDirectory : languageDirectories) {
+ if (!languageDirectory.isDirectory() || languageDirectory.isHidden()) {
+ continue;
+ }
+ File[] countryCodeFiles = languageDirectory.listFiles();
+
+ for (File countryCodeFile : countryCodeFiles) {
+ if (countryCodeFile.isHidden()) {
+ continue;
+ }
+ String countryCodeFileName = countryCodeFile.getName();
+ int indexOfDot = countryCodeFileName.indexOf('.');
+ if (indexOfDot == -1) {
+ LOGGER.log(Level.WARNING,
+ String.format("unexpected file name %s, expected pattern .*\\.txt",
+ countryCodeFileName));
+ continue;
+ }
+ String countryCode = countryCodeFileName.substring(0, indexOfDot);
+ if (!countryCode.matches("\\d+")) {
+ LOGGER.log(Level.WARNING, "ignoring unexpected file " + countryCodeFileName);
+ continue;
+ }
+ mappings.add(new Pair<File, File>(
+ countryCodeFile,
+ new File(outputPath,
+ String.format("%s_%s", countryCode, languageDirectory.getName()))));
+ }
+ }
+ return mappings;
+ }
+
+ /**
+ * Adds a country code/language mapping to the provided map. The country code and language are
+ * generated from the provided file name previously used to output the area code/location mappings
+ * for the given country.
+ *
+ * @VisibleForTesting
+ */
+ static void addConfigurationMapping(SortedMap<Integer, Set<String>> availableDataFiles,
+ File outputAreaCodeMappingsFile) {
+ String outputAreaCodeMappingsFileName = outputAreaCodeMappingsFile.getName();
+ int indexOfUnderscore = outputAreaCodeMappingsFileName.indexOf('_');
+ int countryCode = Integer.parseInt(
+ outputAreaCodeMappingsFileName.substring(0, indexOfUnderscore));
+ String language = outputAreaCodeMappingsFileName.substring(indexOfUnderscore + 1);
+
+ Set<String> languageSet = availableDataFiles.get(countryCode);
+ if (languageSet == null) {
+ languageSet = new HashSet<String>();
+ availableDataFiles.put(countryCode, languageSet);
+ }
+ languageSet.add(language);
+ }
+
+ /**
+ * Outputs the binary configuration file mapping country codes to language strings.
+ *
+ * @VisibleForTesting
+ */
+ static void outputBinaryConfiguration(SortedMap<Integer, Set<String>> availableDataFiles,
+ OutputStream outputStream) throws IOException {
+ MappingFileProvider mappingFileProvider = new MappingFileProvider();
+ mappingFileProvider.readFileConfigs(availableDataFiles);
+ ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
+ mappingFileProvider.writeExternal(objectOutputStream);
+ objectOutputStream.flush();
+ }
+
+ /**
+ * Runs the area code data generator.
+ *
+ * @throws IOException
+ * @throws FileNotFoundException
+ */
+ public void run() throws FileNotFoundException, IOException {
+ List<Pair<File, File>> inputOutputMappings = createInputOutputFileMappings();
+ SortedMap<Integer, Set<String>> availableDataFiles = new TreeMap<Integer, Set<String>>();
+
+ for (Pair<File, File> inputOutputMapping : inputOutputMappings) {
+ FileInputStream fileInputStream = null;
+ FileOutputStream fileOutputStream = null;
+
+ try {
+ File textFile = inputOutputMapping.first;
+ File binaryFile = inputOutputMapping.second;
+ fileInputStream = new FileInputStream(textFile);
+ fileOutputStream = new FileOutputStream(binaryFile);
+ convertData(fileInputStream, fileOutputStream);
+ addConfigurationMapping(availableDataFiles, inputOutputMapping.second);
+ } catch (IOException e) {
+ LOGGER.log(Level.SEVERE, e.getMessage());
+ continue;
+ } finally {
+ closeFile(fileInputStream);
+ closeFile(fileOutputStream);
+ }
+ }
+ // Output the binary configuration file mapping country codes to languages.
+ FileOutputStream fileOutputStream = null;
+
+ try {
+ File configFile = new File(outputPath, "config");
+ fileOutputStream = new FileOutputStream(configFile);
+ outputBinaryConfiguration(availableDataFiles, fileOutputStream);
+ } finally {
+ closeFile(fileOutputStream);
+ }
+ }
+
+ @Override
+ public String getCommandName() {
+ return "GenerateAreaCodeData";
+ }
+
+ @Override
+ public boolean start() {
+ String[] args = getArgs();
+
+ if (args.length != 4) {
+ LOGGER.log(Level.SEVERE,
+ "usage: GenerateAreaCodeData /path/to/input/directory /path/to/output/directory" +
+ " forTesting");
+ return false;
+ }
+ try {
+ GenerateAreaCodeData generateAreaCodeData =
+ new GenerateAreaCodeData(new File(args[1]), new File(args[2]),
+ Boolean.parseBoolean(args[3]));
+ generateAreaCodeData.run();
+ } catch (IOException e) {
+ LOGGER.log(Level.SEVERE, e.getMessage());
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/tools/java/java-build/src/com/google/i18n/phonenumbers/tools/JSArrayBuilder.java b/tools/java/java-build/src/com/google/i18n/phonenumbers/tools/JSArrayBuilder.java
new file mode 100644
index 0000000..fa91b4f
--- /dev/null
+++ b/tools/java/java-build/src/com/google/i18n/phonenumbers/tools/JSArrayBuilder.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.i18n.phonenumbers.tools;
+
+import java.util.Iterator;
+
+/**
+ * A sequence of elements representing a JavaScript Array. The principal operation on a
+ * JSArrayBuilder is the append method that appends an element to the array. To facilitate nesting
+ * beginArray and endArray are also supported. Example of a JSArray: ["a", ["b', "c"]].
+ *
+ * @author Nikolaos Trogkanis
+ */
+public class JSArrayBuilder implements CharSequence {
+ // Internal representation.
+ private StringBuilder data = new StringBuilder();
+ // Flag that keeps track whether the element being added to the array is the first element.
+ private boolean isFirstElement = true;
+
+ /**
+ * Begin a new element.
+ */
+ private void beginElement() {
+ if (!isFirstElement) {
+ data.append(',');
+ }
+ isFirstElement = false;
+ }
+
+ /**
+ * Begin a new array.
+ */
+ public JSArrayBuilder beginArray() {
+ beginElement();
+ data.append('[');
+ isFirstElement = true;
+ return this;
+ }
+
+ /**
+ * End an array.
+ */
+ public JSArrayBuilder endArray() {
+ trimTrailingCommas();
+ data.append("]\n");
+ isFirstElement = false;
+ return this;
+ }
+
+ /**
+ * Add a number to the array.
+ */
+ public JSArrayBuilder append(int number) {
+ return append(Integer.toString(number), false);
+ }
+
+ /**
+ * Add a string to the array.
+ */
+ public JSArrayBuilder append(String string) {
+ return append(string, true);
+ }
+
+ /**
+ * Add a collection of strings to the array.
+ */
+ public final JSArrayBuilder appendIterator(Iterator<String> iterator) {
+ while (iterator.hasNext()) {
+ append(iterator.next());
+ }
+ return this;
+ }
+
+ // Adds a string to the array with an option to escape the string or not.
+ private JSArrayBuilder append(String string, boolean escapeString) {
+ beginElement();
+ if (string != null) {
+ if (escapeString) {
+ escape(string, data);
+ } else {
+ data.append(string);
+ }
+ }
+ return this;
+ }
+
+ // Returns a string representing the data in this JSArray.
+ @Override public String toString() {
+ return data.toString();
+ }
+
+ // Double quotes a string and replaces "\" with "\\".
+ private static void escape(String str, StringBuilder out) {
+ out.append('"');
+ out.append(str.replaceAll("\\\\", "\\\\\\\\"));
+ out.append('"');
+ }
+
+ // Trims trailing commas.
+ private void trimTrailingCommas() {
+ int i = data.length();
+ while (i > 0 && data.charAt(i - 1) == ',') {
+ i--;
+ }
+ if (i < data.length()) {
+ data.delete(i, data.length());
+ }
+ }
+
+ public char charAt(int index) {
+ return data.charAt(index);
+ }
+
+ public int length() {
+ return data.length();
+ }
+
+ public CharSequence subSequence(int start, int end) {
+ return data.subSequence(start, end);
+ }
+}
diff --git a/tools/java/pom.xml b/tools/java/pom.xml
index efd7b7d..e10480e 100644
--- a/tools/java/pom.xml
+++ b/tools/java/pom.xml
@@ -21,6 +21,7 @@
<modules>
<module>cpp-build</module>
+ <module>java-build</module>
</modules>
</project>