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 }