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.tools.plugin.util;
020
021import java.io.File;
022import java.net.MalformedURLException;
023import java.net.URL;
024import java.net.URLClassLoader;
025import java.util.ArrayList;
026import java.util.Collections;
027import java.util.Comparator;
028import java.util.HashMap;
029import java.util.List;
030import java.util.Map;
031
032import org.apache.maven.artifact.DependencyResolutionRequiredException;
033import org.apache.maven.plugin.descriptor.MojoDescriptor;
034import org.apache.maven.plugin.descriptor.Parameter;
035import org.apache.maven.project.MavenProject;
036import org.apache.maven.reporting.MavenReport;
037import org.codehaus.plexus.util.DirectoryScanner;
038import org.codehaus.plexus.util.FileUtils;
039import org.codehaus.plexus.util.StringUtils;
040
041/**
042 * Convenience methods to play with Maven plugins.
043 *
044 * @author jdcasey
045 *
046 */
047public final class PluginUtils {
048    private PluginUtils() {
049        // nop
050    }
051
052    /**
053     * Expression associated with class types to recognize Maven objects (injected in fact as parameters by <a
054     * href="/ref/current/maven-core/apidocs/org/apache/maven/plugin/PluginParameterExpressionEvaluator.html">
055     * maven-core's PluginParameterExpressionEvaluator</a>) like components ("real" components are injected by Plexus).
056     *
057     * @deprecated wrong approach (fake components), documented parameter default values instead to learn people how to
058     *             discover them
059     */
060    @Deprecated
061    public static final Map<String, String> MAVEN_COMPONENTS;
062
063    static {
064        Map<String, String> mavenComponents = new HashMap<>();
065
066        mavenComponents.put("org.apache.maven.execution.MavenSession", "${session}");
067        mavenComponents.put("org.apache.maven.project.MavenProject", "${project}");
068        mavenComponents.put("org.apache.maven.plugin.MojoExecution", "${mojoExecution}");
069        mavenComponents.put("org.apache.maven.plugin.descriptor.PluginDescriptor", "${plugin}");
070        mavenComponents.put("org.apache.maven.settings.Settings", "${settings}");
071
072        mavenComponents.put("org.apache.maven.api.Session", "${session}");
073        mavenComponents.put("org.apache.maven.api.Project", "${project}");
074        mavenComponents.put("org.apache.maven.api.MojoExecution", "${mojoExecution}");
075        // TODO: apiv4: add PluginDescriptor to the api ?
076        // mavenComponents.put( "org.apache.maven.api.descriptor.PluginDescriptor", "${plugin}" );
077        mavenComponents.put("org.apache.maven.api.settings.Settings", "${settings}");
078
079        MAVEN_COMPONENTS = Collections.unmodifiableMap(mavenComponents);
080    }
081
082    /**
083     * @param basedir not null
084     * @param include not null
085     * @return list of included files with default SCM excluded files
086     */
087    public static String[] findSources(String basedir, String include) {
088        return PluginUtils.findSources(basedir, include, null);
089    }
090
091    /**
092     * @param basedir not null
093     * @param include not null
094     * @param exclude could be null
095     * @return list of included files
096     */
097    public static String[] findSources(String basedir, String include, String exclude) {
098        DirectoryScanner scanner = new DirectoryScanner();
099        scanner.setBasedir(basedir);
100        scanner.setIncludes(new String[] {include});
101        if (!(exclude == null || exclude.isEmpty())) {
102            scanner.setExcludes(new String[] {exclude, StringUtils.join(FileUtils.getDefaultExcludes(), ",")});
103        } else {
104            scanner.setExcludes(FileUtils.getDefaultExcludes());
105        }
106
107        scanner.scan();
108
109        return scanner.getIncludedFiles();
110    }
111
112    /**
113     * Sorts the specified mojo descriptors by goal name.
114     *
115     * @param mojoDescriptors The mojo descriptors to sort, may be <code>null</code>.
116     * @see MojoDescriptor#getGoal()
117     */
118    public static void sortMojos(List<MojoDescriptor> mojoDescriptors) {
119        if (mojoDescriptors != null) {
120            Collections.sort(mojoDescriptors, new Comparator<MojoDescriptor>() {
121                /** {@inheritDoc} */
122                @Override
123                public int compare(MojoDescriptor mojo0, MojoDescriptor mojo1) {
124                    return mojo0.getGoal().compareToIgnoreCase(mojo1.getGoal());
125                }
126            });
127        }
128    }
129
130    /**
131     * Sorts the specified mojo parameters by name.
132     *
133     * @param parameters The mojo parameters to sort, may be <code>null</code>.
134     * @see Parameter#getName()
135     * @since 2.4.4
136     */
137    public static void sortMojoParameters(List<Parameter> parameters) {
138        if (parameters != null) {
139            Collections.sort(parameters, new Comparator<Parameter>() {
140                /** {@inheritDoc} */
141                @Override
142                public int compare(Parameter parameter1, Parameter parameter2) {
143                    return parameter1.getName().compareToIgnoreCase(parameter2.getName());
144                }
145            });
146        }
147    }
148
149    /**
150     * @param mojoClassName a fully qualified Mojo implementation class name, not null
151     * @param project a MavenProject instance, could be null
152     * @return <code>true</code> if the Mojo class implements <code>MavenReport</code>,
153     * <code>false</code> otherwise.
154     * @throws IllegalArgumentException if any
155     * @since 3.10.0
156     */
157    public static boolean isMavenReport(String mojoClassName, MavenProject project) throws IllegalArgumentException {
158        if (mojoClassName == null) {
159            throw new IllegalArgumentException("mojo implementation should be declared");
160        }
161
162        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
163        if (project != null) {
164            List<String> classPathStrings;
165            try {
166                classPathStrings = project.getCompileClasspathElements();
167                if (project.getExecutionProject() != null) {
168                    classPathStrings.addAll(project.getExecutionProject().getCompileClasspathElements());
169                }
170            } catch (DependencyResolutionRequiredException e) {
171                throw new IllegalArgumentException(e);
172            }
173
174            List<URL> urls = new ArrayList<>(classPathStrings.size());
175            for (String classPathString : classPathStrings) {
176                try {
177                    urls.add(new File(classPathString).toURL());
178                } catch (MalformedURLException e) {
179                    throw new IllegalArgumentException(e);
180                }
181            }
182
183            classLoader = new URLClassLoader(urls.toArray(new URL[urls.size()]), classLoader);
184        }
185
186        try {
187            Class<?> clazz = Class.forName(mojoClassName, false, classLoader);
188
189            return MavenReport.class.isAssignableFrom(clazz);
190        } catch (ClassNotFoundException e) {
191            return false;
192        }
193    }
194}