1 /*
   2  * Copyright (c) 2000, 2018, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import  java.util.ArrayList;
  25 import  java.util.HashMap;
  26 import  java.util.LinkedList;
  27 import  java.util.List;
  28 import  java.util.Map;
  29 import  java.util.Set;
  30 import  java.util.TreeMap;
  31 import  java.util.TreeSet;
  32 
  33 /**
  34  * <code>Mappings</code> generates two Maps and a List which are used by
  35  * javazic BackEnd.
  36  *
  37  * @since 1.4
  38  */
  39 class Mappings {
  40     // All aliases specified by Link statements. It's alias name to
  41     // real name mappings.
  42     private Map<String,String> aliases;
  43 
  44     private List<Integer> rawOffsetsIndex;
  45 
  46     private List<Set<String>> rawOffsetsIndexTable;
  47 
  48     // Zone names to be excluded from rawOffset table. Those have GMT
  49     // offsets to change some future time.
  50     private List<String> excludeList;
  51 
  52     /**
  53      * Constructor creates some necessary instances.
  54      */
  55     Mappings() {
  56         aliases = new TreeMap<String,String>();
  57         rawOffsetsIndex = new LinkedList<Integer>();
  58         rawOffsetsIndexTable = new LinkedList<Set<String>>();
  59     }
  60 
  61     /**
  62      * Generates aliases and rawOffsets tables.
  63      * @param zi a Zoneinfo containing Zones
  64      */
  65     void add(Zoneinfo zi) {
  66         Map<String,Zone> zones = zi.getZones();
  67 
  68         for (String zoneName : zones.keySet()) {
  69             Zone zone = zones.get(zoneName);
  70             String zonename = zone.getName();
  71             int rawOffset = zone.get(zone.size()-1).getGmtOffset();
  72 
  73             // If the GMT offset of this Zone will change in some
  74             // future time, this Zone is added to the exclude list.
  75             boolean isExcluded = false;
  76             for (int i = 0; i < zone.size(); i++) {
  77                 ZoneRec zrec = zone.get(i);
  78                 if ((zrec.getGmtOffset() != rawOffset)
  79                     && (zrec.getUntilTime(0) > Time.getCurrentTime())) {
  80                     if (excludeList == null) {
  81                         excludeList = new ArrayList<String>();
  82                     }
  83                     excludeList.add(zone.getName());
  84                     isExcluded = true;
  85                     break;
  86                 }
  87             }
  88 
  89             if (!rawOffsetsIndex.contains(new Integer(rawOffset))) {
  90                 // Find the index to insert this raw offset zones
  91                 int n = rawOffsetsIndex.size();
  92                 int i;
  93                 for (i = 0; i < n; i++) {
  94                     if (rawOffsetsIndex.get(i) > rawOffset) {
  95                         break;
  96                     }
  97                 }
  98                 rawOffsetsIndex.add(i, rawOffset);
  99 
 100                 Set<String> perRawOffset = new TreeSet<String>();
 101                 if (!isExcluded) {
 102                     perRawOffset.add(zonename);
 103                 }
 104                 rawOffsetsIndexTable.add(i, perRawOffset);
 105             } else if (!isExcluded) {
 106                 int i = rawOffsetsIndex.indexOf(new Integer(rawOffset));
 107                 Set<String> perRawOffset = rawOffsetsIndexTable.get(i);
 108                 perRawOffset.add(zonename);
 109             }
 110         }
 111 
 112         Map<String,String> a = zi.getAliases();
 113         // If there are time zone names which refer to any of the
 114         // excluded zones, add those names to the excluded list.
 115         if (excludeList != null) {
 116             for (String zoneName : a.keySet()) {
 117                 String realname = a.get(zoneName);
 118                 if (excludeList.contains(realname)) {
 119                     excludeList.add(zoneName);
 120                 }
 121             }
 122         }
 123         aliases.putAll(a);
 124     }
 125 
 126     /**
 127      * Adds valid aliases to one of per-RawOffset table and removes
 128      * invalid aliases from aliases List. Aliases referring to
 129      * excluded zones are not added to a per-RawOffset table.
 130      */
 131     void resolve() {
 132         int index = rawOffsetsIndexTable.size();
 133         List<String> toBeRemoved = new ArrayList<String>();
 134         for (String key : aliases.keySet()) {
 135             boolean validname = false;
 136             for (int j = 0; j < index; j++) {
 137                 Set<String> perRO = rawOffsetsIndexTable.get(j);
 138                 boolean isExcluded = (excludeList == null) ?
 139                                         false : excludeList.contains(key);
 140 
 141                 if ((perRO.contains(aliases.get(key)) || isExcluded)
 142                     && Zone.isTargetZone(key)) {
 143                     validname = true;
 144                     if (!isExcluded) {
 145                         perRO.add(key);
 146                         Main.info("Alias <"+key+"> added to the list.");
 147                     }
 148                     break;
 149                 }
 150             }
 151 
 152             if (!validname) {
 153                 Main.info("Alias <"+key+"> removed from the list.");
 154                 toBeRemoved.add(key);
 155             }
 156         }
 157 
 158         // Remove zones, if any, from the list.
 159         for (String key : toBeRemoved) {
 160             aliases.remove(key);
 161         }
 162         // Eliminate any alias-to-alias mappings. For example, if
 163         // there are A->B and B->C, A->B is changed to A->C.
 164         Map<String, String> newMap = new HashMap<String, String>();
 165         for (String key : aliases.keySet()) {
 166             String realid = aliases.get(key);
 167             String leaf = realid;
 168             while (aliases.get(leaf) != null) {
 169                 leaf = aliases.get(leaf);
 170             }
 171             if (!realid.equals(leaf)) {
 172                 newMap.put(key, leaf);
 173             }
 174         }
 175         aliases.putAll(newMap);
 176     }
 177 
 178     Map<String,String> getAliases() {
 179         return(aliases);
 180     }
 181 
 182     List<Integer> getRawOffsetsIndex() {
 183         return(rawOffsetsIndex);
 184     }
 185 
 186     List<Set<String>> getRawOffsetsIndexTable() {
 187         return(rawOffsetsIndexTable);
 188     }
 189 
 190     List<String> getExcludeList() {
 191         return excludeList;
 192     }
 193 }