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

io.openliberty.tools.maven.server.GenerateFeaturesMojo Maven / Gradle / Ivy

Go to download

Liberty Maven Plugin : Install, Start/Stop, Package, Create Server, Deploy/Undeploy applications

There is a newer version: 3.11.1
Show newest version
/**
 * (C) Copyright IBM Corporation 2021, 2023.
 *
 * 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 io.openliberty.tools.maven.server;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.apache.maven.execution.ProjectDependencyGraph;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.ProjectBuildingResult;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

import io.openliberty.tools.common.plugins.config.ServerConfigXmlDocument;
import io.openliberty.tools.common.plugins.config.XmlDocument;
import io.openliberty.tools.common.plugins.util.BinaryScannerUtil;
import static io.openliberty.tools.common.plugins.util.BinaryScannerUtil.*;
import io.openliberty.tools.common.plugins.util.PluginExecutionException;
import io.openliberty.tools.common.plugins.util.ServerFeatureUtil;
import io.openliberty.tools.maven.ServerFeatureSupport;

/**
 * This mojo generates the features required in the featureManager element in
 * server.xml. It examines the dependencies declared in the pom.xml and the
 * features already declared in the featureManager elements in the XML
 * configuration files. Then it generates any missing feature names and stores
 * them in a new featureManager element in a new XML file in the source
 * config/dropins directory.
 */
@Mojo(name = "generate-features")
public class GenerateFeaturesMojo extends ServerFeatureSupport {

    public static final String FEATURES_FILE_MESSAGE = "The Liberty Maven Plugin has generated Liberty features necessary for your application in "
            + GENERATED_FEATURES_FILE_PATH;
    public static final String HEADER = "This file was generated by the Liberty Maven Plugin and will be overwritten on subsequent runs of the liberty:generate-features goal."
            + "\n It is recommended that you do not edit this file and that you commit this file to your version control.";
    public static final String GENERATED_FEATURES_COMMENT = "The following features were generated based on API usage detected in your application";
    public static final String NO_NEW_FEATURES_COMMENT = "No additional features generated";
    public static final String NO_CLASSES_DIR_WARNING = "Could not find classes directory to generate features against. Liberty features will not be generated. "
            + "Ensure your project has first been compiled.";

    private File binaryScanner;

    @Parameter(property = "classFiles")
    private List classFiles;

    /**
     * If optimize is true, pass all class files and only user specified features to binary scanner
     * Otherwise, if optimize is false, pass only provided updated class files (if any) and all existing features to binary scanner
     */
    @Parameter(property = "optimize", defaultValue = "true")
    private boolean optimize;

    @Override
    protected void init() throws MojoExecutionException {
        // @see io.openliberty.tools.maven.BasicSupport#init() skip server config
        // setup as generate features does not require the server to be set up install
        // dir, wlp dir, outputdir, etc.
        this.skipServerConfigSetup = true;

        super.init();
    }
    
    @Override
    public void execute() throws MojoExecutionException {
        init();

        if (skip) {
            getLog().info("\nSkipping generate-features goal.\n");
            return;
        }
        try {
            generateFeatures();
        } catch (PluginExecutionException e) {
            throw new MojoExecutionException("Error during generation of features.", e);
        }
    }

    /**
     * Generates features for the application given the API usage detected and
     * taking any user specified features into account
     * 
     * @throws MojoExecutionException
     * @throws PluginExecutionException indicates the binary-app-scanner.jar could
     *                                  not be found
     */
    private void generateFeatures() throws MojoExecutionException, PluginExecutionException {
        // If there are downstream projects (e.g. other modules depend on this module in the Maven Reactor build order),
        // then skip generate-features on this module
        ProjectDependencyGraph graph = session.getProjectDependencyGraph();
        List upstreamProjects = new ArrayList();
        if (graph != null) {
            checkMultiModuleConflicts(graph);
            List downstreamProjects = graph.getDownstreamProjects(project, true);
            if (!downstreamProjects.isEmpty()) {
                getLog().debug("Downstream projects: " + downstreamProjects);
                return;
            } else {
                // get all upstream projects
                for (MavenProject upstreamProj : graph.getUpstreamProjects(project, true)) {
                    try {
                        // when GenerateFeaturesMojo is called from dev mode on a multi module project,
                        // the upstream project umbrella dependencies may not be up to date. Call
                        // getMavenProject to rebuild the project with the current Maven session,
                        // ensuring that the latest umbrella dependencies are loaded
                        upstreamProjects.add(getMavenProject(upstreamProj.getFile()));
                    } catch (ProjectBuildingException e) {
                        getLog().debug("Could not resolve the upstream project: " + upstreamProj.getFile()
                                + " using the current Maven session. Falling back to last resolved upstream project.");
                        upstreamProjects.add(upstreamProj); // fail gracefully, use last resolved project
                    }
                }
            }

            if (containsPreviousLibertyModule(graph)) {
                // skip this module
                return;
            }
        }

        binaryScanner = getBinaryScannerJarFromRepository();
        BinaryScannerHandler binaryScannerHandler = new BinaryScannerHandler(binaryScanner);

        getLog().debug("--- Generate Features values ---");
        getLog().debug("Binary scanner jar: " + binaryScanner.getName());
        getLog().debug("optimize generate features: " + optimize);
        if (classFiles != null && !classFiles.isEmpty()) {
            getLog().debug("Generate features for the following class files: " + classFiles.toString());
        }

        // TODO add support for env variables
        // commented out for now as the current logic depends on the server dir existing
        // and specifying features with env variables is an edge case
        /* Map libertyDirPropertyFiles;
        try {
            libertyDirPropertyFiles = BasicSupport.getLibertyDirectoryPropertyFiles(installDirectory, userDirectory, serverDirectory);
        } catch (IOException e) {
            getLog().debug("Exception reading the server property files", e);
            getLog().error("Error attempting to generate server feature list. Ensure your user account has read permission to the property files in the server installation directory.");
            return;
        } */

        // TODO: get user specified features that have not yet been installed in the
        // original case they appear in a server config xml document.
        // getSpecifiedFeatures may not return the features in the correct case
        // Set featuresToInstall = getSpecifiedFeatures(null); 

        // get existing server features from source directory
        ServerFeatureUtil servUtil = getServerFeatureUtil(true, null);

        Set generatedFiles = new HashSet();
        generatedFiles.add(GENERATED_FEATURES_FILE_NAME);

        Set existingFeatures = getServerFeatures(servUtil, generatedFiles, optimize);
        Set nonCustomFeatures = new HashSet(); // binary scanner only handles actual Liberty features
        for (String feature : existingFeatures) { // custom features are "usr:feature-1.0" or "myExt:feature-2.0"
            if (!feature.contains(":")) nonCustomFeatures.add(feature);
        }

        Set scannedFeatureList = null;
        String eeVersion = null;
        String mpVersion = null;
        try {
            List mavenProjects = new ArrayList();
            mavenProjects.addAll(upstreamProjects);
            mavenProjects.add(project);
            Set directories = getClassesDirectories(mavenProjects);
            if (directories.isEmpty() && (classFiles == null || classFiles.isEmpty())) {
                // log as warning and continue to call binary scanner to detect conflicts in
                // user specified features
                getLog().warn(NO_CLASSES_DIR_WARNING);
            }
            eeVersion = getEEVersion(mavenProjects);
            mpVersion = getMPVersion(mavenProjects);

            String logLocation = project.getBuild().getDirectory();
            String eeVersionArg = composeEEVersion(eeVersion);
            String mpVersionArg = composeMPVersion(mpVersion);
            scannedFeatureList = binaryScannerHandler.runBinaryScanner(nonCustomFeatures, classFiles, directories, logLocation, eeVersionArg, mpVersionArg, optimize);
        } catch (BinaryScannerUtil.NoRecommendationException noRecommendation) {
            throw new MojoExecutionException(String.format(BinaryScannerUtil.BINARY_SCANNER_CONFLICT_MESSAGE3, noRecommendation.getConflicts()));
        } catch (BinaryScannerUtil.FeatureModifiedException featuresModified) {
            Set userFeatures = (optimize) ? existingFeatures :
                getServerFeatures(servUtil, generatedFiles, true); // user features excludes generatedFiles
            Set modifiedSet = featuresModified.getFeatures(); // a set that works after being modified by the scanner
            if (modifiedSet.containsAll(userFeatures)) {
                // none of the user features were modified, only features which were generated earlier.
                getLog().debug(
                        "FeatureModifiedException, modifiedSet containsAll userFeatures, pass modifiedSet on to generateFeatures");
                // features were modified to get a working set with the application's API usage, display warning to users and use modified set
                getLog().warn(featuresModified.getMessage());
                scannedFeatureList = modifiedSet;
            } else {
                Set allAppFeatures = featuresModified.getSuggestions(); // suggestions are scanned from binaries
                allAppFeatures.addAll(userFeatures); // scanned plus configured features were detected to be in conflict
                getLog().debug("FeatureModifiedException, combine suggestions from scanner with user features in error msg");
                throw new MojoExecutionException(
                        String.format(BinaryScannerUtil.BINARY_SCANNER_CONFLICT_MESSAGE1, allAppFeatures, modifiedSet));

            }
        } catch (BinaryScannerUtil.RecommendationSetException showRecommendation) {
            if (showRecommendation.isExistingFeaturesConflict()) {
                throw new MojoExecutionException(String.format(BinaryScannerUtil.BINARY_SCANNER_CONFLICT_MESSAGE2, showRecommendation.getConflicts(), showRecommendation.getSuggestions()));
            } else {
                throw new MojoExecutionException(String.format(BinaryScannerUtil.BINARY_SCANNER_CONFLICT_MESSAGE1, showRecommendation.getConflicts(), showRecommendation.getSuggestions()));
            }
        } catch (BinaryScannerUtil.FeatureUnavailableException featureUnavailable) {
            throw new MojoExecutionException(String.format(BinaryScannerUtil.BINARY_SCANNER_CONFLICT_MESSAGE5, featureUnavailable.getConflicts(), featureUnavailable.getMPLevel(), featureUnavailable.getEELevel(), featureUnavailable.getUnavailableFeatures()));
        } catch (BinaryScannerUtil.IllegalTargetComboException illegalCombo) {
            throw new MojoExecutionException(String.format(BinaryScannerUtil.BINARY_SCANNER_INVALID_COMBO_MESSAGE, eeVersion, mpVersion));
        } catch (BinaryScannerUtil.IllegalTargetException illegalTargets) {
            String messages = buildInvalidArgExceptionMessage(illegalTargets.getEELevel(), illegalTargets.getMPLevel(), eeVersion, mpVersion);
            throw new MojoExecutionException(messages);
        } catch (PluginExecutionException x) {
            // throw an error when there is a problem not caught in runBinaryScanner()
            Object o = x.getCause();
            if (o != null) {
                getLog().debug("Caused by exception:" + x.getCause().getClass().getName());
                getLog().debug("Caused by exception message:" + x.getCause().getMessage());
            }
            throw new MojoExecutionException("Failed to generate a working set of features. " + x.getMessage(), x);
        }

        Set missingLibertyFeatures = new HashSet();
        if (scannedFeatureList != null) {
            missingLibertyFeatures.addAll(scannedFeatureList);

            servUtil.setLowerCaseFeatures(false);
            // get set of user defined features so they can be omitted from the generated
            // file that will be written
            Set userDefinedFeatures = optimize ? existingFeatures
                    : servUtil.getServerFeatures(configDirectory, serverXmlFile, new HashMap(),
                            generatedFiles);
            getLog().debug("User defined features:" + userDefinedFeatures);
            servUtil.setLowerCaseFeatures(true);
            if (userDefinedFeatures != null) {
                missingLibertyFeatures.removeAll(userDefinedFeatures);
            }
        }
        getLog().debug("Features detected by binary scanner which are not in server.xml" + missingLibertyFeatures);

        File newServerXmlSrc = new File(configDirectory, GENERATED_FEATURES_FILE_PATH);
        File serverXml = findConfigFile("server.xml", serverXmlFile);
        ServerConfigXmlDocument doc = getServerXmlDocFromConfig(serverXml);
        getLog().debug("Xml document we'll try to update after generate features doc=" + doc + " file=" + serverXml);

        try {
            if (missingLibertyFeatures.size() > 0) {
                Set existingGeneratedFeatures = getGeneratedFeatures(servUtil, newServerXmlSrc);
                if (!missingLibertyFeatures.equals(existingGeneratedFeatures)) {
                    // Create special XML file to contain generated features.
                    ServerConfigXmlDocument configDocument = ServerConfigXmlDocument.newInstance();
                    configDocument.createComment(HEADER);
                    Element featureManagerElem = configDocument.createFeatureManager();
                    configDocument.createComment(featureManagerElem, GENERATED_FEATURES_COMMENT);
                    for (String missing : missingLibertyFeatures) {
                        getLog().debug(String.format("Adding missing feature %s to %s.", missing, GENERATED_FEATURES_FILE_PATH));
                        configDocument.createFeature(missing);
                    }
                    // Generate log message before writing file as the file change event kicks off other dev mode actions
                    getLog().info("Generated the following features: " + missingLibertyFeatures);
                    configDocument.writeXMLDocument(newServerXmlSrc);
                    getLog().debug("Created file " + newServerXmlSrc);
                    // Add a reference to this new file in existing server.xml.
                    addGenerationCommentToConfig(doc, serverXml);
                } else {
                    getLog().info("Regenerated the following features: " + missingLibertyFeatures);
                }
            } else {
                getLog().info("No additional features were generated.");
                if (newServerXmlSrc.exists()) {
                    // generated-features.xml exists but no additional features were generated
                    // create empty features list with comment
                    ServerConfigXmlDocument configDocument = ServerConfigXmlDocument.newInstance();
                    configDocument.createComment(HEADER);
                    Element featureManagerElem = configDocument.createFeatureManager();
                    configDocument.createComment(featureManagerElem, NO_NEW_FEATURES_COMMENT);
                    configDocument.writeXMLDocument(newServerXmlSrc);
                }
            }
        } catch (ParserConfigurationException | TransformerException | IOException e) {
            getLog().debug("Exception creating the server features file", e);
                throw new MojoExecutionException(
                        "Automatic generation of features failed. Error attempting to create the "
                                + GENERATED_FEATURES_FILE_NAME
                                + ". Ensure your id has write permission to the server configuration directory.",
                        e);
        }
    }

    // Get the features from the server config and optionally exclude the specified config files from the search.
    private Set getServerFeatures(ServerFeatureUtil servUtil, Set generatedFiles, boolean excludeGenerated) {
        servUtil.setLowerCaseFeatures(false);
        // if optimizing, ignore generated files when passing in existing features to
        // binary scanner
        Set existingFeatures = servUtil.getServerFeatures(configDirectory, serverXmlFile,
                new HashMap(), excludeGenerated ? generatedFiles : null); // pass generatedFiles to exclude them
        if (existingFeatures == null) {
            existingFeatures = new HashSet();
        }
        servUtil.setLowerCaseFeatures(true);
        return existingFeatures;
    }

    // returns the features specified in the generated-features.xml file
    private Set getGeneratedFeatures(ServerFeatureUtil servUtil, File generatedFeaturesFile) {
        servUtil.setLowerCaseFeatures(false);
        Set genFeatSet = new HashSet();
        servUtil.getServerXmlFeatures(genFeatSet, configDirectory,
                generatedFeaturesFile, null, null);
        servUtil.setLowerCaseFeatures(true);
        return genFeatSet;
    }

    /**
     * Gets the binary scanner jar file from the local cache.
     * Downloads it first from connected repositories such as Maven Central if a newer release is available than the cached version.
     * Note: Maven updates artifacts daily by default based on the last updated timestamp. Users should use 'mvn -U' to force updates if needed.
     * 
     * @return The File object of the binary scanner jar in the local cache.
     * @throws PluginExecutionException
     */
    private File getBinaryScannerJarFromRepository() throws PluginExecutionException {
        try {
            return getArtifact(BINARY_SCANNER_MAVEN_GROUP_ID, BINARY_SCANNER_MAVEN_ARTIFACT_ID, BINARY_SCANNER_MAVEN_TYPE, BINARY_SCANNER_MAVEN_VERSION).getFile();
        } catch (Exception e) {
            throw new PluginExecutionException("Could not retrieve the artifact " + BINARY_SCANNER_MAVEN_GROUP_ID + "."
                    + BINARY_SCANNER_MAVEN_ARTIFACT_ID
                    + " needed for liberty:generate-features. Ensure you have a connection to Maven Central or another repository that contains the "
                    + BINARY_SCANNER_MAVEN_GROUP_ID + "." + BINARY_SCANNER_MAVEN_ARTIFACT_ID
                    + ".jar configured in your pom.xml.",
                    e);
        }
    }

    /*
     * Return specificFile if it exists; otherwise return the file with the requested fileName from the 
     * configDirectory, but only if it exists. Null is returned if the file does not exist in either location.
     */
    private File findConfigFile(String fileName, File specificFile) {
        if (specificFile != null && specificFile.exists()) {
            return specificFile;
        }

        File f = new File(configDirectory, fileName);
        if (configDirectory != null && f.exists()) {
            return f;
        }
        return null;
    }

    private ServerConfigXmlDocument getServerXmlDocFromConfig(File serverXml) {
        if (serverXml == null || !serverXml.exists()) {
            return null;
        }
        try {
            return ServerConfigXmlDocument.newInstance(serverXml);
        } catch (ParserConfigurationException | SAXException | IOException e) {
            getLog().debug("Exception creating server.xml object model", e);
        }
        return null;
    }

    /**
     * Remove the comment in server.xml that warns we created another file with features in it.
     */
    private void removeGenerationCommentFromConfig(ServerConfigXmlDocument doc, File serverXml) {
        if (doc == null) {
            return;
        }
        try {
            doc.removeFMComment(FEATURES_FILE_MESSAGE);
            doc.writeXMLDocument(serverXml);
        } catch (IOException | TransformerException e) {
            getLog().debug("Exception removing comment from server.xml", e);
        }
        return;
    }

    /**
     * Add a comment to server.xml to warn them we created another file with features in it.
     * Only writes the file if the comment does not exist yet.
     */
    private void addGenerationCommentToConfig(ServerConfigXmlDocument doc, File serverXml) {
        if (doc == null) {
            return;
        }
        try {
            if (doc.createFMComment(FEATURES_FILE_MESSAGE)) {
                doc.writeXMLDocument(serverXml);
                XmlDocument.addNewlineBeforeFirstElement(serverXml);
            }
        } catch (IOException | TransformerException e) {
            getLog().debug("Exception adding comment to server.xml", e);
        }
        return;
    }

    // Return a list containing the classes directory of the Maven projects (upstream projects and main project)
    private Set getClassesDirectories(List mavenProjects) throws MojoExecutionException {
        Set dirs = new HashSet();
        String classesDirName = null;
        getLog().debug("For binary scanner gathering Java build output directories for Maven projects, size="
                + mavenProjects.size());
        for (MavenProject mavenProject : mavenProjects) {
            classesDirName = getClassesDirectory(mavenProject.getBuild().getOutputDirectory());
            if (classesDirName != null) {
                dirs.add(classesDirName);
            }
        }
        for (String s : dirs) {
            getLog().debug("Found dir:" + s);
        }
        return dirs;
    }

    // Check one directory and if it exists return its canonical path (or absolute path if error).
    private String getClassesDirectory(String outputDir) {
        File classesDir = new File(outputDir);
        try {
            if (classesDir.exists()) {
                return classesDir.getCanonicalPath();
            }
        } catch (IOException x) {
            String classesDirAbsPath = classesDir.getAbsolutePath();
            getLog().debug("IOException obtaining canonical path name for a project's classes directory: " + classesDirAbsPath);
            return classesDirAbsPath;
        }
        return null; // directory does not exist.
    }

    /**
     * Returns the EE major version detected for the given MavenProjects
     * 
     * @param mavenProjects project modules, for single module projects list of size 1
     * @return the latest version of EE detected across multiple project modules,
     *         null if an EE version is not found or the version number is out of range
     */
    public String getEEVersion(List mavenProjects) {
        String eeVersion = null;
        if (mavenProjects != null) {
            Set eeVersionsDetected = new HashSet();
            for (MavenProject mavenProject : mavenProjects) {
                try {
                    String ver = getEEVersion(mavenProject);
                    getLog().debug("Java and/or Jakarta EE umbrella dependency found in project: " + mavenProject.getName());
                    if (ver != null) {
                        eeVersionsDetected.add(ver);
                    }
                } catch (NoUmbrellaDependencyException e) {
                    // umbrella dependency does not exist, do nothing
                }
            }
            if (!eeVersionsDetected.isEmpty()) {
                eeVersion = eeVersionsDetected.iterator().next();
                // if multiple EE versions are found across multiple modules, return the latest version
                for (String ver : eeVersionsDetected) {
                    if (ver.compareTo(eeVersion) > 0) {
                        eeVersion = ver;
                    }
                }
            }
            if (eeVersionsDetected.size() > 1) {
                getLog().debug(
                        "Multiple Java and/or Jakarta EE versions found across multiple project modules, using the latest version ("
                                + eeVersion + ") found to generate Liberty features.");
            }
        }
        return eeVersion;
    }

    /**
     * Returns the EE major version detected for the given MavenProject.
     * To match the Maven "nearest in the dependency tree" strategy, this method
     * will return the first EE umbrella dependency version detected.
     * 
     * @param project the MavenProject to search
     * @return EE major version corresponding to the EE umbrella dependency
     * @throws NoUmbrellaDependencyException indicates that the umbrella dependency was not found
     */
    private String getEEVersion(MavenProject project) throws NoUmbrellaDependencyException {
        if (project != null) {
            List dependencies = project.getDependencies();
            for (Dependency d : dependencies) {
                if (!d.getScope().equals("provided")) {
                    continue;
                }
                if ((d.getGroupId().equals("javax") && d.getArtifactId().equals("javaee-api")) ||
                    (d.getGroupId().equals("jakarta.platform") && d.getArtifactId().equals("jakarta.jakartaee-api"))) {
                    return d.getVersion();
                }
            }
        }
        throw new NoUmbrellaDependencyException();
    }

    /**
     * Returns the MicroProfile version detected for the given MavenProjects
     * 
     * @param mavenProjects project modules, for single module projects list of size 1
     * @return the latest version of MP detected across multiple project modules,
     *         null if an MP version is not found or the version number is out of range
     */
    public String getMPVersion(List mavenProjects) {
        String mpVersion = null;
        if (mavenProjects != null) {
            Set mpVersionsDetected = new HashSet();
            for (MavenProject mavenProject : mavenProjects) {
                try {
                    String ver = getMPVersion(mavenProject);
                    getLog().debug("MicroProfile umbrella dependency found in project: " + mavenProject.getName());
                    if (ver != null) {
                        mpVersionsDetected.add(ver);
                    }
                } catch (NoUmbrellaDependencyException e) {
                    // umbrella dependency does not exist, do nothing
                }
            }
            if (!mpVersionsDetected.isEmpty()) {
                mpVersion = mpVersionsDetected.iterator().next();
                // if multiple MP versions are found across multiple modules, return the latest version
                for (String ver : mpVersionsDetected) {
                    if (ver.compareTo(mpVersion) > 0) {
                        mpVersion = ver;
                    }
                }
            }
            if (mpVersionsDetected.size() > 1) {
                getLog().debug(
                        "Multiple MicroProfile versions found across multiple project modules, using the latest version ("
                                + mpVersion + ") found to generate Liberty features.");
            }
        }
        return mpVersion;
    }

    /**
     * Returns the MicroProfile (MP) version detected for the given MavenProject
     * To match the Maven "nearest in the dependency tree" strategy, this method
     * will return the first MP umbrella dependency version detected.
     * 
     * @param project the MavenProject to search
     * @return MP exact version code corresponding to the MP umbrella dependency
     * @throws NoUmbrellaDependencyException indicates that the umbrella dependency was not found
     */
    public String getMPVersion(MavenProject project) throws NoUmbrellaDependencyException { // figure out correct level of MP from declared dependencies
        if (project != null) {
            List dependencies = project.getDependencies();
            for (Dependency d : dependencies) {
                if (!d.getScope().equals("provided")) {
                    continue;
                }
                if (d.getGroupId().equals("org.eclipse.microprofile") &&
                        d.getArtifactId().equals("microprofile")) {
                    return d.getVersion();
                }
            }
        }
        throw new NoUmbrellaDependencyException();
    }

    // Define the logging functions of the binary scanner handler and make it available in this plugin
    private class BinaryScannerHandler extends BinaryScannerUtil {
        BinaryScannerHandler(File scannerFile) {
            super(scannerFile);
        }
        @Override
        public void debug(String msg) {
            getLog().debug(msg);
        }
        @Override
        public void debug(String msg, Throwable t) {
            getLog().debug(msg, t);
        }
        @Override
        public void error(String msg) {
            getLog().error(msg);
        }
        @Override
        public void warn(String msg) {
            getLog().warn(msg);
        }
        @Override
        public void info(String msg) {
            getLog().info(msg);
        }
        @Override
        public boolean isDebugEnabled() {
            return getLog().isDebugEnabled();
        }
    }

    // using the current MavenSession build the project (resolves dependencies)
    private MavenProject getMavenProject(File buildFile) throws ProjectBuildingException {
        ProjectBuildingResult build = mavenProjectBuilder.build(buildFile,
                session.getProjectBuildingRequest().setResolveDependencies(true));
        return build.getProject();
    }

    /**
     * Class to indicate that an umbrella dependency was not found in the build file
     */
    public class NoUmbrellaDependencyException extends Exception {
        private static final long serialVersionUID = 1L;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy