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

org.wildfly.channelplugin.manipulation.PomManipulator Maven / Gradle / Ivy

Go to download

This maven plugin overrides dependencies versions in a Maven project according to Wildfly channel definition.

The newest version!
package org.wildfly.channelplugin.manipulation;

import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Stack;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;

import org.apache.http.util.Asserts;
import org.codehaus.mojo.versions.api.PomHelper;
import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.WriterFactory;
import org.codehaus.stax2.XMLInputFactory2;
import org.commonjava.maven.atlas.ident.ref.ArtifactRef;
import org.commonjava.maven.atlas.ident.ref.ProjectRef;
import org.commonjava.maven.ext.common.model.Project;

/**
 * Provides functionality to manipulate properties and dependencies in a POM file.
 */
public class PomManipulator {

    private static final String DEPENDENCY_MANAGEMENT_PATH = "/project/dependencyManagement";
    private static final String DEPENDENCY_MANAGEMENT_DEPENDENCIES_PATH = "/project/dependencyManagement/dependencies";
    private static final String REPOSITORIES_PATH = "/project/repositories";
    private static final String PLUGIN_REPOSITORIES_PATH = "/project/pluginRepositories";
    private static final String PROJECT = "project";
    private static final String DEPENDENCY_MANAGEMENT = "dependencyManagement";
    private static final String DEPENDENCIES = "dependencies";
    private static final String REPOSITORIES = "repositories";
    private static final String PLUGIN_REPOSITORIES = "pluginRepositories";

    private final Project project;
    private final ModifiedPomXMLEventReader eventReader;
    private final StringBuilder content;
    private boolean closed = false;

    /**
     * @param project Project instance
     */
    public PomManipulator(Project project) {
        try {
            this.project = project;
            XMLInputFactory inputFactory = XMLInputFactory2.newInstance();
            inputFactory.setProperty(XMLInputFactory2.P_PRESERVE_LOCATION, Boolean.TRUE);
            this.content = PomHelper.readXmlFile(project.getPom());
            this.eventReader = new ModifiedPomXMLEventReader(content, inputFactory, project.getPom().getPath());
        } catch (IOException | XMLStreamException e) {
            throw new RuntimeException("Couldn't initialize PomWriter instance", e);
        }
    }

    public void overrideDependencyVersion(ArtifactRef d, String newVersion) throws XMLStreamException {
        PomHelper.setDependencyVersion(eventReader, d.getGroupId(), d.getArtifactId(), d.getVersionString(),
                newVersion, project.getModel());
    }

    public void overrideDependencyVersion(String groupId, String artifactId, String oldVersionString, String newVersion) throws XMLStreamException {
        PomHelper.setDependencyVersion(eventReader, groupId, artifactId, oldVersionString, newVersion,
                project.getModel());
    }

    public void overrideDependencyVersionWithComment(ArtifactRef d, String newVersion) throws XMLStreamException {
        overrideDependencyVersionWithComment(eventReader, d.getGroupId(), d.getArtifactId(), d.getVersionString(), newVersion);
    }

    static void overrideDependencyVersionWithComment(final ModifiedPomXMLEventReader eventReader,
                                                     final String groupId, final String artifactId,
                                                     final String oldVersionString, final String newVersion)
            throws XMLStreamException {
        eventReader.rewind();

        Stack stack = new Stack<>();
        String path = "";

        List locations = Arrays.asList(
                "/project/dependencyManagement/dependencies/dependency",
                "/project/dependencies/dependency"
        );

        boolean matchingGroupId = false;
        boolean matchingArtifactId = false;
        boolean hasVersion = false;

        while (eventReader.hasNext()) {
            XMLEvent event = eventReader.nextEvent();
            if (event.isStartElement()) {
                String parentElementPath = path;
                stack.push(path);
                String elementName = event.asStartElement().getName().getLocalPart();
                path = path + "/" + elementName;

                if (locations.contains(parentElementPath)) {
                    switch (elementName) {
                        case "groupId":
                            matchingGroupId = groupId.equals(eventReader.getElementText().trim());
                            path = stack.pop();
                            break;
                        case "artifactId":
                            matchingArtifactId = artifactId.equals(eventReader.getElementText().trim());
                            path = stack.pop();
                            break;
                        case "version":
                            eventReader.mark(0);
                            break;
                    }
                }
            } else if (event.isEndElement()) {
                String parentPath = stack.peek();
                String elementName = event.asEndElement().getName().getLocalPart();
                if (locations.contains(parentPath) || locations.contains(path)) {
                    switch (elementName) {
                        case "version":
                            eventReader.mark(1);
                            String versionString = eventReader.getBetween(0, 1);
                            hasVersion = !versionString.trim().isEmpty();
                            break;
                        case "dependency":
                            if (matchingGroupId && matchingArtifactId && hasVersion) {
                                eventReader.replaceMark(1, " ");
                                eventReader.replaceBetween(0, 1, newVersion);
                            }

                            matchingGroupId = false;
                            matchingArtifactId = false;
                            hasVersion = false;
                            eventReader.clearMark(0);
                            eventReader.clearMark(1);
                            break;
                    }
                }

                path = stack.pop();
            }
        }
    }

    public boolean overrideProperty(String propertyName, String propertyValue) throws XMLStreamException {
        return PomHelper.setPropertyVersion(eventReader, null, propertyName, propertyValue);
    }

    public void injectManagedDependency(ArtifactRef dependency, Collection exclusions, String oldVersion)
            throws XMLStreamException {
        injectDependencyManagementSection(eventReader);
        injectDependencyManagementDependenciesSection(eventReader);
        injectManagedDependency(eventReader, dependency, exclusions, oldVersion);
    }

    static void injectRepositoriesSection(ModifiedPomXMLEventReader eventReader) throws XMLStreamException {
        eventReader.rewind();

        Stack stack = new Stack();
        String path = "";

        while (eventReader.hasNext()) {
            XMLEvent event = eventReader.nextEvent();
            if (event.isStartElement()) {
                if (path.equals("/project") && event.asStartElement().getName().getLocalPart().equals(REPOSITORIES)) {
                    // section is already present
                    return;
                }

                stack.push(path);
                path = path + "/" + event.asStartElement().getName().getLocalPart();
            } else if (event.isEndElement()) {
                if (event.asEndElement().getName().getLocalPart().equals(PROJECT)) {
                    eventReader.mark(0);
                    eventReader.replaceMark(0, composeRepositoriesElementString()
                            + ""
                    );
                    eventReader.clearMark(0);
                    return;
                }

                path = stack.pop();
            }
        }
    }

    static void injectPluginRepositoriesSection(ModifiedPomXMLEventReader eventReader) throws XMLStreamException {
        eventReader.rewind();

        Stack stack = new Stack();
        String path = "";

        while (eventReader.hasNext()) {
            XMLEvent event = eventReader.nextEvent();
            if (event.isStartElement()) {
                if (path.equals("/project") && event.asStartElement().getName().getLocalPart().equals(PLUGIN_REPOSITORIES)) {
                    // section is already present
                    return;
                }

                stack.push(path);
                path = path + "/" + event.asStartElement().getName().getLocalPart();
            } else if (event.isEndElement()) {
                if (event.asEndElement().getName().getLocalPart().equals(PROJECT)) {
                    eventReader.mark(0);
                    eventReader.replaceMark(0, composePluginRepositoriesElementString()
                            + ""
                    );
                    eventReader.clearMark(0);
                    return;
                }

                path = stack.pop();
            }
        }
    }

    public void injectRepository(String id, String url) throws XMLStreamException {
        injectRepository(eventReader, id, url);
    }

    public void injectPluginRepository(String id, String url) throws XMLStreamException {
        injectPluginRepository(eventReader, id, url);
    }

    static void injectRepository(ModifiedPomXMLEventReader eventReader, String id, String url) throws XMLStreamException {
        injectRepositoriesSection(eventReader);

        eventReader.rewind();

        Stack stack = new Stack();
        String path = "";

        while (eventReader.hasNext()) {
            XMLEvent event = eventReader.nextEvent();
            if (event.isStartElement()) {
                stack.push(path);
                path = path + "/" + event.asStartElement().getName().getLocalPart();
            } else if (event.isEndElement()) {
                // replaces "" end element with new repository + the end element
                String elementName = event.asEndElement().getName().getLocalPart();
                if (elementName.equals(REPOSITORIES) && path.equals(REPOSITORIES_PATH)) {
                    eventReader.mark(0);
                    eventReader.replaceMark(0, composeRepositoryElementString(id, url)
                            + "    "
                    );
                    eventReader.clearMark(0);
                    break;
                }

                path = stack.pop();
            }
        }
    }

    static void injectPluginRepository(ModifiedPomXMLEventReader eventReader, String id, String url) throws XMLStreamException {
        injectPluginRepositoriesSection(eventReader);

        eventReader.rewind();

        Stack stack = new Stack<>();
        String path = "";

        while (eventReader.hasNext()) {
            XMLEvent event = eventReader.nextEvent();
            if (event.isStartElement()) {
                stack.push(path);
                path = path + "/" + event.asStartElement().getName().getLocalPart();
            } else if (event.isEndElement()) {
                // replaces "" end element with new repository + the end element
                String elementName = event.asEndElement().getName().getLocalPart();
                if (elementName.equals(PLUGIN_REPOSITORIES) && path.equals(PLUGIN_REPOSITORIES_PATH)) {
                    eventReader.mark(0);
                    eventReader.replaceMark(0, composePluginRepositoryElementString(id, url)
                            + "    "
                    );
                    eventReader.clearMark(0);
                    break;
                }

                path = stack.pop();
            }
        }
    }

    public void injectProperty(String key, String version) throws XMLStreamException {
        injectProperty(eventReader, key, version);
    }

    /**
     * Writes the updated POM file.
     */
    public void writePom() {
        assertOpen();
        try (Writer writer = WriterFactory.newXmlWriter(project.getPom())) {
            closed = true;
            IOUtil.copy(content.toString(), writer);
            eventReader.close();
        } catch (IOException e) {
            throw new RuntimeException("Failed to write to the pom file", e);
        } catch (XMLStreamException e) {
            throw new RuntimeException("Couldn't close event reader", e);
        }
    }

    private void assertOpen() {
        Asserts.check(!closed, "This instance cannot be used repeatedly.");
    }

    /**
     * This method attempts to inject new dependency into at the end of the dependencyManagement section.
     * 

* The dependencyManagement section must be already present in the POM. */ static void injectManagedDependency(ModifiedPomXMLEventReader eventReader, ArtifactRef dependency, Collection exclusions, String oldVersion) throws XMLStreamException { eventReader.rewind(); Stack stack = new Stack<>(); String path = ""; while (eventReader.hasNext()) { XMLEvent event = eventReader.nextEvent(); if (event.isStartElement()) { stack.push(path); path = path + "/" + event.asStartElement().getName().getLocalPart(); } else if (event.isEndElement()) { if (event.asEndElement().getName().getLocalPart().equals(DEPENDENCIES) && path.equals(DEPENDENCY_MANAGEMENT_DEPENDENCIES_PATH)) { eventReader.mark(0); eventReader.replaceMark(0, composeDependencyElementString(dependency, exclusions, oldVersion) + " " ); eventReader.clearMark(0); return; } path = stack.pop(); } } } /** * Inserts dependencyManagement section if it's not already present. */ static void injectDependencyManagementSection(ModifiedPomXMLEventReader eventReader) throws XMLStreamException { eventReader.rewind(); while (eventReader.hasNext()) { XMLEvent event = eventReader.nextEvent(); if (event.isStartElement()) { if (event.asStartElement().getName().getLocalPart().equals(DEPENDENCY_MANAGEMENT)) { // dependency management is already present return; } } else if (event.isEndElement()) { if (event.asEndElement().getName().getLocalPart().equals(PROJECT)) { eventReader.mark(0); eventReader.replaceMark(0, composeDependencyManagementElementString() + "" ); eventReader.clearMark(0); return; } } } } static void injectDependencyManagementDependenciesSection(ModifiedPomXMLEventReader eventReader) throws XMLStreamException { eventReader.rewind(); Stack stack = new Stack<>(); String path = ""; while (eventReader.hasNext()) { XMLEvent event = eventReader.nextEvent(); if (event.isStartElement()) { if (event.asStartElement().getName().getLocalPart().equals(DEPENDENCIES) && path.equals(DEPENDENCY_MANAGEMENT_PATH)) { // dependencies section is already present return; } stack.push(path); path = path + "/" + event.asStartElement().getName().getLocalPart(); } else if (event.isEndElement()) { if (event.asEndElement().getName().getLocalPart().equals(DEPENDENCY_MANAGEMENT)) { eventReader.mark(0); eventReader.replaceMark(0, composeDependenciesElementString() + " " ); eventReader.clearMark(0); return; } path = stack.pop(); } } } /** * This method attempts to inject new property at the end of the properties section. *

* The properties section must be already present in the POM. */ static void injectProperty(ModifiedPomXMLEventReader eventReader, String key, String version) throws XMLStreamException { eventReader.rewind(); Stack stack = new Stack<>(); String path = ""; while (eventReader.hasNext()) { XMLEvent event = eventReader.nextEvent(); if (event.isStartElement()) { stack.push(path); path = path + "/" + event.asStartElement().getName().getLocalPart(); } else if (event.isEndElement()) { if (event.asEndElement().getName().getLocalPart().equals("properties") && path.equals("/project/properties")) { eventReader.mark(0); eventReader.replaceMark(0, String.format(" <%s>%s\n", key, version, key) + " " ); eventReader.clearMark(0); break; } path = stack.pop(); } } } private static String composeDependencyManagementElementString() { return " \n" + " \n"; } private static String composeDependenciesElementString() { return " \n" + " \n"; } private static String composeRepositoriesElementString() { return " \n" + " \n"; } private static String composePluginRepositoriesElementString() { return " \n" + " \n"; } private static String composeDependencyElementString(ArtifactRef artifact, Collection exclusions, String oldVersion) { StringBuilder sb = new StringBuilder(); sb.append(" \n"); sb.append(String.format(" %s\n", artifact.getGroupId())); sb.append(String.format(" %s\n", artifact.getArtifactId())); sb.append(String.format(" %s \n", artifact.getVersionString(), oldVersion)); if (artifact.getClassifier() != null) { sb.append(String.format(" %s\n", artifact.getClassifier())); } if (!"jar".equals(artifact.getType())) { sb.append(String.format(" %s\n", artifact.getType())); } if (exclusions != null && !exclusions.isEmpty()) { sb.append(" \n"); for (ProjectRef e: exclusions) { sb.append(" \n"); sb.append(" " + e.getGroupId() + "\n"); sb.append(" " + e.getArtifactId() + "\n"); sb.append(" \n"); } sb.append(" \n"); } sb.append(" \n"); return sb.toString(); } private static String composeRepositoryElementString(String id, String url) { StringBuilder sb = new StringBuilder(); sb.append(" \n"); sb.append(String.format(" %s\n", id)); sb.append(String.format(" %s\n", url)); sb.append(" \n"); sb.append(" true\n"); sb.append(" always\n"); sb.append(" \n"); sb.append(" \n"); sb.append(" true\n"); sb.append(" always\n"); sb.append(" \n"); sb.append(" \n"); return sb.toString(); } private static String composePluginRepositoryElementString(String id, String url) { StringBuilder sb = new StringBuilder(); sb.append(" \n"); sb.append(String.format(" %s\n", id)); sb.append(String.format(" %s\n", url)); sb.append(" \n"); sb.append(" true\n"); sb.append(" always\n"); sb.append(" \n"); sb.append(" \n"); sb.append(" true\n"); sb.append(" always\n"); sb.append(" \n"); sb.append(" \n"); return sb.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy