| /* |
| * Copyright 2000-2014 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.facet.impl; |
| |
| import com.intellij.facet.*; |
| import com.intellij.openapi.util.SimpleModificationTracker; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.openapi.util.ModificationTracker; |
| import com.intellij.openapi.util.Disposer; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.Disposable; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.module.ModuleManager; |
| import com.intellij.openapi.module.Module; |
| import com.intellij.psi.util.CachedValueProvider; |
| import com.intellij.psi.util.CachedValuesManager; |
| import com.intellij.psi.util.CachedValue; |
| import com.intellij.util.SmartList; |
| import org.jetbrains.annotations.Nullable; |
| import org.jetbrains.annotations.NotNull; |
| |
| import java.util.*; |
| |
| /** |
| * @author nik |
| */ |
| public class FacetFinderImpl extends FacetFinder { |
| private static final Logger LOG = Logger.getInstance("#com.intellij.facet.impl.FacetFinderImpl"); |
| private final Map<FacetTypeId, AllFacetsOfTypeModificationTracker> myAllFacetTrackers = new HashMap<FacetTypeId, AllFacetsOfTypeModificationTracker>(); |
| private final Map<FacetTypeId, CachedValue<Map<VirtualFile, List<Facet>>>> myCachedMaps = |
| new HashMap<FacetTypeId, CachedValue<Map<VirtualFile, List<Facet>>>>(); |
| private final Project myProject; |
| private final CachedValuesManager myCachedValuesManager; |
| private final ModuleManager myModuleManager; |
| |
| public FacetFinderImpl(Project project) { |
| myProject = project; |
| myCachedValuesManager = CachedValuesManager.getManager(project); |
| myModuleManager = ModuleManager.getInstance(myProject); |
| } |
| |
| @Override |
| public <F extends Facet> ModificationTracker getAllFacetsOfTypeModificationTracker(FacetTypeId<F> type) { |
| AllFacetsOfTypeModificationTracker tracker = myAllFacetTrackers.get(type); |
| if (tracker == null) { |
| tracker = new AllFacetsOfTypeModificationTracker<F>(myProject, type); |
| Disposer.register(myProject, tracker); |
| myAllFacetTrackers.put(type, tracker); |
| } |
| return tracker; |
| } |
| |
| private <F extends Facet & FacetRootsProvider> Map<VirtualFile, List<Facet>> getRootToFacetsMap(final FacetTypeId<F> type) { |
| CachedValue<Map<VirtualFile, List<Facet>>> cachedValue = myCachedMaps.get(type); |
| if (cachedValue == null) { |
| cachedValue = myCachedValuesManager.createCachedValue(new CachedValueProvider<Map<VirtualFile, List<Facet>>>() { |
| @Override |
| public Result<Map<VirtualFile, List<Facet>>> compute() { |
| Map<VirtualFile, List<Facet>> map = computeRootToFacetsMap(type); |
| return Result.create(map, getAllFacetsOfTypeModificationTracker(type)); |
| } |
| }, false); |
| myCachedMaps.put(type, cachedValue); |
| } |
| final Map<VirtualFile, List<Facet>> value = cachedValue.getValue(); |
| LOG.assertTrue(value != null); |
| return value; |
| } |
| |
| @NotNull |
| private <F extends Facet&FacetRootsProvider> Map<VirtualFile, List<Facet>> computeRootToFacetsMap(final FacetTypeId<F> type) { |
| final Module[] modules = myModuleManager.getModules(); |
| final HashMap<VirtualFile, List<Facet>> map = new HashMap<VirtualFile, List<Facet>>(); |
| for (Module module : modules) { |
| final Collection<F> facets = FacetManager.getInstance(module).getFacetsByType(type); |
| for (F facet : facets) { |
| for (VirtualFile root : facet.getFacetRoots()) { |
| List<Facet> list = map.get(root); |
| if (list == null) { |
| list = new SmartList<Facet>(); |
| map.put(root, list); |
| } |
| list.add(facet); |
| } |
| } |
| } |
| return map; |
| } |
| |
| @Override |
| @Nullable |
| public <F extends Facet & FacetRootsProvider> F findFacet(VirtualFile file, FacetTypeId<F> type) { |
| final List<F> list = findFacets(file, type); |
| return list.size() > 0 ? list.get(0) : null; |
| } |
| |
| @Override |
| @NotNull |
| public <F extends Facet & FacetRootsProvider> List<F> findFacets(VirtualFile file, FacetTypeId<F> type) { |
| final Map<VirtualFile, List<Facet>> map = getRootToFacetsMap(type); |
| if (!map.isEmpty()) { |
| while (file != null) { |
| final List<F> list = (List<F>)((List)map.get(file)); |
| if (list != null) { |
| return list; |
| } |
| file = file.getParent(); |
| } |
| } |
| return Collections.<F>emptyList(); |
| } |
| |
| private static class AllFacetsOfTypeModificationTracker<F extends Facet> extends SimpleModificationTracker implements Disposable, ProjectWideFacetListener<F> { |
| public AllFacetsOfTypeModificationTracker(final Project project, final FacetTypeId<F> type) { |
| ProjectWideFacetListenersRegistry.getInstance(project).registerListener(type, this, this); |
| } |
| |
| @Override |
| public void facetAdded(final F facet) { |
| incModificationCount(); |
| } |
| |
| @Override |
| public void facetRemoved(final F facet) { |
| incModificationCount(); |
| } |
| |
| @Override |
| public void facetConfigurationChanged(final F facet) { |
| incModificationCount(); |
| } |
| |
| @Override |
| public void firstFacetAdded() { |
| |
| } |
| |
| @Override |
| public void beforeFacetRemoved(F facet) { |
| |
| } |
| |
| @Override |
| public void allFacetsRemoved() { |
| |
| } |
| |
| @Override |
| public void dispose() { |
| } |
| } |
| } |