1 /*
2  * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package build.tools.cldrconverter;
27 
28 import java.io.File;
29 import java.io.IOException;
30 import java.util.HashMap;
31 import java.util.Map;
32 import org.xml.sax.Attributes;
33 import org.xml.sax.InputSource;
34 import org.xml.sax.SAXException;
35 
36 /**
37  * Handles parsing of files in Locale Data Markup Language for SupplementData.xml
38  * and produces a map that uses the keys and values of JRE locale data.
39  */
40 
41 class SupplementDataParseHandler extends AbstractLDMLHandler<Object> {
42     //UNM49 region and composition code used in supplementalData.xml
43     private static final String WORLD = "001";
44 
45     private static final String JAVA_FIRSTDAY = "firstDayOfWeek";
46     private static final String JAVA_MINDAY = "minimalDaysInFirstWeek";
47 
48     // The weekData is now in supplementalData.xml,
49     // which is not a locale specific file.
50     // Map for JRE is created locale specific way.
51     // When parsing the locale neutral file (supplementalData.xml),
52     // we need to rely on the country code because
53     // the weekData is listed using country code.
54     //
55     // weekData are generated per each country
56     private final Map<String, Object> firstDayMap;
57     private final Map<String, Object> minDaysMap;
58 
59     // Parent locales. These information will only be
60     // generated towards the base meta info, with the format of
61     //
62     // parentLocale.<parent_locale_id>=<child_locale_id>(" "<child_locale_id>)+
63     private final Map<String, String> parentLocalesMap;
64 
SupplementDataParseHandler()65     SupplementDataParseHandler() {
66         firstDayMap = new HashMap<>();
67         minDaysMap = new HashMap<>();
68         parentLocalesMap = new HashMap<>();
69     }
70 
71     /**
72      * It returns Map that contains the firstDay and minDays information for
73      * the country. The Map is created in JRE format after obtaining the data
74      * from two Maps, firstDayMap and minDaysMap.
75      *
76      * It returns null when there is no firstDay and minDays for the country
77      * although this should not happen because supplementalData.xml includes
78      * default value for the world ("001") for firstDay and minDays.
79      */
getData(String id)80     Map<String, Object> getData(String id) {
81         Map<String, Object> values = new HashMap<>();
82         if ("root".equals(id)) {
83             parentLocalesMap.keySet().forEach(key -> {
84             values.put(CLDRConverter.PARENT_LOCALE_PREFIX+key,
85                 parentLocalesMap.get(key));
86             });
87             firstDayMap.keySet().forEach(key -> {
88             values.put(CLDRConverter.CALENDAR_FIRSTDAY_PREFIX+firstDayMap.get(key),
89                 key);
90             });
91             minDaysMap.keySet().forEach(key -> {
92             values.put(CLDRConverter.CALENDAR_MINDAYS_PREFIX+minDaysMap.get(key),
93                 key);
94             });
95         }
96         return values.isEmpty() ? null : values;
97     }
98 
99     @Override
resolveEntity(String publicID, String systemID)100     public InputSource resolveEntity(String publicID, String systemID) throws IOException, SAXException {
101         // avoid HTTP traffic to unicode.org
102         if (systemID.startsWith(CLDRConverter.SPPL_LDML_DTD_SYSTEM_ID)) {
103             return new InputSource((new File(CLDRConverter.LOCAL_SPPL_LDML_DTD)).toURI().toString());
104         }
105         return null;
106     }
107 
108     /**
109      * JRE requires all the data to be organized by the locale while CLDR 1.4 list
110      * Calendar related data (weekData)in SupplementalData.xml.
111      * startElement stores JRE required data into two Maps,
112      * firstDayMap and minDaysMap.
113      */
114     @Override
startElement(String uri, String localName, String qName, Attributes attributes)115     public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
116         // elements we need to actively ignore
117         switch (qName) {
118         case "firstDay":
119             if (!isIgnored(attributes)) {
120                 String fd;
121 
122                 switch (attributes.getValue("day")) {
123                     case "sun":
124                         fd = "1";
125                         break;
126                     default:
127                     case "mon":
128                         fd = "2";
129                         break;
130                     case "tue":
131                         fd = "3";
132                         break;
133                     case "wed":
134                         fd = "4";
135                         break;
136                     case "thu":
137                         fd = "5";
138                         break;
139                     case "fri":
140                         fd = "6";
141                         break;
142                     case "sat":
143                         fd = "7";
144                         break;
145                 }
146                 firstDayMap.put(attributes.getValue("territories"), fd);
147             }
148             break;
149         case "minDays":
150             if (!isIgnored(attributes)) {
151                 minDaysMap.put(attributes.getValue("territories"), attributes.getValue("count"));
152             }
153             break;
154         case "parentLocale":
155             if (!isIgnored(attributes)) {
156                 parentLocalesMap.put(
157                     attributes.getValue("parent").replaceAll("_", "-"),
158                     attributes.getValue("locales").replaceAll("_", "-"));
159             }
160             break;
161         default:
162             // treat anything else as a container
163             pushContainer(qName, attributes);
164             break;
165         }
166     }
167 
168 }
169