1 /*
2  * Copyright (C) 2019 The Android Open Source Project
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 package com.android.libcore.timezone.telephonylookup;
17 
18 import java.io.FileOutputStream;
19 import java.io.IOException;
20 import java.io.OutputStreamWriter;
21 import java.io.StringReader;
22 import java.io.StringWriter;
23 import java.io.Writer;
24 import java.nio.charset.StandardCharsets;
25 import java.util.List;
26 import java.util.Objects;
27 
28 import javax.xml.stream.XMLOutputFactory;
29 import javax.xml.stream.XMLStreamException;
30 import javax.xml.stream.XMLStreamWriter;
31 import javax.xml.transform.OutputKeys;
32 import javax.xml.transform.Transformer;
33 import javax.xml.transform.TransformerException;
34 import javax.xml.transform.TransformerFactory;
35 import javax.xml.transform.stream.StreamResult;
36 import javax.xml.transform.stream.StreamSource;
37 
38 /**
39  * A class that knows about the structure of the telephonylookup.xml file.
40  */
41 final class TelephonyLookupXmlFile {
42 
43     // <telephony_lookup>
44     private static final String TELEPHONY_LOOKUP_ELEMENT = "telephony_lookup";
45 
46     // <networks>
47     private static final String NETWORKS_ELEMENT = "networks";
48 
49     // <network mcc="123" mnc="456" country="gu">
50     private static final String NETWORK_ELEMENT = "network";
51     private static final String MOBILE_COUNTRY_CODE_ATTRIBUTE = "mcc";
52     private static final String MOBILE_NETWORK_CODE_ATTRIBUTE = "mnc";
53     private static final String COUNTRY_ISO_CODE_ATTRIBUTE = "country";
54 
write(TelephonyLookup telephonyLookup, String outputFile)55     static void write(TelephonyLookup telephonyLookup, String outputFile)
56             throws XMLStreamException, IOException {
57         /*
58          * The required XML structure is:
59          * <telephony_lookup>
60          *   <networks>
61          *     <network mcc="123" mnc="456" country="zz"/>
62          *     <network mcc="123" mnc="789" country="zz"/>
63          *     </network>
64          *   </networks>
65          * </telephony_lookup>
66          */
67 
68         StringWriter writer = new StringWriter();
69         writeRaw(telephonyLookup, writer);
70         String rawXml = writer.getBuffer().toString();
71 
72         TransformerFactory factory = TransformerFactory.newInstance();
73         try (Writer fileWriter = new OutputStreamWriter(
74                 new FileOutputStream(outputFile), StandardCharsets.UTF_8)) {
75 
76             // Transform the XML with the identity transform but with indenting
77             // so it's more human-readable.
78             Transformer transformer = factory.newTransformer();
79             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
80             transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "1");
81             transformer.transform(
82                     new StreamSource(new StringReader(rawXml)), new StreamResult(fileWriter));
83         } catch (TransformerException e) {
84             throw new XMLStreamException(e);
85         }
86     }
87 
writeRaw(TelephonyLookup telephonyLookup, Writer fileWriter)88     private static void writeRaw(TelephonyLookup telephonyLookup, Writer fileWriter)
89             throws XMLStreamException {
90         XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newFactory();
91         XMLStreamWriter xmlWriter = xmlOutputFactory.createXMLStreamWriter(fileWriter);
92         xmlWriter.writeStartDocument();
93         xmlWriter.writeComment("\n\n **** Autogenerated file - DO NOT EDIT ****\n\n");
94         TelephonyLookup.writeXml(telephonyLookup, xmlWriter);
95         xmlWriter.writeEndDocument();
96     }
97 
98     static class TelephonyLookup {
99         private final List<Network> networks;
100 
TelephonyLookup(List<Network> networks)101         TelephonyLookup(List<Network> networks) {
102             this.networks = networks;
103         }
104 
writeXml(TelephonyLookup telephonyLookup, XMLStreamWriter writer)105         static void writeXml(TelephonyLookup telephonyLookup, XMLStreamWriter writer)
106                 throws XMLStreamException {
107             writer.writeStartElement(TELEPHONY_LOOKUP_ELEMENT);
108             writer.writeStartElement(NETWORKS_ELEMENT);
109             for (Network network : telephonyLookup.networks) {
110                 network.writeXml(network, writer);
111             }
112             writer.writeEndElement(); // NETWORKS_ELEMENT
113             writer.writeEndElement(); // TELEPHONY_LOOKUP_ELEMENT
114         }
115     }
116 
117     static class Network {
118 
119         private final String mcc;
120         private final String mnc;
121         private final String countryIsoCode;
122 
Network(String mcc, String mnc, String countryIsoCode)123         Network(String mcc, String mnc, String countryIsoCode) {
124             this.mcc = Objects.requireNonNull(mcc);
125             this.mnc = Objects.requireNonNull(mnc);
126             this.countryIsoCode = Objects.requireNonNull(countryIsoCode);
127         }
128 
writeXml(Network network, XMLStreamWriter writer)129         static void writeXml(Network network, XMLStreamWriter writer)
130                 throws XMLStreamException {
131             writer.writeStartElement(NETWORK_ELEMENT);
132             writer.writeAttribute(MOBILE_COUNTRY_CODE_ATTRIBUTE, network.mcc);
133             writer.writeAttribute(MOBILE_NETWORK_CODE_ATTRIBUTE, network.mnc);
134             writer.writeAttribute(COUNTRY_ISO_CODE_ATTRIBUTE, network.countryIsoCode);
135             writer.writeEndElement(); // NETWORK_ELEMENT
136         }
137     }
138 }
139