1 /*
   2  * Copyright (c) 2000, 2012, 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 import  java.util.ArrayList;
  27 import  java.util.HashMap;
  28 import  java.util.LinkedList;
  29 import  java.util.List;
  30 import  java.util.Map;
  31 import  java.util.Set;
  32 import  java.util.TreeMap;
  33 import  java.util.TreeSet;
  34 
  35 /**
  36  * <code>Mappings</code> generates two Maps and a List which are used by
  37  * javazic BackEnd.
  38  *
  39  * @since 1.4
  40  */
  41 class Mappings {
  42     // All aliases specified by Link statements. It's alias name to
  43     // real name mappings.
  44     private Map<String,String> aliases;
  45 
  46     private List<Integer> rawOffsetsIndex;
  47 
  48     private List<Set<String>> rawOffsetsIndexTable;
  49 
  50     // Zone names to be excluded from rawOffset table. Those have GMT
  51     // offsets to change some future time.
  52     private List<String> excludeList;
  53 
  54     /**
  55      * Constructor creates some necessary instances.
  56      */
  57     Mappings() {
  58         aliases = new TreeMap<String,String>();
  59         rawOffsetsIndex = new LinkedList<Integer>();
  60         rawOffsetsIndexTable = new LinkedList<Set<String>>();
  61     }
  62 
  63     /**
  64      * Generates aliases and rawOffsets tables.
  65      * @param zi a Zoneinfo containing Zones
  66      */
  67     void add(Zoneinfo zi) {
  68         Map<String,Zone> zones = zi.getZones();
  69 
  70         for (String zoneName : zones.keySet()) {
  71             Zone zone = zones.get(zoneName);
  72             String zonename = zone.getName();
  73             int rawOffset = zone.get(zone.size()-1).getGmtOffset();
  74 
  75             // If the GMT offset of this Zone will change in some
  76             // future time, this Zone is added to the exclude list.
  77             boolean isExcluded = false;
  78             for (int i = 0; i < zone.size(); i++) {
  79                 ZoneRec zrec = zone.get(i);
  80                 if ((zrec.getGmtOffset() != rawOffset)
  81                     && (zrec.getUntilTime(0) > Time.getCurrentTime())) {
  82                     if (excludeList == null) {
  83                         excludeList = new ArrayList<String>();
  84                     }
  85                     excludeList.add(zone.getName());
  86                     isExcluded = true;
  87                     break;
  88                 }
  89             }
  90 
  91             if (!rawOffsetsIndex.contains(new Integer(rawOffset))) {
  92                 // Find the index to insert this raw offset zones
  93                 int n = rawOffsetsIndex.size();
  94                 int i;
  95                 for (i = 0; i < n; i++) {
  96                     if (rawOffsetsIndex.get(i) > rawOffset) {
  97                         break;
  98                     }
  99                 }
 100                 rawOffsetsIndex.add(i, rawOffset);
 101 
 102                 Set<String> perRawOffset = new TreeSet<String>();
 103                 if (!isExcluded) {
 104                     perRawOffset.add(zonename);
 105                 }
 106                 rawOffsetsIndexTable.add(i, perRawOffset);
 107             } else if (!isExcluded) {
 108                 int i = rawOffsetsIndex.indexOf(new Integer(rawOffset));
 109                 Set<String> perRawOffset = rawOffsetsIndexTable.get(i);
 110                 perRawOffset.add(zonename);
 111             }
 112         }
 113 
 114         Map<String,String> a = zi.getAliases();
 115         // If there are time zone names which refer to any of the
 116         // excluded zones, add those names to the excluded list.
 117         if (excludeList != null) {
 118             for (String zoneName : a.keySet()) {
 119                 String realname = a.get(zoneName);
 120                 if (excludeList.contains(realname)) {
 121                     excludeList.add(zoneName);
 122                 }
 123             }
 124         }
 125         aliases.putAll(a);
 126     }
 127 
 128     /**
 129      * Adds valid aliases to one of per-RawOffset table and removes
 130      * invalid aliases from aliases List. Aliases referring to
 131      * excluded zones are not added to a per-RawOffset table.
 132      */
 133     void resolve() {
 134         int index = rawOffsetsIndexTable.size();
 135         List<String> toBeRemoved = new ArrayList<String>();
 136         for (String key : aliases.keySet()) {
 137             boolean validname = false;
 138             for (int j = 0; j < index; j++) {
 139                 Set<String> perRO = rawOffsetsIndexTable.get(j);
 140                 boolean isExcluded = (excludeList == null) ?
 141                                         false : excludeList.contains(key);
 142 
 143                 if ((perRO.contains(aliases.get(key)) || isExcluded)
 144                     && Zone.isTargetZone(key)) {
 145                     validname = true;
 146                     if (!isExcluded) {
 147                         perRO.add(key);
 148                         Main.info("Alias <"+key+"> added to the list.");
 149                     }
 150                     break;
 151                 }
 152             }
 153 
 154             if (!validname) {
 155                 Main.info("Alias <"+key+"> removed from the list.");
 156                 toBeRemoved.add(key);
 157             }
 158         }
 159 
 160         // Remove zones, if any, from the list.
 161         for (String key : toBeRemoved) {
 162             aliases.remove(key);
 163         }
 164         // Eliminate any alias-to-alias mappings. For example, if
 165         // there are A->B and B->C, A->B is changed to A->C.
 166         Map<String, String> newMap = new HashMap<String, String>();
 167         for (String key : aliases.keySet()) {
 168             String realid = aliases.get(key);
 169             String leaf = realid;
 170             while (aliases.get(leaf) != null) {
 171                 leaf = aliases.get(leaf);
 172             }
 173             if (!realid.equals(leaf)) {
 174                 newMap.put(key, leaf);
 175             }
 176         }
 177         aliases.putAll(newMap);
 178     }
 179 
 180     Map<String,String> getAliases() {
 181         return(aliases);
 182     }
 183 
 184     List<Integer> getRawOffsetsIndex() {
 185         return(rawOffsetsIndex);
 186     }
 187 
 188     List<Set<String>> getRawOffsetsIndexTable() {
 189         return(rawOffsetsIndexTable);
 190     }
 191 
 192     List<String> getExcludeList() {
 193         return excludeList;
 194     }
 195 }