review cleanup
[idea/community.git] / platform / util / src / com / intellij / openapi / util / Disposer.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.openapi.util;
17
18 import com.intellij.openapi.Disposable;
19 import com.intellij.openapi.util.objectTree.ObjectTree;
20 import com.intellij.openapi.util.objectTree.ObjectTreeAction;
21 import com.intellij.util.ReflectionUtil;
22 import com.intellij.util.containers.ContainerUtil;
23 import org.jetbrains.annotations.NonNls;
24 import org.jetbrains.annotations.NotNull;
25 import org.jetbrains.annotations.Nullable;
26 import org.jetbrains.annotations.TestOnly;
27
28 import java.lang.reflect.Field;
29 import java.lang.reflect.Modifier;
30 import java.util.Map;
31
32 public class Disposer {
33   private static final ObjectTree<Disposable> ourTree;
34
35   static {
36     try {
37       ourTree = new ObjectTree<Disposable>();
38     }
39     catch (NoClassDefFoundError e) {
40       throw new RuntimeException("loader=" + Disposer.class.getClassLoader(), e);
41     }
42   }
43
44   private static final ObjectTreeAction<Disposable> ourDisposeAction = new ObjectTreeAction<Disposable>() {
45     @Override
46     public void execute(@NotNull final Disposable each) {
47       //noinspection SSBasedInspection
48       each.dispose();
49     }
50
51     @Override
52     public void beforeTreeExecution(@NotNull final Disposable parent) {
53       if (parent instanceof Disposable.Parent) {
54         ((Disposable.Parent)parent).beforeTreeDispose();
55       }
56     }
57   };
58
59   private static boolean ourDebugMode;
60
61   private Disposer() {
62   }
63
64   @NotNull
65   public static Disposable newDisposable() {
66     return new Disposable() {
67       @Override
68       public void dispose() {
69       }
70     };
71   }
72
73   private static final Map<String, Disposable> ourKeyDisposables = ContainerUtil.createConcurrentWeakMap();
74
75   public static void register(@NotNull Disposable parent, @NotNull Disposable child) {
76     register(parent, child, null);
77   }
78
79   public static void register(@NotNull Disposable parent, @NotNull Disposable child, @NonNls @Nullable final String key) {
80     assert parent != child : " Cannot register to itself";
81
82     ourTree.register(parent, child);
83
84     if (key != null) {
85       assert get(key) == null;
86       ourKeyDisposables.put(key, child);
87       register(child, new Disposable() {
88         @Override
89         public void dispose() {
90           ourKeyDisposables.remove(key);
91         }
92       });
93     }
94   }
95
96   public static boolean isDisposed(@NotNull Disposable disposable) {
97     return !ourTree.containsKey(disposable);
98   }
99
100   public static Disposable get(@NotNull String key) {
101     return ourKeyDisposables.get(key);
102   }
103
104   public static void dispose(@NotNull Disposable disposable) {
105     dispose(disposable, true);
106   }
107
108   public static void dispose(@NotNull Disposable disposable, boolean processUnregistered) {
109     ourTree.executeAll(disposable, true, ourDisposeAction, processUnregistered);
110   }
111
112   public static void disposeChildAndReplace(@NotNull Disposable toDispose, @NotNull Disposable toReplace) {
113     ourTree.executeChildAndReplace(toDispose, toReplace, true, ourDisposeAction);
114   }
115
116   @NotNull
117   public static ObjectTree<Disposable> getTree() {
118     return ourTree;
119   }
120
121   public static void assertIsEmpty() {
122     assertIsEmpty(false);
123   }
124   public static void assertIsEmpty(boolean throwError) {
125     if (ourDebugMode) {
126       ourTree.assertIsEmpty(throwError);
127     }
128   }
129
130   @TestOnly
131   public static boolean isEmpty() {
132     return ourDebugMode && ourTree.isEmpty();
133   }
134
135   /**
136    * @return old value
137    */
138   public static boolean setDebugMode(final boolean debugMode) {
139     boolean oldValue = ourDebugMode;
140     ourDebugMode = debugMode;
141     return oldValue;
142   }
143
144   public static boolean isDebugMode() {
145     return ourDebugMode;
146   }
147
148   public static void clearOwnFields(@NotNull Object object) {
149     final Field[] all = object.getClass().getDeclaredFields();
150     for (Field each : all) {
151       if ((each.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) > 0) continue;
152       ReflectionUtil.resetField(object, each);
153     }
154   }
155
156   /**
157    * @return object registered on parentDisposable which is equal to object, or null if not found
158    */
159   @Nullable
160   public static <T extends Disposable> T findRegisteredObject(@NotNull Disposable parentDisposable, @NotNull T object) {
161     return ourTree.findRegisteredObject(parentDisposable, object);
162   }
163 }