/* * Copyright (c) 2007-2009, Osmorc Development Team * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * Neither the name of 'Osmorc Development Team' nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.osmorc.maven.inspection; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.codeInspection.XmlSuppressableInspectionTool; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiFile; import com.intellij.psi.XmlElementVisitor; import com.intellij.psi.xml.XmlTag; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.xml.DomElement; import com.intellij.util.xml.DomManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.maven.dom.MavenDomUtil; import org.jetbrains.idea.maven.dom.model.MavenDomDependency; import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel; import org.jetbrains.idea.maven.dom.model.MavenDomRepository; import org.jetbrains.idea.maven.model.MavenConstants; import org.jetbrains.idea.maven.project.MavenProjectsManager; import org.jetbrains.idea.maven.utils.MavenArtifactUtil; import org.jetbrains.osgi.jps.build.CachingBundleInfoProvider; import org.osmorc.facet.OsmorcFacet; import org.osmorc.i18n.OsmorcBundle; import org.osmorc.inspection.AbstractOsgiQuickFix; import org.osmorc.obrimport.MavenRepository; import org.osmorc.obrimport.ObrSearchDialog; import org.osmorc.obrimport.springsource.ObrMavenResult; import java.io.File; import java.util.Iterator; import java.util.List; import java.util.Set; /** * Inspection which detects non-OSGi dependencies. * * @author <a href="mailto:janthomae@janthomae.de">Jan Thomä</a> */ public class NonOsgiMavenDependencyInspection extends XmlSuppressableInspectionTool { @NotNull @Override public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder problemsHolder, boolean isOnTheFly) { boolean isMaven = MavenDomUtil.isMavenFile(problemsHolder.getFile()); return !isMaven ? PsiElementVisitor.EMPTY_VISITOR : new XmlElementVisitor() { @Override public void visitXmlTag(XmlTag tag) { if (OsmorcFacet.hasOsmorcFacet(tag)) { MavenDomDependency dependency = getDependency(tag); if (dependency != null) { String scope = dependency.getScope().getStringValue(); if (!MavenConstants.SCOPE_TEST.equals(scope)) { File repo = MavenProjectsManager.getInstance(tag.getProject()).getLocalRepository(); String groupId = dependency.getGroupId().getStringValue(); String artifactId = dependency.getArtifactId().getStringValue(); String version = dependency.getVersion().getStringValue(); File artifactFile = MavenArtifactUtil.getArtifactFile(repo, groupId, artifactId, version, MavenConstants.TYPE_JAR); if (artifactFile.exists() && !CachingBundleInfoProvider.isBundle(artifactFile.getPath())) { problemsHolder.registerProblem(tag, OsmorcBundle.message("NonOsgiMavenDependencyInspection.message"), new FindOsgiCapableMavenDependencyQuickFix()); } } } } } }; } private static MavenDomDependency getDependency(XmlTag tag) { if ("dependency".equals(tag.getName())) { PsiElement parent = tag.getParent(); if (parent != null) { PsiElement grand = parent.getParent(); if (!(grand instanceof XmlTag && "plugin".equals(((XmlTag)grand).getName()))) { DomElement dom = DomManager.getDomManager(tag.getProject()).getDomElement(tag); if (dom != null) { return dom.getParentOfType(MavenDomDependency.class, false); } } } } return null; } /** * Fix which tries to find a compatible OSGi-ready version of a Maven dependency. */ private static class FindOsgiCapableMavenDependencyQuickFix extends AbstractOsgiQuickFix { @NotNull @Override public String getName() { return OsmorcBundle.message("NonOsgiMavenDependencyInspection.fix"); } @Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor problemDescriptor) { final MavenDomDependency dependency = getDependency((XmlTag)problemDescriptor.getPsiElement()); if (dependency == null) return; final ObrMavenResult result = ObrSearchDialog.queryForMavenArtifact(project, dependency.getArtifactId().toString()); if (result == null) return; final PsiFile psiFile = problemDescriptor.getPsiElement().getContainingFile(); new WriteCommandAction(project, psiFile) { @Override protected void run(@NotNull Result _result) throws Throwable { MavenDomProjectModel model = MavenDomUtil.getMavenDomProjectModel(getProject(), psiFile.getVirtualFile()); if (model == null) return; // replace dependency element MavenDomDependency dummy = model.getDependencies().addDependency(); dummy.getGroupId().setStringValue(result.getGroupId()); dummy.getArtifactId().setStringValue(result.getArtifactId()); dummy.getVersion().setStringValue(result.getVersion()); String scope = dependency.getScope().getStringValue(); if (!StringUtil.isEmpty(scope)) { dummy.getScope().setStringValue(scope); } PsiElement newDep = dummy.getXmlElement(); PsiElement oldDep = dependency.getXmlElement(); assert newDep != null : dummy; assert oldDep != null : dependency; oldDep.replace(newDep.copy()); newDep.delete(); // add new repository if needed Set<String> projectRepositoryUrls = ContainerUtil.map2Set(model.getRepositories().getRepositories(), repository -> repository.getUrl().getStringValue()); List<MavenRepository> newRepositories = ContainerUtil.newSmartList(result.getBundleRepository().getMavenRepositories()); for (Iterator<MavenRepository> i = newRepositories.iterator(); i.hasNext(); ) { MavenRepository repository = i.next(); if (projectRepositoryUrls.contains(repository.getRepositoryUrl())) { i.remove(); } } for (MavenRepository repository : newRepositories) { MavenDomRepository added = model.getRepositories().addRepository(); added.getId().setStringValue(repository.getRepositoryId()); added.getUrl().setStringValue(repository.getRepositoryUrl()); added.getName().setStringValue(repository.getRepositoryDescription()); } } }.execute(); } } }