1 /*
   2  * Copyright (c) 2011, 2014, 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  * To change this template, choose Tools | Templates
  28  * and open the template in the editor.
  29  */
  30 
  31 package com.sun.webkit;
  32 
  33 import java.lang.ref.ReferenceQueue;
  34 import java.lang.ref.WeakReference;
  35 import java.util.Arrays;
  36 import java.util.Collection;
  37 import java.util.HashSet;
  38 import java.util.Set;
  39 import java.util.concurrent.LinkedBlockingQueue;
  40 
  41 /**
  42  * This class is used for registering and disposing the native
  43  * data associated with java objects.
  44  *
  45  * The object can register itself by calling the addRecord method and
  46  * providing a descendant of the DisposerRecord class with overridden
  47  * dispose() method.
  48  *
  49  * When the object becomes unreachable, the dispose() method
  50  * of the associated DisposerRecord object will be called.
  51  *
  52  * @see DisposerRecord
  53  */
  54 public final class Disposer implements Runnable {
  55     private static final ReferenceQueue queue = new ReferenceQueue();
  56     private static final Disposer disposerInstance = new Disposer();
  57     private static final Set<WeakDisposerRecord> records =
  58             new HashSet<WeakDisposerRecord>();
  59 
  60     static {
  61         Thread t = new Thread(disposerInstance, "Disposer");
  62         t.setDaemon(true);
  63         t.setPriority(Thread.MAX_PRIORITY);
  64         t.start();
  65     }
  66 
  67     /**
  68      * Registers the object and the native data for later disposal.
  69      * @param target Object to be registered
  70      * @param rec the associated DisposerRecord object
  71      * @see DisposerRecord
  72      */
  73     public static void addRecord(Object target, DisposerRecord rec) {
  74         disposerInstance.add(target, rec);
  75     }
  76 
  77     /**
  78      * Performs the actual registration of the target object to be disposed.
  79      * @param target Object to be registered
  80      * @param rec the associated DisposerRecord object
  81      * @see DisposerRecord
  82      */
  83     private synchronized void add(Object target, DisposerRecord rec) {
  84         records.add(new WeakDisposerRecord(target, rec));
  85     }
  86 
  87     public void run() {
  88         while (true) {
  89             try {
  90                 WeakDisposerRecord obj = (WeakDisposerRecord) queue.remove();
  91                 obj.clear();
  92                 DisposerRunnable.getInstance().enqueue(obj);
  93             } catch (Exception e) {
  94                 System.out.println("Exception while removing reference: " + e);
  95                 e.printStackTrace();
  96             }
  97         }
  98     }
  99 
 100     private static final class DisposerRunnable implements Runnable {
 101         private static final DisposerRunnable theInstance = new DisposerRunnable();
 102 
 103         private static DisposerRunnable getInstance() {
 104             return theInstance;
 105         }
 106 
 107         private boolean isRunning = false;
 108         private final Object disposerLock = new Object();
 109         private final LinkedBlockingQueue<WeakDisposerRecord> disposerQueue
 110                 = new LinkedBlockingQueue<WeakDisposerRecord>();
 111 
 112         private void enqueueAll(Collection<WeakDisposerRecord> objs) {
 113             synchronized (disposerLock) {
 114                 disposerQueue.addAll(objs);
 115                 if (!isRunning) {
 116                     Invoker.getInvoker().invokeOnEventThread(this);
 117                     isRunning = true;
 118                 }
 119             }
 120         }
 121 
 122         private void enqueue(WeakDisposerRecord obj) {
 123             enqueueAll(Arrays.asList(obj));
 124         }
 125 
 126         @Override public void run() {
 127             while (true) {
 128                 WeakDisposerRecord obj;
 129                 synchronized (disposerLock) {
 130                     obj = disposerQueue.poll();
 131                     if (obj == null) {
 132                         isRunning = false;
 133                         break;
 134                     }
 135                 }
 136                 // Check if the object has not yet been removed & disposed.
 137                 if (records.contains(obj)) {
 138                     records.remove(obj);
 139                     obj.dispose();
 140                 }
 141             }
 142         }
 143     }
 144 
 145     public static class WeakDisposerRecord
 146         extends WeakReference
 147         implements DisposerRecord
 148     {
 149         protected WeakDisposerRecord(Object referent) {
 150             super(referent, Disposer.queue);
 151             this.record = null;
 152         }
 153 
 154         private WeakDisposerRecord(Object referent, DisposerRecord record) {
 155             super(referent, Disposer.queue);
 156             this.record = record;
 157         }
 158 
 159         private final DisposerRecord record;
 160 
 161         @Override
 162         public void dispose() {
 163             record.dispose();
 164         }
 165     }
 166 }