| /* |
| * 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.extensions; |
| |
| import com.intellij.openapi.Disposable; |
| import com.intellij.openapi.extensions.impl.ExtensionsAreaImpl; |
| import com.intellij.openapi.util.Disposer; |
| import gnu.trove.THashMap; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.jetbrains.annotations.TestOnly; |
| |
| import java.util.Map; |
| import java.util.concurrent.ConcurrentHashMap; |
| |
| public class Extensions { |
| public static final ExtensionPointName<AreaListener> AREA_LISTENER_EXTENSION_POINT = new ExtensionPointName<AreaListener>("com.intellij.arealistener"); |
| private static LogProvider ourLogger = new SimpleLogProvider(); |
| private static Map<AreaInstance,ExtensionsAreaImpl> ourAreaInstance2area = new THashMap<AreaInstance, ExtensionsAreaImpl>(); |
| private static Map<String,AreaClassConfiguration> ourAreaClass2Configuration = new THashMap<String, AreaClassConfiguration>(); |
| |
| @NotNull private static ExtensionsAreaImpl ourRootArea = createRootArea(); |
| |
| private Extensions() { |
| } |
| |
| @NotNull |
| private static ExtensionsAreaImpl createRootArea() { |
| ExtensionsAreaImpl rootArea = new ExtensionsAreaImpl(null, null, null, ourLogger); |
| rootArea.registerExtensionPoint(AREA_LISTENER_EXTENSION_POINT.getName(), AreaListener.class.getName()); |
| return rootArea; |
| } |
| |
| public static void setSynchronized() { |
| assert ourAreaInstance2area.isEmpty(); |
| assert ourAreaClass2Configuration.isEmpty(); |
| |
| ourAreaInstance2area = new ConcurrentHashMap<AreaInstance, ExtensionsAreaImpl>(); |
| ourAreaClass2Configuration = new ConcurrentHashMap<String, AreaClassConfiguration>(); |
| } |
| |
| @NotNull |
| public static ExtensionsArea getRootArea() { |
| return ourRootArea; |
| } |
| |
| @NotNull |
| public static ExtensionsArea getArea(@Nullable AreaInstance areaInstance) { |
| if (areaInstance == null) { |
| return ourRootArea; |
| } |
| ExtensionsAreaImpl area = ourAreaInstance2area.get(areaInstance); |
| if (area == null) { |
| throw new IllegalArgumentException("No area instantiated for: " + areaInstance); |
| } |
| return area; |
| } |
| |
| @TestOnly |
| public static void cleanRootArea(@NotNull Disposable parentDisposable) { |
| final ExtensionsAreaImpl oldRootArea = (ExtensionsAreaImpl)getRootArea(); |
| final ExtensionsAreaImpl newArea = createRootArea(); |
| ourRootArea = newArea; |
| oldRootArea.notifyAreaReplaced(); |
| Disposer.register(parentDisposable, new Disposable() { |
| @Override |
| public void dispose() { |
| ourRootArea = oldRootArea; |
| newArea.notifyAreaReplaced(); |
| } |
| }); |
| } |
| |
| @NotNull |
| public static Object[] getExtensions(@NonNls String extensionPointName) { |
| return getExtensions(extensionPointName, null); |
| } |
| |
| @NotNull |
| @SuppressWarnings({"unchecked"}) |
| public static <T> T[] getExtensions(@NotNull ExtensionPointName<T> extensionPointName) { |
| return (T[])getExtensions(extensionPointName.getName(), null); |
| } |
| |
| @NotNull |
| @SuppressWarnings({"unchecked"}) |
| public static <T> T[] getExtensions(@NotNull ExtensionPointName<T> extensionPointName, AreaInstance areaInstance) { |
| // keep it until 1.7 JDK |
| return Extensions.<T>getExtensions(extensionPointName.getName(), areaInstance); |
| } |
| |
| @NotNull |
| public static <T> T[] getExtensions(String extensionPointName, @Nullable AreaInstance areaInstance) { |
| ExtensionsArea area = getArea(areaInstance); |
| ExtensionPoint<T> extensionPoint = area.getExtensionPoint(extensionPointName); |
| return extensionPoint.getExtensions(); |
| } |
| |
| @NotNull |
| public static <T, U extends T> U findExtension(@NotNull ExtensionPointName<T> extensionPointName, @NotNull Class<U> extClass) { |
| for (T t : getExtensions(extensionPointName)) { |
| if (extClass.isInstance(t)) { |
| //noinspection unchecked |
| return (U) t; |
| } |
| } |
| throw new IllegalArgumentException("could not find extension implementation " + extClass); |
| } |
| |
| @NotNull |
| public static <T, U extends T> U findExtension(@NotNull ExtensionPointName<T> extensionPointName, AreaInstance areaInstance, @NotNull Class<U> extClass) { |
| for (T t : getExtensions(extensionPointName, areaInstance)) { |
| if (extClass.isInstance(t)) { |
| //noinspection unchecked |
| return (U) t; |
| } |
| } |
| throw new IllegalArgumentException("could not find extension implementation " + extClass); |
| } |
| |
| public static void instantiateArea(@NonNls @NotNull String areaClass, @NotNull AreaInstance areaInstance, @Nullable AreaInstance parentAreaInstance) { |
| AreaClassConfiguration configuration = ourAreaClass2Configuration.get(areaClass); |
| if (configuration == null) { |
| throw new IllegalArgumentException("Area class is not registered: " + areaClass); |
| } |
| ExtensionsArea parentArea = getArea(parentAreaInstance); |
| if (!equals(parentArea.getAreaClass(), configuration.getParentClassName())) { |
| throw new IllegalArgumentException("Wrong parent area. Expected class: " + configuration.getParentClassName() + " actual class: " + parentArea.getAreaClass()); |
| } |
| ExtensionsAreaImpl area = new ExtensionsAreaImpl(areaClass, areaInstance, parentArea.getPicoContainer(), ourLogger); |
| if (ourAreaInstance2area.put(areaInstance, area) != null) { |
| throw new IllegalArgumentException("Area already instantiated for: " + areaInstance); |
| } |
| for (AreaListener listener : getAreaListeners()) { |
| listener.areaCreated(areaClass, areaInstance); |
| } |
| } |
| |
| @NotNull |
| private static AreaListener[] getAreaListeners() { |
| return getRootArea().getExtensionPoint(AREA_LISTENER_EXTENSION_POINT).getExtensions(); |
| } |
| |
| public static void registerAreaClass(@NonNls @NotNull String areaClass, @Nullable @NonNls String parentAreaClass) { |
| if (ourAreaClass2Configuration.containsKey(areaClass)) { |
| // allow duplicate area class registrations if they are the same - fixing duplicate registration in tests is much more trouble |
| AreaClassConfiguration configuration = ourAreaClass2Configuration.get(areaClass); |
| if (!equals(configuration.getParentClassName(), parentAreaClass)) { |
| throw new RuntimeException("Area class already registered: " + areaClass + ", "+ ourAreaClass2Configuration.get(areaClass)); |
| } |
| else { |
| return; |
| } |
| } |
| AreaClassConfiguration configuration = new AreaClassConfiguration(areaClass, parentAreaClass); |
| ourAreaClass2Configuration.put(areaClass, configuration); |
| } |
| |
| public static void disposeArea(@NotNull AreaInstance areaInstance) { |
| assert ourAreaInstance2area.containsKey(areaInstance); |
| |
| String areaClass = ourAreaInstance2area.get(areaInstance).getAreaClass(); |
| if (areaClass == null) { |
| throw new IllegalArgumentException("Area class is null (area never instantiated?). Instance: " + areaInstance); |
| } |
| try { |
| for (AreaListener listener : getAreaListeners()) { |
| listener.areaDisposing(areaClass, areaInstance); |
| } |
| } |
| finally { |
| ourAreaInstance2area.remove(areaInstance); |
| } |
| } |
| |
| private static boolean equals(@Nullable Object object1, @Nullable Object object2) { |
| return object1 == object2 || object1 != null && object2 != null && object1.equals(object2); |
| } |
| |
| public static void setLogProvider(@NotNull LogProvider logProvider) { |
| ourLogger = logProvider; |
| } |
| |
| private static class AreaClassConfiguration { |
| private final String myClassName; |
| private final String myParentClassName; |
| |
| AreaClassConfiguration(@NotNull String className, String parentClassName) { |
| myClassName = className; |
| myParentClassName = parentClassName; |
| } |
| |
| @NotNull |
| public String getClassName() { |
| return myClassName; |
| } |
| |
| public String getParentClassName() { |
| return myParentClassName; |
| } |
| } |
| |
| @SuppressWarnings("CallToPrintStackTrace") |
| public static class SimpleLogProvider implements LogProvider { |
| @Override |
| public void error(String message) { |
| new Throwable(message).printStackTrace(); |
| } |
| |
| @Override |
| public void error(String message, @NotNull Throwable t) { |
| System.err.println(message); |
| t.printStackTrace(); |
| } |
| |
| @Override |
| public void error(@NotNull Throwable t) { |
| t.printStackTrace(); |
| } |
| |
| @Override |
| public void warn(String message) { |
| System.err.println(message); |
| } |
| |
| @Override |
| public void warn(String message, @NotNull Throwable t) { |
| System.err.println(message); |
| t.printStackTrace(); |
| } |
| |
| @Override |
| public void warn(@NotNull Throwable t) { |
| t.printStackTrace(); |
| } |
| } |
| } |