allow upsource to unregister components and services in plugin.xml: overrides="true" and implementationClass=""

This commit is contained in:
Alexey Kudravtsev
2015-04-13 14:09:04 +03:00
parent 1c5595f289
commit 3628013da1
8 changed files with 110 additions and 121 deletions
@@ -16,6 +16,8 @@
package com.intellij.openapi.components.impl;
import com.intellij.diagnostic.PluginException;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.*;
import com.intellij.openapi.components.ex.ComponentManagerEx;
@@ -24,10 +26,12 @@ import com.intellij.openapi.extensions.PluginDescriptor;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ReflectionUtil;
@@ -150,7 +154,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
@SuppressWarnings("unchecked")
@Nullable
protected <T> T getComponentFromContainer(@NotNull Class<T> interfaceClass) {
private <T> T getComponentFromContainer(@NotNull Class<T> interfaceClass) {
final T initializedComponent = (T)myInitializedComponents.get(interfaceClass);
if (initializedComponent != null) return initializedComponent;
@@ -285,16 +289,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
@NotNull
protected MutablePicoContainer createPicoContainer() {
MutablePicoContainer result;
if (myParentComponentManager != null) {
result = new DefaultPicoContainer(myParentComponentManager.getPicoContainer());
}
else {
result = new DefaultPicoContainer();
}
return result;
return myParentComponentManager == null ? new DefaultPicoContainer() : new DefaultPicoContainer(myParentComponentManager.getPicoContainer());
}
@Override
@@ -336,8 +331,18 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
temporarilyDisposed = disposed;
}
protected void loadComponentsConfiguration(@NotNull ComponentConfig[] components, @Nullable PluginDescriptor descriptor, boolean defaultProject) {
myConfigurator.loadComponentsConfiguration(components, descriptor, defaultProject);
protected void loadComponents() {
final IdeaPluginDescriptor[] plugins = PluginManagerCore.getPlugins();
boolean isDefaultProject = this instanceof Project && ((Project)this).isDefault();
for (IdeaPluginDescriptor plugin : plugins) {
if (PluginManagerCore.shouldSkipPlugin(plugin)) continue;
myConfigurator.loadComponentsConfiguration(getMyComponentConfigsFromDescriptor(plugin), plugin, isDefaultProject);
}
}
@NotNull
protected ComponentConfig[] getMyComponentConfigsFromDescriptor(@NotNull IdeaPluginDescriptor plugin) {
return plugin.getAppComponents();
}
protected void bootstrapPicoContainer(@NotNull String name) {
@@ -390,9 +395,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
if (component instanceof NamedComponent) {
return ((NamedComponent)component).getComponentName();
}
else {
return component.getClass().getName();
}
return component.getClass().getName();
}
protected boolean logSlowComponents() {
@@ -425,16 +428,30 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
try {
final Class<?> interfaceClass = Class.forName(config.getInterfaceClass(), true, loader);
final Class<?> implementationClass = Comparing.equal(config.getInterfaceClass(), config.getImplementationClass()) ?
interfaceClass : Class.forName(config.getImplementationClass(), true, loader);
if (myInterfaceToClassMap.get(interfaceClass) != null) {
throw new RuntimeException("Component already registered: " + interfaceClass.getName());
interfaceClass : StringUtil.isEmpty(config.getImplementationClass()) ? null : Class.forName(config.getImplementationClass(), true, loader);
boolean overrides = Boolean.parseBoolean(config.options.get("overrides"));
MutablePicoContainer picoContainer = getPicoContainer();
if (overrides) {
ComponentAdapter oldAdapter = picoContainer.getComponentAdapterOfType(interfaceClass);
if (oldAdapter == null) {
throw new RuntimeException(config + " does not override anything");
}
picoContainer.unregisterComponent(oldAdapter.getComponentKey());
myInterfaceToClassMap.remove(interfaceClass);
myComponentClassToConfig.remove(oldAdapter.getComponentImplementation());
myComponentInterfaces.remove(interfaceClass);
}
// implementationClass == null means we want to unregister this component
if (implementationClass != null) {
if (myInterfaceToClassMap.get(interfaceClass) != null) {
throw new RuntimeException("Component already registered: " + interfaceClass.getName());
}
getPicoContainer().registerComponent(new ComponentConfigComponentAdapter(config, implementationClass));
myInterfaceToClassMap.put(interfaceClass, implementationClass);
myComponentClassToConfig.put(implementationClass, config);
myComponentInterfaces.add(interfaceClass);
picoContainer.registerComponent(new ComponentConfigComponentAdapter(config, implementationClass));
myInterfaceToClassMap.put(interfaceClass, implementationClass);
myComponentClassToConfig.put(implementationClass, config);
myComponentInterfaces.add(interfaceClass);
}
}
catch (Throwable t) {
handleInitComponentError(t, null, config);
@@ -515,6 +532,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
return array.toArray((T[])Array.newInstance(baseClass, array.size()));
}
@NotNull
private ComponentConfig[] getComponentConfigurations() {
return myComponentConfigs.toArray(new ComponentConfig[myComponentConfigs.size()]);
}
@@ -17,8 +17,8 @@ package com.intellij.openapi.module.impl;
import com.intellij.ide.highlighter.ModuleFileType;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
import com.intellij.openapi.components.ComponentConfig;
import com.intellij.openapi.components.ExtensionAreas;
import com.intellij.openapi.components.impl.ModulePathMacroManager;
import com.intellij.openapi.components.impl.PlatformComponentManagerImpl;
@@ -105,17 +105,18 @@ public class ModuleImpl extends PlatformComponentManagerImpl implements ModuleEx
getStateStore().setModuleFilePath(filePath);
myName = moduleNameByFileName(PathUtil.getFileName(filePath));
MyVirtualFileListener myVirtualFileListener = new MyVirtualFileListener();
VirtualFileManager.getInstance().addVirtualFileListener(myVirtualFileListener, this);
VirtualFileManager.getInstance().addVirtualFileListener(new MyVirtualFileListener(), this);
}
@Override
public void init() {
loadComponents();
super.init();
}
@Override
public void loadModuleComponents() {
final IdeaPluginDescriptor[] plugins = PluginManagerCore.getPlugins();
for (IdeaPluginDescriptor plugin : plugins) {
if (PluginManagerCore.shouldSkipPlugin(plugin)) continue;
loadComponentsConfiguration(plugin.getModuleComponents(), plugin, false);
}
loadComponents();
}
@Override
@@ -180,6 +181,11 @@ public class ModuleImpl extends PlatformComponentManagerImpl implements ModuleEx
super.dispose();
}
@NotNull
@Override
protected ComponentConfig[] getMyComponentConfigsFromDescriptor(@NotNull IdeaPluginDescriptor plugin) {
return plugin.getModuleComponents();
}
@Override
public void projectOpened() {
@@ -21,7 +21,6 @@ import com.intellij.diagnostic.PerformanceWatcher;
import com.intellij.diagnostic.ThreadDumper;
import com.intellij.ide.*;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.idea.IdeaApplication;
import com.intellij.idea.Main;
import com.intellij.idea.StartupUtil;
@@ -29,6 +28,7 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.*;
import com.intellij.openapi.application.ex.ApplicationEx;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.components.ComponentConfig;
import com.intellij.openapi.components.StateStorageException;
import com.intellij.openapi.components.impl.ApplicationPathMacroManager;
import com.intellij.openapi.components.impl.PlatformComponentManagerImpl;
@@ -47,7 +47,6 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.util.ProgressWindow;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ex.ProjectEx;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.project.impl.ProjectManagerImpl;
import com.intellij.openapi.ui.DialogWrapper;
@@ -120,12 +119,11 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
private final Disposable myLastDisposable = Disposer.newDisposable(); // will be disposed last
private final AtomicBoolean mySaveSettingsIsInProgress = new AtomicBoolean(false);
@SuppressWarnings({"UseOfArchaicSystemPropertyAccessors"})
@SuppressWarnings("UseOfArchaicSystemPropertyAccessors")
private static final int ourDumpThreadsOnLongWriteActionWaiting = Integer.getInteger("dump.threads.on.long.write.action.waiting", 0);
private final ExecutorService ourThreadExecutorsService = PooledThreadExecutor.INSTANCE;
private boolean myIsFiringLoadingEvent = false;
private boolean myLoaded = false;
private boolean myLoaded;
@NonNls private static final String WAS_EVER_SHOWN = "was.ever.shown";
private Boolean myActive;
@@ -186,6 +184,12 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
getStateStore().initComponent(component, service);
}
@Override
public void init() {
loadComponents();
super.init();
}
public ApplicationImpl(boolean isInternal,
boolean isUnitTestMode,
boolean isHeadless,
@@ -216,8 +220,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
myDoNotSave = isUnitTestMode || isHeadless;
loadApplicationComponents();
if (myTestModeFlag) {
registerShutdownHook();
}
@@ -235,13 +237,8 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
String currentDirectory = args.isEmpty() ? null : args.get(0);
List<String> realArgs = args.isEmpty() ? args : args.subList(1, args.size());
final Project project = CommandLineProcessor.processExternalCommandLine(realArgs, currentDirectory);
final JFrame frame;
if (project != null) {
frame = (JFrame)WindowManager.getInstance().getIdeFrame(project);
}
else {
frame = WindowManager.getInstance().findVisibleFrame();
}
JFrame frame = project == null ? WindowManager.getInstance().findVisibleFrame() :
(JFrame)WindowManager.getInstance().getIdeFrame(project);
if (frame != null) frame.requestFocus();
}
});
@@ -348,16 +345,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
return BitUtil.isSet(status.flags, IS_READ_LOCK_ACQUIRED_FLAG);
}
private void loadApplicationComponents() {
PluginManagerCore.initPlugins(mySplash);
IdeaPluginDescriptor[] plugins = PluginManagerCore.getPlugins();
for (IdeaPluginDescriptor plugin : plugins) {
if (!PluginManagerCore.shouldSkipPlugin(plugin)) {
loadComponentsConfiguration(plugin.getAppComponents(), plugin, false);
}
}
}
@Override
protected synchronized Object createComponent(@NotNull Class componentInterface) {
Object component = super.createComponent(componentInterface);
@@ -495,14 +482,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
store.setOptionsPath(optionsPath);
store.setConfigPath(configPath);
myIsFiringLoadingEvent = true;
try {
fireBeforeApplicationLoaded();
}
finally {
myIsFiringLoadingEvent = false;
}
AccessToken token = HeavyProcessLatch.INSTANCE.processStarted("Loading application components");
try {
store.load();
@@ -534,25 +513,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
return myLoaded;
}
@Override
protected <T> T getComponentFromContainer(@NotNull final Class<T> interfaceClass) {
if (myIsFiringLoadingEvent) {
return null;
}
return super.getComponentFromContainer(interfaceClass);
}
private void fireBeforeApplicationLoaded() {
for (ApplicationLoadListener listener : ApplicationLoadListener.EP_NAME.getExtensions()) {
try {
listener.beforeApplicationLoaded(this);
}
catch (Exception e) {
LOG.error(e);
}
}
}
@Override
public void dispose() {
fireApplicationExiting();
@@ -567,6 +527,12 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
Disposer.dispose(myLastDisposable); // dispose it last
}
@NotNull
@Override
protected ComponentConfig[] getMyComponentConfigsFromDescriptor(@NotNull IdeaPluginDescriptor plugin) {
return plugin.getAppComponents();
}
@Override
public boolean runProcessWithProgressSynchronously(@NotNull final Runnable process,
@NotNull String progressTitle,
@@ -802,7 +768,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
* Note: there are possible scenarios when we get a quit notification at a moment when another
* quit message is shown. In that case, showing multiple messages sounds contra-intuitive as well
*/
private static volatile boolean exiting = false;
private static volatile boolean exiting;
public void exit(final boolean force, final boolean exitConfirmed, final boolean allowListenersToCancel, final boolean restart) {
if (!force && exiting) {
@@ -1453,8 +1419,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
for (Project openProject : openProjects) {
ProjectEx project = (ProjectEx)openProject;
project.save();
openProject.save();
}
saveSettings();
@@ -29,6 +29,7 @@ import com.intellij.openapi.extensions.impl.ExtensionComponentAdapter;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.PairProcessor;
import com.intellij.util.PlatformUtils;
import com.intellij.util.io.storage.HeavyProcessLatch;
@@ -61,7 +62,8 @@ public class ServiceManagerImpl implements BaseComponent {
protected ServiceManagerImpl(boolean ignoreInit) {
}
protected void installEP(final ExtensionPointName<ServiceDescriptor> pointName, final ComponentManager componentManager) {
protected void installEP(@NotNull ExtensionPointName<ServiceDescriptor> pointName, @NotNull final ComponentManager componentManager) {
LOG.assertTrue(myExtensionPointName == null, "Already called installEP with " + myExtensionPointName);
myExtensionPointName = pointName;
final ExtensionPoint<ServiceDescriptor> extensionPoint = Extensions.getArea(null).getExtensionPoint(pointName);
final MutablePicoContainer picoContainer = (MutablePicoContainer)componentManager.getPicoContainer();
@@ -77,7 +79,10 @@ public class ServiceManagerImpl implements BaseComponent {
}
}
picoContainer.registerComponent(new MyComponentAdapter(descriptor, pluginDescriptor, (ComponentManagerEx)componentManager));
// empty serviceImplementation means we want to unregister service
if (!StringUtil.isEmpty(descriptor.serviceImplementation)) {
picoContainer.registerComponent(new MyComponentAdapter(descriptor, pluginDescriptor, (ComponentManagerEx)componentManager));
}
}
@Override
@@ -17,7 +17,6 @@ package com.intellij.openapi.project.impl;
import com.intellij.ide.RecentProjectsManager;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.ide.startup.StartupManagerEx;
import com.intellij.notification.NotificationsManager;
import com.intellij.openapi.application.ApplicationManager;
@@ -25,10 +24,7 @@ import com.intellij.openapi.application.PathMacros;
import com.intellij.openapi.application.ex.ApplicationEx;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
import com.intellij.openapi.components.ExtensionAreas;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.components.StorageScheme;
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
import com.intellij.openapi.components.*;
import com.intellij.openapi.components.impl.PlatformComponentManagerImpl;
import com.intellij.openapi.components.impl.ProjectPathMacroManager;
import com.intellij.openapi.components.impl.stores.IComponentStore;
@@ -73,7 +69,7 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
public static final String NAME_FILE = ".name";
public static Key<Long> CREATION_TIME = Key.create("ProjectImpl.CREATION_TIME");
private ProjectManager myManager;
private ProjectManager myProjectManager;
private volatile IProjectStore myComponentStore;
private MyProjectManagerListener myProjectManagerListener;
private final AtomicBoolean mySavingInProgress = new AtomicBoolean(false);
@@ -81,7 +77,10 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
private String myName;
private String myOldName;
protected ProjectImpl(@NotNull ProjectManager manager, @NotNull String filePath, boolean optimiseTestLoadSpeed, @Nullable String projectName) {
protected ProjectImpl(@NotNull ProjectManager projectManager,
@NotNull String filePath,
boolean optimiseTestLoadSpeed,
@Nullable String projectName) {
super(ApplicationManager.getApplication(), "Project " + (projectName == null ? filePath : projectName));
putUserData(CREATION_TIME, System.nanoTime());
@@ -93,7 +92,7 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
}
myOptimiseTestLoadSpeed = optimiseTestLoadSpeed;
myManager = manager;
myProjectManager = projectManager;
myName = projectName == null ? getStateStore().getProjectName() : projectName;
if (!isDefault() && projectName != null && getStateStore().getStorageScheme().equals(StorageScheme.DIRECTORY_BASED)) {
@@ -132,9 +131,9 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
picoContainer.registerComponentImplementation(ProjectPathMacroManager.class);
picoContainer.registerComponent(new ComponentAdapter() {
ComponentAdapter myDelegate;
private ComponentAdapter myDelegate;
public ComponentAdapter getDelegate() {
private ComponentAdapter getDelegate() {
if (myDelegate == null) {
final Class storeClass = projectStoreClassProvider.getProjectStoreClass(isDefault());
myDelegate = new ConstructorInjectionComponentAdapter(storeClass, storeClass, null, true);
@@ -211,12 +210,10 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
return !isDisposed() && isOpen() && StartupManagerEx.getInstanceEx(this).startupActivityPassed();
}
public void loadProjectComponents() {
final IdeaPluginDescriptor[] plugins = PluginManagerCore.getPlugins();
for (IdeaPluginDescriptor plugin : plugins) {
if (PluginManagerCore.shouldSkipPlugin(plugin)) continue;
loadComponentsConfiguration(plugin.getProjectComponents(), plugin, isDefault());
}
@NotNull
@Override
protected ComponentConfig[] getMyComponentConfigsFromDescriptor(@NotNull IdeaPluginDescriptor plugin) {
return plugin.getProjectComponents();
}
@Override
@@ -289,6 +286,7 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
if (progressIndicator != null) {
progressIndicator.pushState();
}
loadComponents();
super.init();
if (progressIndicator != null) {
progressIndicator.popState();
@@ -302,11 +300,11 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
//noinspection SynchronizeOnThis
synchronized (this) {
myProjectManagerListener = new MyProjectManagerListener();
myManager.addProjectManagerListener(this, myProjectManagerListener);
myProjectManager.addProjectManagerListener(this, myProjectManagerListener);
}
}
public boolean isToSaveProjectName() {
private boolean isToSaveProjectName() {
if (!isDefault()) {
final IProjectStore stateStore = getStateStore();
if (stateStore.getStorageScheme().equals(StorageScheme.DIRECTORY_BASED)) {
@@ -370,12 +368,12 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
LOG.assertTrue(!isDisposed());
if (myProjectManagerListener != null) {
myManager.removeProjectManagerListener(this, myProjectManagerListener);
myProjectManager.removeProjectManagerListener(this, myProjectManagerListener);
}
disposeComponents();
Extensions.disposeArea(this);
myManager = null;
myProjectManager = null;
myProjectManagerListener = null;
myComponentStore = null;
@@ -457,7 +455,7 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
unknownMacros.addAll(substitutor.getUnknownMacros(null));
}
if (unknownMacros.isEmpty() || (showDialog && !ProjectMacrosUtil.checkMacros(this, new THashSet<String>(unknownMacros)))) {
if (unknownMacros.isEmpty() || showDialog && !ProjectMacrosUtil.checkMacros(this, new THashSet<String>(unknownMacros))) {
return;
}
@@ -312,13 +312,12 @@ public class ProjectManagerImpl extends ProjectManagerEx implements PersistentSt
boolean succeed = false;
try {
if (template != null) {
project.getStateStore().loadProjectFromTemplate(template);
}
else {
if (template == null) {
project.getStateStore().load();
}
project.loadProjectComponents();
else {
project.getStateStore().loadProjectFromTemplate(template);
}
project.init();
succeed = true;
}
@@ -707,10 +706,8 @@ public class ProjectManagerImpl extends ProjectManagerEx implements PersistentSt
}
}
if (causes.isEmpty()) {
return false;
}
return ComponentStoreImpl.reloadStore(causes, ((ProjectEx)project).getStateStore()) == ReloadComponentStoreStatus.RESTART_AGREED;
return !causes.isEmpty() &&
ComponentStoreImpl.reloadStore(causes, ((ProjectEx)project).getStateStore()) == ReloadComponentStoreStatus.RESTART_AGREED;
}
@Override
@@ -721,7 +718,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements PersistentSt
@Override
public void unblockReloadingProjectOnExternalChanges() {
if (myReloadBlockCount.decrementAndGet() == 0 && myChangedFilesAlarm.isEmpty()) {
ApplicationManager.getApplication().invokeLater(restartApplicationOrReloadProjectTask, ModalityState.NON_MODAL);
ApplicationManager.getApplication().invokeLater(restartApplicationOrReloadProjectTask, ModalityState.NON_MODAL, ApplicationManager.getApplication().getDisposed());
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -22,6 +22,7 @@ import com.intellij.openapi.module.Module;
*/
public interface ModuleEx extends Module {
void init();
@Deprecated
void loadModuleComponents();
void moduleAdded();
void projectOpened();
@@ -784,7 +784,6 @@ public abstract class ModuleManagerImpl extends ModuleManager implements Project
String path = module.getModuleFilePath();
myModulesCache = null;
myPathToModule.put(path, module);
module.loadModuleComponents();
module.init();
}