blob: 4ef73ee0952bb6ce1d6a7eb4369b10a7442904b4 [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 org.jetbrains.idea.maven.dom.converters;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.RecursionManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.ArrayUtil;
import com.intellij.util.xml.*;
import com.intellij.util.xml.impl.GenericDomValueReference;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.dom.DependencyConflictId;
import org.jetbrains.idea.maven.dom.MavenDomBundle;
import org.jetbrains.idea.maven.dom.MavenDomProjectProcessorUtils;
import org.jetbrains.idea.maven.dom.model.*;
import org.jetbrains.idea.maven.indices.MavenProjectIndicesManager;
import org.jetbrains.idea.maven.model.MavenArtifact;
import org.jetbrains.idea.maven.model.MavenId;
import org.jetbrains.idea.maven.model.MavenPlugin;
import org.jetbrains.idea.maven.project.MavenProject;
import org.jetbrains.idea.maven.project.MavenProjectsManager;
import org.jetbrains.idea.maven.utils.MavenArtifactUtil;
import java.io.File;
import java.util.Collection;
import java.util.Set;
public abstract class MavenArtifactCoordinatesConverter extends ResolvingConverter<String> implements MavenDomSoftAwareConverter {
public String fromString(@Nullable @NonNls String s, ConvertContext context) {
if (s == null) return null;
MavenId id = MavenArtifactCoordinatesHelper.getId(context);
MavenProjectIndicesManager manager = MavenProjectIndicesManager.getInstance(context.getProject());
return selectStrategy(context).isValid(id, manager, context) ? s : null;
}
protected abstract boolean doIsValid(MavenId id, MavenProjectIndicesManager manager, ConvertContext context);
public String toString(@Nullable String s, ConvertContext context) {
return s;
}
@NotNull
public Collection<String> getVariants(ConvertContext context) {
MavenProjectIndicesManager manager = MavenProjectIndicesManager.getInstance(context.getProject());
MavenId id = MavenArtifactCoordinatesHelper.getId(context);
MavenDomShortArtifactCoordinates coordinates = MavenArtifactCoordinatesHelper.getCoordinates(context);
return selectStrategy(context).getVariants(id, manager, coordinates);
}
protected abstract Set<String> doGetVariants(MavenId id, MavenProjectIndicesManager manager);
@Override
public PsiElement resolve(String o, ConvertContext context) {
MavenId id = MavenArtifactCoordinatesHelper.getId(context);
PsiFile result = selectStrategy(context).resolve(id, context);
return result != null ? result : super.resolve(o, context);
}
@Override
public String getErrorMessage(@Nullable String s, ConvertContext context) {
return selectStrategy(context).getContextName() + " '''" + MavenArtifactCoordinatesHelper.getId(context) + "''' not found";
}
@Override
public LocalQuickFix[] getQuickFixes(ConvertContext context) {
return ArrayUtil.append(super.getQuickFixes(context), new MyUpdateIndicesFix());
}
public boolean isSoft(@NotNull DomElement element) {
DomElement dependencyOrPluginElement = element.getParent();
if (dependencyOrPluginElement instanceof MavenDomDependency) {
DomElement dependencies = dependencyOrPluginElement.getParent();
if (dependencies instanceof MavenDomDependencies) {
if (dependencies.getParent() instanceof MavenDomDependencyManagement) {
return true;
}
}
}
else if (dependencyOrPluginElement instanceof MavenDomPlugin) {
DomElement pluginsElement = dependencyOrPluginElement.getParent();
if (pluginsElement instanceof MavenDomPlugins) {
if (pluginsElement.getParent() instanceof MavenDomPluginManagement) {
return true;
}
}
}
return false;
}
@Nullable
protected MavenProject findMavenProject(ConvertContext context) {
PsiFile psiFile = context.getFile().getOriginalFile();
VirtualFile file = psiFile.getVirtualFile();
if (file == null) return null;
return MavenProjectsManager.getInstance(psiFile.getProject()).findProject(file);
}
private ConverterStrategy selectStrategy(ConvertContext context) {
DomElement parent = context.getInvocationElement().getParent();
if (parent instanceof MavenDomProjectModel) {
return new ProjectStrategy();
}
if (parent instanceof MavenDomParent) {
return new ParentStrategy((MavenDomParent)parent);
}
if (parent instanceof MavenDomDependency) {
return new DependencyStrategy((MavenDomDependency)parent);
}
if (parent instanceof MavenDomExclusion) {
return new ExclusionStrategy();
}
if (parent instanceof MavenDomPlugin) {
return new PluginOrExtensionStrategy(true);
}
if (parent instanceof MavenDomExtension) {
return new PluginOrExtensionStrategy(false);
}
return new ConverterStrategy();
}
private static class MyUpdateIndicesFix implements LocalQuickFix {
@NotNull
public String getFamilyName() {
return MavenDomBundle.message("inspection.group");
}
@NotNull
public String getName() {
return MavenDomBundle.message("fix.update.indices");
}
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
MavenProjectIndicesManager.getInstance(project).scheduleUpdateAll();
}
}
private class ConverterStrategy {
public String getContextName() {
return "Artifact";
}
public boolean isValid(MavenId id, MavenProjectIndicesManager manager, ConvertContext context) {
return doIsValid(id, manager, context) || resolveBySpecifiedPath() != null;
}
public Set<String> getVariants(MavenId id, MavenProjectIndicesManager manager, MavenDomShortArtifactCoordinates coordinates) {
return doGetVariants(id, manager);
}
public PsiFile resolve(MavenId id, ConvertContext context) {
PsiManager psiManager = context.getPsiManager();
MavenProjectsManager projectsManager = MavenProjectsManager.getInstance(psiManager.getProject());
PsiFile result = resolveBySpecifiedPath();
if (result != null) return result;
result = resolveInProjects(id, projectsManager, psiManager);
if (result != null) return result;
return resolveInLocalRepository(id, projectsManager, psiManager);
}
@Nullable
protected PsiFile resolveBySpecifiedPath() {
return null;
}
private PsiFile resolveInProjects(MavenId id, MavenProjectsManager projectsManager, PsiManager psiManager) {
MavenProject project = projectsManager.findProject(id);
return project == null ? null : psiManager.findFile(project.getFile());
}
private PsiFile resolveInLocalRepository(MavenId id, MavenProjectsManager projectsManager, PsiManager psiManager) {
File file = makeLocalRepositoryFile(id, projectsManager.getLocalRepository());
if (file == null) return null;
VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(file);
if (virtualFile == null) return null;
return psiManager.findFile(virtualFile);
}
private File makeLocalRepositoryFile(MavenId id, File localRepository) {
String relPath = (StringUtil.notNullize(id.getGroupId(), "null")).replace(".", "/");
relPath += "/" + id.getArtifactId();
relPath += "/" + id.getVersion();
relPath += "/" + id.getArtifactId() + "-" + id.getVersion() + ".pom";
return new File(localRepository, relPath);
}
}
private class ProjectStrategy extends ConverterStrategy {
@Override
public PsiFile resolve(MavenId id, ConvertContext context) {
return null;
}
@Override
public boolean isValid(MavenId id, MavenProjectIndicesManager manager, ConvertContext context) {
return true;
}
}
private class ParentStrategy extends ConverterStrategy {
private final MavenDomParent myParent;
public ParentStrategy(MavenDomParent parent) {
myParent = parent;
}
@Override
public String getContextName() {
return "Project";
}
@Override
public PsiFile resolveBySpecifiedPath() {
return myParent.getRelativePath().getValue();
}
}
private class DependencyStrategy extends ConverterStrategy {
private final MavenDomDependency myDependency;
public DependencyStrategy(MavenDomDependency dependency) {
myDependency = dependency;
}
@Override
public String getContextName() {
return "Dependency";
}
@Override
public PsiFile resolve(MavenId id, ConvertContext context) {
PsiFile res = super.resolve(id, context);
if (res != null) return res;
DomElement parent = context.getInvocationElement().getParent();
if (!(parent instanceof MavenDomDependency)) return null;
DependencyConflictId dependencyId = DependencyConflictId.create((MavenDomDependency)parent);
if (dependencyId == null) return null;
MavenProject mavenProject = findMavenProject(context);
if (mavenProject != null) {
MavenArtifact artifact = mavenProject.getDependencyArtifactIndex().findArtifacts(dependencyId);
if (artifact != null && artifact.isResolved()) {
return super.resolve(new MavenId(id.getGroupId(), id.getArtifactId(), artifact.getVersion()), context);
}
}
if (id.getVersion() == null) {
MavenDomDependency managedDependency = MavenDomProjectProcessorUtils.searchManagingDependency((MavenDomDependency)parent);
if (managedDependency != null) {
final GenericDomValue<String> managedDependencyArtifactId = managedDependency.getArtifactId();
return RecursionManager.doPreventingRecursion(managedDependencyArtifactId, false, new Computable<PsiFile>() {
@Override
public PsiFile compute() {
PsiElement res = new GenericDomValueReference(managedDependencyArtifactId).resolve();
return res instanceof PsiFile ? (PsiFile)res : null;
}
});
}
}
return null;
}
@Override
public PsiFile resolveBySpecifiedPath() {
return myDependency.getSystemPath().getValue();
}
@Override
public Set<String> getVariants(MavenId id, MavenProjectIndicesManager manager, MavenDomShortArtifactCoordinates coordinates) {
if (StringUtil.isEmpty(id.getGroupId())) {
Set<String> result = new THashSet<String>();
for (String each : manager.getGroupIds()) {
id = new MavenId(each, id.getArtifactId(), id.getVersion());
result.addAll(super.getVariants(id, manager, coordinates));
}
return result;
}
return super.getVariants(id, manager, coordinates);
}
}
private class ExclusionStrategy extends ConverterStrategy {
@Override
public PsiFile resolve(MavenId id, ConvertContext context) {
return null;
}
@Override
public boolean isValid(MavenId id, MavenProjectIndicesManager manager, ConvertContext context) {
return true;
}
}
private class PluginOrExtensionStrategy extends ConverterStrategy {
private final boolean myPlugin;
public PluginOrExtensionStrategy(boolean isPlugin) {
myPlugin = isPlugin;
}
@Override
public String getContextName() {
return myPlugin ? "Plugin" : "Build Extension";
}
public boolean isValid(MavenId id, MavenProjectIndicesManager manager, ConvertContext context) {
if (StringUtil.isEmpty(id.getGroupId())) {
for (String each : MavenArtifactUtil.DEFAULT_GROUPS) {
id = new MavenId(each, id.getArtifactId(), id.getVersion());
if (super.isValid(id, manager, context)) return true;
}
return false;
}
return super.isValid(id, manager, context);
}
@Override
public Set<String> getVariants(MavenId id, MavenProjectIndicesManager manager, MavenDomShortArtifactCoordinates coordinates) {
if (StringUtil.isEmpty(id.getGroupId())) {
Set<String> result = new THashSet<String>();
for (String each : getGroupIdVariants(manager, coordinates)) {
id = new MavenId(each, id.getArtifactId(), id.getVersion());
result.addAll(super.getVariants(id, manager, coordinates));
}
return result;
}
return super.getVariants(id, manager, coordinates);
}
private String[] getGroupIdVariants(MavenProjectIndicesManager manager, MavenDomShortArtifactCoordinates coordinates) {
if (DomUtil.hasXml(coordinates.getGroupId())) {
Set<String> strings = manager.getGroupIds();
return ArrayUtil.toStringArray(strings);
}
return MavenArtifactUtil.DEFAULT_GROUPS;
}
@Override
public PsiFile resolve(MavenId id, ConvertContext context) {
PsiFile res = super.resolve(id, context);
if (res != null) return res;
// Try to resolve to imported plugin
MavenProject mavenProject = findMavenProject(context);
if (mavenProject != null) {
for (MavenPlugin plugin : mavenProject.getPlugins()) {
if (MavenArtifactUtil.isPluginIdEquals(id.getGroupId(), id.getArtifactId(), plugin.getGroupId(), plugin.getArtifactId())) {
return super.resolve(plugin.getMavenId(), context);
}
}
}
// Try to resolve to plugin with latest version
PsiManager psiManager = context.getPsiManager();
MavenProjectsManager projectsManager = MavenProjectsManager.getInstance(psiManager.getProject());
File artifactFile = MavenArtifactUtil
.getArtifactFile(projectsManager.getLocalRepository(), id.getGroupId(), id.getArtifactId(), id.getVersion(), "pom");
VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(artifactFile);
if (virtualFile != null) {
return psiManager.findFile(virtualFile);
}
return null;
}
}
}