/* * Copyright 2000-2010 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.packaging.impl.artifacts; import com.intellij.openapi.project.Project; import com.intellij.packaging.artifacts.Artifact; import com.intellij.packaging.artifacts.ArtifactManager; import com.intellij.packaging.elements.PackagingElementResolvingContext; import com.intellij.packaging.impl.elements.ArtifactElementType; import com.intellij.packaging.impl.elements.ArtifactPackagingElement; import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.util.graph.CachingSemiGraph; import com.intellij.util.graph.DFSTBuilder; import com.intellij.util.graph.GraphGenerator; import gnu.trove.TIntArrayList; import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; import java.util.*; /** * @author nik */ public class ArtifactSortingUtilImpl extends ArtifactSortingUtil { private final Project myProject; private CachedValue<Map<String, String>> myArtifactToSelfIncludingName; private CachedValue<List<String>> mySortedArtifacts; public ArtifactSortingUtilImpl(Project project) { myProject = project; } @Override public Map<String, String> getArtifactToSelfIncludingNameMap() { if (myArtifactToSelfIncludingName == null) { myArtifactToSelfIncludingName = CachedValuesManager.getManager(myProject).createCachedValue(new CachedValueProvider<Map<String, String>>() { public Result<Map<String, String>> compute() { return Result.create(computeArtifactToSelfIncludingNameMap(), ArtifactManager.getInstance(myProject).getModificationTracker()); } }, false); } return myArtifactToSelfIncludingName.getValue(); } @Override public List<String> getArtifactsSortedByInclusion() { if (mySortedArtifacts == null) { mySortedArtifacts = CachedValuesManager.getManager(myProject).createCachedValue(new CachedValueProvider<List<String>>() { @Override public Result<List<String>> compute() { return Result.create(doGetSortedArtifacts(), ArtifactManager.getInstance(myProject).getModificationTracker()); } }, false); } return mySortedArtifacts.getValue(); } private List<String> doGetSortedArtifacts() { GraphGenerator<String> graph = createArtifactsGraph(); DFSTBuilder<String> builder = new DFSTBuilder<String>(graph); List<String> names = new ArrayList<String>(); names.addAll(graph.getNodes()); Collections.sort(names, builder.comparator()); return names; } private Map<String, String> computeArtifactToSelfIncludingNameMap() { final Map<String, String> result = new HashMap<String, String>(); final GraphGenerator<String> graph = createArtifactsGraph(); for (String artifactName : graph.getNodes()) { final Iterator<String> in = graph.getIn(artifactName); while (in.hasNext()) { String next = in.next(); if (next.equals(artifactName)) { result.put(artifactName, artifactName); break; } } } final DFSTBuilder<String> builder = new DFSTBuilder<String>(graph); if (builder.isAcyclic() && result.isEmpty()) return Collections.emptyMap(); final TIntArrayList sccs = builder.getSCCs(); sccs.forEach(new TIntProcedure() { int myTNumber = 0; public boolean execute(int size) { if (size > 1) { for (int j = 0; j < size; j++) { final String artifactName = builder.getNodeByTNumber(myTNumber + j); result.put(artifactName, artifactName); } } myTNumber += size; return true; } }); for (int i = 0; i < graph.getNodes().size(); i++) { final String artifactName = builder.getNodeByTNumber(i); if (!result.containsKey(artifactName)) { final Iterator<String> in = graph.getIn(artifactName); while (in.hasNext()) { final String name = result.get(in.next()); if (name != null) { result.put(artifactName, name); } } } } return result; } private GraphGenerator<String> createArtifactsGraph() { final ArtifactManager artifactManager = ArtifactManager.getInstance(myProject); return GraphGenerator.create(CachingSemiGraph.create(new ArtifactsGraph(artifactManager))); } private class ArtifactsGraph implements GraphGenerator.SemiGraph<String> { private final ArtifactManager myArtifactManager; private final Set<String> myArtifactNames; public ArtifactsGraph(ArtifactManager artifactManager) { myArtifactManager = artifactManager; myArtifactNames = new LinkedHashSet<String>(); for (Artifact artifact : myArtifactManager.getSortedArtifacts()) { myArtifactNames.add(artifact.getName()); } } @Override public Collection<String> getNodes() { return myArtifactNames; } @Override public Iterator<String> getIn(String name) { final Set<String> included = new LinkedHashSet<String>(); final PackagingElementResolvingContext context = myArtifactManager.getResolvingContext(); final Artifact artifact = context.getArtifactModel().findArtifact(name); if (artifact != null) { ArtifactUtil.processPackagingElements(artifact, ArtifactElementType.getInstance(), new PackagingElementProcessor<ArtifactPackagingElement>() { @Override public boolean process(@NotNull ArtifactPackagingElement element, @NotNull PackagingElementPath path) { final String artifactName = element.getArtifactName(); if (myArtifactNames.contains(artifactName)) { included.add(artifactName); } return true; } }, context, false); } return included.iterator(); } } }