1 /*
   2  * Copyright (c) 2011, 2015, 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 package com.sun.javafx.util;
  27 
  28 import java.lang.ref.ReferenceQueue;
  29 import java.lang.ref.WeakReference;
  30 import java.util.Iterator;
  31 
  32 /**
  33  * This is a helper class for handling weak references across all devices.
  34  * We tried to use WeakHashMap, but it isn't available on mobile. We tried to
  35  * add it to mobile, but it requires ReferenceQueue and it appears that
  36  * ReferenceQueue requires support from the VM which we don't know that we
  37  * have on mobile. So this class attempts to lesson the likelyhood of
  38  * memory leaks.
  39  *
  40  * As we abandoned mobile, we considered removal of this class. But replacement
  41  * by WeakHashMap is not always possible as we use mutable elements. At least
  42  * it was now possible to optimize this class using the ReferenceQueue.
  43  */
  44 public class WeakReferenceQueue<E> {
  45     /**
  46      * Reference queue for cleared weak references
  47      */
  48     private final ReferenceQueue garbage = new ReferenceQueue();
  49 
  50     /**
  51      * Strongly referenced list head
  52      */
  53     private Object strongRef = new Object();
  54     private ListEntry head = new ListEntry(strongRef, garbage);
  55 
  56     /**
  57      * Size of the queue
  58      */
  59     int size = 0;
  60 
  61     @SuppressWarnings("unchecked")
  62     public void add(E obj) {
  63         cleanup();
  64         size++;
  65         new ListEntry(obj, garbage).insert(head.prev);
  66     }
  67     
  68     public void remove(E obj) {
  69         cleanup();
  70 
  71         ListEntry entry = head.next;
  72         while (entry != head) {
  73             Object other = entry.get();
  74             if (other == obj) {
  75                 size--;
  76                 entry.remove();
  77                 return;
  78             }
  79             entry = entry.next;
  80         }
  81     }
  82     
  83     public void cleanup() {
  84         ListEntry entry;
  85         while ((entry = (ListEntry) garbage.poll()) != null) {
  86             size--;
  87             entry.remove();
  88         }
  89     }
  90 
  91     public Iterator<? super E> iterator() {
  92         return new Iterator() {
  93             private ListEntry index = head;
  94             private Object next = null;
  95 
  96             public boolean hasNext() {
  97                 next = null;
  98                 while (next == null) {
  99                     ListEntry nextIndex = index.prev;
 100                     if (nextIndex == head) {
 101                         break;
 102                     }
 103                     next = nextIndex.get();
 104                     if (next == null) {
 105                         size--;
 106                         nextIndex.remove();
 107                     }
 108                 }
 109 
 110                 return next != null;
 111             }
 112 
 113             public Object next() {
 114                 hasNext(); // forces us to clear out crap up to the next
 115                            // valid spot
 116                 index = index.prev;
 117                 return next;
 118             }
 119 
 120             public void remove() {
 121                 if (index != head) {
 122                     ListEntry nextIndex = index.next;
 123                     size--;
 124                     index.remove();
 125                     index = nextIndex;
 126                 }
 127             }
 128         };
 129     }
 130 
 131     private static class ListEntry extends WeakReference {
 132         ListEntry prev, next;
 133 
 134         public ListEntry(Object o, ReferenceQueue queue) {
 135             super(o, queue);
 136             prev = this;
 137             next = this;
 138         }
 139 
 140         public void insert(ListEntry where) {
 141             prev = where;
 142             next = where.next;
 143             where.next = this;
 144             next.prev = this;
 145         }
 146 
 147         public void remove() {
 148             prev.next = next;
 149             next.prev = prev;
 150             next = this;
 151             prev = this;
 152         }
 153     }
 154 
 155 }