1 /*
   2  * Copyright (c) 2003, 2008, 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 package sun.rmi.server;
  26 
  27 import java.lang.ref.Reference;
  28 import java.lang.ref.SoftReference;
  29 import java.util.Map;
  30 import java.util.WeakHashMap;
  31 
  32 /**
  33  * Abstract class that maps Class objects to lazily-computed values of
  34  * type V.  A concrete subclass must implement the computeValue method
  35  * to determine how the values are computed.
  36  *
  37  * The keys are only weakly reachable through this map, so this map
  38  * does not prevent a class (along with its class loader, etc.) from
  39  * being garbage collected if it is not otherwise strongly reachable.
  40  * The values are only softly reachable through this map, so that the
  41  * computed values generally persist while not otherwise strongly
  42  * reachable, but their storage may be reclaimed if necessary.  Also,
  43  * note that if a key is strongly reachable from a value, then the key
  44  * is effectively softly reachable through this map, which may delay
  45  * garbage collection of classes (see 4429536).
  46  **/
  47 public abstract class WeakClassHashMap<V> {
  48 
  49     private Map<Class<?>,ValueCell<V>> internalMap = new WeakHashMap<>();
  50 
  51     protected WeakClassHashMap() { }
  52 
  53     public V get(Class<?> remoteClass) {
  54         /*
  55          * Use a mutable cell (a one-element list) to hold the soft
  56          * reference to a value, to allow the lazy value computation
  57          * to be synchronized with entry-level granularity instead of
  58          * by locking the whole table.
  59          */
  60         ValueCell<V> valueCell;
  61         synchronized (internalMap) {
  62             valueCell = internalMap.get(remoteClass);
  63             if (valueCell == null) {
  64                 valueCell = new ValueCell<V>();
  65                 internalMap.put(remoteClass, valueCell);
  66             }
  67         }
  68         synchronized (valueCell) {
  69             V value = null;
  70             if (valueCell.ref != null) {
  71                 value = valueCell.ref.get();
  72             }
  73             if (value == null) {
  74                 value = computeValue(remoteClass);
  75                 valueCell.ref = new SoftReference<V>(value);
  76             }
  77             return value;
  78         }
  79     }
  80 
  81     protected abstract V computeValue(Class<?> remoteClass);
  82 
  83     private static class ValueCell<T> {
  84         Reference<T> ref = null;
  85         ValueCell() { }
  86     }
  87 }