blob: a860efed2edff8366332d430f5843469d30e17f8 [file] [log] [blame]
/*
* Copyright 2000-2013 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.compiler.classFilesIndex.api.index;
import com.intellij.compiler.classFilesIndex.impl.MethodsUsageIndexConfigure;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompileTask;
import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.registry.RegistryValue;
import com.intellij.openapi.util.registry.RegistryValueListener;
import com.intellij.util.Processor;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
/**
* @author Dmitry Batkovich
*/
public class ClassFilesIndexFeaturesHolder extends AbstractProjectComponent {
private final Map<ClassFilesIndexConfigure, ClassFilesIndexReaderBase> myEnabledIndexReaders =
new HashMap<ClassFilesIndexConfigure, ClassFilesIndexReaderBase>();
private final Map<ClassFilesIndexFeature, FeatureState> myEnabledFeatures = new HashMap<ClassFilesIndexFeature, FeatureState>();
public static ClassFilesIndexFeaturesHolder getInstance(final Project project) {
return project.getComponent(ClassFilesIndexFeaturesHolder.class);
}
protected ClassFilesIndexFeaturesHolder(final Project project) {
super(project);
}
@Override
public final void projectOpened() {
for (final ClassFilesIndexFeature feature : ClassFilesIndexFeature.values()) {
final RegistryValue registryValue = feature.getRegistryValue();
registryValue.addListener(new RegistryValueListener.Adapter() {
@Override
public void afterValueChanged(final RegistryValue rawValue) {
if (!rawValue.asBoolean() && myEnabledFeatures.containsKey(feature)) {
disposeFeature(feature);
}
}
}, myProject);
}
final CompilerManager compilerManager = CompilerManager.getInstance(myProject);
compilerManager.addBeforeTask(new CompileTask() {
@Override
public boolean execute(final CompileContext context) {
close();
return true;
}
});
}
public synchronized boolean enableFeatureIfNeed(final ClassFilesIndexFeature feature) {
if (!feature.isEnabled()) {
return false;
}
FeatureState state = myEnabledFeatures.get(feature);
if (state == null) {
state = initializeFeature(feature);
}
return state == FeatureState.AVAILABLE;
}
public synchronized void visitConfigures(final ConfigureVisitor visitor) {
for (final ClassFilesIndexConfigure configure : myEnabledIndexReaders.keySet()) {
visitor.visit(configure, true);
}
for (final ClassFilesIndexFeature feature : ClassFilesIndexFeature.values()) {
if (feature.isEnabled() && !myEnabledFeatures.containsKey(feature)) {
for (final ClassFilesIndexConfigure configure : feature.getRequiredIndicesConfigures()) {
if (!myEnabledIndexReaders.containsKey(configure)) {
visitor.visit(configure, false);
}
}
}
}
}
private synchronized void disposeFeature(final ClassFilesIndexFeature featureToRemove) {
for (final ClassFilesIndexConfigure requiredConfigure : featureToRemove.getRequiredIndicesConfigures()) {
boolean needClose = true;
for (final ClassFilesIndexFeature enabledFeature : myEnabledFeatures.keySet()) {
if (!enabledFeature.equals(featureToRemove) && enabledFeature.getRequiredIndicesConfigures().contains(requiredConfigure)) {
needClose = false;
break;
}
}
if (needClose) {
final ClassFilesIndexReaderBase readerToClose = myEnabledIndexReaders.remove(requiredConfigure);
readerToClose.close();
}
}
myEnabledFeatures.remove(featureToRemove);
}
private synchronized FeatureState initializeFeature(final ClassFilesIndexFeature feature) {
if (myEnabledFeatures.containsKey(feature)) {
throw new IllegalStateException(String.format("feature %s already contains", feature.getKey()));
}
final Map<ClassFilesIndexConfigure, ClassFilesIndexReaderBase> newIndices =
new HashMap<ClassFilesIndexConfigure, ClassFilesIndexReaderBase>();
FeatureState newFeatureState = FeatureState.AVAILABLE;
for (final ClassFilesIndexConfigure requiredConfigure : feature.getRequiredIndicesConfigures()) {
boolean isIndexAlreadyLoaded = false;
for (final ClassFilesIndexFeature enabledFeature : myEnabledFeatures.keySet()) {
if (enabledFeature.getRequiredIndicesConfigures().contains(requiredConfigure)) {
isIndexAlreadyLoaded = true;
break;
}
}
if (!isIndexAlreadyLoaded) {
final ClassFilesIndexReaderBase reader = requiredConfigure.createIndexReader(myProject);
newIndices.put(requiredConfigure, reader);
if (reader.isEmpty()) {
newFeatureState = FeatureState.NOT_AVAILABLE;
}
}
}
myEnabledIndexReaders.putAll(newIndices);
myEnabledFeatures.put(feature, newFeatureState);
return newFeatureState;
}
private synchronized void close() {
for (final ClassFilesIndexReaderBase reader : myEnabledIndexReaders.values()) {
reader.close();
}
myEnabledIndexReaders.clear();
myEnabledFeatures.clear();
}
@Override
public void projectClosed() {
close();
}
/**
* try to find index with corresponding class only in currently enabled indexes
*/
@Nullable
@SuppressWarnings("unchecked")
public <T extends ClassFilesIndexReaderBase> T getAvailableIndexReader(final Class<T> tClass) {
final String indexReaderClassName = tClass.getCanonicalName();
for (final ClassFilesIndexReaderBase reader : myEnabledIndexReaders.values()) {
if (reader.getClass().getCanonicalName().equals(indexReaderClassName)) {
return (T)reader;
}
}
throw new RuntimeException(String.format("index reader for class %s not found", indexReaderClassName));
}
public Project getProject() {
return myProject;
}
private enum FeatureState {
AVAILABLE,
NOT_AVAILABLE
}
}