[duplicates] enable duplicates analysis in PyCharm/WebStorm/PhpStorm/RubyMine
[idea/community.git] / platform / core-api / src / com / intellij / openapi / util / BusyObject.java
1 // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.openapi.util;
3
4 import org.jetbrains.annotations.NotNull;
5 import org.jetbrains.annotations.Nullable;
6
7 import java.util.ArrayList;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.WeakHashMap;
11 import java.util.concurrent.atomic.AtomicInteger;
12
13 public interface BusyObject {
14
15   @NotNull
16   ActionCallback getReady(@NotNull Object requestor);
17
18   abstract class Impl implements BusyObject {
19
20     private final Map<Object, ActionCallback> myReadyCallbacks = new WeakHashMap<>();
21
22     public abstract boolean isReady();
23
24     public final void onReady() {
25       onReady(null);
26     }
27
28     public final void onReady(@Nullable Object readyRequestor) {
29       if (!isReady()) return;
30
31       if (readyRequestor != null) {
32         Pair<ActionCallback, List<ActionCallback>> callbacks = getReadyCallbacks(readyRequestor);
33         callbacks.getFirst().setDone();
34         for (ActionCallback each : callbacks.getSecond()) {
35           each.setRejected();
36         }
37       } else {
38         ActionCallback[] callbacks = getReadyCallbacks();
39         for (ActionCallback each : callbacks) {
40           each.setDone();
41         }
42       }
43
44       onReadyWasSent();
45     }
46
47     protected void onReadyWasSent() {
48     }
49
50     @Override
51     @NotNull
52     public final ActionCallback getReady(@NotNull Object requestor) {
53       if (isReady()) {
54         return ActionCallback.DONE;
55       }
56       return addReadyCallback(requestor);
57     }
58
59     @NotNull
60     private ActionCallback addReadyCallback(Object requestor) {
61       synchronized (myReadyCallbacks) {
62         ActionCallback cb = myReadyCallbacks.get(requestor);
63         if (cb == null) {
64           cb = new ActionCallback();
65           myReadyCallbacks.put(requestor, cb);
66         }
67
68         return cb;
69       }
70     }
71
72     @NotNull
73     private ActionCallback[] getReadyCallbacks() {
74       synchronized (myReadyCallbacks) {
75         ActionCallback[] result = myReadyCallbacks.values().toArray(new ActionCallback[0]);
76         myReadyCallbacks.clear();
77         return result;
78       }
79     }
80
81     @NotNull
82     private Pair<ActionCallback, List<ActionCallback>> getReadyCallbacks(Object readyRequestor) {
83       synchronized (myReadyCallbacks) {
84         ActionCallback done = myReadyCallbacks.get(readyRequestor);
85         if (done == null) {
86           done = new ActionCallback();
87         }
88
89         myReadyCallbacks.remove(readyRequestor);
90         ArrayList<ActionCallback> rejected = new ArrayList<>(myReadyCallbacks.values());
91         myReadyCallbacks.clear();
92         return new Pair<>(done, rejected);
93       }
94     }
95
96     public static class Simple extends Impl {
97
98       private final AtomicInteger myBusyCount = new AtomicInteger();
99
100       @Override
101       public boolean isReady() {
102         return myBusyCount.get() == 0;
103       }
104
105       @NotNull
106       public ActionCallback execute(@NotNull ActiveRunnable runnable) {
107         myBusyCount.addAndGet(1);
108         ActionCallback cb = runnable.run();
109         cb.doWhenProcessed(() -> {
110           myBusyCount.addAndGet(-1);
111           if (isReady()) {
112             onReady();
113           }
114         });
115         return cb;
116       }
117     }
118   }
119
120 }