001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.maven.plugin.plugin.report;
020
021import java.util.Arrays;
022import java.util.Map;
023import java.util.Objects;
024import java.util.Optional;
025
026import org.apache.commons.lang3.StringUtils;
027import org.apache.maven.model.Plugin;
028import org.apache.maven.model.Prerequisites;
029import org.apache.maven.plugin.descriptor.PluginDescriptor;
030import org.apache.maven.project.MavenProject;
031import org.apache.maven.tools.plugin.ExtendedPluginDescriptor;
032import org.codehaus.plexus.util.xml.Xpp3Dom;
033
034/**
035 * Plugin requirements history.
036 *
037 * @author Slawomir Jaranowski
038 */
039public class RequirementsHistory {
040    /**
041     * The plugin version.
042     */
043    private String version;
044
045    /**
046     * The minimum version of Maven to run this plugin.
047     */
048    private String maven;
049
050    /**
051     * The minimum version of the JDK to run this plugin.
052     */
053    private String jdk;
054
055    public String getVersion() {
056        return version;
057    }
058
059    public String getMaven() {
060        return maven;
061    }
062
063    public String getJdk() {
064        return jdk;
065    }
066
067    @Override
068    public String toString() {
069        final StringBuilder sb = new StringBuilder("RequirementsHistory{");
070        sb.append("version='").append(version).append('\'');
071        sb.append(", maven='").append(maven).append('\'');
072        sb.append(", jdk='").append(jdk).append('\'');
073        sb.append('}');
074        return sb.toString();
075    }
076
077    public static RequirementsHistory discoverRequirements(MavenProject project) {
078        RequirementsHistory req = new RequirementsHistory();
079        req.version = project.getVersion();
080        req.jdk = discoverJdkRequirement(project, null);
081        req.maven = discoverMavenRequirement(project, null);
082        return req;
083    }
084    /**
085     * Tries to determine the Maven requirement from either the plugin descriptor or (if not set) from the
086     * Maven prerequisites element in the POM.
087     *
088     * @param project      not null
089     * @param pluginDescriptor the plugin descriptor (can be null)
090     * @return the Maven version or null if not specified
091     */
092    public static String discoverMavenRequirement(MavenProject project, PluginDescriptor pluginDescriptor) {
093        if (pluginDescriptor != null && StringUtils.isNotBlank(pluginDescriptor.getRequiredMavenVersion())) {
094            return pluginDescriptor.getRequiredMavenVersion();
095        }
096        return Optional.ofNullable(project.getPrerequisites())
097                .map(Prerequisites::getMaven)
098                .orElse(null);
099    }
100
101    /**
102     * Tries to determine the JDK requirement from the following sources (until one is found)
103     * <ol>
104     * <li>use JDK requirement from plugin descriptor</li>
105     * <li>use {@code release} configuration of {@code org.apache.maven.plugins:maven-compiler-plugin}</li>
106     * <li>use {@code maven.compiler.release<} property</li>
107     * <li>use {@code target} configuration of {@code org.apache.maven.plugins:maven-compiler-plugin}</li>
108     * <li>use {@code maven.compiler.target} property</li>
109     * </ol>
110     *
111     * @param project      not null
112     * @param pluginDescriptor the plugin descriptor (can be null)
113     * @return the JDK version
114     */
115    public static String discoverJdkRequirement(MavenProject project, PluginDescriptor pluginDescriptor) {
116        String jdk = null;
117        if (pluginDescriptor instanceof ExtendedPluginDescriptor) {
118            ExtendedPluginDescriptor extPluginDescriptor = (ExtendedPluginDescriptor) pluginDescriptor;
119            jdk = extPluginDescriptor.getRequiredJavaVersion();
120        }
121        if (jdk != null) {
122            return jdk;
123        }
124        Plugin compiler = getCompilerPlugin(project.getBuild().getPluginsAsMap());
125        if (compiler == null) {
126            compiler = getCompilerPlugin(project.getPluginManagement().getPluginsAsMap());
127        }
128
129        jdk = getPluginParameter(compiler, "release");
130        if (jdk == null) {
131            jdk = project.getProperties().getProperty("maven.compiler.release");
132        }
133
134        if (jdk == null) {
135            jdk = getPluginParameter(compiler, "target");
136        }
137
138        if (jdk == null) {
139            // default value
140            jdk = project.getProperties().getProperty("maven.compiler.target");
141        }
142
143        if (jdk == null) {
144            String version = (compiler == null) ? null : compiler.getVersion();
145
146            if (version != null) {
147                return "Default target for maven-compiler-plugin version " + version;
148            }
149        } else {
150            if (Arrays.asList("1.5", "1.6", "1.7", "1.8").contains(jdk)) {
151                jdk = jdk.substring(2);
152            }
153        }
154
155        return jdk;
156    }
157
158    private static Plugin getCompilerPlugin(Map<String, Plugin> pluginsAsMap) {
159        return pluginsAsMap.get("org.apache.maven.plugins:maven-compiler-plugin");
160    }
161
162    private static String getPluginParameter(Plugin plugin, String parameter) {
163        if (plugin != null) {
164            Xpp3Dom pluginConf = (Xpp3Dom) plugin.getConfiguration();
165
166            if (pluginConf != null) {
167                Xpp3Dom target = pluginConf.getChild(parameter);
168
169                if (target != null) {
170                    return target.getValue();
171                }
172            }
173        }
174
175        return null;
176    }
177
178    public boolean hasSameRequirements(RequirementsHistory other) {
179        return Objects.equals(this.maven, other.getMaven()) && Objects.equals(this.jdk, other.getJdk());
180    }
181}