| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.chromoting; |
| 6 |
| 7 import java.util.HashSet; |
| 8 |
| 9 /** |
| 10 * A thread-safe event queue which provides both {@link #add} and {@link #remove
} functions with |
| 11 * O(log(n)) time complexity, and a {@link raise} function in the derived class |
| 12 * {@link Event.Raisable} to execute all queued callbacks. |
| 13 * |
| 14 * @param <ParamT> The parameter used in {@link ParameterRunnable} callback. |
| 15 */ |
| 16 public class Event<ParamT> { |
| 17 /** A runnable with parameter. */ |
| 18 public static interface ParameterRunnable<ParamT> { |
| 19 void run(ParamT p); |
| 20 } |
| 21 |
| 22 /** A callback with parameter. */ |
| 23 public static interface ParameterCallback<ReturnT, ParamT> { |
| 24 ReturnT run(ParamT p); |
| 25 } |
| 26 |
| 27 /** |
| 28 * An event provider version of {@link Event} implementation, provides {@lin
k raise} function to |
| 29 * execute appended {@link ParameterRunnable}, and {@link clear} function to
clear all appended |
| 30 * callbacks. |
| 31 */ |
| 32 public static final class Raisable<ParamT> extends Event<ParamT> { |
| 33 /** Clears all appended callbacks */ |
| 34 public void clear() { |
| 35 synchronized (mSet) { |
| 36 mSet.clear(); |
| 37 } |
| 38 } |
| 39 |
| 40 /** |
| 41 * Executes all queued {@link ParameterRunnable} with |parameter|, retur
ns an integer of |
| 42 * total callbacks executed. Note, if an 'add' function call is executin
g concurrently |
| 43 * with the 'raise' function call, the newly added object may not be exe
cuted. |
| 44 */ |
| 45 public int raise(ParamT parameter) { |
| 46 Object[] array; |
| 47 synchronized (mSet) { |
| 48 array = mSet.toArray(); |
| 49 } |
| 50 int count = 0; |
| 51 for (Object obj : array) { |
| 52 execute(obj, parameter); |
| 53 count++; |
| 54 } |
| 55 return count; |
| 56 } |
| 57 |
| 58 /** Executes |obj| as ParameterRunnable<ParamT> with |parameter| as Para
mT. */ |
| 59 @SuppressWarnings("unchecked") |
| 60 private void execute(Object obj, ParamT parameter) { |
| 61 ParameterRunnable<ParamT> runnable = (ParameterRunnable<ParamT>) obj
; |
| 62 runnable.run(parameter); |
| 63 } |
| 64 } |
| 65 |
| 66 /** |
| 67 * A self removable {@link ParameterRunner}, uses a boolean {@link Parameter
Callback} to decide |
| 68 * whether removes self from {@link Event} or not. |
| 69 */ |
| 70 private static class SelfRemovableParameterRunnable<ParamT> |
| 71 implements ParameterRunnable<ParamT> { |
| 72 private final ParameterCallback<Boolean, ParamT> mCallback; |
| 73 private final Event<ParamT> mOwner; |
| 74 |
| 75 // This lock is used to make sure mEvent is correctly set before remove
in run function. |
| 76 // i.e. mOwner.add and assigment of mEvent need to be atomic. |
| 77 private final Object mLock; |
| 78 private final Object mEvent; |
| 79 |
| 80 private SelfRemovableParameterRunnable(Event<ParamT> owner, |
| 81 ParameterCallback<Boolean, ParamT
> callback) { |
| 82 Preconditions.notNull(callback); |
| 83 mCallback = callback; |
| 84 mOwner = owner; |
| 85 mLock = new Object(); |
| 86 synchronized (mLock) { |
| 87 mEvent = mOwner.add(this); |
| 88 } |
| 89 Preconditions.notNull(mEvent); |
| 90 } |
| 91 |
| 92 public final void run(ParamT p) { |
| 93 synchronized (mLock) { |
| 94 if (mOwner.contains(mEvent)) { |
| 95 if (!mCallback.run(p)) { |
| 96 // Event.Raisable.clear may be called in a different thr
ead. |
| 97 mOwner.remove(mEvent); |
| 98 } |
| 99 } |
| 100 } |
| 101 } |
| 102 } |
| 103 |
| 104 protected final HashSet<ParameterRunnable<ParamT>> mSet; |
| 105 |
| 106 public Event() { |
| 107 mSet = new HashSet<>(); |
| 108 } |
| 109 |
| 110 /** |
| 111 * Adds a {@link ParameterRunnable} object into current instance, returns an
object which can |
| 112 * be used to {@link remove} the runnable from this instance. If |runnable|
is null or it has |
| 113 * been added to this instance already, this function returns null. |
| 114 */ |
| 115 public Object add(ParameterRunnable<ParamT> runnable) { |
| 116 if (runnable == null) { |
| 117 return null; |
| 118 } |
| 119 synchronized (mSet) { |
| 120 if (mSet.add(runnable)) { |
| 121 return runnable; |
| 122 } |
| 123 } |
| 124 return null; |
| 125 } |
| 126 |
| 127 /** |
| 128 * Adds a self removable {@link ParameterRunnable} object into current insta
nce; the runnable |
| 129 * will remove itself from {@link Event} instance when callback returns fals
e. |
| 130 */ |
| 131 public void addSelfRemovable(ParameterCallback<Boolean, ParamT> callback) { |
| 132 Preconditions.notNull(callback); |
| 133 |
| 134 // SelfRemovableParameterRunner is self-contained, i.e. consumers do not
need to have a |
| 135 // reference of this instance, but all the logic is in new function. |
| 136 new SelfRemovableParameterRunnable<ParamT>(this, callback); |
| 137 } |
| 138 |
| 139 /** |
| 140 * Removes an object that was previously returned by {@link add}. Returns fa
lse if the object |
| 141 * is not in the event queue, or not returned by {@link add} function. |
| 142 */ |
| 143 public boolean remove(Object obj) { |
| 144 synchronized (mSet) { |
| 145 return mSet.remove(obj); |
| 146 } |
| 147 } |
| 148 |
| 149 /** |
| 150 * Returns whether current instance contains the object that was previously
returned by |
| 151 * {@link add}. |
| 152 */ |
| 153 public boolean contains(Object obj) { |
| 154 synchronized (mSet) { |
| 155 return mSet.contains(obj); |
| 156 } |
| 157 } |
| 158 |
| 159 /** |
| 160 * Returns the total count of runnables attached to current instance. |
| 161 */ |
| 162 public int size() { |
| 163 synchronized (mSet) { |
| 164 return mSet.size(); |
| 165 } |
| 166 } |
| 167 |
| 168 /** |
| 169 * Returns true if there is no runnable attached to current instance. |
| 170 */ |
| 171 public boolean isEmpty() { |
| 172 synchronized (mSet) { |
| 173 return mSet.isEmpty(); |
| 174 } |
| 175 } |
| 176 } |
| OLD | NEW |