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