001package org.apache.maven.plugin.plugin;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.maven.artifact.Artifact;
023import org.apache.maven.artifact.repository.ArtifactRepository;
024import org.apache.maven.plugin.AbstractMojo;
025import org.apache.maven.plugin.MojoExecutionException;
026import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException;
027import org.apache.maven.plugin.descriptor.PluginDescriptor;
028import org.apache.maven.plugins.annotations.Component;
029import org.apache.maven.plugins.annotations.Parameter;
030import org.apache.maven.project.MavenProject;
031import org.apache.maven.tools.plugin.DefaultPluginToolsRequest;
032import org.apache.maven.tools.plugin.PluginToolsRequest;
033import org.apache.maven.tools.plugin.extractor.ExtractionException;
034import org.apache.maven.tools.plugin.generator.Generator;
035import org.apache.maven.tools.plugin.generator.GeneratorException;
036import org.apache.maven.tools.plugin.generator.GeneratorUtils;
037import org.apache.maven.tools.plugin.scanner.MojoScanner;
038import org.codehaus.plexus.component.repository.ComponentDependency;
039import org.codehaus.plexus.util.ReaderFactory;
040
041import java.io.File;
042import java.util.Arrays;
043import java.util.List;
044import java.util.Set;
045
046/**
047 * Abstract class for this Plugin.
048 *
049 * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
050 * @version $Id: AbstractGeneratorMojo.html 934269 2014-12-28 23:25:17Z hboutemy $
051 */
052public abstract class AbstractGeneratorMojo
053    extends AbstractMojo
054{
055    /**
056     * The project currently being built.
057     */
058    @Parameter( defaultValue = "${project}", readonly = true )
059    protected MavenProject project;
060
061    /**
062     * The component used for scanning the source tree for mojos.
063     */
064    @Component
065    protected MojoScanner mojoScanner;
066
067    /**
068     * The file encoding of the source files.
069     *
070     * @since 2.5
071     */
072    @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
073    protected String encoding;
074
075    /**
076     * The goal prefix that will appear before the ":".
077     */
078    @Parameter
079    protected String goalPrefix;
080
081    /**
082     * By default an exception is throw if no mojo descriptor is found. As the maven-plugin is defined in core, the
083     * descriptor generator mojo is bound to generate-resources phase.
084     * But for annotations, the compiled classes are needed, so skip error
085     *
086     * @since 3.0
087     */
088    @Parameter( property = "maven.plugin.skipErrorNoDescriptorsFound", defaultValue = "false" )
089    protected boolean skipErrorNoDescriptorsFound;
090
091    /**
092     * The role names of mojo extractors to use.
093     * <p/>
094     * If not set, all mojo extractors will be used. If set to an empty extractor name, no mojo extractors
095     * will be used.
096     * <p/>
097     * Example:
098     * <p/>
099     * <pre>
100     *  &lt;!-- Use all mojo extractors --&gt;
101     *  &lt;extractors/&gt;
102     *
103     *  &lt;!-- Use no mojo extractors --&gt;
104     *  &lt;extractors&gt;
105     *      &lt;extractor/&gt;
106     *  &lt;/extractors&gt;
107     *
108     *  &lt;!-- Use only bsh mojo extractor --&gt;
109     *  &lt;extractors&gt;
110     *      &lt;extractor&gt;bsh&lt;/extractor&gt;
111     *  &lt;/extractors&gt;
112     * </pre>
113     */
114    @Parameter
115    protected Set<String> extractors;
116
117    /**
118     * Set this to "true" to skip invoking any goals or reports of the plugin.
119     *
120     * @since 2.8
121     */
122    @Parameter( defaultValue = "false", property = "maven.plugin.skip" )
123    protected boolean skip;
124
125    /**
126     * The set of dependencies for the current project
127     *
128     * @since 3.0
129     */
130    @Parameter( defaultValue = "${project.artifacts}", required = true, readonly = true )
131    protected Set<Artifact> dependencies;
132
133    /**
134     * List of Remote Repositories used by the resolver
135     *
136     * @since 3.0
137     */
138    @Parameter( defaultValue = "${project.remoteArtifactRepositories}", required = true, readonly = true )
139    protected List<ArtifactRepository> remoteRepos;
140
141    /**
142     * Location of the local repository.
143     *
144     * @since 3.0
145     */
146    @Parameter( defaultValue = "${localRepository}", required = true, readonly = true )
147    protected ArtifactRepository local;
148
149    /**
150     * Maven plugin packaging types. Default is single "maven-plugin".
151     * 
152     * @since 3.3
153     */
154    @Parameter
155    protected List<String> packagingTypes = Arrays.asList( "maven-plugin" );
156
157    /**
158     * @return the output directory where files will be generated.
159     */
160    protected abstract File getOutputDirectory();
161
162    /**
163     * @return the wanted <code>Generator</code> implementation.
164     */
165    protected abstract Generator createGenerator();
166
167    /**
168     * {@inheritDoc}
169     */
170    public void execute()
171        throws MojoExecutionException
172    {
173        if ( !packagingTypes.contains( project.getPackaging() ) )
174        {
175            getLog().warn( "Unsupported packaging type " + project.getPackaging() + ", execution skipped" );
176            return;
177        }
178        if ( skip )
179        {
180            getLog().warn( "Execution skipped" );
181            return;
182        }
183
184        if ( project.getArtifactId().toLowerCase().startsWith( "maven-" )
185            && project.getArtifactId().toLowerCase().endsWith( "-plugin" ) && !"org.apache.maven.plugins".equals(
186            project.getGroupId() ) )
187        {
188            getLog().error( "\n\nArtifact Ids of the format maven-___-plugin are reserved for \n"
189                                + "plugins in the Group Id org.apache.maven.plugins\n"
190                                + "Please change your artifactId to the format ___-maven-plugin\n"
191                                + "In the future this error will break the build.\n\n" );
192        }
193
194        String defaultGoalPrefix = PluginDescriptor.getGoalPrefixFromArtifactId( project.getArtifactId() );
195        if ( goalPrefix == null )
196        {
197            goalPrefix = defaultGoalPrefix;
198        }
199        else if ( !goalPrefix.equals( defaultGoalPrefix ) )
200        {
201            getLog().warn(
202                "\n\nGoal prefix is specified as: '" + goalPrefix + "'. " + "Maven currently expects it to be '"
203                    + defaultGoalPrefix + "'.\n" );
204        }
205
206        mojoScanner.setActiveExtractors( extractors );
207
208        // TODO: could use this more, eg in the writing of the plugin descriptor!
209        PluginDescriptor pluginDescriptor = new PluginDescriptor();
210
211        pluginDescriptor.setGroupId( project.getGroupId() );
212
213        pluginDescriptor.setArtifactId( project.getArtifactId() );
214
215        pluginDescriptor.setVersion( project.getVersion() );
216
217        pluginDescriptor.setGoalPrefix( goalPrefix );
218
219        pluginDescriptor.setName( project.getName() );
220
221        pluginDescriptor.setDescription( project.getDescription() );
222
223        if ( encoding == null || encoding.length() < 1 )
224        {
225            getLog().warn( "Using platform encoding (" + ReaderFactory.FILE_ENCODING
226                               + " actually) to read mojo metadata, i.e. build is platform dependent!" );
227        }
228        else
229        {
230            getLog().info( "Using '" + encoding + "' encoding to read mojo metadata." );
231        }
232
233        try
234        {
235            List<ComponentDependency> deps = GeneratorUtils.toComponentDependencies( project.getRuntimeDependencies() );
236            pluginDescriptor.setDependencies( deps );
237
238            PluginToolsRequest request = new DefaultPluginToolsRequest( project, pluginDescriptor );
239            request.setEncoding( encoding );
240            request.setSkipErrorNoDescriptorsFound( skipErrorNoDescriptorsFound );
241            request.setDependencies( dependencies );
242            request.setLocal( this.local );
243            request.setRemoteRepos( this.remoteRepos );
244
245            mojoScanner.populatePluginDescriptor( request );
246
247            getOutputDirectory().mkdirs();
248
249            createGenerator().execute( getOutputDirectory(), request );
250        }
251        catch ( GeneratorException e )
252        {
253            throw new MojoExecutionException( "Error writing plugin descriptor", e );
254        }
255        catch ( InvalidPluginDescriptorException e )
256        {
257            throw new MojoExecutionException( "Error extracting plugin descriptor: \'" + e.getLocalizedMessage() + "\'",
258                                              e );
259        }
260        catch ( ExtractionException e )
261        {
262            throw new MojoExecutionException( "Error extracting plugin descriptor: \'" + e.getLocalizedMessage() + "\'",
263                                              e );
264        }
265        catch ( LinkageError e )
266        {
267            throw new MojoExecutionException( "The API of the mojo scanner is not compatible with this plugin version."
268                + " Please check the plugin dependencies configured in the POM and ensure the versions match.", e );
269        }
270    }
271
272}