All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.plugins.xml.checks.maven.PomElementOrderCheck Maven / Gradle / Ivy

/*
 * SonarQube XML Plugin
 * Copyright (C) 2010-2023 SonarSource SA
 * mailto:info AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.plugins.xml.checks.maven;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.sonar.check.Rule;
import org.sonarsource.analyzer.commons.annotations.DeprecatedRuleKey;
import org.sonarsource.analyzer.commons.xml.XmlFile;
import org.sonarsource.analyzer.commons.xml.checks.SonarXmlCheck;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

@Rule(key = "S3423")
@DeprecatedRuleKey(repositoryKey = "java", ruleKey = "S3423")
public class PomElementOrderCheck extends SonarXmlCheck {

  private static final Comparator LINE_COMPARATOR = Comparator.comparingInt(n -> XmlFile.nodeLocation(n).getStartLine());

  private static final List REQUIRED_ORDER = Arrays.asList(
    "modelVersion",
    "parent",
    "groupId",
    "artifactId",
    "version",
    "packaging",
    "name",
    "description",
    "url",
    "inceptionYear",
    "organization",
    "licenses",
    "developers",
    "contributors",
    "mailingLists",
    "prerequisites",
    "modules",
    "scm",
    "issueManagement",
    "ciManagement",
    "distributionManagement",
    "properties",
    "dependencyManagement",
    "dependencies",
    "repositories",
    "pluginRepositories",
    "build",
    "reporting",
    "profiles");

  @Override
  public void scanFile(XmlFile xmlFile) {
    if (!"pom.xml".equalsIgnoreCase(xmlFile.getInputFile().filename())) {
      return;
    }

    checkPositions(xmlFile.getDocument().getDocumentElement());
  }

  private static Optional getChildElementByName(String name, List children) {
    return children.stream()
      .filter(child -> child.getNodeType() == Node.ELEMENT_NODE)
      .map(Element.class::cast)
      .filter(element -> element.getTagName().equals(name))
      .findFirst();
  }

  private void checkPositions(Element project) {
    List children = XmlFile.children(project);
    List expectedOrder = REQUIRED_ORDER.stream()
      .map(elementName -> getChildElementByName(elementName, children))
      .filter(Optional::isPresent)
      .map(Optional::get)
      .collect(Collectors.toList());

    List observedOrder = expectedOrder.stream().sorted(LINE_COMPARATOR).collect(Collectors.toList());

    int lastWrongPosition = -1;
    int firstWrongPosition = -1;

    for (int index = 0; index < expectedOrder.size(); index++) {
      if (observedOrder.indexOf(expectedOrder.get(index)) != index) {
        lastWrongPosition = index;
        if (firstWrongPosition == -1) {
          firstWrongPosition = index;
        }
      }
    }

    if (lastWrongPosition == -1) {
      return;
    }

    List inconsistencies = new ArrayList<>();
    // only reports between first and last wrong position
    for (int index = firstWrongPosition; index <= lastWrongPosition; index++) {
      inconsistencies.add(new Secondary(expectedOrder.get(index), "Expected position: " + (index + 1)));
    }

    if (!inconsistencies.isEmpty()) {
      reportIssue(XmlFile.startLocation(project),
        "Reorder the elements of this pom to match the recommended order.", inconsistencies);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy