--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/util/resources/ParallelListResourceBundle.java Fri Apr 12 07:57:35 2013 -0700
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.util.resources;
+
+import java.util.AbstractSet;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicMarkableReference;
+
+/**
+ * ParallelListResourceBundle is another variant of ListResourceBundle
+ * supporting "parallel" contents provided by another resource bundle
+ * (OpenListResourceBundle). Parallel contents, if any, are added into this
+ * bundle on demand.
+ *
+ * @author Masayoshi Okutsu
+ */
+public abstract class ParallelListResourceBundle extends ResourceBundle {
+ private volatile ConcurrentMap<String, Object> lookup;
+ private volatile Set<String> keyset;
+ private final AtomicMarkableReference<Object[][]> parallelContents
+ = new AtomicMarkableReference<>(null, false);
+
+ /**
+ * Sole constructor. (For invocation by subclass constructors, typically
+ * implicit.)
+ */
+ protected ParallelListResourceBundle() {
+ }
+
+ /**
+ * Returns an array in which each item is a pair of objects in an
+ * Object array. The first element of each pair is the key, which
+ * must be a String, and the second element is the value
+ * associated with that key. See the class description for
+ * details.
+ *
+ * @return an array of an Object array representing a key-value pair.
+ */
+ protected abstract Object[][] getContents();
+
+ /**
+ * Returns the parent of this resource bundle or null if there's no parent.
+ *
+ * @return the parent or null if no parent
+ */
+ ResourceBundle getParent() {
+ return parent;
+ }
+
+ /**
+ * Sets the parallel contents to the data given by rb. If rb is null, this
+ * bundle will be marked as `complete'.
+ *
+ * @param rb an OpenResourceBundle for parallel contents, or null indicating
+ * there are no parallel contents for this bundle
+ */
+ public void setParallelContents(OpenListResourceBundle rb) {
+ if (rb == null) {
+ parallelContents.compareAndSet(null, null, false, true);
+ } else {
+ parallelContents.compareAndSet(null, rb.getContents(), false, false);
+ }
+ }
+
+ /**
+ * Returns true if any parallel contents have been set or if this bundle is
+ * marked as complete.
+ *
+ * @return true if any parallel contents have been processed
+ */
+ boolean areParallelContentsComplete() {
+ // Quick check for `complete'
+ if (parallelContents.isMarked()) {
+ return true;
+ }
+ boolean[] done = new boolean[1];
+ Object[][] data = parallelContents.get(done);
+ return data != null || done[0];
+ }
+
+ @Override
+ protected Object handleGetObject(String key) {
+ if (key == null) {
+ throw new NullPointerException();
+ }
+
+ loadLookupTablesIfNecessary();
+ return lookup.get(key);
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(keySet());
+ }
+
+ @Override
+ public boolean containsKey(String key) {
+ return keySet().contains(key);
+ }
+
+ @Override
+ protected Set<String> handleKeySet() {
+ loadLookupTablesIfNecessary();
+ return lookup.keySet();
+ }
+
+ @Override
+ @SuppressWarnings("UnusedAssignment")
+ public Set<String> keySet() {
+ Set<String> ks;
+ while ((ks = keyset) == null) {
+ ks = new KeySet(handleKeySet(), parent);
+ synchronized (this) {
+ if (keyset == null) {
+ keyset = ks;
+ }
+ }
+ }
+ return ks;
+ }
+
+ /**
+ * Discards any cached keyset value. This method is called from
+ * LocaleData for re-creating a KeySet.
+ */
+ synchronized void resetKeySet() {
+ keyset = null;
+ }
+
+ /**
+ * Loads the lookup table if they haven't been loaded already.
+ */
+ void loadLookupTablesIfNecessary() {
+ ConcurrentMap<String, Object> map = lookup;
+ if (map == null) {
+ map = new ConcurrentHashMap<>();
+ for (Object[] item : getContents()) {
+ map.put((String) item[0], item[1]);
+ }
+ }
+
+ // If there's any parallel contents data, merge the data into map.
+ Object[][] data = parallelContents.getReference();
+ if (data != null) {
+ for (Object[] item : data) {
+ map.putIfAbsent((String) item[0], item[1]);
+ }
+ parallelContents.set(null, true);
+ }
+ if (lookup == null) {
+ synchronized (this) {
+ if (lookup == null) {
+ lookup = map;
+ }
+ }
+ }
+ }
+
+ /**
+ * This class implements the Set interface for
+ * ParallelListResourceBundle methods.
+ */
+ private static class KeySet extends AbstractSet<String> {
+ private final Set<String> set;
+ private final ResourceBundle parent;
+
+ private KeySet(Set<String> set, ResourceBundle parent) {
+ this.set = set;
+ this.parent = parent;
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ if (set.contains(o)) {
+ return true;
+ }
+ return (parent != null) ? parent.containsKey((String) o) : false;
+ }
+
+ @Override
+ public Iterator<String> iterator() {
+ if (parent == null) {
+ return set.iterator();
+ }
+ return new Iterator<String>() {
+ private Iterator<String> itr = set.iterator();
+ private boolean usingParent;
+
+ @Override
+ public boolean hasNext() {
+ if (itr.hasNext()) {
+ return true;
+ }
+ if (!usingParent) {
+ Set<String> nextset = new HashSet<>(parent.keySet());
+ nextset.removeAll(set);
+ itr = nextset.iterator();
+ usingParent = true;
+ }
+ return itr.hasNext();
+ }
+
+ @Override
+ public String next() {
+ if (hasNext()) {
+ return itr.next();
+ }
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ @Override
+ public int size() {
+ if (parent == null) {
+ return set.size();
+ }
+ Set<String> allset = new HashSet<>(set);
+ allset.addAll(parent.keySet());
+ return allset.size();
+ }
+ }
+}