1 /* 2 * Copyright (c) 2005, 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 /* 27 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved 28 * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved 29 * 30 * The original version of this source code and documentation 31 * is copyrighted and owned by Taligent, Inc., a wholly-owned 32 * subsidiary of IBM. These materials are provided under terms 33 * of a License Agreement between Taligent and Sun. This technology 34 * is protected by multiple US and International patents. 35 * 36 * This notice and attribution to Taligent may not be removed. 37 * Taligent is a registered trademark of Taligent, Inc. 38 * 39 */ 40 41 package sun.util.resources; 42 43 import java.util.Enumeration; 44 import java.util.HashMap; 45 import java.util.HashSet; 46 import java.util.Map; 47 import java.util.ResourceBundle; 48 import java.util.Set; 49 import sun.util.ResourceBundleEnumeration; 50 51 /** 52 * Subclass of <code>ResourceBundle</code> which mimics 53 * <code>ListResourceBundle</code>, but provides more hooks 54 * for specialized subclass behavior. For general description, 55 * see {@link java.util.ListResourceBundle}. 56 * <p> 57 * This class leaves handleGetObject non-final, and 58 * adds a method createMap which allows subclasses to 59 * use specialized Map implementations. 60 */ 61 public abstract class OpenListResourceBundle extends ResourceBundle { 62 /** 63 * Sole constructor. (For invocation by subclass constructors, typically 64 * implicit.) 65 */ 66 protected OpenListResourceBundle() { 67 } 68 69 // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification. 70 public Object handleGetObject(String key) { 71 if (key == null) { 72 throw new NullPointerException(); 73 } 74 75 loadLookupTablesIfNecessary(); 76 return lookup.get(key); // this class ignores locales 77 } 78 79 /** 80 * Implementation of ResourceBundle.getKeys. 81 */ 82 public Enumeration<String> getKeys() { 83 ResourceBundle parent = this.parent; 84 return new ResourceBundleEnumeration(handleGetKeys(), 85 (parent != null) ? parent.getKeys() : null); 86 } 87 88 /** 89 * Returns a set of keys provided in this resource bundle 90 */ 91 public Set<String> handleGetKeys() { 92 loadLookupTablesIfNecessary(); 93 94 return lookup.keySet(); 95 } 96 97 @Override 98 public Set<String> keySet() { 99 if (keyset != null) { 100 return keyset; 101 } 102 Set<String> ks = new HashSet<>(); 103 ks.addAll(handleGetKeys()); 104 if (parent != null) { 105 ks.addAll(parent.keySet()); 106 } 107 synchronized (this) { 108 if (keyset == null) { 109 keyset = ks; 110 } 111 } 112 return keyset; 113 } 114 115 /** 116 * Returns the parent bundle 117 */ 118 public OpenListResourceBundle getParent() { 119 return (OpenListResourceBundle)parent; 120 } 121 122 /** 123 * See ListResourceBundle class description. 124 */ 125 abstract protected Object[][] getContents(); 126 127 /** 128 * Load lookup tables if they haven't been loaded already. 129 */ 130 void loadLookupTablesIfNecessary() { 131 if (lookup == null) { 132 loadLookup(); 133 } 134 } 135 136 /** 137 * We lazily load the lookup hashtable. This function does the 138 * loading. 139 */ 140 private void loadLookup() { 141 Object[][] contents = getContents(); 142 Map<String, Object> temp = createMap(contents.length); 143 for (int i = 0; i < contents.length; ++i) { 144 // key must be non-null String, value must be non-null 145 String key = (String) contents[i][0]; 146 Object value = contents[i][1]; 147 if (key == null || value == null) { 148 throw new NullPointerException(); 149 } 150 temp.put(key, value); 151 } 152 synchronized (this) { 153 if (lookup == null) { 154 lookup = temp; 155 } 156 } 157 } 158 159 /** 160 * Lets subclasses provide specialized Map implementations. 161 * Default uses HashMap. 162 */ 163 protected Map<String, Object> createMap(int size) { 164 return new HashMap<>(size); 165 } 166 167 private volatile Map<String, Object> lookup = null; 168 private volatile Set<String> keyset; 169 }