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.scanner;
020
021import javax.inject.Inject;
022import javax.inject.Named;
023
024import java.util.ArrayList;
025import java.util.Collections;
026import java.util.HashMap;
027import java.util.HashSet;
028import java.util.List;
029import java.util.Map;
030import java.util.Set;
031
032import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException;
033import org.apache.maven.plugin.descriptor.MojoDescriptor;
034import org.apache.maven.tools.plugin.PluginToolsRequest;
035import org.apache.maven.tools.plugin.extractor.ExtractionException;
036import org.apache.maven.tools.plugin.extractor.GroupKey;
037import org.apache.maven.tools.plugin.extractor.MojoDescriptorExtractor;
038import org.apache.maven.tools.plugin.extractor.MojoDescriptorExtractorComparator;
039import org.codehaus.plexus.logging.AbstractLogEnabled;
040import org.codehaus.plexus.logging.Logger;
041import org.codehaus.plexus.logging.console.ConsoleLogger;
042
043/**
044 * @author jdcasey
045 */
046@Named
047public class DefaultMojoScanner extends AbstractLogEnabled implements MojoScanner {
048
049    private Map<String, MojoDescriptorExtractor> mojoDescriptorExtractors;
050
051    /**
052     * The names of the active extractors
053     */
054    private Set<String> activeExtractors;
055
056    /**
057     * Default constructor
058     *
059     * @param extractors not null
060     */
061    @Inject
062    public DefaultMojoScanner(Map<String, MojoDescriptorExtractor> extractors) {
063        this.mojoDescriptorExtractors = extractors;
064
065        this.enableLogging(new ConsoleLogger(Logger.LEVEL_INFO, "standalone-scanner-logger"));
066    }
067
068    /**
069     * Empty constructor
070     */
071    public DefaultMojoScanner() {
072        // nop
073    }
074
075    /**
076     * {@inheritDoc}
077     */
078    @Override
079    public void populatePluginDescriptor(PluginToolsRequest request)
080            throws ExtractionException, InvalidPluginDescriptorException {
081        Logger logger = getLogger();
082
083        int numMojoDescriptors = 0;
084
085        List<MojoDescriptorExtractor> orderedExtractors = getOrderedExtractors();
086
087        logger.debug("Using " + orderedExtractors.size() + " mojo extractors.");
088
089        HashMap<String, Integer> groupStats = new HashMap<>();
090
091        for (MojoDescriptorExtractor extractor : orderedExtractors) {
092            GroupKey groupKey = extractor.getGroupKey();
093            String extractorId = extractor.getName();
094
095            logger.debug("Applying " + extractorId + " mojo extractor");
096
097            List<MojoDescriptor> extractorDescriptors = extractor.execute(request);
098
099            int extractorDescriptorsCount = extractorDescriptors.size();
100
101            logger.info(extractorId + " mojo extractor found " + extractorDescriptorsCount + " mojo descriptor"
102                    + (extractorDescriptorsCount > 1 ? "s" : "") + ".");
103            numMojoDescriptors += extractorDescriptorsCount;
104
105            if (extractor.isDeprecated() && extractorDescriptorsCount > 0) {
106                logger.warn("");
107                logger.warn("Deprecated extractor " + extractorId
108                        + " extracted " + extractorDescriptorsCount
109                        + " descriptor" + (extractorDescriptorsCount > 1 ? "s" : "")
110                        + ". Upgrade your Mojo definitions.");
111                if (GroupKey.JAVA_GROUP.equals(groupKey.getGroup())) {
112                    logger.warn("You should use Mojo Annotations instead of Javadoc tags.");
113                }
114                logger.warn("");
115            }
116
117            if (groupStats.containsKey(groupKey.getGroup())) {
118                groupStats.put(groupKey.getGroup(), groupStats.get(groupKey.getGroup()) + extractorDescriptorsCount);
119            } else {
120                groupStats.put(groupKey.getGroup(), extractorDescriptorsCount);
121            }
122
123            for (MojoDescriptor descriptor : extractorDescriptors) {
124                logger.debug("Adding mojo: " + descriptor + " to plugin descriptor.");
125
126                descriptor.setPluginDescriptor(request.getPluginDescriptor());
127
128                request.getPluginDescriptor().addMojo(descriptor);
129            }
130        }
131
132        logger.debug("Discovered descriptors by groups: " + groupStats);
133
134        if (numMojoDescriptors == 0 && !request.isSkipErrorNoDescriptorsFound()) {
135            throw new InvalidPluginDescriptorException("No mojo definitions were found for plugin: "
136                    + request.getPluginDescriptor().getPluginLookupKey() + ".");
137        }
138    }
139
140    /**
141     * Returns a list of extractors sorted by {@link MojoDescriptorExtractor#getGroupKey()}s, never {@code null}.
142     */
143    private List<MojoDescriptorExtractor> getOrderedExtractors() throws ExtractionException {
144        Set<String> extractors = activeExtractors;
145
146        if (extractors == null) {
147            extractors = new HashSet<>(mojoDescriptorExtractors.keySet());
148        }
149
150        ArrayList<MojoDescriptorExtractor> orderedExtractors = new ArrayList<>();
151        for (String extractorId : extractors) {
152            MojoDescriptorExtractor extractor = mojoDescriptorExtractors.get(extractorId);
153
154            if (extractor == null) {
155                throw new ExtractionException("No mojo extractor with '" + extractorId + "' id.");
156            }
157
158            orderedExtractors.add(extractor);
159        }
160
161        Collections.sort(orderedExtractors, MojoDescriptorExtractorComparator.INSTANCE);
162
163        return orderedExtractors;
164    }
165
166    @Override
167    public void setActiveExtractors(Set<String> extractors) {
168        if (extractors == null) {
169            this.activeExtractors = null;
170        } else {
171            this.activeExtractors = new HashSet<>();
172
173            for (String extractor : extractors) {
174                if (extractor != null && !extractor.isEmpty()) {
175                    this.activeExtractors.add(extractor);
176                }
177            }
178        }
179    }
180}