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

org.jboss.maven.plugins.qstools.BomUpdaterMojo Maven / Gradle / Ivy

Go to download

This a Maven Plugin that helps JBoss Developer quickstarts maintenance. You can use it to verify if your project/quickstart follow the JBoss Developer Guidelines. It will run all JBoss Developer Guideline checkers and generate a report that provides information about any violations that your project/quickstarts has.

There is a newer version: 1.4.1.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2013, Red Hat, Inc. and/or its affiliates, and individual
 * contributors by the @authors tag. See the copyright.txt in the
 * distribution for a full listing of individual contributors.
 *
 * 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.jboss.maven.plugins.qstools;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.List;
import java.util.Properties;
import java.util.Scanner;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.interpolation.InterpolationException;
import org.jboss.maven.plugins.qstools.config.ConfigurationProvider;
import org.jboss.maven.plugins.qstools.config.Rules;
import org.jboss.maven.plugins.qstools.maven.MavenDependency;
import org.jboss.maven.plugins.qstools.xml.PositionalXMLReader;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.puppycrawl.tools.checkstyle.checks.UpperEllCheck;

/**
 * Update all BOMs to use the recommended versions. Note that the update only will be made from previous version to newer
 * recommended versions. It doesn't downgrade the versions;
 * 
 * @author Rafael Benevides
 * 
 */
@Mojo(name = "updateBoms", defaultPhase = LifecyclePhase.PACKAGE, requiresDependencyResolution = ResolutionScope.COMPILE, requiresProject = true, threadSafe = true, aggregator = true)
public class BomUpdaterMojo extends AbstractMojo {

    @Parameter(property = "reactorProjects", readonly = true, required = true)
    private List reactorProjects;

    @Component
    private DependencyProvider dependencyProvider;

    @Component
    private ConfigurationProvider configurationProvider;

    @Component
    private MavenSession mavenSession;

    @Component
    private PlexusContainer container;

    private boolean pomModified = false;

    private int updatedProjects = 0;

    /**
     * Overwrite the config file
     */
    @Parameter(property = "qstools.configFileURL",
        defaultValue = "https://raw.github.com/jboss-developer/maven-qstools-plugin/master/config/qstools_config.yaml")
    private URL configFileURL;

    private XPath xPath = XPathFactory.newInstance().newXPath();

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.maven.plugin.Mojo#execute()
     */
    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        try {
            configure();
            getLog().warn("Running this plugin CAN MODIFY your pom.xml files. Make sure to have your changes commited before running this plugin");
            getLog().warn("Do you want to continue[yes/no]");
            String answer = new Scanner(System.in).nextLine();
            if (answer.equalsIgnoreCase("yes")) {
                for (MavenProject project : reactorProjects) {
                    processProject(project);
                }
                getLog().info(" ***** All projects were processed! Total Processed: " + reactorProjects.size() + " - Total Updates: " + updatedProjects +
                    "\nRun [mvn clean compile] to get sure that everything is working" +
                    "\nRun [git diff] to see the changes made." +
                    "\n");
            } else {
                getLog().info("Aborted");
            }
        } catch (Exception e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }

    private void configure() {
        getLog().info("Using the following QSTools config file: " + configFileURL);
        container.getContext().put(Constants.CONFIG_FILE_CONTEXT, configFileURL);

        container.getContext().put(Constants.LOG_CONTEXT, getLog());
        container.getContext().put(Constants.MAVEN_SESSION_CONTEXT, mavenSession);
    }

    /**
     * @param project
     * @throws Exception
     */
    private void processProject(MavenProject project) throws Exception {
        pomModified = false;
        Rules rules = configurationProvider.getQuickstartsRules(project.getGroupId());
        getLog().debug("Processing " + project.getArtifactId());
        Document doc = PositionalXMLReader.readXML(new FileInputStream(project.getFile()));
        NodeList dependencies = (NodeList) xPath.evaluate("/project/dependencyManagement/dependencies/dependency", doc, XPathConstants.NODESET);
        replaceBOMsIfNeeded(project, dependencies, rules);
        updateBomsVersionIfNeeded(project, dependencies, rules, doc);
        if (pomModified) {
            getLog().info("*** Saving changes to " + project.getFile() + "\n");
            updatedProjects++;
            write(doc, new FileOutputStream(project.getFile()));
        }
    }

    private void updateBomsVersionIfNeeded(MavenProject project, NodeList dependencies, Rules rules, Document doc) throws InterpolationException, XPathExpressionException {
        // Iterate over all Declared Managed Dependencies - Needs to update BOM version?
        for (int x = 0; x < dependencies.getLength(); x++) {
            Node dependency = dependencies.item(x);
            MavenDependency mavenDependency = dependencyProvider.getDependencyFromNode(project, dependency);
            String version = mavenDependency.getInterpoledVersion();
            String expectedBomVersion = (String) rules.getExpectedBomVersion().get(mavenDependency.getGroupId());
            // If not using expected Bom Version
            if (expectedBomVersion != null && !expectedBomVersion.equals(version)) {
                String declaredVersion = mavenDependency.getDeclaredVersion().replace("${", "").replace("}", "");
                // There's a declared property ?
                if (project.getProperties().get(declaredVersion) != null) { // Properties.contains() didn't work
                    // Alter ir
                    Node propertyNode = (Node) xPath.evaluate("/project/properties/" + declaredVersion, doc, XPathConstants.NODE);
                    if (propertyNode != null) { // It can be null for inherited property
                        getLog().info("Updating property [" + declaredVersion + "] from " + version + " to " + expectedBomVersion);
                        pomModified = true;
                        propertyNode.setTextContent(expectedBomVersion);
                    }
                } else {
                    // Create the property if it doesn't exist
                    Node propertiesNode = (Node) xPath.evaluate("/project/properties", doc, XPathConstants.NODE);
                    String comment = String.format("Automatically created property by QSTools for"
                        + "\n        %s:%s BOM", mavenDependency.getGroupId(), mavenDependency.getArtifactId());
                    Comment commentNode = doc.createComment(comment);
                    getLog().info("* CREATING property [" + declaredVersion + "] with value " + expectedBomVersion);
                    pomModified = true;
                    Element propertyNode = doc.createElement(declaredVersion);
                    propertyNode.setTextContent(expectedBomVersion);
                    propertiesNode.appendChild(doc.createTextNode("\n        ")); // LF + 8 spaces
                    propertiesNode.appendChild(commentNode);
                    propertiesNode.appendChild(doc.createTextNode("\n        ")); // LF + 8 spaces
                    propertiesNode.appendChild(propertyNode);
                }
            }
        }
    }

    private void replaceBOMsIfNeeded(MavenProject project, NodeList dependencies, Rules rules) throws InterpolationException {
        Properties bomsMigration = rules.getProjectBomsMigration();
        // Iterate over all Declared Managed Dependencies - Needs BOM replacement?
        for (int x = 0; x < dependencies.getLength(); x++) {
            Node dependency = dependencies.item(x);
            MavenDependency mavenDependency = dependencyProvider.getDependencyFromNode(project, dependency);
            String oldBomGA = mavenDependency.getGroupId() + "|" + mavenDependency.getArtifactId();
            String newBomGAV = bomsMigration.getProperty(oldBomGA);

            if (newBomGAV != null) {
                getLog().info("Replacing " + oldBomGA + " BOM by " + newBomGAV);
                pomModified = true;
                String[] newBomGavSplited = newBomGAV.split("[|]");
                updateBomNode(dependency, newBomGavSplited[0], newBomGavSplited[1], newBomGavSplited[2]);
            }
        }
    }

    private void updateBomNode(Node dependencyNode, String groupId, String artifactId, String version) {
        NodeList childrenNodes = dependencyNode.getChildNodes();
        for (int i = 0; i < childrenNodes.getLength(); i++) {
            Node node = childrenNodes.item(i);
            if (node.getNodeName().equals("groupId")) {
                node.setTextContent(groupId);
            } else if (node.getNodeName().equals("artifactId")) {
                node.setTextContent(artifactId);
            } else if (node.getNodeName().equals("version")) {
                node.setTextContent("${" + version + "}");
            }
        }
    }

    public void write(Document doc, OutputStream out) throws Exception {
        Transformer t = TransformerFactory.newInstance().newTransformer();
        t.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); // NOI18N
        t.setOutputProperty(OutputKeys.INDENT, "yes"); // NOI18N
        t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); // NOI18N
        Source source = new DOMSource(doc);
        Result result = new StreamResult(out);
        t.transform(source, result);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy