| /* |
| * Copyright 2000-2009 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.openapi.util; |
| |
| import com.intellij.openapi.Disposable; |
| import com.intellij.openapi.util.objectTree.ObjectTree; |
| import com.intellij.openapi.util.objectTree.ObjectTreeAction; |
| import com.intellij.util.ReflectionUtil; |
| import com.intellij.util.containers.ConcurrentWeakHashMap; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Modifier; |
| import java.util.Map; |
| |
| @SuppressWarnings({"SSBasedInspection"}) |
| public class Disposer { |
| private static final ObjectTree<Disposable> ourTree; |
| |
| static { |
| try { |
| ourTree = new ObjectTree<Disposable>(); |
| } |
| catch (NoClassDefFoundError e) { |
| throw new RuntimeException("loader=" + Disposer.class.getClassLoader(), e); |
| } |
| } |
| |
| private static final ObjectTreeAction<Disposable> ourDisposeAction = new ObjectTreeAction<Disposable>() { |
| @Override |
| public void execute(@NotNull final Disposable each) { |
| each.dispose(); |
| } |
| |
| @Override |
| public void beforeTreeExecution(@NotNull final Disposable parent) { |
| if (parent instanceof Disposable.Parent) { |
| ((Disposable.Parent)parent).beforeTreeDispose(); |
| } |
| } |
| }; |
| |
| private static boolean ourDebugMode; |
| |
| private Disposer() { |
| } |
| |
| @NotNull |
| public static Disposable newDisposable() { |
| return new Disposable() { |
| @Override |
| public void dispose() { |
| } |
| }; |
| } |
| |
| private static final Map<String, Disposable> ourKeyDisposables = new ConcurrentWeakHashMap<String, Disposable>(); |
| |
| public static void register(@NotNull Disposable parent, @NotNull Disposable child) { |
| register(parent, child, null); |
| } |
| |
| public static void register(@NotNull Disposable parent, @NotNull Disposable child, @NonNls @Nullable final String key) { |
| assert parent != child : " Cannot register to itself"; |
| |
| ourTree.register(parent, child); |
| |
| if (key != null) { |
| assert get(key) == null; |
| ourKeyDisposables.put(key, child); |
| register(child, new Disposable() { |
| @Override |
| public void dispose() { |
| ourKeyDisposables.remove(key); |
| } |
| }); |
| } |
| } |
| |
| public static boolean isDisposed(@NotNull Disposable disposable) { |
| return !ourTree.containsKey(disposable); |
| } |
| |
| public static Disposable get(@NotNull String key) { |
| return ourKeyDisposables.get(key); |
| } |
| |
| public static void dispose(@NotNull Disposable disposable) { |
| dispose(disposable, true); |
| } |
| |
| public static void dispose(@NotNull Disposable disposable, boolean processUnregistered) { |
| ourTree.executeAll(disposable, true, ourDisposeAction, processUnregistered); |
| } |
| |
| public static void disposeChildAndReplace(@NotNull Disposable toDispose, @NotNull Disposable toReplace) { |
| ourTree.executeChildAndReplace(toDispose, toReplace, true, ourDisposeAction); |
| } |
| |
| @NotNull |
| public static ObjectTree<Disposable> getTree() { |
| return ourTree; |
| } |
| |
| public static void assertIsEmpty() { |
| assertIsEmpty(false); |
| } |
| public static void assertIsEmpty(boolean throwError) { |
| if (ourDebugMode) { |
| ourTree.assertIsEmpty(throwError); |
| } |
| } |
| |
| public static boolean isEmpty() { |
| return ourDebugMode && ourTree.isEmpty(); |
| } |
| |
| public static void setDebugMode(final boolean b) { |
| ourDebugMode = b; |
| } |
| |
| public static boolean isDebugMode() { |
| return ourDebugMode; |
| } |
| |
| public static void clearOwnFields(@NotNull Object object) { |
| final Field[] all = object.getClass().getDeclaredFields(); |
| for (Field each : all) { |
| if ((each.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) > 0) continue; |
| ReflectionUtil.resetField(object, each); |
| } |
| } |
| |
| /** |
| * @return object registered on parentDisposable which is equal to object, or null if not found |
| */ |
| @Nullable |
| public static <T extends Disposable> T findRegisteredObject(@NotNull Disposable parentDisposable, @NotNull T object) { |
| return ourTree.findRegisteredObject(parentDisposable, object); |
| } |
| } |