save memory — don't keep list of componentConfigs

avoid list (of componentConfigs) to array transformation just to get size
simplify code — we don't need to use and keep bool flag myClassesLoaded, we can just move init logic to constructor and, so, we don't have to assert

make app init progress bar more precise — component could require other components, and, so, we should call setFraction not in init() after getComponent() call, but on each component initialization (as it was implemented in case of Project — now this logic is unified)
This commit is contained in:
Vladimir Krivosheev
2015-07-17 15:34:03 +02:00
parent 531f53cf55
commit 8fcf420a67
9 changed files with 115 additions and 205 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 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.
@@ -15,18 +15,12 @@
*/
package com.intellij.openapi.components.ex;
import com.intellij.openapi.components.ComponentConfig;
import com.intellij.openapi.components.ComponentManager;
import com.intellij.openapi.extensions.PluginDescriptor;
import org.jetbrains.annotations.NotNull;
/**
* @author max
*/
public interface ComponentManagerEx extends ComponentManager {
void registerComponent(@NotNull ComponentConfig config);
void registerComponent(@NotNull ComponentConfig config, PluginDescriptor pluginDescriptor);
void initializeComponent(@NotNull Object component, boolean service);
}
}
@@ -1,46 +0,0 @@
/*
* 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.
* 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.components.impl;
import com.intellij.openapi.components.ComponentConfig;
import com.intellij.openapi.extensions.PluginDescriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
class ComponentManagerConfigurator {
private final ComponentManagerImpl myComponentManager;
public ComponentManagerConfigurator(@NotNull ComponentManagerImpl componentManager) {
myComponentManager = componentManager;
}
private void loadSingleConfig(@NotNull ComponentConfig config,
@Nullable PluginDescriptor descriptor,
boolean defaultProject) {
if (defaultProject && !config.isLoadForDefaultProject()) return;
if (!myComponentManager.isComponentSuitable(config.options)) return;
myComponentManager.registerComponent(config, descriptor);
}
void loadComponentsConfiguration(@NotNull ComponentConfig[] components,
@Nullable PluginDescriptor descriptor,
final boolean defaultProject) {
for (ComponentConfig config : components) {
loadSingleConfig(config, descriptor, defaultProject);
}
}
}
@@ -22,7 +22,6 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.*;
import com.intellij.openapi.components.ex.ComponentManagerEx;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginDescriptor;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
@@ -47,6 +46,7 @@ import org.picocontainer.*;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -66,9 +66,8 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
private MessageBus myMessageBus;
private final ComponentManagerConfigurator myConfigurator = new ComponentManagerConfigurator(this);
private final ComponentManager myParentComponentManager;
private ComponentsRegistry myComponentsRegistry = new ComponentsRegistry();
private ComponentsRegistry myComponentsRegistry;
private final Condition myDisposedCondition = new Condition() {
@Override
public boolean value(final Object o) {
@@ -76,44 +75,50 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
}
};
protected ComponentManagerImpl(ComponentManager parentComponentManager) {
protected ComponentManagerImpl(@Nullable ComponentManager parentComponentManager) {
myParentComponentManager = parentComponentManager;
bootstrapPicoContainer(toString());
}
protected ComponentManagerImpl(ComponentManager parentComponentManager, @NotNull String name) {
protected ComponentManagerImpl(@Nullable ComponentManager parentComponentManager, @NotNull String name) {
myParentComponentManager = parentComponentManager;
bootstrapPicoContainer(name);
}
protected void init() {
init(null);
protected final void init(@Nullable ProgressIndicator progressIndicator) {
init(progressIndicator, null);
}
protected final void init(@Nullable Runnable classesLoaded) {
protected final void init(@Nullable ProgressIndicator indicator, @Nullable Runnable componentsRegistered) {
try {
myComponentsRegistry.loadClasses();
ArrayList<ComponentConfig> componentConfigs = new ArrayList<ComponentConfig>();
registerComponents(componentConfigs);
myComponentsRegistry = new ComponentsRegistry(componentConfigs);
if (classesLoaded != null) {
classesLoaded.run();
if (componentsRegistered != null) {
componentsRegistered.run();
}
ProgressManager progressManager = ProgressManager.getInstance();
for (Class componentInterface : myComponentsRegistry.getComponentInterfaces()) {
ProgressIndicator indicator = progressManager.getProgressIndicator();
if (indicator != null) {
indicator.checkCanceled();
}
getComponent(componentInterface);
componentCreatedDuringInit();
if (indicator != null) {
indicator.setIndeterminate(false);
}
createComponents(indicator);
}
finally {
myComponentsCreated = true;
}
}
protected void componentCreatedDuringInit() {
protected void setProgressDuringInit(@NotNull ProgressIndicator indicator) {
indicator.setFraction(getPercentageOfComponentsLoaded());
}
protected void createComponents(@Nullable ProgressIndicator indicator) {
for (Class componentInterface : myComponentsRegistry.myComponentInterfaces) {
getComponent(componentInterface);
if (indicator != null) {
indicator.checkCanceled();
}
}
}
@NotNull
@@ -134,7 +139,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
protected synchronized void disposeComponents() {
assert !myDisposeCompleted : "Already disposed!";
final List<Object> components = myComponentsRegistry.getRegisteredImplementations();
final List<Object> components = myComponentsRegistry == null ? Collections.emptyList() : myComponentsRegistry.getRegisteredImplementations();
myDisposed = true;
for (int i = components.size() - 1; i >= 0; i--) {
@@ -207,7 +212,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
return ProgressManager.getInstance().getProgressIndicator();
}
protected float getPercentageOfComponentsLoaded() {
protected final double getPercentageOfComponentsLoaded() {
return myComponentsRegistry.getPercentageOfComponentsLoaded();
}
@@ -219,15 +224,6 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
LOG.error(ex);
}
@Override
@SuppressWarnings("NonPrivateFieldAccessedInSynchronizedContext")
public synchronized void registerComponent(@NotNull final ComponentConfig config, final PluginDescriptor pluginDescriptor) {
if (!config.prepareClasses(isHeadless())) return;
config.pluginDescriptor = pluginDescriptor;
myComponentsRegistry.registerComponent(config);
}
public synchronized void registerComponentImplementation(@NotNull Class componentKey, @NotNull Class componentImplementation) {
getPicoContainer().registerComponentImplementation(componentKey.getName(), componentImplementation);
myInitializedComponents.remove(componentKey);
@@ -301,12 +297,22 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
return myDisposed;
}
protected void loadComponents() {
final IdeaPluginDescriptor[] plugins = PluginManagerCore.getPlugins();
private void registerComponents(@NotNull ArrayList<ComponentConfig> componentConfigs) {
boolean isDefaultProject = this instanceof Project && ((Project)this).isDefault();
for (IdeaPluginDescriptor plugin : plugins) {
if (PluginManagerCore.shouldSkipPlugin(plugin)) continue;
myConfigurator.loadComponentsConfiguration(getMyComponentConfigsFromDescriptor(plugin), plugin, isDefaultProject);
boolean headless = ApplicationManager.getApplication().isHeadlessEnvironment();
for (IdeaPluginDescriptor plugin : PluginManagerCore.getPlugins()) {
if (PluginManagerCore.shouldSkipPlugin(plugin)) {
continue;
}
ComponentConfig[] configs = getMyComponentConfigsFromDescriptor(plugin);
componentConfigs.ensureCapacity(componentConfigs.size() + configs.length);
for (ComponentConfig config : configs) {
if ((!isDefaultProject || config.isLoadForDefaultProject()) && isComponentSuitable(config.options) && config.prepareClasses(headless)) {
config.pluginDescriptor = plugin;
componentConfigs.add(config);
}
}
}
}
@@ -328,21 +334,8 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
return myParentComponentManager;
}
private static class HeadlessHolder {
private static final boolean myHeadless = ApplicationManager.getApplication().isHeadlessEnvironment();
}
private static boolean isHeadless() {
return HeadlessHolder.myHeadless;
}
@Override
public void registerComponent(@NotNull final ComponentConfig config) {
registerComponent(config, null);
}
@NotNull
public ComponentConfig[] getComponentConfigurations() {
return myComponentsRegistry.getComponentConfigurations();
protected final int getComponentConfigurationsSize() {
return myComponentsRegistry.myComponentConfigsSize;
}
@Nullable
@@ -375,24 +368,21 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
private class ComponentsRegistry {
private final Map<Class, Object> myInterfaceToLockMap = new THashMap<Class, Object>();
private final Map<Class, Class> myInterfaceToClassMap = new THashMap<Class, Class>();
private final List<Class> myComponentInterfaces = new ArrayList<Class>(); // keeps order of component's registration
private final List<Class> myComponentInterfaces; // keeps order of component's registration
private final Map<String, BaseComponent> myNameToComponent = new THashMap<String, BaseComponent>();
private final List<ComponentConfig> myComponentConfigs = new ArrayList<ComponentConfig>();
private final int myComponentConfigsSize;
private final List<Object> myImplementations = new ArrayList<Object>();
private final Map<Class, ComponentConfig> myComponentClassToConfig = new THashMap<Class, ComponentConfig>();
private boolean myClassesLoaded;
private void loadClasses() {
assert !myClassesLoaded;
for (ComponentConfig config : myComponentConfigs) {
public ComponentsRegistry(@NotNull List<ComponentConfig> componentConfigs) {
myComponentInterfaces = new ArrayList<Class>(componentConfigs.size());
for (ComponentConfig config : componentConfigs) {
loadClasses(config);
}
myClassesLoaded = true;
myComponentConfigsSize = componentConfigs.size();
}
private void loadClasses(final ComponentConfig config) {
private void loadClasses(@NotNull ComponentConfig config) {
ClassLoader loader = config.getClassLoader();
try {
@@ -436,17 +426,12 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
return lock;
}
private Class[] getComponentInterfaces() {
assert myClassesLoaded;
return myComponentInterfaces.toArray(new Class[myComponentInterfaces.size()]);
}
private boolean containsInterface(final Class interfaceClass) {
return myInterfaceToClassMap.containsKey(interfaceClass);
}
private float getPercentageOfComponentsLoaded() {
return ((float)myImplementations.size()) / myComponentConfigs.size();
private double getPercentageOfComponentsLoaded() {
return ((double)myImplementations.size()) / myComponentConfigsSize;
}
private void registerComponentInstance(final Object component) {
@@ -474,14 +459,6 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
return myImplementations;
}
private void registerComponent(ComponentConfig config) {
myComponentConfigs.add(config);
if (myClassesLoaded) {
loadClasses(config);
}
}
private BaseComponent getComponentByName(final String name) {
return myNameToComponent.get(name);
}
@@ -502,11 +479,6 @@ 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()]);
}
public ComponentConfig getConfig(final Class componentImplementation) {
return myComponentClassToConfig.get(componentImplementation);
}
@@ -525,21 +497,9 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
myDelegate = new ConstructorInjectionComponentAdapter(componentKey, implementationClass, null, true) {
@Override
public Object getComponentInstance(PicoContainer picoContainer) throws PicoInitializationException, PicoIntrospectionException, ProcessCanceledException {
if (myInitialized) {
// so, instance cached and we don't need to do anything
// we have to avoid getProgressIndicator() because it could lead to cyclic call
// (get app component -> get app state store to init component -> get progress indicator -> get app state store to init progress indicator -> get progress indicator -> ... )
return super.getComponentInstance(picoContainer);
}
ProgressIndicator indicator = getProgressIndicator();
if (indicator != null) {
indicator.checkCanceled();
}
Object componentInstance = null;
try {
long startTime = myInitialized ? 0 : System.nanoTime();
long startTime = System.nanoTime();
componentInstance = super.getComponentInstance(picoContainer);
@@ -558,6 +518,11 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
myInitializing = true;
myComponentsRegistry.registerComponentInstance(componentInstance);
ProgressIndicator indicator = getProgressIndicator();
if (indicator != null) {
indicator.checkCanceled();
setProgressDuringInit(indicator);
}
initializeComponent(componentInstance, false);
if (componentInstance instanceof BaseComponent) {
((BaseComponent)componentInstance).initComponent();
@@ -33,6 +33,8 @@ import com.intellij.openapi.module.ModifiableModuleModel;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleComponent;
import com.intellij.openapi.module.impl.scopes.ModuleScopeProviderImpl;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.impl.storage.ClasspathStorage;
import com.intellij.openapi.util.Comparing;
@@ -93,11 +95,6 @@ public class ModuleImpl extends PlatformComponentManagerImpl implements ModuleEx
return (ModuleStoreImpl)getPicoContainer().getComponentInstance(IComponentStore.class);
}
@Override
public void initializeComponent(@NotNull Object component, boolean service) {
getStateStore().initComponent(component, service);
}
private void init(String filePath) {
getStateStore().setModuleFilePath(filePath);
myName = moduleNameByFileName(PathUtil.getFileName(filePath));
@@ -107,13 +104,12 @@ public class ModuleImpl extends PlatformComponentManagerImpl implements ModuleEx
@Override
public void init() {
loadComponents();
super.init();
init(ProgressManager.getInstance().getProgressIndicator());
}
@Override
public void loadModuleComponents() {
loadComponents();
protected void setProgressDuringInit(@NotNull ProgressIndicator indicator) {
// module loading progress is not tracked, progress updated by ModuleManagerImpl on module load
}
@Override
@@ -29,7 +29,10 @@ 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.*;
import com.intellij.openapi.components.ComponentConfig;
import com.intellij.openapi.components.ComponentsPackage;
import com.intellij.openapi.components.StateStorageException;
import com.intellij.openapi.components.StoragePathMacros;
import com.intellij.openapi.components.impl.PlatformComponentManagerImpl;
import com.intellij.openapi.components.impl.ServiceManagerImpl;
import com.intellij.openapi.components.impl.stores.IComponentStore;
@@ -175,13 +178,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
return ComponentsPackage.getStateStore(this);
}
@Override
public void initializeComponent(@NotNull Object component, boolean service) {
if (!service || !(component instanceof PathMacroManager || component instanceof IComponentStore)) {
ComponentsPackage.getStateStore(this).initComponent(component, service);
}
}
public ApplicationImpl(boolean isInternal,
boolean isUnitTestMode,
boolean isHeadless,
@@ -337,13 +333,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
return BitUtil.isSet(status.flags, IS_READ_LOCK_ACQUIRED_FLAG);
}
@Override
protected void componentCreatedDuringInit() {
if (mySplash != null) {
mySplash.showProgress("", 0.65f + getPercentageOfComponentsLoaded() * 0.35f);
}
}
@NotNull
@Override
protected MutablePicoContainer createPicoContainer() {
@@ -471,9 +460,12 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
AccessToken token = HeavyProcessLatch.INSTANCE.processStarted("Loading application components");
try {
long t = System.currentTimeMillis();
loadComponents();
init(new Runnable() {
init(mySplash == null ? null : new EmptyProgressIndicator() {
@Override
public void setFraction(double fraction) {
mySplash.showProgress("", (float)(0.65 + getPercentageOfComponentsLoaded() * 0.35));
}
}, new Runnable() {
@Override
public void run() {
// create ServiceManagerImpl at first to force extension classes registration
@@ -494,7 +486,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
}
});
t = System.currentTimeMillis() - t;
LOG.info(getComponentConfigurations().length + " application components initialized in " + t + " ms");
LOG.info(getComponentConfigurationsSize() + " application components initialized in " + t + " ms");
}
catch (StateStorageException e) {
throw new IOException(e);
@@ -507,6 +499,26 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
createLocatorFile();
}
@Override
protected void createComponents(@Nullable final ProgressIndicator indicator) {
// we cannot wrap "init()" call because ProgressManager instance could be created only after component registration (our "componentsRegistered" callback)
Runnable task = new Runnable() {
@Override
public void run() {
ApplicationImpl.super.createComponents(indicator);
}
};
if (indicator == null) {
// no splash, no need to to use progress manager
task.run();
}
else {
ProgressManager.getInstance().runProcess(task, indicator);
}
}
@Override
@Nullable
protected ProgressIndicator getProgressIndicator() {
// could be called before full initialization
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 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.
@@ -18,16 +18,20 @@ package com.intellij.openapi.components.impl;
import com.intellij.ide.plugins.PluginManager;
import com.intellij.openapi.components.ComponentConfig;
import com.intellij.openapi.components.ComponentManager;
import com.intellij.openapi.components.ComponentsPackage;
import com.intellij.openapi.components.PathMacroManager;
import com.intellij.openapi.components.impl.stores.IComponentStore;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class PlatformComponentManagerImpl extends ComponentManagerImpl {
private boolean myHandlingInitComponentError;
protected PlatformComponentManagerImpl(ComponentManager parent) {
protected PlatformComponentManagerImpl(@Nullable ComponentManager parent) {
super(parent);
}
protected PlatformComponentManagerImpl(ComponentManager parent, @NotNull String name) {
protected PlatformComponentManagerImpl(@Nullable ComponentManager parent, @NotNull String name) {
super(parent, name);
}
@@ -43,4 +47,11 @@ public abstract class PlatformComponentManagerImpl extends ComponentManagerImpl
}
}
}
@Override
public void initializeComponent(@NotNull Object component, boolean service) {
if (!service || !(component instanceof PathMacroManager || component instanceof IComponentStore)) {
ComponentsPackage.getStateStore(this).initComponent(component, service);
}
}
}
@@ -36,7 +36,6 @@ import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
@@ -202,20 +201,6 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
return (IProjectStore)getPicoContainer().getComponentInstance(IComponentStore.class);
}
@Override
public void initializeComponent(@NotNull Object component, boolean service) {
if (!service) {
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (indicator != null) {
// indicator.setText2(getComponentName(component));
indicator.setIndeterminate(false);
indicator.setFraction(getPercentageOfComponentsLoaded());
}
}
getStateStore().initComponent(component, service);
}
@Override
public boolean isOpen() {
return ProjectManagerEx.getInstanceEx().isProjectOpened(this);
@@ -302,14 +287,13 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
if (progressIndicator != null) {
progressIndicator.pushState();
}
loadComponents();
super.init();
super.init(progressIndicator);
if (progressIndicator != null) {
progressIndicator.popState();
}
long time = System.currentTimeMillis() - start;
LOG.info(getComponentConfigurations().length + " project components initialized in " + time + " ms");
LOG.info(getComponentConfigurationsSize() + " project components initialized in " + time + " ms");
getMessageBus().syncPublisher(ProjectLifecycleListener.TOPIC).projectComponentsInitialized(this);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 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.
@@ -117,10 +117,6 @@ public class CoreModule extends MockComponentManager implements ModuleEx {
public void init() {
}
@Override
public void loadModuleComponents() {
}
@Override
public void moduleAdded() {
}
@@ -22,8 +22,6 @@ import com.intellij.openapi.module.Module;
*/
public interface ModuleEx extends Module {
void init();
@Deprecated
void loadModuleComponents();
void moduleAdded();
void projectOpened();
void projectClosed();