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.plugins.enforcer.internal;
020
021import javax.inject.Inject;
022import javax.inject.Named;
023import javax.inject.Provider;
024import javax.inject.Singleton;
025
026import java.util.ArrayList;
027import java.util.List;
028import java.util.Objects;
029import java.util.Optional;
030
031import org.apache.maven.enforcer.rule.api.EnforcerLevel;
032import org.apache.maven.enforcer.rule.api.EnforcerLogger;
033import org.apache.maven.enforcer.rule.api.EnforcerRuleBase;
034import org.apache.maven.execution.MavenSession;
035import org.apache.maven.plugin.MojoExecution;
036import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
037import org.apache.maven.plugin.logging.Log;
038import org.codehaus.plexus.PlexusContainer;
039import org.codehaus.plexus.classworlds.realm.ClassRealm;
040import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
041import org.codehaus.plexus.component.configurator.ComponentConfigurator;
042import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
043import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
044import org.codehaus.plexus.configuration.PlexusConfiguration;
045
046/**
047 * Manage enforcer rules.
048 *
049 * @author Slawomir Jaranowski
050 * @since 3.2.0
051 */
052@Named
053@Singleton
054public class EnforcerRuleManager {
055
056    private final Provider<MavenSession> sessionProvider;
057
058    private final Provider<MojoExecution> mojoExecutionProvider;
059
060    private final ComponentConfigurator componentConfigurator;
061
062    private final PlexusContainer plexusContainer;
063
064    @Inject
065    public EnforcerRuleManager(
066            Provider<MavenSession> sessionProvider,
067            Provider<MojoExecution> mojoExecutionProvider,
068            @Named("basic") ComponentConfigurator componentConfigurator,
069            PlexusContainer plexusContainer) {
070        this.sessionProvider = Objects.requireNonNull(sessionProvider, "sessionProvider must be not null");
071        this.mojoExecutionProvider =
072                Objects.requireNonNull(mojoExecutionProvider, "mojoExecutionProvider must be not null");
073        this.componentConfigurator =
074                Objects.requireNonNull(componentConfigurator, "componentConfigurator must be not null");
075        this.plexusContainer = Objects.requireNonNull(plexusContainer, "plexusContainer must be not null");
076    }
077
078    /**
079     * Create enforcer rules based on xml configuration.
080     *
081     * @param rules a rules configuration
082     * @param log   a Mojo logger
083     * @return List of rule instances
084     * @throws EnforcerRuleManagerException report a problem during rules creating
085     */
086    public List<EnforcerRuleDesc> createRules(PlexusConfiguration rules, Log log) throws EnforcerRuleManagerException {
087
088        List<EnforcerRuleDesc> result = new ArrayList<>();
089
090        if (rules == null || rules.getChildCount() == 0) {
091            return result;
092        }
093
094        ClassRealm classRealm = mojoExecutionProvider
095                .get()
096                .getMojoDescriptor()
097                .getPluginDescriptor()
098                .getClassRealm();
099
100        ExpressionEvaluator evaluator =
101                new PluginParameterExpressionEvaluator(sessionProvider.get(), mojoExecutionProvider.get());
102
103        EnforcerLogger enforcerLoggerError = new EnforcerLoggerError(log);
104        EnforcerLogger enforcerLoggerWarn = new EnforcerLoggerWarn(log);
105
106        for (PlexusConfiguration ruleConfig : rules.getChildren()) {
107            // we need rule level before configuration in order to proper set logger
108            EnforcerLevel ruleLevel = getRuleLevelFromConfig(ruleConfig);
109
110            EnforcerRuleDesc ruleDesc = createRuleDesc(ruleConfig.getName(), ruleConfig.getAttribute("implementation"));
111            // setup logger before rule configuration
112            ruleDesc.getRule().setLog(ruleLevel == EnforcerLevel.ERROR ? enforcerLoggerError : enforcerLoggerWarn);
113            if (ruleConfig.getChildCount() > 0) {
114                try {
115                    componentConfigurator.configureComponent(ruleDesc.getRule(), ruleConfig, evaluator, classRealm);
116                } catch (ComponentConfigurationException e) {
117                    throw new EnforcerRuleManagerException(e);
118                }
119            }
120            result.add(ruleDesc);
121        }
122        return result;
123    }
124
125    private EnforcerLevel getRuleLevelFromConfig(PlexusConfiguration ruleConfig) {
126        PlexusConfiguration levelConfig = ruleConfig.getChild("level", false);
127        String level = Optional.ofNullable(levelConfig)
128                .map(PlexusConfiguration::getValue)
129                .orElse(EnforcerLevel.ERROR.name());
130        return EnforcerLevel.valueOf(level);
131    }
132
133    private EnforcerRuleDesc createRuleDesc(String name, String implementation) throws EnforcerRuleManagerException {
134
135        // component name should always start at lowercase character
136        String ruleName = Character.toLowerCase(name.charAt(0)) + name.substring(1);
137
138        if (plexusContainer.hasComponent(EnforcerRuleBase.class, ruleName)) {
139            try {
140                return new EnforcerRuleDesc(ruleName, plexusContainer.lookup(EnforcerRuleBase.class, ruleName));
141            } catch (ComponentLookupException e) {
142                throw new EnforcerRuleManagerException(e);
143            }
144        }
145
146        String ruleClass;
147        if (implementation != null && !implementation.isEmpty()) {
148            ruleClass = implementation;
149        } else {
150            ruleClass = name;
151        }
152
153        if (!ruleClass.contains(".")) {
154            ruleClass = "org.apache.maven.plugins.enforcer." + Character.toUpperCase(ruleClass.charAt(0))
155                    + ruleClass.substring(1);
156        }
157
158        try {
159            return new EnforcerRuleDesc(
160                    ruleName, (EnforcerRuleBase) Class.forName(ruleClass).newInstance());
161        } catch (Exception e) {
162            throw new EnforcerRuleManagerException(
163                    "Failed to create enforcer rules with name: " + ruleName + " or for class: " + ruleClass, e);
164        }
165    }
166}