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 
  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      */
  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
 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
 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 }