View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.enforcer.internal;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Provider;
24  import javax.inject.Singleton;
25  
26  import java.util.ArrayList;
27  import java.util.List;
28  import java.util.Objects;
29  import java.util.Optional;
30  
31  import org.apache.maven.enforcer.rule.api.EnforcerLevel;
32  import org.apache.maven.enforcer.rule.api.EnforcerLogger;
33  import org.apache.maven.enforcer.rule.api.EnforcerRuleBase;
34  import org.apache.maven.execution.MavenSession;
35  import org.apache.maven.plugin.MojoExecution;
36  import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
37  import org.apache.maven.plugin.logging.Log;
38  import org.codehaus.plexus.PlexusContainer;
39  import org.codehaus.plexus.classworlds.realm.ClassRealm;
40  import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
41  import org.codehaus.plexus.component.configurator.ComponentConfigurator;
42  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
43  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
44  import org.codehaus.plexus.configuration.PlexusConfiguration;
45  
46  /**
47   * Manage enforcer rules.
48   *
49   * @author Slawomir Jaranowski
50   * @since 3.2.0
51   */
52  @Named
53  @Singleton
54  public class EnforcerRuleManager {
55  
56      private final Provider<MavenSession> sessionProvider;
57  
58      private final Provider<MojoExecution> mojoExecutionProvider;
59  
60      private final ComponentConfigurator componentConfigurator;
61  
62      private final PlexusContainer plexusContainer;
63  
64      @Inject
65      public EnforcerRuleManager(
66              Provider<MavenSession> sessionProvider,
67              Provider<MojoExecution> mojoExecutionProvider,
68              @Named("basic") ComponentConfigurator componentConfigurator,
69              PlexusContainer plexusContainer) {
70          this.sessionProvider = Objects.requireNonNull(sessionProvider, "sessionProvider must be not null");
71          this.mojoExecutionProvider =
72                  Objects.requireNonNull(mojoExecutionProvider, "mojoExecutionProvider must be not null");
73          this.componentConfigurator =
74                  Objects.requireNonNull(componentConfigurator, "componentConfigurator must be not null");
75          this.plexusContainer = Objects.requireNonNull(plexusContainer, "plexusContainer must be not null");
76      }
77  
78      /**
79       * Create enforcer rules based on xml configuration.
80       *
81       * @param rules a rules configuration
82       * @param log   a Mojo logger
83       * @return List of rule instances
84       * @throws EnforcerRuleManagerException report a problem during rules creating
85       */
86      public List<EnforcerRuleDesc> createRules(PlexusConfiguration rules, Log log) throws EnforcerRuleManagerException {
87  
88          List<EnforcerRuleDesc> result = new ArrayList<>();
89  
90          if (rules == null || rules.getChildCount() == 0) {
91              return result;
92          }
93  
94          ClassRealm classRealm = mojoExecutionProvider
95                  .get()
96                  .getMojoDescriptor()
97                  .getPluginDescriptor()
98                  .getClassRealm();
99  
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 }