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.PluginContainer;
029import org.apache.maven.model.Prerequisites;
030import org.apache.maven.plugin.descriptor.PluginDescriptor;
031import org.apache.maven.project.MavenProject;
032import org.apache.maven.tools.plugin.ExtendedPluginDescriptor;
033import org.codehaus.plexus.util.xml.Xpp3Dom;
034
035/**
036 * Plugin requirements history.
037 *
038 * @author Slawomir Jaranowski
039 */
040public class RequirementsHistory {
041    /**
042     * The plugin version.
043     */
044    private String version;
045
046    /**
047     * The minimum version of Maven to run this plugin.
048     */
049    private String maven;
050
051    /**
052     * The minimum version of the JDK to run this plugin.
053     */
054    private String jdk;
055
056    public String getVersion() {
057        return version;
058    }
059
060    public String getMaven() {
061        return maven;
062    }
063
064    public String getJdk() {
065        return jdk;
066    }
067
068    @Override
069    public String toString() {
070        final StringBuilder sb = new StringBuilder("RequirementsHistory{");
071        sb.append("version='").append(version).append('\'');
072        sb.append(", maven='").append(maven).append('\'');
073        sb.append(", jdk='").append(jdk).append('\'');
074        sb.append('}');
075        return sb.toString();
076    }
077
078    public static RequirementsHistory discoverRequirements(MavenProject project) {
079        RequirementsHistory req = new RequirementsHistory();
080        req.version = project.getVersion();
081        req.jdk = discoverJdkRequirement(project, null);
082        req.maven = discoverMavenRequirement(project, null);
083        return req;
084    }
085    /**
086     * Tries to determine the Maven requirement from either the plugin descriptor or (if not set) from the
087     * Maven prerequisites element in the POM.
088     *
089     * @param project      not null
090     * @param pluginDescriptor the plugin descriptor (can be null)
091     * @return the Maven version or null if not specified
092     */
093    public static String discoverMavenRequirement(MavenProject project, PluginDescriptor pluginDescriptor) {
094        if (pluginDescriptor != null && StringUtils.isNotBlank(pluginDescriptor.getRequiredMavenVersion())) {
095            return pluginDescriptor.getRequiredMavenVersion();
096        }
097        return Optional.ofNullable(project.getPrerequisites())
098                .map(Prerequisites::getMaven)
099                .orElse(null);
100    }
101
102    /**
103     * Tries to determine the JDK requirement from the following sources (until one is found)
104     * <ol>
105     * <li>use JDK requirement from plugin descriptor</li>
106     * <li>use {@code release} configuration of {@code org.apache.maven.plugins:maven-compiler-plugin}</li>
107     * <li>use {@code maven.compiler.release<} property</li>
108     * <li>use {@code target} configuration of {@code org.apache.maven.plugins:maven-compiler-plugin}</li>
109     * <li>use {@code maven.compiler.target} property</li>
110     * </ol>
111     *
112     * @param project      not null
113     * @param pluginDescriptor the plugin descriptor (can be null)
114     * @return the JDK version
115     */
116    public static String discoverJdkRequirement(MavenProject project, PluginDescriptor pluginDescriptor) {
117        String jdk = null;
118        if (pluginDescriptor instanceof ExtendedPluginDescriptor) {
119            ExtendedPluginDescriptor extPluginDescriptor = (ExtendedPluginDescriptor) pluginDescriptor;
120            jdk = extPluginDescriptor.getRequiredJavaVersion();
121        }
122        if (jdk != null) {
123            return jdk;
124        }
125        Plugin compiler = getCompilerPlugin(project.getBuild());
126        if (compiler == null) {
127            compiler = getCompilerPlugin(project.getPluginManagement());
128        }
129
130        jdk = getPluginParameter(compiler, "release");
131        if (jdk == null) {
132            jdk = project.getProperties().getProperty("maven.compiler.release");
133        }
134
135        if (jdk == null) {
136            jdk = getPluginParameter(compiler, "target");
137        }
138
139        if (jdk == null) {
140            // default value
141            jdk = project.getProperties().getProperty("maven.compiler.target");
142        }
143
144        if (jdk == null) {
145            String version = (compiler == null) ? null : compiler.getVersion();
146
147            if (version != null) {
148                return "Default target for maven-compiler-plugin version " + version;
149            }
150        } else {
151            if (Arrays.asList("1.5", "1.6", "1.7", "1.8").contains(jdk)) {
152                jdk = jdk.substring(2);
153            }
154        }
155
156        return jdk;
157    }
158
159    private static Plugin getCompilerPlugin(PluginContainer container) {
160        if (container != null) {
161            Map<String, Plugin> pluginsAsMap = container.getPluginsAsMap();
162            return pluginsAsMap.get("org.apache.maven.plugins:maven-compiler-plugin");
163        }
164        return null;
165    }
166
167    private static String getPluginParameter(Plugin plugin, String parameter) {
168        if (plugin != null) {
169            Xpp3Dom pluginConf = (Xpp3Dom) plugin.getConfiguration();
170
171            if (pluginConf != null) {
172                Xpp3Dom target = pluginConf.getChild(parameter);
173
174                if (target != null) {
175                    return target.getValue();
176                }
177            }
178        }
179
180        return null;
181    }
182
183    public boolean hasSameRequirements(RequirementsHistory other) {
184        return Objects.equals(this.maven, other.getMaven()) && Objects.equals(this.jdk, other.getJdk());
185    }
186}