You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sj...@apache.org on 2023/01/04 23:01:34 UTC

[maven-enforcer] branch master updated: [MENFORCER-455] New Enforcer API

This is an automated email from the ASF dual-hosted git repository.

sjaranowski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-enforcer.git


The following commit(s) were added to refs/heads/master by this push:
     new ec44333  [MENFORCER-455] New Enforcer API
ec44333 is described below

commit ec443334dc2711a723e7b4f4aae3def3df593a4b
Author: Slawomir Jaranowski <s....@gmail.com>
AuthorDate: Sun Jan 1 16:30:15 2023 +0100

    [MENFORCER-455] New Enforcer API
    
    - New API based on JSR 330 components
---
 enforcer-api/pom.xml                               |  23 ++
 enforcer-api/src/custom-rule-sample/pom.xml        |  51 ++--
 .../apache/maven/enforcer/rule/MyCustomRule.java   | 130 ----------
 .../java/org/example/custom/rule/MyCustomRule.java | 103 ++++++++
 enforcer-api/src/custom-rule-sample/usage-pom.xml  |  85 ++++---
 .../src/main/assembly/custom-rule-sample.xml       |  19 +-
 .../enforcer/rule/api/AbstractEnforcerRule.java    |  92 +++++++
 .../maven/enforcer/rule/api/EnforcerLogger.java    | 110 +++++++++
 .../maven/enforcer/rule/api/EnforcerRule.java      |  16 +-
 .../maven/enforcer/rule/api/EnforcerRule2.java     |   3 +
 .../maven/enforcer/rule/api/EnforcerRuleBase.java  |  14 +-
 .../{EnforcerRule2.java => EnforcerRuleError.java} |  28 ++-
 .../enforcer/rule/api/EnforcerRuleException.java   |  19 +-
 .../enforcer/rule/api/EnforcerRuleHelper.java      |  21 +-
 .../src/site/apt/writing-a-custom-rule.apt.vm      | 271 +++------------------
 enforcer-rules/pom.xml                             |  11 -
 .../enforcer => enforcer/rules}/AlwaysFail.java    |  19 +-
 .../rules}/RequireJavaVendor.java                  |  50 +++-
 .../rules}/RequireNoRepositories.java              | 137 ++++++-----
 .../rules}/utils/ArtifactMatcher.java              |   2 +-
 .../rules}/utils/ArtifactUtils.java                |   5 +-
 .../rules}/utils/DependencyVersionMap.java         |   2 +-
 .../rules}/utils/DistributionManagementCheck.java  |   2 +-
 .../rules}/utils/EnforcerRuleUtils.java            |   2 +-
 .../rules}/utils/NormalizeLineSeparatorReader.java |   2 +-
 .../rules}/utils/ParentNodeProvider.java           |   2 +-
 .../rules}/utils/ParentsVisitor.java               |   2 +-
 .../rules}/utils/PluginWrapper.java                |   2 +-
 .../plugins/enforcer/AbstractBanDependencies.java  |   2 +-
 .../enforcer/BanDependencyManagementScope.java     |   2 +-
 .../enforcer/BanDistributionManagement.java        |   2 +-
 .../maven/plugins/enforcer/BanDynamicVersions.java |   4 +-
 .../enforcer/BanTransitiveDependencies.java        |   4 +-
 .../maven/plugins/enforcer/BannedDependencies.java |   2 +-
 .../plugins/enforcer/BannedDependenciesBase.java   |   2 +-
 .../maven/plugins/enforcer/BannedPlugins.java      |   2 +-
 .../plugins/enforcer/DependencyConvergence.java    |   4 +-
 .../plugins/enforcer/RequirePluginVersions.java    |   4 +-
 .../maven/plugins/enforcer/RequireReleaseDeps.java |   4 +-
 .../plugins/enforcer/RequireTextFileChecksum.java  |   4 +-
 .../plugins/enforcer/RequireUpperBoundDeps.java    |   6 +-
 .../rules}/TestAlwaysFail.java                     |   4 +-
 .../rules}/TestRequireJavaVendor.java              |  36 ++-
 .../rules}/TestRequireNoRepositories.java          |  45 ++--
 .../rules}/utils/DependencyNodeBuilder.java        |   2 +-
 .../rules}/utils/EnforcerRuleUtilsHelper.java      |   2 +-
 .../utils/MockEnforcerExpressionEvaluator.java     |   2 +-
 .../rules}/utils/TestArtifactMatcher.java          |   4 +-
 .../utils/TestMockEnforcerExpressionEvaluator.java |   2 +-
 .../utils/TestNormalizeLineSeparatorReader.java    |   4 +-
 .../maven/plugins/enforcer/EnforcerTestUtils.java  |   5 +-
 .../enforcer/RequireUpperBoundDepsTest.java        |   2 +-
 .../plugins/enforcer/TestBannedDependencies.java   |   2 +-
 .../enforcer/TestRequirePluginVersions.java        |   2 +-
 .../plugins/enforcer/TestRequireReleaseDeps.java   |   2 +-
 .../enforcer/TestRequireReleaseVersion.java        |   2 +-
 .../enforcer/TestRequireSnapshotVersion.java       |   2 +-
 .../enforcer/TestRequireTextFileChecksum.java      |   2 +-
 maven-enforcer-plugin/pom.xml                      |  11 +-
 .../src/it/projects/always-fail-warn/verify.groovy |   2 +-
 .../src/it/projects/always-fail/pom.xml            |   4 +-
 .../verify.groovy                                  |   3 +-
 .../verify.groovy                                  |   2 +-
 .../invoker.properties                             |  18 ++
 .../mod1}/pom.xml                                  |  33 +--
 .../mod2}/pom.xml                                  |  33 +--
 .../pom.xml                                        |  14 +-
 .../verify.groovy                                  |   8 +-
 .../verify.groovy                                  |   2 +-
 .../verify.groovy                                  |   2 +-
 .../require-no-repositories_failure/verify.groovy  |   2 +-
 .../verify.groovy                                  |   2 +-
 .../verify.groovy                                  |   2 +-
 .../verify.groovy                                  |   2 +-
 .../apache/maven/plugins/enforcer/EnforceMojo.java | 166 +++++++++----
 .../enforcer/internal/AbstractEnforcerLogger.java  |  88 +++++++
 .../enforcer/internal/EnforcerLoggerError.java     |  30 ++-
 .../enforcer/internal/EnforcerLoggerWarn.java      |  30 ++-
 .../enforcer/internal/EnforcerRuleCache.java       |  70 ++++++
 .../enforcer/internal}/EnforcerRuleDesc.java       |  22 +-
 .../enforcer/internal}/EnforcerRuleManager.java    |  52 +++-
 .../enforcer/TestDefaultEnforcementRuleHelper.java |  38 ---
 .../maven/plugins/enforcer/TestEnforceMojo.java    | 121 ++++++---
 .../apache/maven/plugins/enforcer/TestRule1.java}  |  11 +-
 .../apache/maven/plugins/enforcer/TestRule2.java}  |  11 +-
 .../internal}/EnforcerRuleManagerTest.java         |  84 +++++--
 86 files changed, 1314 insertions(+), 934 deletions(-)

diff --git a/enforcer-api/pom.xml b/enforcer-api/pom.xml
index 670716d..ff3c41b 100644
--- a/enforcer-api/pom.xml
+++ b/enforcer-api/pom.xml
@@ -48,6 +48,29 @@
 
   <build>
     <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>custom-rule</id>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <phase>pre-site</phase>
+            <configuration>
+              <outputDirectory>${project.build.directory}/custom-rule-sample</outputDirectory>
+              <escapeString>\</escapeString>
+              <resources>
+                <resource>
+                  <directory>src/custom-rule-sample</directory>
+                  <filtering>true</filtering>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-assembly-plugin</artifactId>
diff --git a/enforcer-api/src/custom-rule-sample/pom.xml b/enforcer-api/src/custom-rule-sample/pom.xml
index 5b109d3..7ebd3a8 100644
--- a/enforcer-api/src/custom-rule-sample/pom.xml
+++ b/enforcer-api/src/custom-rule-sample/pom.xml
@@ -18,46 +18,65 @@
   * under the License. 
   *
 -->
+<!-- START SNIPPET: project-pom -->
 <project xmlns="http://maven.apache.org/POM/4.0.0"
-  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
+
   <groupId>custom-rule</groupId>
   <artifactId>custom-rule-sample</artifactId>
-  <packaging>jar</packaging>
   <version>1.0</version>
+
   <name>My Custom Rule</name>
   <description>This is my custom rule.</description>
+
   <properties>
     <api.version>${project.version}</api.version>
-    <maven.version>3.0</maven.version>
+    <maven.version>${maven.version}</maven.version>
+    <!-- use JDK 1.8 at least -->
+    <maven.compiler.source>1.8</maven.compiler.source>
+    <maven.compiler.target>1.8</maven.compiler.target>
   </properties>
+
   <dependencies>
     <dependency>
       <groupId>org.apache.maven.enforcer</groupId>
       <artifactId>enforcer-api</artifactId>
-      <version>${api.version}</version>
+      <version>\${api.version}</version>
       <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.maven</groupId>
       <artifactId>maven-core</artifactId>
-      <version>${maven.version}</version>
+      <version>\${maven.version}</version>
       <scope>provided</scope>
     </dependency>
     <dependency>
-      <groupId>org.apache.maven</groupId>
-      <artifactId>maven-plugin-api</artifactId>
-      <version>${maven.version}</version>
+      <groupId>javax.inject</groupId>
+      <artifactId>javax.inject</artifactId>
+      <version>1</version>
       <scope>provided</scope>
     </dependency>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>4.13.2</version>
-      <scope>test</scope>
-    </dependency>
   </dependencies>
+
   <build>
+    <plugins>
+      <plugin>
+        <!-- generate index of project components -->
+        <groupId>org.eclipse.sisu</groupId>
+        <artifactId>sisu-maven-plugin</artifactId>
+        <version>0.9.0.M1</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>main-index</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
   </build>
-</project>
\ No newline at end of file
+
+</project>
+    <!-- END SNIPPET: project-pom -->
diff --git a/enforcer-api/src/custom-rule-sample/src/main/java/org/apache/maven/enforcer/rule/MyCustomRule.java b/enforcer-api/src/custom-rule-sample/src/main/java/org/apache/maven/enforcer/rule/MyCustomRule.java
deleted file mode 100644
index ad2e416..0000000
--- a/enforcer-api/src/custom-rule-sample/src/main/java/org/apache/maven/enforcer/rule/MyCustomRule.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.maven.enforcer.rule;
-
-import org.apache.maven.ProjectDependenciesResolver;
-import org.apache.maven.enforcer.rule.api.EnforcerRule;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
-import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
-
-/**
- * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
- * @author <a href="mailto:belingueres@gmail.com">Gabriel Belingueres</a>
- */
-public class MyCustomRule
-    implements EnforcerRule
-{
-    /**
-     * Simple param. This rule fails if the value is true.
-     */
-    private boolean shouldIfail = false;
-
-    public void execute( EnforcerRuleHelper helper )
-        throws EnforcerRuleException
-    {
-        Log log = helper.getLog();
-
-        try
-        {
-            // get the various expressions out of the helper.
-            MavenProject project = (MavenProject) helper.evaluate( "${project}" );
-            MavenSession session = (MavenSession) helper.evaluate( "${session}" );
-            String target = (String) helper.evaluate( "${project.build.directory}" );
-            String artifactId = (String) helper.evaluate( "${project.artifactId}" );
-            String mavenVersion = (String) helper.evaluate( "${maven.version}" );
-
-            // retrieve any component out of the session directly
-            ProjectDependenciesResolver resolver = helper.getComponent( ProjectDependenciesResolver.class );
-
-            log.info( "Retrieved Target Folder: " + target );
-            log.info( "Retrieved ArtifactId: " +artifactId );
-            log.info( "Retrieved Project: " + project );
-            log.info( "Retrieved Maven version: " + mavenVersion );
-            log.info( "Retrieved Session: " + session );
-            log.info( "Retrieved Resolver: " + resolver );
-
-            if ( this.shouldIfail )
-            {
-                throw new EnforcerRuleException( "Failing because my param said so." );
-            }
-        }
-        catch ( ComponentLookupException e )
-        {
-            throw new EnforcerRuleException( "Unable to lookup a component " + e.getLocalizedMessage(), e );
-        }
-        catch ( ExpressionEvaluationException e )
-        {
-            throw new EnforcerRuleException( "Unable to lookup an expression " + e.getLocalizedMessage(), e );
-        }
-    }
-
-    /**
-     * If your rule is cacheable, you must return a unique id when parameters or conditions
-     * change that would cause the result to be different. Multiple cached results are stored
-     * based on their id.
-     * 
-     * The easiest way to do this is to return a hash computed from the values of your parameters.
-     * 
-     * If your rule is not cacheable, then the result here is not important, you may return anything.
-     */
-    public String getCacheId()
-    {
-        //no hash on boolean...only parameter so no hash is needed.
-        return Boolean.toString( this.shouldIfail );
-    }
-
-    /**
-     * This tells the system if the results are cacheable at all. Keep in mind that during
-     * forked builds and other things, a given rule may be executed more than once for the same
-     * project. This means that even things that change from project to project may still 
-     * be cacheable in certain instances.
-     */
-    public boolean isCacheable()
-    {
-        return false;
-    }
-
-    /**
-     * If the rule is cacheable and the same id is found in the cache, the stored results
-     * are passed to this method to allow double checking of the results. Most of the time 
-     * this can be done by generating unique ids, but sometimes the results of objects returned
-     * by the helper need to be queried. You may for example, store certain objects in your rule
-     * and then query them later.
-     */
-    public boolean isResultValid( EnforcerRule rule )
-    {
-        return false;
-    }
-
-    /**
-     * Injects the value of the shouldIfail parameter into the custom rule.
-     * 
-     * @param shouldIfail set to true if you want the rule to fail. false to succeed.
-     */
-    public void setShouldIfail( boolean shouldIfail )
-    {
-        this.shouldIfail = shouldIfail;
-    }
-
-}
diff --git a/enforcer-api/src/custom-rule-sample/src/main/java/org/example/custom/rule/MyCustomRule.java b/enforcer-api/src/custom-rule-sample/src/main/java/org/example/custom/rule/MyCustomRule.java
new file mode 100644
index 0000000..d7a36ea
--- /dev/null
+++ b/enforcer-api/src/custom-rule-sample/src/main/java/org/example/custom/rule/MyCustomRule.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// START SNIPPET: rule-implementation
+package org.example.custom.rule;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import java.util.List;
+
+import org.apache.maven.enforcer.rule.api.AbstractEnforcerRule;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.rtinfo.RuntimeInformation;
+
+/**
+ * Custom Enforcer Rule - example
+ */
+@Named("myCustomRule") // rule name - must start from lowercase character
+public class MyCustomRule extends AbstractEnforcerRule {
+
+    /**
+     * Simple param. This rule fails if the value is true.
+     */
+    private boolean shouldIfail = false;
+
+    /**
+     * Rule parameter as list of items.
+     */
+    private List<String> listParameters;
+
+    // Inject needed Maven components
+
+    @Inject
+    private MavenProject project;
+
+    @Inject
+    private MavenSession session;
+
+    @Inject
+    private RuntimeInformation runtimeInformation;
+
+    public void execute() throws EnforcerRuleException {
+
+        getLog().info("Retrieved Target Folder: " + project.getBuild().getDirectory());
+        getLog().info("Retrieved ArtifactId: " + project.getArtifactId());
+        getLog().info("Retrieved Project: " + project);
+        getLog().info("Retrieved Maven version: " + runtimeInformation.getMavenVersion());
+        getLog().info("Retrieved Session: " + session);
+        getLog().warnOrError("Parameter shouldIfail: " + shouldIfail);
+        getLog().info(() -> "Parameter listParameters: " + listParameters);
+
+        if (this.shouldIfail) {
+            throw new EnforcerRuleException("Failing because my param said so.");
+        }
+    }
+
+    /**
+     * If your rule is cacheable, you must return a unique id when parameters or conditions
+     * change that would cause the result to be different. Multiple cached results are stored
+     * based on their id.
+     * <p>
+     * The easiest way to do this is to return a hash computed from the values of your parameters.
+     * <p>
+     * If your rule is not cacheable, then you don't need to override this method or return null
+     */
+    @Override
+    public String getCacheId() {
+        //no hash on boolean...only parameter so no hash is needed.
+        return Boolean.toString(shouldIfail);
+    }
+
+    /**
+     * A good practice is provided toString method for Enforcer Rule.
+     * <p>
+     * Output is used in verbose Maven logs, can help during investigate problems.
+     *
+     * @return rule description
+     */
+    @Override
+    public String toString() {
+        return String.format("MyCustomRule[level=%s, shouldIfail=%b]", getLevel(), shouldIfail);
+    }
+}
+// END SNIPPET: rule-implementation
diff --git a/enforcer-api/src/custom-rule-sample/usage-pom.xml b/enforcer-api/src/custom-rule-sample/usage-pom.xml
index 7af9b80..d02adf0 100644
--- a/enforcer-api/src/custom-rule-sample/usage-pom.xml
+++ b/enforcer-api/src/custom-rule-sample/usage-pom.xml
@@ -18,42 +18,53 @@
   * under the License. 
   *
 -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <groupId>org.apache.maven.plugins</groupId>
-    <artifactId>maven-enforcer-plugin-sample-usage</artifactId>
-    <version>1</version>
-    <packaging>jar</packaging>
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-enforcer-plugin</artifactId>
-                <version>${project.version}</version>
-                <dependencies>
-                    <dependency>
-                        <groupId>custom-rule</groupId>
-                        <artifactId>custom-rule-sample</artifactId>
-                        <version>1.0</version>
-                    </dependency>
-                </dependencies>
-                <executions>
-                    <execution>
-                        <id>enforce</id>
-                        <configuration>
-                            <rules>
-                                <myCustomRule implementation="org.apache.maven.enforcer.rule.MyCustomRule">
-                                    <shouldIfail>false</shouldIfail>
-                                </myCustomRule>
-                            </rules>
-                        </configuration>
-                        <goals>
-                            <goal>enforce</goal>
-                        </goals>
+<!-- START SNIPPET: usage-pom -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
 
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
+  <groupId>custom-rule</groupId>
+  <artifactId>maven-enforcer-plugin-sample-usage</artifactId>
+  <version>1</version>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-enforcer-plugin</artifactId>
+        <version>${project.version}</version>
+        <dependencies>
+          <!-- dependencies to your artifact contains rule implementation -->
+          <dependency>
+            <groupId>custom-rule</groupId>
+            <artifactId>custom-rule-sample</artifactId>
+            <version>1.0</version>
+          </dependency>
+        </dependencies>
+        <executions>
+          <execution>
+            <id>enforce</id>
+            <configuration>
+              <rules>
+                <!-- rule name -->
+                <myCustomRule>
+                  <!-- rule parameters -->
+                  <shouldIfail>true</shouldIfail>
+                  <listParameters>
+                    <item>item 1</item>
+                    <item>item 2</item>
+                  </listParameters>
+                </myCustomRule>
+              </rules>
+            </configuration>
+            <goals>
+              <goal>enforce</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
 </project>
+    <!-- END SNIPPET: usage-pom -->
diff --git a/enforcer-api/src/main/assembly/custom-rule-sample.xml b/enforcer-api/src/main/assembly/custom-rule-sample.xml
index 63eb1c1..864e2dc 100644
--- a/enforcer-api/src/main/assembly/custom-rule-sample.xml
+++ b/enforcer-api/src/main/assembly/custom-rule-sample.xml
@@ -18,9 +18,9 @@
   * under the License. 
   *
 -->
-<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
+<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.1"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 https://maven.apache.org/xsd/assembly-2.1.0.xsd">
+    xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.1 https://maven.apache.org/xsd/assembly-2.1.1.xsd">
   <id>sample</id>
   <includeBaseDirectory>false</includeBaseDirectory>
   <formats>
@@ -28,21 +28,8 @@
   </formats>
   <fileSets>
     <fileSet>
-      <directory>src/custom-rule-sample</directory>
+      <directory>target/custom-rule-sample</directory>
       <outputDirectory>/custom-rule-sample</outputDirectory>
     </fileSet>
   </fileSets>
-  <files>
-    <!-- filters custom-rule's pom.xml to replace 'api.version' property with the current project version -->
-    <file>
-      <source>src/custom-rule-sample/pom.xml</source>
-      <outputDirectory>/custom-rule-sample</outputDirectory>
-      <filtered>true</filtered>
-    </file>
-    <file>
-      <source>src/custom-rule-sample/usage-pom.xml</source>
-      <outputDirectory>/custom-rule-sample</outputDirectory>
-      <filtered>true</filtered>
-    </file>
-  </files>
 </assembly>
\ No newline at end of file
diff --git a/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/AbstractEnforcerRule.java b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/AbstractEnforcerRule.java
new file mode 100644
index 0000000..34c1c28
--- /dev/null
+++ b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/AbstractEnforcerRule.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.enforcer.rule.api;
+
+/**
+ * Entry point for custom {@code Enforcer Rule}.
+ * <p>
+ * Please see
+ * <a href="https://maven.apache.org/enforcer/enforcer-api/writing-a-custom-rule.html">Writing a custom rule</a>
+ *
+ * @author Slawomir Jaranowski
+ * @since 3.2.0
+ */
+public abstract class AbstractEnforcerRule implements EnforcerRuleBase {
+
+    /**
+     * EnforcerLogger instance
+     */
+    private EnforcerLogger log;
+
+    /**
+     * Enforcer Rule execution level
+     */
+    private EnforcerLevel level = EnforcerLevel.ERROR;
+
+    /**
+     * Used by {@code EnforcerMojo} to inject logger instance
+     *
+     * @param log an {@link EnforcerLogger} instance
+     */
+    public void setLog(EnforcerLogger log) {
+        this.log = log;
+    }
+
+    /**
+     * Provide an {@link  EnforcerLogger} instance for Rule
+     *
+     * @return an {@link EnforcerLogger} instance
+     */
+    public EnforcerLogger getLog() {
+        return log;
+    }
+
+    /**
+     * Current Enforcer execution level
+     *
+     * @return an Enforcer execution level
+     */
+    public EnforcerLevel getLevel() {
+        return level;
+    }
+
+    /**
+     * If the rule is to be cached during session scope, whole executing of Maven build,
+     * this id is used as part of the key.
+     * <p>
+     * Rule of the same class and the same cache id will be executed once.
+     *
+     * @return id to be used by the Enforcer to determine uniqueness of cache results.
+     *         Return {@code null} disable cache of rule executing.
+     */
+    public String getCacheId() {
+        return null;
+    }
+
+    /**
+     * This is the interface into the rule. This method should throw an exception
+     * containing a reason message if the rule fails the check. The plugin will
+     * then decide based on the fail flag and rule level if it should stop or just log the
+     * message as a warning.
+     *
+     * @throws EnforcerRuleException the enforcer rule exception
+     * @throws EnforcerRuleError     in order to brake a build immediately
+     */
+    public abstract void execute() throws EnforcerRuleException;
+}
diff --git a/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerLogger.java b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerLogger.java
new file mode 100644
index 0000000..64c5d0b
--- /dev/null
+++ b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerLogger.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.enforcer.rule.api;
+
+import java.util.function.Supplier;
+
+/**
+ * Logger used by enforcer rule.
+ *
+ * @author Slawomir Jaranowski
+ * @since 3.2.0
+ */
+public interface EnforcerLogger {
+
+    /**
+     * Log message in {@code warn} or {@code error} level according to current rule {@link EnforcerLevel}.
+     *
+     * @param message a massage to log
+     */
+    void warnOrError(CharSequence message);
+
+    /**
+     * Log message in {@code warn} or {@code error} level according to current rule {@link EnforcerLevel}.
+     * <p>
+     * {@code messageSupplier} will be evaluate only when corresponding log level is enabled.
+     *
+     * @param messageSupplier a supplier for message to log
+     */
+    void warnOrError(Supplier<CharSequence> messageSupplier);
+
+    /**
+     * Log message in {@code debug} level.
+     *
+     * @param message a massage to log
+     */
+    void debug(CharSequence message);
+
+    /**
+     * Log message in {@code debug} level.
+     * <p>
+     * {@code messageSupplier} will be evaluate only when corresponding log level is enabled.
+     *
+     * @param messageSupplier a supplier for message to log
+     */
+    void debug(Supplier<CharSequence> messageSupplier);
+
+    /**
+     * Log message in {@code info} level.
+     *
+     * @param message a massage to log
+     */
+    void info(CharSequence message);
+
+    /**
+     * Log message in {@code info} level.
+     * <p>
+     * {@code messageSupplier} will be evaluate only when corresponding log level is enabled.
+     *
+     * @param messageSupplier a supplier for message to log
+     */
+    void info(Supplier<CharSequence> messageSupplier);
+
+    /**
+     * Log message in {@code warn} level.
+     *
+     * @param message a massage to log
+     */
+    void warn(CharSequence message);
+
+    /**
+     * Log message in {@code warn} level.
+     * <p>
+     * {@code messageSupplier} will be evaluate only when corresponding log level is enabled.
+     *
+     * @param messageSupplier a supplier for message to log
+     */
+    void warn(Supplier<CharSequence> messageSupplier);
+
+    /**
+     * Log message in {@code error} level.
+     *
+     * @param message a massage to log
+     */
+    void error(CharSequence message);
+
+    /**
+     * Log message in {@code error} level.
+     * <p>
+     * {@code messageSupplier} will be evaluate only when corresponding log level is enabled.
+     *
+     * @param messageSupplier a supplier for message to log
+     */
+    void error(Supplier<CharSequence> messageSupplier);
+}
diff --git a/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRule.java b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRule.java
index 45441b5..8999726 100644
--- a/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRule.java
+++ b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRule.java
@@ -25,8 +25,11 @@ import javax.annotation.Nullable;
  * Interface to be implemented by any rules executed by the enforcer.
  *
  * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
+ * @deprecated Please see
+ *         <a href="https://maven.apache.org/enforcer/enforcer-api/writing-a-custom-rule.html">Writing a custom rule</a>
  */
-public interface EnforcerRule {
+@Deprecated
+public interface EnforcerRule extends EnforcerRuleBase {
 
     /**
      * This is the interface into the rule. This method should throw an exception
@@ -35,9 +38,8 @@ public interface EnforcerRule {
      * message as a warning.
      *
      * @param helper The helper provides access to the log, MavenSession and has
-     * helpers to get common components. It is also able to lookup components
-     * by class name.
-     *
+     *               helpers to get common components. It is also able to lookup components
+     *               by class name.
      * @throws EnforcerRuleException the enforcer rule exception
      */
     void execute(@Nonnull EnforcerRuleHelper helper) throws EnforcerRuleException;
@@ -59,8 +61,8 @@ public interface EnforcerRule {
      * your rule and then query them later.
      *
      * @param cachedRule the last cached instance of the rule. This is to be used by the rule to
-     * potentially determine if the results are still valid (ie if the configuration has been overridden)
-     *
+     *                   potentially determine if the results are still valid (ie if the configuration has been
+     *                   overridden)
      * @return <code>true</code> if the stored results are valid for the same id.
      */
     boolean isResultValid(@Nonnull EnforcerRule cachedRule);
@@ -70,7 +72,7 @@ public interface EnforcerRule {
      * that allow multiple results of the same rule to be cached.
      *
      * @return id to be used by the enforcer to determine uniqueness of cache results. The ids only need to be unique
-     * within a given rule implementation as the full key will be [classname]-[id]
+     *         within a given rule implementation as the full key will be [classname]-[id]
      */
     @Nullable
     String getCacheId();
diff --git a/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRule2.java b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRule2.java
index e19585c..335c420 100644
--- a/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRule2.java
+++ b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRule2.java
@@ -25,7 +25,10 @@ import javax.annotation.Nonnull;
  *
  * @author Mirko Friedenhagen
  * @since 1.4
+ * @deprecated Please see
+ *         <a href="https://maven.apache.org/enforcer/enforcer-api/writing-a-custom-rule.html">Writing a custom rule</a>
  */
+@Deprecated
 public interface EnforcerRule2 extends EnforcerRule {
     /**
      * Returns the level of enforcement.
diff --git a/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRuleBase.java
similarity index 79%
copy from maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy
copy to enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRuleBase.java
index c05c677..328c307 100644
--- a/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy
+++ b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRuleBase.java
@@ -16,8 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[WARNING] Rule 0: org.apache.maven.plugins.enforcer.AlwaysFail warned with message:' )
+package org.apache.maven.enforcer.rule.api;
 
-
- 
\ No newline at end of file
+/**
+ * Base interface for old and new API.
+ * <p>
+ * Used for internal purpose.
+ *
+ * @author Slawomir Jaranowski
+ * @since 3.2.0
+ */
+public interface EnforcerRuleBase {}
diff --git a/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRule2.java b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRuleError.java
similarity index 65%
copy from enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRule2.java
copy to enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRuleError.java
index e19585c..b7d7efc 100644
--- a/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRule2.java
+++ b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRuleError.java
@@ -18,20 +18,22 @@
  */
 package org.apache.maven.enforcer.rule.api;
 
-import javax.annotation.Nonnull;
-
 /**
- * Interface to be implemented by any rules as of version 2.0 executed by the enforcer.
+ * An error occurring during the execution of a rule.
+ * Rule can inform Enforcer plugin about critical state.
+ * <p>
+ * This exception break a build immediate.
  *
- * @author Mirko Friedenhagen
- * @since 1.4
+ * @author Slawomir Jaranowski
+ * @since 3.2.0
  */
-public interface EnforcerRule2 extends EnforcerRule {
-    /**
-     * Returns the level of enforcement.
-     *
-     * @return level
-     */
-    @Nonnull
-    EnforcerLevel getLevel();
+public class EnforcerRuleError extends EnforcerRuleException {
+
+    public EnforcerRuleError(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public EnforcerRuleError(String message) {
+        super(message);
+    }
 }
diff --git a/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRuleException.java b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRuleException.java
index fc3d78d..a8285a5 100644
--- a/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRuleException.java
+++ b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRuleException.java
@@ -19,9 +19,10 @@
 package org.apache.maven.enforcer.rule.api;
 
 /**
- * An exception occurring during the execution of a rule. Based off of
- * EnforcerRuleException, but separated to keep the rule dependencies to a
- * minimum.
+ * An exception occurring during the execution of a rule.
+ * <p>
+ * Enforcer plugin takes decision based on configuration and {@code Enforcer Rule} level
+ * whether build should pass or fail.
  *
  * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
  */
@@ -40,7 +41,9 @@ public class EnforcerRuleException extends Exception {
      * Gets the long message.
      *
      * @return the long message
+     * @deprecated not used
      */
+    @Deprecated
     public String getLongMessage() {
         return longMessage;
     }
@@ -49,7 +52,9 @@ public class EnforcerRuleException extends Exception {
      * Gets the source.
      *
      * @return the source
+     * @deprecated not used
      */
+    @Deprecated
     public Object getSource() {
         return source;
     }
@@ -58,10 +63,12 @@ public class EnforcerRuleException extends Exception {
      * Construct a new <code>EnforcerRuleException</code> exception providing
      * the source and a short and long message.
      *
-     * @param source the source
+     * @param source       the source
      * @param shortMessage the short message
-     * @param longMessage the long message
+     * @param longMessage  the long message
+     * @deprecated {@code source} and {@code longMessage} are not used
      */
+    @Deprecated
     public EnforcerRuleException(Object source, String shortMessage, String longMessage) {
         super(shortMessage);
         this.source = source;
@@ -86,7 +93,7 @@ public class EnforcerRuleException extends Exception {
      * <code>message</code>.
      *
      * @param message the message
-     * @param cause the cause
+     * @param cause   the cause
      */
     public EnforcerRuleException(String message, Throwable cause) {
         super(message, cause);
diff --git a/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRuleHelper.java b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRuleHelper.java
index e931c73..2c57263 100644
--- a/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRuleHelper.java
+++ b/enforcer-api/src/main/java/org/apache/maven/enforcer/rule/api/EnforcerRuleHelper.java
@@ -35,7 +35,10 @@ import org.codehaus.plexus.component.repository.exception.ComponentLookupExcepti
  * rules.
  *
  * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
+ * @deprecated Please see
+ *         <a href="https://maven.apache.org/enforcer/enforcer-api/writing-a-custom-rule.html">Writing a custom rule</a>
  */
+@Deprecated
 public interface EnforcerRuleHelper extends ExpressionEvaluator {
 
     /**
@@ -50,9 +53,7 @@ public interface EnforcerRuleHelper extends ExpressionEvaluator {
      * Gets the component.
      *
      * @param clazz the clazz
-     *
      * @return the component
-     *
      * @throws ComponentLookupException the component lookup exception
      */
     @Nonnull
@@ -62,9 +63,7 @@ public interface EnforcerRuleHelper extends ExpressionEvaluator {
      * Gets the component.
      *
      * @param componentKey the component key
-     *
      * @return the component
-     *
      * @throws ComponentLookupException the component lookup exception
      */
     @Nonnull
@@ -73,11 +72,9 @@ public interface EnforcerRuleHelper extends ExpressionEvaluator {
     /**
      * Gets the component.
      *
-     * @param role the role
+     * @param role     the role
      * @param roleHint the role hint
-     *
      * @return the component
-     *
      * @throws ComponentLookupException the component lookup exception
      */
     Object getComponent(String role, String roleHint) throws ComponentLookupException;
@@ -85,11 +82,9 @@ public interface EnforcerRuleHelper extends ExpressionEvaluator {
     /**
      * Gets the component.
      *
-     * @param clazz the clazz
+     * @param clazz    the clazz
      * @param roleHint the role hint
-     *
      * @return the component
-     *
      * @throws ComponentLookupException the component lookup exception
      */
     <T> T getComponent(Class<T> clazz, String roleHint) throws ComponentLookupException;
@@ -98,9 +93,7 @@ public interface EnforcerRuleHelper extends ExpressionEvaluator {
      * Gets the component map.
      *
      * @param role the role
-     *
      * @return the component map
-     *
      * @throws ComponentLookupException the component lookup exception
      */
     Map<String, ?> getComponentMap(String role) throws ComponentLookupException;
@@ -109,9 +102,7 @@ public interface EnforcerRuleHelper extends ExpressionEvaluator {
      * Gets the component list.
      *
      * @param role the role
-     *
      * @return the component list
-     *
      * @throws ComponentLookupException the component lookup exception
      */
     List<?> getComponentList(String role) throws ComponentLookupException;
@@ -126,7 +117,7 @@ public interface EnforcerRuleHelper extends ExpressionEvaluator {
     /**
      * Gets a cached value, or uses the provided producer to compute it.
      *
-     * @param key a key to identify the value stored
+     * @param key      a key to identify the value stored
      * @param producer a supplier for the value if it's not already present
      * @return a previously-cached or freshly-computed value
      */
diff --git a/enforcer-api/src/site/apt/writing-a-custom-rule.apt.vm b/enforcer-api/src/site/apt/writing-a-custom-rule.apt.vm
index b0472dd..1216f4e 100644
--- a/enforcer-api/src/site/apt/writing-a-custom-rule.apt.vm
+++ b/enforcer-api/src/site/apt/writing-a-custom-rule.apt.vm
@@ -29,261 +29,52 @@ Writing a custom rule
   {{{http://maven.apache.org/plugins/maven-enforcer-plugin/}maven-enforcer-plugin}}. 
   
   Note: The files shown below may be downloaded here: {{{./custom-rule.zip}custom-rule.zip}}
+
+* Project with custom Enforcer Rule
+
+  First make a new jar project starting with the sample pom below:
   
-  [[1]] First make a new jar project starting with the sample pom below:
-  
-+---+
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>custom-rule</groupId>
-  <artifactId>custom-rule-sample</artifactId>
-  <packaging>jar</packaging>
-  <version>1.0</version>
-  <name>My Custom Rule</name>
-  <description>This is my custom rule.</description>
-  <properties>
-    <api.version>${project.version}</api.version>
-    <maven.version>${mavenPrerequisite}</maven.version>
-  </properties>
-  <dependencies>
-    <dependency>
-      <groupId>org.apache.maven.enforcer</groupId>
-      <artifactId>enforcer-api</artifactId>
-      <version>${api.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven</groupId>
-      <artifactId>maven-core</artifactId>
-      <version>${maven.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven</groupId>
-      <artifactId>maven-plugin-api</artifactId>
-      <version>${maven.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>3.8.1</version>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-  <build>
-  </build>
-</project>
-+---+
-  Note that the classloader is shared with the embedding <<<maven-enforcer-plugin>>> (a regular {{{https://maven.apache.org/guides/mini/guide-maven-classloading.html#Plugin_Classloaders}plugin classloader}}) 
-  and therefore the artifacts <<<org.apache.maven.enforcer:enforcer-api>>> and <<<org.apache.maven.enforcer:enforcer-rules>>> are always loaded in the same version as the embedding <<<maven-enforcer-plugin>>>.
-  Custom rule artifacts should therefore only depend on `enforcer-api` and core Maven artifacts with <<<provided>>> scope (for details refer to {{{https://issues.apache.org/jira/browse/MNG-7097}MNG-7097}}).
-  The classes available from `enforcer-rules` must not be used from custom rules, as those are not considered API and may change in backwards-incompatible ways with every `maven-enforcer` version (even minor ones).
-  
-  [[2]] Create your rule class. The rule must implement the {{{./apidocs/index.html}EnforcerRule}} interface.
-   The rule can get access to components and the log via the {{{./apidocs/index.html}EnforcerRuleHelper}} interface.
-   In addition, the rule must provide a setter method for each parameter allowed to be configured in the pom.xml file (like the parameter <<<shouldIfail>>> shown in point 5).
-   
-   If the rule succeeds, it should just simply return. If the rule fails, it should throw an {{{./apidocs/index.html}EnforcerRuleException}} with a descriptive message telling the user why the rule failed.
-   
-   There are several methods that must be implemented related to caching.
-   
-   Here's a sample class that shows how to access the helper methods and retrieve components by class name from the helper:
-   
-+---+
-package org.apache.maven.enforcer.rule;
+%{snippet|id=project-pom|file=enforcer-api/target/custom-rule-sample/pom.xml}
 
-import org.apache.maven.ProjectDependenciesResolver;
-import org.apache.maven.enforcer.rule.api.EnforcerRule;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
-import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+  Note that the classloader is shared with the embedding <<<maven-enforcer-plugin>>> (a regular {{{https://maven.apache.org/guides/mini/guide-maven-classloading.html#Plugin_Classloaders}plugin classloader}})
+  and therefore the artifacts <<<org.apache.maven.enforcer:enforcer-api>>> are always loaded in the same version as the embedding <<<maven-enforcer-plugin>>>.
 
-/**
- * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
- * @author <a href="mailto:belingueres@gmail.com">Gabriel Belingueres</a>
- */
-public class MyCustomRule
-    implements EnforcerRule
-{
-    /**
-     * Simple param. This rule fails if the value is true.
-     */
-    private boolean shouldIfail = false;
+  Custom rule artifacts should therefore only depend on <<<enforcer-api>>> and core Maven artifacts with <<<provided>>> scope (for details refer to {{{https://issues.apache.org/jira/browse/MNG-7097}MNG-7097}}).
 
-    public void execute( EnforcerRuleHelper helper )
-        throws EnforcerRuleException
-    {
-        Log log = helper.getLog();
+  The classes available from <<<enforcer-rules>>> must not be used from custom rules, as those are not considered API and may change in backwards-incompatible ways with every <<<maven-enforcer>>> version (even minor ones).
 
-        try
-        {
-            // get the various expressions out of the helper.
-            MavenProject project = (MavenProject) helper.evaluate( "\${project}" );
-            MavenSession session = (MavenSession) helper.evaluate( "${session}" );
-            String target = (String) helper.evaluate( "\${project.build.directory}" );
-            String artifactId = (String) helper.evaluate( "\${project.artifactId}" );
-            String mavenVersion = (String) helper.evaluate( "${maven.version}" );
+  Other dependencies used by custom rule at run time should have <<<compile>>> scope.
 
-            // retrieve any component out of the session directly
-            ProjectDependenciesResolver resolver = helper.getComponent( ProjectDependenciesResolver.class );
+* Implementation of custom Enforcer Rule
 
-            log.info( "Retrieved Target Folder: " + target );
-            log.info( "Retrieved ArtifactId: " +artifactId );
-            log.info( "Retrieved Project: " + project );
-            log.info( "Retrieved Maven version: " + mavenVersion );
-            log.info( "Retrieved Session: " + session );
-            log.info( "Retrieved Resolver: " + resolver );
+  The rule must extends the {{{./apidocs/index.html}AbstractEnforcerRule}} and implements <<<execute>>> method.
 
-            if ( this.shouldIfail )
-            {
-                throw new EnforcerRuleException( "Failing because my param said so." );
-            }
-        }
-        catch ( ComponentLookupException e )
-        {
-            throw new EnforcerRuleException( "Unable to lookup a component " + e.getLocalizedMessage(), e );
-        }
-        catch ( ExpressionEvaluationException e )
-        {
-            throw new EnforcerRuleException( "Unable to lookup an expression " + e.getLocalizedMessage(), e );
-        }
-    }
+  Add annotation <<<@Named("yourRuleName")>>> to your Rule class. Your Rule name must start with lowercase character.
 
-    /**
-     * If your rule is cacheable, you must return a unique id when parameters or conditions
-     * change that would cause the result to be different. Multiple cached results are stored
-     * based on their id.
-     * 
-     * The easiest way to do this is to return a hash computed from the values of your parameters.
-     * 
-     * If your rule is not cacheable, then the result here is not important, you may return anything.
-     */
-    public String getCacheId()
-    {
-        //no hash on boolean...only parameter so no hash is needed.
-        return Boolean.toString( this.shouldIfail );
-    }
+  In addition, the rule can provide a setter method or simply field for each parameter allowed to be configured in the pom.xml file (like the parameter <<<shouldIfail>>> shown example).
 
-    /**
-     * This tells the system if the results are cacheable at all. Keep in mind that during
-     * forked builds and other things, a given rule may be executed more than once for the same
-     * project. This means that even things that change from project to project may still 
-     * be cacheable in certain instances.
-     */
-    public boolean isCacheable()
-    {
-        return false;
-    }
+  Maven component can be injected into Rule by annotation <<<...@Inject>>> on field or constructor.
 
-    /**
-     * If the rule is cacheable and the same id is found in the cache, the stored results
-     * are passed to this method to allow double checking of the results. Most of the time 
-     * this can be done by generating unique ids, but sometimes the results of objects returned
-     * by the helper need to be queried. You may for example, store certain objects in your rule
-     * and then query them later.
-     */
-    public boolean isResultValid( EnforcerRule rule )
-    {
-        return false;
-    }
+  Entry point for Rule executing is <<<execute>>> method, tf the rule succeeds, it should just simply return.
+  If the rule fails, it should throw an {{{./apidocs/index.html}EnforcerRuleException}} with a descriptive message telling the user why the rule failed.
+  Enforcer plugin takes decision based on configuration and Enforcer Rule level whether build should pass or fail.
+  In case when you want to brake build immediately, <<<execute>>> method can throw an {{{./apidocs/index.html}EnforcerRuleError}}.
 
-    /**
-     * Injects the value of the shouldIfail parameter into the custom rule.
-     * 
-     * @param shouldIfail set to true if you want the rule to fail. false to succeed.
-     */
-    public void setShouldIfail( boolean shouldIfail )
-    {
-        this.shouldIfail = shouldIfail;
-    }
+  Here's a sample class:
 
-}
-+---+   
+%{snippet|id=rule-implementation|file=enforcer-api/target/custom-rule-sample/src/main/java/org/example/custom/rule/MyCustomRule.java}
 
-  [[3]] Build and Install or Deploy your custom rule.
- 
-  [[4]] Add your custom-rule artifact as a dependency of the <<<maven-enforcer-plugin>>> in your build:
-  
-+---+
-<project>
-  ...
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-enforcer-plugin</artifactId>
-        <version>${project.version}</version>
-        <dependencies>
-          <dependency>
-            <groupId>custom-rule</groupId>
-            <artifactId>custom-rule-sample</artifactId>
-            <version>1.0</version>
-          </dependency>
-        </dependencies>
-        ...
-      </plugin>   
-    </plugins>
-  </build>
-  ...
-</project>
-+---+
 
-  [[5]] Add your rule to the configuration section of the <<<maven-enforcer-plugin>>>. The name of your class will be the name of the rule, and
- you must add an <<<implementation>>> hint that contains the fully qualified class name:
+* Using custom Rule
+
+  * Build and Install or Deploy your custom rule.
  
-+---+
-        ...
-        <configuration>
-          <rules>
-            <myCustomRule implementation="org.apache.maven.enforcer.rule.MyCustomRule">
-              <shouldIfail>true</shouldIfail>
-            </myCustomRule>
-          </rules>
-        </configuration>
-        ...
-+---+
+  * Add your custom-rule artifact as a dependency of the <<<maven-enforcer-plugin>>> in your build.
+
+  * Add your rule to the configuration section of the <<<maven-enforcer-plugin>>>, the name used in <<<...@Named>>> annotation of your Rule will be the name of the rule.
+
+  []
 
-  [[6]] That's it. The full plugin config may look like this:
+  That's it. The full plugin config may look like this:
   
-+---+
-<project>
-  ...
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-enforcer-plugin</artifactId>
-        <version>${project.version}</version>
-        <dependencies>
-          <dependency>
-            <groupId>custom-rule</groupId>
-            <artifactId>custom-rule-sample</artifactId>
-            <version>1.0</version>
-          </dependency>
-        </dependencies>
-        <executions>
-          <execution>
-            <id>enforce</id>
-            <configuration>
-              <rules>
-                <myCustomRule implementation="org.apache.maven.enforcer.rule.MyCustomRule">
-                  <shouldIfail>false</shouldIfail>
-                </myCustomRule>
-              </rules>
-            </configuration>
-            <goals>
-              <goal>enforce</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-  ...
-</project>
-+---+
+%{snippet|id=usage-pom|file=enforcer-api/target/custom-rule-sample/usage-pom.xml}
diff --git a/enforcer-rules/pom.xml b/enforcer-rules/pom.xml
index efa660b..50dcac3 100644
--- a/enforcer-rules/pom.xml
+++ b/enforcer-rules/pom.xml
@@ -127,17 +127,6 @@
         <groupId>org.eclipse.sisu</groupId>
         <artifactId>sisu-maven-plugin</artifactId>
       </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <executions>
-          <execution>
-            <goals>
-              <goal>test-jar</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
     </plugins>
   </build>
 </project>
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/AlwaysFail.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/AlwaysFail.java
similarity index 75%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/AlwaysFail.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/AlwaysFail.java
index 586b8ef..9ddbe41 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/AlwaysFail.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/AlwaysFail.java
@@ -16,21 +16,25 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer;
+package org.apache.maven.enforcer.rules;
 
+import javax.inject.Named;
+
+import org.apache.maven.enforcer.rule.api.AbstractEnforcerRule;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
 
 /**
  * Always fail. This rule is useful for testing the Enforcer configuration, or to always fail the build if a particular
  * profile is enabled.
  * @author Ben Lidgey
  */
-public class AlwaysFail extends AbstractNonCacheableEnforcerRule {
+@Named("alwaysFail")
+public final class AlwaysFail extends AbstractEnforcerRule {
+
+    private String message;
 
     @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        String message = getMessage();
+    public void execute() throws EnforcerRuleException {
 
         StringBuilder buf = new StringBuilder();
         if (message != null) {
@@ -39,4 +43,9 @@ public class AlwaysFail extends AbstractNonCacheableEnforcerRule {
         buf.append("Always fails!");
         throw new EnforcerRuleException(buf.toString());
     }
+
+    @Override
+    public String toString() {
+        return String.format("AlwaysFail[level=%s, message=%s]", getLevel(), message);
+    }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireJavaVendor.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireJavaVendor.java
similarity index 74%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireJavaVendor.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireJavaVendor.java
index 5d2d62b..805a48e 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireJavaVendor.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireJavaVendor.java
@@ -16,13 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer;
+package org.apache.maven.enforcer.rules;
+
+import javax.inject.Named;
 
 import java.util.List;
 
 import org.apache.commons.lang3.SystemUtils;
+import org.apache.maven.enforcer.rule.api.AbstractEnforcerRule;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
 
 /**
  * This rule checks that the Java vendor is allowed.
@@ -31,7 +33,8 @@ import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
  * @author Tim Sijstermans
  * @since 3.0.0
  */
-public class RequireJavaVendor extends AbstractNonCacheableEnforcerRule {
+@Named("requireJavaVendor")
+public final class RequireJavaVendor extends AbstractEnforcerRule {
     /**
      * Java vendors to include. If none is defined, all are included.
      *
@@ -43,10 +46,39 @@ public class RequireJavaVendor extends AbstractNonCacheableEnforcerRule {
      */
     private List<String> excludes;
 
+    /**
+     * A message used if the rule fails.
+     */
+    private String message;
+
+    /**
+     * The Java Vendor not changed during one Maven session,
+     * so can be cached.
+     *
+     * @return a cache id
+     */
+    @Override
+    public String getCacheId() {
+        String result = "";
+
+        if (includes != null) {
+            result += "" + includes.hashCode();
+        }
+
+        if (excludes != null) {
+            result += "" + excludes.hashCode();
+        }
+
+        if (message != null) {
+            result += "" + message.hashCode();
+        }
+
+        return result;
+    }
+
     @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
+    public void execute() throws EnforcerRuleException {
         if (excludes != null && excludes.contains(SystemUtils.JAVA_VENDOR)) {
-            String message = getMessage();
             if (message == null) {
                 message = String.format(
                         "%s is an excluded Required Java Vendor (JAVA_HOME=%s)",
@@ -54,7 +86,6 @@ public class RequireJavaVendor extends AbstractNonCacheableEnforcerRule {
             }
             throw new EnforcerRuleException(message);
         } else if (includes != null && !includes.contains(SystemUtils.JAVA_VENDOR)) {
-            String message = getMessage();
             if (message == null) {
                 message = String.format(
                         "%s is not an included Required Java Vendor (JAVA_HOME=%s)",
@@ -94,4 +125,11 @@ public class RequireJavaVendor extends AbstractNonCacheableEnforcerRule {
     public void setIncludes(List<String> theIncludes) {
         this.includes = theIncludes;
     }
+
+    @Override
+    public String toString() {
+        return String.format(
+                "RequireJavaVendor[level=%s, message=%s, includes=%s, excludes=%s]",
+                getLevel(), message, includes, excludes);
+    }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireNoRepositories.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireNoRepositories.java
similarity index 52%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireNoRepositories.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireNoRepositories.java
index 8e58777..4c63af5 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireNoRepositories.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireNoRepositories.java
@@ -16,20 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer;
+package org.apache.maven.enforcer.rules;
+
+import javax.inject.Inject;
+import javax.inject.Named;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
+import org.apache.maven.enforcer.rule.api.AbstractEnforcerRule;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.model.Model;
 import org.apache.maven.model.Repository;
-import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 import org.codehaus.plexus.util.StringUtils;
 
 /**
@@ -37,7 +39,9 @@ import org.codehaus.plexus.util.StringUtils;
  *
  * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
  */
-public class RequireNoRepositories extends AbstractNonCacheableEnforcerRule {
+@Named("requireNoRepositories")
+public final class RequireNoRepositories extends AbstractEnforcerRule {
+
     private static final String VERSION = " version:";
 
     /**
@@ -78,104 +82,105 @@ public class RequireNoRepositories extends AbstractNonCacheableEnforcerRule {
     /**
      * Whether to allow plugin repositories which only resolve snapshots. By default they are banned.
      *
-     * @see {@link #setAllowSnapshotPluginRepositories(boolean)}
+     * @see #setAllowSnapshotPluginRepositories(boolean)
      */
     private boolean allowSnapshotPluginRepositories = false;
 
-    public final void setBanRepositories(boolean banRepositories) {
+    private String message;
+
+    private final MavenSession session;
+
+    @Inject
+    public RequireNoRepositories(MavenSession session) {
+        this.session = Objects.requireNonNull(session);
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public void setBanRepositories(boolean banRepositories) {
         this.banRepositories = banRepositories;
     }
 
-    public final void setBanPluginRepositories(boolean banPluginRepositories) {
+    public void setBanPluginRepositories(boolean banPluginRepositories) {
         this.banPluginRepositories = banPluginRepositories;
     }
 
-    public final void setAllowedRepositories(List<String> allowedRepositories) {
+    public void setAllowedRepositories(List<String> allowedRepositories) {
         this.allowedRepositories = allowedRepositories;
     }
 
-    public final void setAllowedPluginRepositories(List<String> allowedPluginRepositories) {
+    public void setAllowedPluginRepositories(List<String> allowedPluginRepositories) {
         this.allowedPluginRepositories = allowedPluginRepositories;
     }
 
-    public final void setAllowSnapshotRepositories(boolean allowSnapshotRepositories) {
+    public void setAllowSnapshotRepositories(boolean allowSnapshotRepositories) {
         this.allowSnapshotRepositories = allowSnapshotRepositories;
     }
 
-    public final void setAllowSnapshotPluginRepositories(boolean allowSnapshotPluginRepositories) {
+    public void setAllowSnapshotPluginRepositories(boolean allowSnapshotPluginRepositories) {
         this.allowSnapshotPluginRepositories = allowSnapshotPluginRepositories;
     }
 
     @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        Log logger = helper.getLog();
+    public void execute() throws EnforcerRuleException {
 
-        MavenSession session;
-        try {
-            session = (MavenSession) helper.evaluate("${session}");
+        List<MavenProject> sortedProjects = session.getProjectDependencyGraph().getSortedProjects();
 
-            List<MavenProject> sortedProjects =
-                    session.getProjectDependencyGraph().getSortedProjects();
-
-            List<Model> models = new ArrayList<>();
-            for (MavenProject mavenProject : sortedProjects) {
-                logger.debug("Scanning project: " + mavenProject.getGroupId() + ":" + mavenProject.getArtifactId()
-                        + VERSION + mavenProject.getVersion());
-                models.add(mavenProject.getOriginalModel());
-            }
+        List<Model> models = new ArrayList<>();
+        for (MavenProject mavenProject : sortedProjects) {
+            getLog().debug("Scanning project: " + mavenProject.getGroupId() + ":" + mavenProject.getArtifactId()
+                    + VERSION + mavenProject.getVersion());
+            models.add(mavenProject.getOriginalModel());
+        }
 
-            List<Model> badModels = new ArrayList<>();
-
-            StringBuilder newMsg = new StringBuilder();
-            newMsg.append("Some poms have repositories defined:" + System.lineSeparator());
-
-            for (Model model : models) {
-                if (banRepositories) {
-                    List<Repository> repos = model.getRepositories();
-                    if (repos != null && !repos.isEmpty()) {
-                        List<String> bannedRepos =
-                                findBannedRepositories(repos, allowedRepositories, allowSnapshotRepositories);
-                        if (!bannedRepos.isEmpty()) {
-                            badModels.add(model);
-                            newMsg.append(model.getGroupId() + ":" + model.getArtifactId() + VERSION
-                                    + model.getVersion() + " has repositories " + bannedRepos);
-                        }
+        List<Model> badModels = new ArrayList<>();
+
+        StringBuilder newMsg = new StringBuilder();
+        newMsg.append("Some poms have repositories defined:" + System.lineSeparator());
+
+        for (Model model : models) {
+            if (banRepositories) {
+                List<Repository> repos = model.getRepositories();
+                if (repos != null && !repos.isEmpty()) {
+                    List<String> bannedRepos =
+                            findBannedRepositories(repos, allowedRepositories, allowSnapshotRepositories);
+                    if (!bannedRepos.isEmpty()) {
+                        badModels.add(model);
+                        newMsg.append(model.getGroupId() + ":" + model.getArtifactId() + VERSION + model.getVersion()
+                                + " has repositories " + bannedRepos);
                     }
                 }
-                if (banPluginRepositories) {
-                    List<Repository> repos = model.getPluginRepositories();
-                    if (repos != null && !repos.isEmpty()) {
-                        List<String> bannedRepos = findBannedRepositories(
-                                repos, allowedPluginRepositories, allowSnapshotPluginRepositories);
-                        if (!bannedRepos.isEmpty()) {
-                            badModels.add(model);
-                            newMsg.append(model.getGroupId() + ":" + model.getArtifactId() + VERSION
-                                    + model.getVersion() + " has plugin repositories " + bannedRepos);
-                        }
+            }
+            if (banPluginRepositories) {
+                List<Repository> repos = model.getPluginRepositories();
+                if (repos != null && !repos.isEmpty()) {
+                    List<String> bannedRepos =
+                            findBannedRepositories(repos, allowedPluginRepositories, allowSnapshotPluginRepositories);
+                    if (!bannedRepos.isEmpty()) {
+                        badModels.add(model);
+                        newMsg.append(model.getGroupId() + ":" + model.getArtifactId() + VERSION + model.getVersion()
+                                + " has plugin repositories " + bannedRepos);
                     }
                 }
             }
+        }
 
-            // if anything was found, log it then append the
-            // optional message.
-            if (!badModels.isEmpty()) {
-                String message = getMessage();
-                if (StringUtils.isNotEmpty(message)) {
-                    newMsg.append(message);
-                }
-
-                throw new EnforcerRuleException(newMsg.toString());
+        // if anything was found, log it then append the
+        // optional message.
+        if (!badModels.isEmpty()) {
+            if (StringUtils.isNotEmpty(message)) {
+                newMsg.append(message);
             }
 
-        } catch (ExpressionEvaluationException e) {
-            throw new EnforcerRuleException(e.getLocalizedMessage());
+            throw new EnforcerRuleException(newMsg.toString());
         }
     }
 
     /**
-     *
-     * @param repos all repositories, never {@code null}
-     * @param allowedRepos allowed repositories, never {@code null}
+     * @param repos          all repositories, never {@code null}
+     * @param allowedRepos   allowed repositories, never {@code null}
      * @param allowSnapshots
      * @return List of banned repositoreis.
      */
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/ArtifactMatcher.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/ArtifactMatcher.java
similarity index 99%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/ArtifactMatcher.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/ArtifactMatcher.java
index c3e8653..8e20d1b 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/ArtifactMatcher.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/ArtifactMatcher.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.utils;
+package org.apache.maven.enforcer.rules.utils;
 
 import java.util.Collection;
 import java.util.HashSet;
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/ArtifactUtils.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/ArtifactUtils.java
similarity index 98%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/ArtifactUtils.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/ArtifactUtils.java
index c5c09bd..68164d3 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/ArtifactUtils.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/ArtifactUtils.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.utils;
+package org.apache.maven.enforcer.rules.utils;
 
 import java.util.Collection;
 import java.util.HashSet;
@@ -31,7 +31,6 @@ import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.plugins.enforcer.utils.ArtifactMatcher.Pattern;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
@@ -203,6 +202,6 @@ public final class ArtifactUtils {
      * @return <code>true</code> if the artifact matches one of the patterns
      */
     static boolean compareDependency(String pattern, Artifact artifact) {
-        return new Pattern(pattern).match(artifact);
+        return new ArtifactMatcher.Pattern(pattern).match(artifact);
     }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/DependencyVersionMap.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/DependencyVersionMap.java
similarity index 99%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/DependencyVersionMap.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/DependencyVersionMap.java
index 5f3ce3b..01567fc 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/DependencyVersionMap.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/DependencyVersionMap.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.utils;
+package org.apache.maven.enforcer.rules.utils;
 
 import java.util.ArrayList;
 import java.util.HashMap;
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/DistributionManagementCheck.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/DistributionManagementCheck.java
similarity index 98%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/DistributionManagementCheck.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/DistributionManagementCheck.java
index abaf583..e294215 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/DistributionManagementCheck.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/DistributionManagementCheck.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.utils;
+package org.apache.maven.enforcer.rules.utils;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.model.DistributionManagement;
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/EnforcerRuleUtils.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/EnforcerRuleUtils.java
similarity index 98%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/EnforcerRuleUtils.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/EnforcerRuleUtils.java
index 2283924..add55e1 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/EnforcerRuleUtils.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/EnforcerRuleUtils.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.utils;
+package org.apache.maven.enforcer.rules.utils;
 
 import java.util.List;
 
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/NormalizeLineSeparatorReader.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/NormalizeLineSeparatorReader.java
similarity index 99%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/NormalizeLineSeparatorReader.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/NormalizeLineSeparatorReader.java
index 50fbe02..ef7ef25 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/NormalizeLineSeparatorReader.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/NormalizeLineSeparatorReader.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.utils;
+package org.apache.maven.enforcer.rules.utils;
 
 import java.io.FilterReader;
 import java.io.IOException;
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/ParentNodeProvider.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/ParentNodeProvider.java
similarity index 96%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/ParentNodeProvider.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/ParentNodeProvider.java
index 0edecfa..e99c051 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/ParentNodeProvider.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/ParentNodeProvider.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.utils;
+package org.apache.maven.enforcer.rules.utils;
 
 import org.eclipse.aether.graph.DependencyNode;
 
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/ParentsVisitor.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/ParentsVisitor.java
similarity index 97%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/ParentsVisitor.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/ParentsVisitor.java
index 0e9bd9e..f2a39bb 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/ParentsVisitor.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/ParentsVisitor.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.utils;
+package org.apache.maven.enforcer.rules.utils;
 
 import java.util.HashMap;
 import java.util.Map;
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/PluginWrapper.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/PluginWrapper.java
similarity index 99%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/PluginWrapper.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/PluginWrapper.java
index e1d8e51..18103fd 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/PluginWrapper.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/PluginWrapper.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.utils;
+package org.apache.maven.enforcer.rules.utils;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/AbstractBanDependencies.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/AbstractBanDependencies.java
index 5e5461f..3910f6a 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/AbstractBanDependencies.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/AbstractBanDependencies.java
@@ -23,9 +23,9 @@ import java.util.Set;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.enforcer.rules.utils.ArtifactUtils;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.plugins.enforcer.utils.ArtifactUtils;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 
 /**
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDependencyManagementScope.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDependencyManagementScope.java
index 7507f24..2b3dd87 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDependencyManagementScope.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDependencyManagementScope.java
@@ -25,10 +25,10 @@ import java.util.List;
 import org.apache.maven.enforcer.rule.api.EnforcerRule2;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.enforcer.rules.utils.ArtifactMatcher;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.model.DependencyManagement;
 import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.plugins.enforcer.utils.ArtifactMatcher;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDistributionManagement.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDistributionManagement.java
index ee6027a..96df784 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDistributionManagement.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDistributionManagement.java
@@ -20,8 +20,8 @@ package org.apache.maven.plugins.enforcer;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.enforcer.rules.utils.DistributionManagementCheck;
 import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.plugins.enforcer.utils.DistributionManagementCheck;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDynamicVersions.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDynamicVersions.java
index 8dadd4c..aa684c0 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDynamicVersions.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDynamicVersions.java
@@ -32,9 +32,9 @@ import java.util.stream.Collectors;
 import org.apache.maven.RepositoryUtils;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.enforcer.rules.utils.ArtifactMatcher;
+import org.apache.maven.enforcer.rules.utils.ArtifactUtils;
 import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.plugins.enforcer.utils.ArtifactMatcher;
-import org.apache.maven.plugins.enforcer.utils.ArtifactUtils;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.shared.utils.logging.MessageBuilder;
 import org.apache.maven.shared.utils.logging.MessageUtils;
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanTransitiveDependencies.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanTransitiveDependencies.java
index 50beb20..7d96582 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanTransitiveDependencies.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanTransitiveDependencies.java
@@ -27,9 +27,9 @@ import org.apache.maven.RepositoryUtils;
 import org.apache.maven.enforcer.rule.api.EnforcerRule;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.enforcer.rules.utils.ArtifactMatcher;
+import org.apache.maven.enforcer.rules.utils.ArtifactUtils;
 import org.apache.maven.execution.MavenSession;
-import org.apache.maven.plugins.enforcer.utils.ArtifactMatcher;
-import org.apache.maven.plugins.enforcer.utils.ArtifactUtils;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 import org.eclipse.aether.artifact.ArtifactTypeRegistry;
 import org.eclipse.aether.graph.Dependency;
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedDependencies.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedDependencies.java
index e65464e..6d6596d 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedDependencies.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedDependencies.java
@@ -19,7 +19,7 @@
 package org.apache.maven.plugins.enforcer;
 
 import org.apache.maven.artifact.Artifact;
-import org.apache.maven.plugins.enforcer.utils.ArtifactUtils;
+import org.apache.maven.enforcer.rules.utils.ArtifactUtils;
 
 /**
  * This rule checks that lists of dependencies are not included.
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedDependenciesBase.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedDependenciesBase.java
index db16b61..e7776ac 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedDependenciesBase.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedDependenciesBase.java
@@ -24,8 +24,8 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.enforcer.rules.utils.ArtifactUtils;
 import org.apache.maven.execution.MavenSession;
-import org.apache.maven.plugins.enforcer.utils.ArtifactUtils;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 import org.eclipse.aether.graph.DependencyNode;
 
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedPlugins.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedPlugins.java
index 03deb7c..73db174 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedPlugins.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedPlugins.java
@@ -21,8 +21,8 @@ package org.apache.maven.plugins.enforcer;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.enforcer.rules.utils.ArtifactUtils;
 import org.apache.maven.execution.MavenSession;
-import org.apache.maven.plugins.enforcer.utils.ArtifactUtils;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 
 /**
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/DependencyConvergence.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/DependencyConvergence.java
index 1214930..7d8503b 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/DependencyConvergence.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/DependencyConvergence.java
@@ -25,9 +25,9 @@ import java.util.List;
 import org.apache.maven.enforcer.rule.api.EnforcerRule;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.enforcer.rules.utils.ArtifactUtils;
+import org.apache.maven.enforcer.rules.utils.DependencyVersionMap;
 import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.plugins.enforcer.utils.ArtifactUtils;
-import org.apache.maven.plugins.enforcer.utils.DependencyVersionMap;
 import org.eclipse.aether.collection.DependencyCollectionContext;
 import org.eclipse.aether.collection.DependencySelector;
 import org.eclipse.aether.graph.Dependency;
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequirePluginVersions.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequirePluginVersions.java
index 429adce..eb75161 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequirePluginVersions.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequirePluginVersions.java
@@ -37,6 +37,8 @@ import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException
 import org.apache.maven.artifact.versioning.VersionRange;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.enforcer.rules.utils.EnforcerRuleUtils;
+import org.apache.maven.enforcer.rules.utils.PluginWrapper;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.lifecycle.DefaultLifecycles;
 import org.apache.maven.lifecycle.Lifecycle;
@@ -56,8 +58,6 @@ import org.apache.maven.plugin.descriptor.PluginDescriptor;
 import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.plugin.version.PluginVersionNotFoundException;
 import org.apache.maven.plugin.version.PluginVersionResolutionException;
-import org.apache.maven.plugins.enforcer.utils.EnforcerRuleUtils;
-import org.apache.maven.plugins.enforcer.utils.PluginWrapper;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.rtinfo.RuntimeInformation;
 import org.apache.maven.settings.Settings;
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireReleaseDeps.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireReleaseDeps.java
index f78ff3a..3875a7d 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireReleaseDeps.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireReleaseDeps.java
@@ -24,12 +24,12 @@ import java.util.Set;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
-import org.apache.maven.plugins.enforcer.utils.ArtifactUtils;
+import org.apache.maven.enforcer.rules.utils.ArtifactUtils;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 
 import static java.util.Optional.ofNullable;
-import static org.apache.maven.plugins.enforcer.utils.ArtifactUtils.matchDependencyArtifact;
+import static org.apache.maven.enforcer.rules.utils.ArtifactUtils.matchDependencyArtifact;
 
 /**
  * This rule checks that no snapshots are included.
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireTextFileChecksum.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireTextFileChecksum.java
index 7d3a31e..17dfcd2 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireTextFileChecksum.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireTextFileChecksum.java
@@ -28,8 +28,8 @@ import org.apache.commons.io.input.ReaderInputStream;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
-import org.apache.maven.plugins.enforcer.utils.NormalizeLineSeparatorReader;
-import org.apache.maven.plugins.enforcer.utils.NormalizeLineSeparatorReader.LineSeparator;
+import org.apache.maven.enforcer.rules.utils.NormalizeLineSeparatorReader;
+import org.apache.maven.enforcer.rules.utils.NormalizeLineSeparatorReader.LineSeparator;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 
 /**
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireUpperBoundDeps.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireUpperBoundDeps.java
index 9369743..acbcec6 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireUpperBoundDeps.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireUpperBoundDeps.java
@@ -30,10 +30,10 @@ import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
 import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.enforcer.rules.utils.ArtifactUtils;
+import org.apache.maven.enforcer.rules.utils.ParentNodeProvider;
+import org.apache.maven.enforcer.rules.utils.ParentsVisitor;
 import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.plugins.enforcer.utils.ArtifactUtils;
-import org.apache.maven.plugins.enforcer.utils.ParentNodeProvider;
-import org.apache.maven.plugins.enforcer.utils.ParentsVisitor;
 import org.apache.maven.shared.utils.logging.MessageUtils;
 import org.eclipse.aether.graph.DependencyNode;
 import org.eclipse.aether.graph.DependencyVisitor;
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestAlwaysFail.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestAlwaysFail.java
similarity index 93%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestAlwaysFail.java
rename to enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestAlwaysFail.java
index f458dc3..6f2d245 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestAlwaysFail.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestAlwaysFail.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer;
+package org.apache.maven.enforcer.rules;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.junit.jupiter.api.Test;
@@ -36,7 +36,7 @@ public class TestAlwaysFail {
         final AlwaysFail rule = new AlwaysFail();
         try {
             // execute rule -- should throw EnforcerRuleException
-            rule.execute(EnforcerTestUtils.getHelper());
+            rule.execute();
             fail("Should throw EnforcerRuleException");
         } catch (EnforcerRuleException e) {
             assertNotNull(e.getMessage());
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireJavaVendor.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestRequireJavaVendor.java
similarity index 73%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireJavaVendor.java
rename to enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestRequireJavaVendor.java
index c4153dd..4c2f733 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireJavaVendor.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestRequireJavaVendor.java
@@ -16,17 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer;
+package org.apache.maven.enforcer.rules;
 
 import java.util.Arrays;
 import java.util.Collections;
 
 import org.apache.commons.lang3.SystemUtils;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
+import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 /**
@@ -48,18 +48,16 @@ class TestRequireJavaVendor {
     void matchingInclude() throws EnforcerRuleException {
         // Set the required vendor to the current system vendor
         underTest.setIncludes(Collections.singletonList(SystemUtils.JAVA_VENDOR));
-        final EnforcerRuleHelper helper = EnforcerTestUtils.getHelper();
-        underTest.execute(helper);
-        // No assert and no expected exception because this test should not fail
+
+        assertThatCode(() -> underTest.execute()).doesNotThrowAnyException();
     }
 
     @Test
     void nonMatchingInclude() {
         // Set the included vendor to something irrelevant
         underTest.setIncludes(Collections.singletonList(NON_MATCHING_VENDOR));
-        final EnforcerRuleHelper helper = EnforcerTestUtils.getHelper();
 
-        assertThatThrownBy(() -> underTest.execute(helper))
+        assertThatThrownBy(() -> underTest.execute())
                 .isInstanceOf(EnforcerRuleException.class)
                 .hasMessage(
                         "%s is not an included Required Java Vendor (JAVA_HOME=%s)",
@@ -70,9 +68,8 @@ class TestRequireJavaVendor {
     void matchingExclude() {
         // Set the excluded vendor to current vendor name
         underTest.setExcludes(Collections.singletonList(SystemUtils.JAVA_VENDOR));
-        final EnforcerRuleHelper helper = EnforcerTestUtils.getHelper();
 
-        assertThatThrownBy(() -> underTest.execute(helper))
+        assertThatThrownBy(() -> underTest.execute())
                 .isInstanceOf(EnforcerRuleException.class)
                 .hasMessage(
                         "%s is an excluded Required Java Vendor (JAVA_HOME=%s)",
@@ -83,18 +80,16 @@ class TestRequireJavaVendor {
     void nonMatchingExclude() throws EnforcerRuleException {
         // Set the excluded vendor to something nonsensical
         underTest.setExcludes(Collections.singletonList(NON_MATCHING_VENDOR));
-        final EnforcerRuleHelper helper = EnforcerTestUtils.getHelper();
-        underTest.execute(helper);
-        // No assert and no expected exception because this test should not fail
+
+        assertThatCode(() -> underTest.execute()).doesNotThrowAnyException();
     }
 
     @Test
     void matchingIncludeAndMatchingExclude() {
         underTest.setExcludes(Collections.singletonList(SystemUtils.JAVA_VENDOR));
         underTest.setIncludes(Collections.singletonList(SystemUtils.JAVA_VENDOR));
-        final EnforcerRuleHelper helper = EnforcerTestUtils.getHelper();
 
-        assertThatThrownBy(() -> underTest.execute(helper))
+        assertThatThrownBy(() -> underTest.execute())
                 .isInstanceOf(EnforcerRuleException.class)
                 .hasMessage(
                         "%s is an excluded Required Java Vendor (JAVA_HOME=%s)",
@@ -105,9 +100,8 @@ class TestRequireJavaVendor {
     void matchAnyExclude() {
         // Set a bunch of excluded vendors
         underTest.setExcludes(Arrays.asList(SystemUtils.JAVA_VENDOR, SystemUtils.JAVA_VENDOR + "modified"));
-        final EnforcerRuleHelper helper = EnforcerTestUtils.getHelper();
 
-        assertThatThrownBy(() -> underTest.execute(helper))
+        assertThatThrownBy(() -> underTest.execute())
                 .isInstanceOf(EnforcerRuleException.class)
                 .hasMessage(
                         "%s is an excluded Required Java Vendor (JAVA_HOME=%s)",
@@ -118,15 +112,13 @@ class TestRequireJavaVendor {
     void matchAnyInclude() throws EnforcerRuleException {
         // Set a bunch of included vendors
         underTest.setIncludes(Arrays.asList(SystemUtils.JAVA_VENDOR, SystemUtils.JAVA_VENDOR + "modified"));
-        final EnforcerRuleHelper helper = EnforcerTestUtils.getHelper();
-        underTest.execute(helper);
-        // No assert and no expected exception because this test should not fail
+
+        assertThatCode(() -> underTest.execute()).doesNotThrowAnyException();
     }
 
     @Test
     void defaultRule() throws EnforcerRuleException {
-        final EnforcerRuleHelper helper = EnforcerTestUtils.getHelper();
-        underTest.execute(helper);
-        // No assert and no expected exception because this test should not fail
+
+        assertThatCode(() -> underTest.execute()).doesNotThrowAnyException();
     }
 }
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireNoRepositories.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestRequireNoRepositories.java
similarity index 93%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireNoRepositories.java
rename to enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestRequireNoRepositories.java
index 260e691..ca8cc70 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireNoRepositories.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestRequireNoRepositories.java
@@ -16,20 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer;
+package org.apache.maven.enforcer.rules;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.maven.enforcer.rule.api.EnforcerLogger;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.execution.ProjectDependencyGraph;
 import org.apache.maven.model.Model;
 import org.apache.maven.model.Repository;
 import org.apache.maven.model.RepositoryPolicy;
-import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 import org.junit.jupiter.api.BeforeEach;
@@ -46,7 +45,6 @@ import static org.mockito.Mockito.when;
  * @author <a href="mailto:khmarbaise@apache.org">Karl Heinz Marbaise</a>
  */
 public class TestRequireNoRepositories {
-    private EnforcerRuleHelper helper;
 
     private RequireNoRepositories rule;
 
@@ -55,15 +53,10 @@ public class TestRequireNoRepositories {
     @BeforeEach
     public void before() throws ExpressionEvaluationException {
         session = mock(MavenSession.class);
-        helper = mock(EnforcerRuleHelper.class);
 
-        when(helper.evaluate("${session}")).thenReturn(session);
-
-        Log log = mock(Log.class);
-        when(helper.getLog()).thenReturn(log);
-
-        rule = new RequireNoRepositories();
+        rule = new RequireNoRepositories(session);
         rule.setMessage("my message");
+        rule.setLog(mock(EnforcerLogger.class));
     }
 
     private MavenProject createMavenProject() {
@@ -171,7 +164,7 @@ public class TestRequireNoRepositories {
         MavenProject baseProject = createStandAloneProject();
         setupSortedProjects(Collections.singletonList(baseProject));
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     /**
@@ -184,7 +177,7 @@ public class TestRequireNoRepositories {
             addRepository(baseProject, createRepository("repo", "http://example.com/repo"));
             setupSortedProjects(Collections.singletonList(baseProject));
 
-            rule.execute(helper);
+            rule.execute();
         });
     }
 
@@ -198,7 +191,7 @@ public class TestRequireNoRepositories {
             addPluginRepository(baseProject, createRepository("repo", "http://example.com/repo"));
             setupSortedProjects(Collections.singletonList(baseProject));
 
-            rule.execute(helper);
+            rule.execute();
         });
     }
 
@@ -214,7 +207,7 @@ public class TestRequireNoRepositories {
         addRepository(baseProject, createRepository(repositoryId, "http://example.com/repo"));
         setupSortedProjects(Collections.singletonList(baseProject));
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     /**
@@ -230,7 +223,7 @@ public class TestRequireNoRepositories {
         addRepository(baseProject, createRepository(repositoryId, "http://example.com/repo"));
         setupSortedProjects(Collections.singletonList(baseProject));
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     /**
@@ -243,7 +236,7 @@ public class TestRequireNoRepositories {
         MavenProject baseProject = createStandAloneProject();
         setupSortedProjects(Collections.singletonList(baseProject));
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     /**
@@ -259,7 +252,7 @@ public class TestRequireNoRepositories {
         addPluginRepository(baseProject, createRepository(repositoryId, "http://example.com/repo"));
         setupSortedProjects(Collections.singletonList(baseProject));
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     /**
@@ -275,7 +268,7 @@ public class TestRequireNoRepositories {
         addPluginRepository(baseProject, createRepository(repositoryId, "http://example.com/repo"));
         setupSortedProjects(Collections.singletonList(baseProject));
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     /**
@@ -288,7 +281,7 @@ public class TestRequireNoRepositories {
         MavenProject baseProject = createStandAloneProject();
         setupSortedProjects(Collections.singletonList(baseProject));
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
@@ -298,7 +291,7 @@ public class TestRequireNoRepositories {
             addRepository(baseProject, createSnapshotRepository("repo", "http://example.com/repo"));
             setupSortedProjects(Collections.singletonList(baseProject));
 
-            rule.execute(helper);
+            rule.execute();
         });
     }
 
@@ -311,7 +304,7 @@ public class TestRequireNoRepositories {
         addRepository(baseProject, createSnapshotRepository(repositoryId, "http://example.com/repo"));
         setupSortedProjects(Collections.singletonList(baseProject));
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
@@ -323,7 +316,7 @@ public class TestRequireNoRepositories {
         addRepository(baseProject, createSnapshotRepository(repositoryId, "http://example.com/repo"));
         setupSortedProjects(Collections.singletonList(baseProject));
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
@@ -336,7 +329,7 @@ public class TestRequireNoRepositories {
         addPluginRepository(baseProject, createSnapshotRepository(repositoryId, "http://example.com/repo"));
         setupSortedProjects(Collections.singletonList(baseProject));
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
@@ -345,7 +338,7 @@ public class TestRequireNoRepositories {
         addEmptyRepository(baseProject);
         setupSortedProjects(Collections.singletonList(baseProject));
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
@@ -354,6 +347,6 @@ public class TestRequireNoRepositories {
         addEmptyPluginRepository(baseProject);
         setupSortedProjects(Collections.singletonList(baseProject));
 
-        rule.execute(helper);
+        rule.execute();
     }
 }
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/DependencyNodeBuilder.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/DependencyNodeBuilder.java
similarity index 98%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/DependencyNodeBuilder.java
rename to enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/DependencyNodeBuilder.java
index 4079523..fb3940a 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/DependencyNodeBuilder.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/DependencyNodeBuilder.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.utils;
+package org.apache.maven.enforcer.rules.utils;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/EnforcerRuleUtilsHelper.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/EnforcerRuleUtilsHelper.java
similarity index 97%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/EnforcerRuleUtilsHelper.java
rename to enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/EnforcerRuleUtilsHelper.java
index 207e4a7..e03ce1a 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/EnforcerRuleUtilsHelper.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/EnforcerRuleUtilsHelper.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.utils;
+package org.apache.maven.enforcer.rules.utils;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRule;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/MockEnforcerExpressionEvaluator.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/MockEnforcerExpressionEvaluator.java
similarity index 97%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/MockEnforcerExpressionEvaluator.java
rename to enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/MockEnforcerExpressionEvaluator.java
index 893ca70..80f47bf 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/MockEnforcerExpressionEvaluator.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/MockEnforcerExpressionEvaluator.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.utils;
+package org.apache.maven.enforcer.rules.utils;
 
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.plugin.MojoExecution;
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/TestArtifactMatcher.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/TestArtifactMatcher.java
similarity index 98%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/TestArtifactMatcher.java
rename to enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/TestArtifactMatcher.java
index ffdc9df..4f67e43 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/TestArtifactMatcher.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/TestArtifactMatcher.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.utils;
+package org.apache.maven.enforcer.rules.utils;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -27,7 +27,7 @@ import org.apache.maven.artifact.handler.ArtifactHandler;
 import org.apache.maven.artifact.handler.DefaultArtifactHandler;
 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
 import org.apache.maven.artifact.versioning.VersionRange;
-import org.apache.maven.plugins.enforcer.utils.ArtifactMatcher.Pattern;
+import org.apache.maven.enforcer.rules.utils.ArtifactMatcher.Pattern;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/TestMockEnforcerExpressionEvaluator.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/TestMockEnforcerExpressionEvaluator.java
similarity index 97%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/TestMockEnforcerExpressionEvaluator.java
rename to enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/TestMockEnforcerExpressionEvaluator.java
index 4a9feff..7894b25 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/TestMockEnforcerExpressionEvaluator.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/TestMockEnforcerExpressionEvaluator.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.utils;
+package org.apache.maven.enforcer.rules.utils;
 
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/TestNormalizeLineSeparatorReader.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/TestNormalizeLineSeparatorReader.java
similarity index 94%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/TestNormalizeLineSeparatorReader.java
rename to enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/TestNormalizeLineSeparatorReader.java
index 30e462c..1ebfd0a 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/utils/TestNormalizeLineSeparatorReader.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/utils/TestNormalizeLineSeparatorReader.java
@@ -16,14 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer.utils;
+package org.apache.maven.enforcer.rules.utils;
 
 import java.io.IOException;
 import java.io.Reader;
 import java.io.StringReader;
 
 import org.apache.commons.io.IOUtils;
-import org.apache.maven.plugins.enforcer.utils.NormalizeLineSeparatorReader.LineSeparator;
+import org.apache.maven.enforcer.rules.utils.NormalizeLineSeparatorReader.LineSeparator;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/EnforcerTestUtils.java b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/EnforcerTestUtils.java
index c1ef1e2..aa3d26d 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/EnforcerTestUtils.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/EnforcerTestUtils.java
@@ -21,6 +21,8 @@ package org.apache.maven.plugins.enforcer;
 import java.util.Properties;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.enforcer.rules.utils.DependencyNodeBuilder;
+import org.apache.maven.enforcer.rules.utils.MockEnforcerExpressionEvaluator;
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenExecutionResult;
 import org.apache.maven.execution.MavenSession;
@@ -31,8 +33,6 @@ import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.logging.SystemStreamLog;
-import org.apache.maven.plugins.enforcer.utils.DependencyNodeBuilder;
-import org.apache.maven.plugins.enforcer.utils.MockEnforcerExpressionEvaluator;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.ProjectBuildingRequest;
 import org.codehaus.plexus.PlexusContainer;
@@ -58,7 +58,6 @@ import static org.mockito.Mockito.when;
 public final class EnforcerTestUtils {
 
     private static RepositorySystem REPOSITORY_SYSTEM = mock(RepositorySystem.class);
-    ;
 
     /**
      * Gets the maven session.
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/RequireUpperBoundDepsTest.java b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/RequireUpperBoundDepsTest.java
index ef2a11d..59be79b 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/RequireUpperBoundDepsTest.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/RequireUpperBoundDepsTest.java
@@ -20,7 +20,7 @@ package org.apache.maven.plugins.enforcer;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
-import org.apache.maven.plugins.enforcer.utils.DependencyNodeBuilder;
+import org.apache.maven.enforcer.rules.utils.DependencyNodeBuilder;
 import org.junit.jupiter.api.Test;
 
 import static org.hamcrest.MatcherAssert.assertThat;
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestBannedDependencies.java b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestBannedDependencies.java
index c766334..069fb32 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestBannedDependencies.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestBannedDependencies.java
@@ -21,7 +21,7 @@ package org.apache.maven.plugins.enforcer;
 import java.io.IOException;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.plugins.enforcer.utils.DependencyNodeBuilder;
+import org.apache.maven.enforcer.rules.utils.DependencyNodeBuilder;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequirePluginVersions.java b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequirePluginVersions.java
index 4fa906f..c1bd3f1 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequirePluginVersions.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequirePluginVersions.java
@@ -25,9 +25,9 @@ import java.util.List;
 import java.util.Set;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.enforcer.rules.utils.PluginWrapper;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugins.enforcer.utils.PluginWrapper;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.*;
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireReleaseDeps.java b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireReleaseDeps.java
index 3be6b31..41569e1 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireReleaseDeps.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireReleaseDeps.java
@@ -22,8 +22,8 @@ import java.io.IOException;
 import java.util.Collections;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.enforcer.rules.utils.EnforcerRuleUtilsHelper;
 import org.apache.maven.plugin.testing.ArtifactStubFactory;
-import org.apache.maven.plugins.enforcer.utils.EnforcerRuleUtilsHelper;
 import org.apache.maven.project.MavenProject;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireReleaseVersion.java b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireReleaseVersion.java
index e6e3117..bf8da0b 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireReleaseVersion.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireReleaseVersion.java
@@ -22,8 +22,8 @@ import java.io.IOException;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRule;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.enforcer.rules.utils.EnforcerRuleUtilsHelper;
 import org.apache.maven.plugin.testing.ArtifactStubFactory;
-import org.apache.maven.plugins.enforcer.utils.EnforcerRuleUtilsHelper;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireSnapshotVersion.java b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireSnapshotVersion.java
index f780a5f..1da0d7b 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireSnapshotVersion.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireSnapshotVersion.java
@@ -21,8 +21,8 @@ package org.apache.maven.plugins.enforcer;
 import java.io.IOException;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.enforcer.rules.utils.EnforcerRuleUtilsHelper;
 import org.apache.maven.plugin.testing.ArtifactStubFactory;
-import org.apache.maven.plugins.enforcer.utils.EnforcerRuleUtilsHelper;
 import org.apache.maven.project.MavenProject;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireTextFileChecksum.java b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireTextFileChecksum.java
index b1031bd..4d7fb16 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireTextFileChecksum.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireTextFileChecksum.java
@@ -24,7 +24,7 @@ import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.plugins.enforcer.utils.NormalizeLineSeparatorReader.LineSeparator;
+import org.apache.maven.enforcer.rules.utils.NormalizeLineSeparatorReader.LineSeparator;
 import org.codehaus.plexus.util.FileUtils;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
diff --git a/maven-enforcer-plugin/pom.xml b/maven-enforcer-plugin/pom.xml
index dffedf4..8feed4e 100644
--- a/maven-enforcer-plugin/pom.xml
+++ b/maven-enforcer-plugin/pom.xml
@@ -52,6 +52,12 @@
       <artifactId>maven-plugin-annotations</artifactId>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <version>1.7.36</version>
+      <scope>provided</scope>
+    </dependency>
 
     <dependency>
       <groupId>org.apache.maven.enforcer</groupId>
@@ -62,11 +68,6 @@
       <artifactId>enforcer-rules</artifactId>
     </dependency>
 
-    <dependency>
-      <groupId>org.apache.maven.enforcer</groupId>
-      <artifactId>enforcer-rules</artifactId>
-      <type>test-jar</type>
-    </dependency>
     <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-junit-jupiter</artifactId>
diff --git a/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy b/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy
index c05c677..4b5d6c4 100644
--- a/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy
@@ -17,7 +17,7 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[WARNING] Rule 0: org.apache.maven.plugins.enforcer.AlwaysFail warned with message:' )
+assert buildLog.text.contains( '[WARNING] Rule 0: org.apache.maven.enforcer.rules.AlwaysFail warned with message:' )
 
 
  
\ No newline at end of file
diff --git a/maven-enforcer-plugin/src/it/projects/always-fail/pom.xml b/maven-enforcer-plugin/src/it/projects/always-fail/pom.xml
index 53c77c8..89127c3 100644
--- a/maven-enforcer-plugin/src/it/projects/always-fail/pom.xml
+++ b/maven-enforcer-plugin/src/it/projects/always-fail/pom.xml
@@ -43,7 +43,9 @@ under the License.
             </goals>
             <configuration>
               <rules>
-                <AlwaysFail/>
+                <alwaysFail>
+                  <message>alwaysFail test message</message>
+                </alwaysFail>
               </rules>
             </configuration>
           </execution>
diff --git a/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy b/maven-enforcer-plugin/src/it/projects/always-fail/verify.groovy
similarity index 83%
copy from maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy
copy to maven-enforcer-plugin/src/it/projects/always-fail/verify.groovy
index c05c677..3656737 100644
--- a/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/always-fail/verify.groovy
@@ -17,7 +17,8 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[WARNING] Rule 0: org.apache.maven.plugins.enforcer.AlwaysFail warned with message:' )
+assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.AlwaysFail failed with message:' )
+assert buildLog.text.contains( 'alwaysFail test message' )
 
 
  
\ No newline at end of file
diff --git a/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy b/maven-enforcer-plugin/src/it/projects/always-pass/verify.groovy
similarity index 87%
copy from maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy
copy to maven-enforcer-plugin/src/it/projects/always-pass/verify.groovy
index c05c677..4079a1c 100644
--- a/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/always-pass/verify.groovy
@@ -17,7 +17,7 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[WARNING] Rule 0: org.apache.maven.plugins.enforcer.AlwaysFail warned with message:' )
+assert buildLog.text.contains( '[INFO] Rule 0: org.apache.maven.plugins.enforcer.AlwaysPass executed' )
 
 
  
\ No newline at end of file
diff --git a/maven-enforcer-plugin/src/it/projects/require-java-vendor-multi-module/invoker.properties b/maven-enforcer-plugin/src/it/projects/require-java-vendor-multi-module/invoker.properties
new file mode 100644
index 0000000..2dca44c
--- /dev/null
+++ b/maven-enforcer-plugin/src/it/projects/require-java-vendor-multi-module/invoker.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+invoker.goals = -T3 verify
\ No newline at end of file
diff --git a/maven-enforcer-plugin/src/it/projects/always-fail/pom.xml b/maven-enforcer-plugin/src/it/projects/require-java-vendor-multi-module/mod1/pom.xml
similarity index 55%
copy from maven-enforcer-plugin/src/it/projects/always-fail/pom.xml
copy to maven-enforcer-plugin/src/it/projects/require-java-vendor-multi-module/mod1/pom.xml
index 53c77c8..0888298 100644
--- a/maven-enforcer-plugin/src/it/projects/always-fail/pom.xml
+++ b/maven-enforcer-plugin/src/it/projects/require-java-vendor-multi-module/mod1/pom.xml
@@ -22,33 +22,12 @@ under the License.
 <project>
   <modelVersion>4.0.0</modelVersion>
 
-  <groupId>org.apache.maven.its.enforcer</groupId>
-  <artifactId>test</artifactId>
-  <version>1.0</version>
+  <parent>
+  	<groupId>org.apache.maven.its.enforcer</groupId>
+    <artifactId>test-multimodule-project</artifactId>
+    <version>1.0</version>
+  </parent>
 
-  <description>
-  </description>
+  <artifactId>test-multimodule-mod1</artifactId>
 
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-enforcer-plugin</artifactId>
-        <version>@project.version@</version>
-        <executions>
-          <execution>
-            <id>test</id>
-            <goals>
-              <goal>enforce</goal>
-            </goals>
-            <configuration>
-              <rules>
-                <AlwaysFail/>
-              </rules>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
 </project>
diff --git a/maven-enforcer-plugin/src/it/projects/always-fail/pom.xml b/maven-enforcer-plugin/src/it/projects/require-java-vendor-multi-module/mod2/pom.xml
similarity index 55%
copy from maven-enforcer-plugin/src/it/projects/always-fail/pom.xml
copy to maven-enforcer-plugin/src/it/projects/require-java-vendor-multi-module/mod2/pom.xml
index 53c77c8..64dbbc9 100644
--- a/maven-enforcer-plugin/src/it/projects/always-fail/pom.xml
+++ b/maven-enforcer-plugin/src/it/projects/require-java-vendor-multi-module/mod2/pom.xml
@@ -22,33 +22,12 @@ under the License.
 <project>
   <modelVersion>4.0.0</modelVersion>
 
-  <groupId>org.apache.maven.its.enforcer</groupId>
-  <artifactId>test</artifactId>
-  <version>1.0</version>
+  <parent>
+  	<groupId>org.apache.maven.its.enforcer</groupId>
+    <artifactId>test-multimodule-project</artifactId>
+    <version>1.0</version>
+  </parent>
 
-  <description>
-  </description>
+  <artifactId>test-multimodule-mod2</artifactId>
 
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-enforcer-plugin</artifactId>
-        <version>@project.version@</version>
-        <executions>
-          <execution>
-            <id>test</id>
-            <goals>
-              <goal>enforce</goal>
-            </goals>
-            <configuration>
-              <rules>
-                <AlwaysFail/>
-              </rules>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
 </project>
diff --git a/maven-enforcer-plugin/src/it/projects/always-fail/pom.xml b/maven-enforcer-plugin/src/it/projects/require-java-vendor-multi-module/pom.xml
similarity index 81%
copy from maven-enforcer-plugin/src/it/projects/always-fail/pom.xml
copy to maven-enforcer-plugin/src/it/projects/require-java-vendor-multi-module/pom.xml
index 53c77c8..10061ce 100644
--- a/maven-enforcer-plugin/src/it/projects/always-fail/pom.xml
+++ b/maven-enforcer-plugin/src/it/projects/require-java-vendor-multi-module/pom.xml
@@ -23,12 +23,18 @@ under the License.
   <modelVersion>4.0.0</modelVersion>
 
   <groupId>org.apache.maven.its.enforcer</groupId>
-  <artifactId>test</artifactId>
+  <artifactId>test-multimodule-project</artifactId>
   <version>1.0</version>
+  <packaging>pom</packaging>
 
   <description>
   </description>
 
+  <modules>
+  	<module>mod1</module>
+  	<module>mod2</module>
+  </modules>
+
   <build>
     <plugins>
       <plugin>
@@ -43,7 +49,11 @@ under the License.
             </goals>
             <configuration>
               <rules>
-                <AlwaysFail/>
+                <requireJavaVendor>
+                  <excludes>
+                    <exclude>NOT-EXISTING-VENDOR</exclude>
+                  </excludes>
+                </requireJavaVendor>
               </rules>
             </configuration>
           </execution>
diff --git a/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy b/maven-enforcer-plugin/src/it/projects/require-java-vendor-multi-module/verify.groovy
similarity index 78%
copy from maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy
copy to maven-enforcer-plugin/src/it/projects/require-java-vendor-multi-module/verify.groovy
index c05c677..7fdcfe3 100644
--- a/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/require-java-vendor-multi-module/verify.groovy
@@ -16,8 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[WARNING] Rule 0: org.apache.maven.plugins.enforcer.AlwaysFail warned with message:' )
 
+File buildLog = new File(basedir, 'build.log')
 
- 
\ No newline at end of file
+rulesExecuted = buildLog.readLines()
+        .findAll {it == '[INFO] Rule 0: org.apache.maven.enforcer.rules.RequireJavaVendor executed'}
+
+assert rulesExecuted.size() == 1
\ No newline at end of file
diff --git a/maven-enforcer-plugin/src/it/projects/require-no-repositories-allow-plugin-repo/verify.groovy b/maven-enforcer-plugin/src/it/projects/require-no-repositories-allow-plugin-repo/verify.groovy
index 01f63fb..cc7a56e 100644
--- a/maven-enforcer-plugin/src/it/projects/require-no-repositories-allow-plugin-repo/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/require-no-repositories-allow-plugin-repo/verify.groovy
@@ -17,6 +17,6 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.plugins.enforcer.RequireNoRepositories failed with message:' )
+assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.RequireNoRepositories failed with message:' )
 assert buildLog.text.contains( 'Some poms have repositories defined:' )
 assert buildLog.text.contains( 'org.apache.maven.its.enforcer:test version:1.0 has repositories [com.asual.maven.public]' )
diff --git a/maven-enforcer-plugin/src/it/projects/require-no-repositories-allow-repo/verify.groovy b/maven-enforcer-plugin/src/it/projects/require-no-repositories-allow-repo/verify.groovy
index 639dd56..a6a9979 100644
--- a/maven-enforcer-plugin/src/it/projects/require-no-repositories-allow-repo/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/require-no-repositories-allow-repo/verify.groovy
@@ -17,6 +17,6 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.plugins.enforcer.RequireNoRepositories failed with message:' )
+assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.RequireNoRepositories failed with message:' )
 assert buildLog.text.contains( 'Some poms have repositories defined:' )
 assert buildLog.text.contains( 'org.apache.maven.its.enforcer:test version:1.0 has plugin repositories [plugin-repo]' )
diff --git a/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure/verify.groovy b/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure/verify.groovy
index 01f63fb..cc7a56e 100644
--- a/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure/verify.groovy
@@ -17,6 +17,6 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.plugins.enforcer.RequireNoRepositories failed with message:' )
+assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.RequireNoRepositories failed with message:' )
 assert buildLog.text.contains( 'Some poms have repositories defined:' )
 assert buildLog.text.contains( 'org.apache.maven.its.enforcer:test version:1.0 has repositories [com.asual.maven.public]' )
diff --git a/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure_allowed-plugin-repo/verify.groovy b/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure_allowed-plugin-repo/verify.groovy
index 01f63fb..cc7a56e 100644
--- a/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure_allowed-plugin-repo/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure_allowed-plugin-repo/verify.groovy
@@ -17,6 +17,6 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.plugins.enforcer.RequireNoRepositories failed with message:' )
+assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.RequireNoRepositories failed with message:' )
 assert buildLog.text.contains( 'Some poms have repositories defined:' )
 assert buildLog.text.contains( 'org.apache.maven.its.enforcer:test version:1.0 has repositories [com.asual.maven.public]' )
diff --git a/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure_plugin-repositories/verify.groovy b/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure_plugin-repositories/verify.groovy
index 634d4aa..8096a1d 100644
--- a/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure_plugin-repositories/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure_plugin-repositories/verify.groovy
@@ -17,6 +17,6 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.plugins.enforcer.RequireNoRepositories failed with message:' )
+assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.RequireNoRepositories failed with message:' )
 assert buildLog.text.contains( 'Some poms have repositories defined:' )
 assert buildLog.text.contains( 'org.apache.maven.its.enforcer:test version:1.0 has plugin repositories [repo]' )
diff --git a/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure_repositories/verify.groovy b/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure_repositories/verify.groovy
index 01f63fb..cc7a56e 100644
--- a/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure_repositories/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/require-no-repositories_failure_repositories/verify.groovy
@@ -17,6 +17,6 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.plugins.enforcer.RequireNoRepositories failed with message:' )
+assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.RequireNoRepositories failed with message:' )
 assert buildLog.text.contains( 'Some poms have repositories defined:' )
 assert buildLog.text.contains( 'org.apache.maven.its.enforcer:test version:1.0 has repositories [com.asual.maven.public]' )
diff --git a/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/EnforceMojo.java b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/EnforceMojo.java
index 24c2545..ad2a8f7 100644
--- a/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/EnforceMojo.java
+++ b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/EnforceMojo.java
@@ -25,9 +25,13 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.stream.Collectors;
 
+import org.apache.maven.enforcer.rule.api.AbstractEnforcerRule;
 import org.apache.maven.enforcer.rule.api.EnforcerLevel;
+import org.apache.maven.enforcer.rule.api.EnforcerLogger;
 import org.apache.maven.enforcer.rule.api.EnforcerRule;
 import org.apache.maven.enforcer.rule.api.EnforcerRule2;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleBase;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleError;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
 import org.apache.maven.execution.MavenSession;
@@ -41,6 +45,11 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.plugins.enforcer.internal.EnforcerLoggerError;
+import org.apache.maven.plugins.enforcer.internal.EnforcerLoggerWarn;
+import org.apache.maven.plugins.enforcer.internal.EnforcerRuleCache;
+import org.apache.maven.plugins.enforcer.internal.EnforcerRuleDesc;
+import org.apache.maven.plugins.enforcer.internal.EnforcerRuleManager;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.configuration.DefaultPlexusConfiguration;
@@ -147,6 +156,9 @@ public class EnforceMojo extends AbstractMojo {
     @Component
     private EnforcerRuleManager enforcerRuleManager;
 
+    @Component
+    private EnforcerRuleCache ruleCache;
+
     private List<String> rulesToExecute;
 
     /**
@@ -180,6 +192,10 @@ public class EnforceMojo extends AbstractMojo {
         setRulesToExecute(rulesToExecute);
     }
 
+    private EnforcerLogger enforcerLoggerError;
+
+    private EnforcerLogger enforcerLoggerWarn;
+
     @Override
     public void execute() throws MojoExecutionException {
         Log log = this.getLog();
@@ -209,6 +225,9 @@ public class EnforceMojo extends AbstractMojo {
             }
         }
 
+        enforcerLoggerError = new EnforcerLoggerError(log);
+        enforcerLoggerWarn = new EnforcerLoggerWarn(log);
+
         // messages with warn/error flag
         Map<String, Boolean> messages = new LinkedHashMap<>();
 
@@ -225,55 +244,31 @@ public class EnforceMojo extends AbstractMojo {
         boolean hasErrors = false;
 
         // go through each rule
-        for (int i = 0; i < rulesList.size(); i++) {
+        for (int ruleIndex = 0; ruleIndex < rulesList.size(); ruleIndex++) {
 
             // prevent against empty rules
-            EnforcerRuleDesc ruleDesc = rulesList.get(i);
+            EnforcerRuleDesc ruleDesc = rulesList.get(ruleIndex);
             if (ruleDesc != null) {
-                EnforcerRule rule = ruleDesc.getRule();
+                EnforcerRuleBase rule = ruleDesc.getRule();
                 EnforcerLevel level = getLevel(rule);
-                // store the current rule for
-                // logging purposes
-                String currentRule = rule.getClass().getName();
                 try {
-                    if (ignoreCache || shouldExecute(rule)) {
-                        // execute the rule
-                        // noinspection SynchronizationOnLocalVariableOrMethodParameter
-                        synchronized (rule) {
-                            log.info("Executing rule: " + currentRule);
-                            rule.execute(helper);
-                        }
-                    }
+                    executeRule(ruleIndex, ruleDesc, helper);
+                } catch (EnforcerRuleError e) {
+                    String ruleMessage = createRuleMessage(ruleIndex, ruleDesc, EnforcerLevel.ERROR, e);
+                    throw new MojoExecutionException(ruleMessage, e);
                 } catch (EnforcerRuleException e) {
-                    // i can throw an exception
-                    // because failfast will be
-                    // false if fail is false.
+
+                    String ruleMessage = createRuleMessage(ruleIndex, ruleDesc, level, e);
+
                     if (failFast && level == EnforcerLevel.ERROR) {
-                        throw new MojoExecutionException(
-                                currentRule + " failed with message:" + System.lineSeparator() + e.getMessage(), e);
+                        throw new MojoExecutionException(ruleMessage, e);
+                    }
+
+                    if (level == EnforcerLevel.ERROR) {
+                        hasErrors = true;
+                        messages.put(ruleMessage, true);
                     } else {
-                        // log a warning in case the exception message is missing
-                        // so that the user can figure out what is going on
-                        final String exceptionMessage = e.getMessage();
-                        if (exceptionMessage != null) {
-                            log.debug("Adding " + level + " message due to exception", e);
-                        } else {
-                            log.warn("Rule " + i + ": " + currentRule + " failed without a message", e);
-                        }
-                        // add the 'failed/warned' message including exceptionMessage
-                        // which might be null in rare cases
-                        if (level == EnforcerLevel.ERROR) {
-                            hasErrors = true;
-                            messages.put(
-                                    "Rule " + i + ": " + currentRule + " failed with message:" + System.lineSeparator()
-                                            + exceptionMessage,
-                                    true);
-                        } else {
-                            messages.put(
-                                    "Rule " + i + ": " + currentRule + " warned with message:" + System.lineSeparator()
-                                            + exceptionMessage,
-                                    false);
-                        }
+                        messages.put(ruleMessage, false);
                     }
                 }
             }
@@ -294,6 +289,52 @@ public class EnforceMojo extends AbstractMojo {
         }
     }
 
+    private void executeRule(int ruleIndex, EnforcerRuleDesc ruleDesc, EnforcerRuleHelper helper)
+            throws EnforcerRuleException {
+
+        if (getLog().isDebugEnabled()) {
+            getLog().debug(String.format("Executing Rule %d: %s", ruleIndex, ruleDesc.getRule()));
+        }
+
+        long startTime = System.currentTimeMillis();
+
+        try {
+            if (ruleDesc.getRule() instanceof EnforcerRule) {
+                executeRuleOld(ruleIndex, ruleDesc, helper);
+            } else if (ruleDesc.getRule() instanceof AbstractEnforcerRule) {
+                executeRuleNew(ruleIndex, ruleDesc);
+            }
+        } finally {
+            if (getLog().isDebugEnabled()) {
+                long workTime = System.currentTimeMillis() - startTime;
+                getLog().debug(String.format(
+                        "Finish Rule %d: %s take %d ms", ruleIndex, getRuleName(ruleDesc), workTime));
+            }
+        }
+    }
+
+    private void executeRuleOld(int ruleIndex, EnforcerRuleDesc ruleDesc, EnforcerRuleHelper helper)
+            throws EnforcerRuleException {
+
+        EnforcerRule rule = (EnforcerRule) ruleDesc.getRule();
+
+        if (ignoreCache || shouldExecute(rule)) {
+            rule.execute(helper);
+            getLog().info(String.format("Rule %d: %s executed", ruleIndex, getRuleName(ruleDesc)));
+        }
+    }
+
+    private void executeRuleNew(int ruleIndex, EnforcerRuleDesc ruleDesc) throws EnforcerRuleException {
+
+        AbstractEnforcerRule rule = (AbstractEnforcerRule) ruleDesc.getRule();
+        rule.setLog(rule.getLevel() == EnforcerLevel.ERROR ? enforcerLoggerError : enforcerLoggerWarn);
+
+        if (ignoreCache || !ruleCache.isCached(rule)) {
+            rule.execute();
+            getLog().info(String.format("Rule %d: %s executed", ruleIndex, getRuleName(ruleDesc)));
+        }
+    }
+
     /**
      * Create rules configuration based on command line provided rules list.
      *
@@ -316,7 +357,6 @@ public class EnforceMojo extends AbstractMojo {
      * Filter out (remove) rules that have been specifically skipped via additional configuration.
      *
      * @param allRules list of enforcer rules to go through and filter
-     *
      * @return list of filtered rules
      */
     private List<EnforcerRuleDesc> filterOutSkippedRules(List<EnforcerRuleDesc> allRules) {
@@ -379,18 +419,50 @@ public class EnforceMojo extends AbstractMojo {
         return failFast;
     }
 
-    protected String createRuleMessage(int i, String currentRule, EnforcerRuleException e) {
-        return "Rule " + i + ": " + currentRule + " failed with message:" + System.lineSeparator() + e.getMessage();
+    private String createRuleMessage(
+            int ruleIndex, EnforcerRuleDesc ruleDesc, EnforcerLevel level, EnforcerRuleException e) {
+
+        StringBuilder result = new StringBuilder();
+        result.append("Rule ").append(ruleIndex).append(": ").append(getRuleName(ruleDesc));
+
+        if (level == EnforcerLevel.ERROR) {
+            result.append(" failed");
+        } else {
+            result.append(" warned");
+        }
+
+        if (e.getMessage() != null) {
+            result.append(" with message:").append(System.lineSeparator()).append(e.getMessage());
+        } else {
+            result.append(" without a message");
+        }
+
+        return result.toString();
+    }
+
+    private String getRuleName(EnforcerRuleDesc ruleDesc) {
+
+        Class<? extends EnforcerRuleBase> ruleClass = ruleDesc.getRule().getClass();
+
+        String ruleName = ruleClass.getName();
+
+        if (!ruleClass.getSimpleName().equalsIgnoreCase(ruleDesc.getName())) {
+            ruleName += "(" + ruleDesc.getName() + ")";
+        }
+
+        return ruleName;
     }
 
     /**
      * Returns the level of the rule, defaults to {@link EnforcerLevel#ERROR} for backwards compatibility.
      *
-     * @param rule might be of type {@link EnforcerRule2}.
+     * @param rule might be of type {{@link AbstractEnforcerRule} or {@link EnforcerRule2}
      * @return level of the rule.
      */
-    private EnforcerLevel getLevel(EnforcerRule rule) {
-        if (rule instanceof EnforcerRule2) {
+    private EnforcerLevel getLevel(EnforcerRuleBase rule) {
+        if (rule instanceof AbstractEnforcerRule) {
+            return ((AbstractEnforcerRule) rule).getLevel();
+        } else if (rule instanceof EnforcerRule2) {
             return ((EnforcerRule2) rule).getLevel();
         } else {
             return EnforcerLevel.ERROR;
diff --git a/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/AbstractEnforcerLogger.java b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/AbstractEnforcerLogger.java
new file mode 100644
index 0000000..bfd0920
--- /dev/null
+++ b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/AbstractEnforcerLogger.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugins.enforcer.internal;
+
+import java.util.Objects;
+import java.util.function.Supplier;
+
+import org.apache.maven.enforcer.rule.api.EnforcerLogger;
+import org.apache.maven.plugin.logging.Log;
+
+/**
+ * Base EnforcerLogger implementation
+ *
+ * @author Slawomir Jaranowski
+ * @since 3.2.0
+ */
+public abstract class AbstractEnforcerLogger implements EnforcerLogger {
+
+    protected final Log log;
+
+    protected AbstractEnforcerLogger(Log log) {
+        this.log = Objects.requireNonNull(log, "log must be not null");
+    }
+
+    @Override
+    public void debug(CharSequence message) {
+        log.debug(message);
+    }
+
+    @Override
+    public void debug(Supplier<CharSequence> messageSupplier) {
+        if (log.isDebugEnabled()) {
+            log.debug(messageSupplier.get());
+        }
+    }
+
+    @Override
+    public void info(CharSequence message) {
+        log.info(message);
+    }
+
+    @Override
+    public void info(Supplier<CharSequence> messageSupplier) {
+        if (log.isInfoEnabled()) {
+            log.info(messageSupplier.get());
+        }
+    }
+
+    @Override
+    public void warn(CharSequence message) {
+        log.warn(message);
+    }
+
+    @Override
+    public void warn(Supplier<CharSequence> messageSupplier) {
+        if (log.isWarnEnabled()) {
+            log.warn(messageSupplier.get());
+        }
+    }
+
+    @Override
+    public void error(CharSequence message) {
+        log.error(message);
+    }
+
+    @Override
+    public void error(Supplier<CharSequence> messageSupplier) {
+        if (log.isErrorEnabled()) {
+            log.error(messageSupplier.get());
+        }
+    }
+}
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedDependencies.java b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerLoggerError.java
similarity index 57%
copy from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedDependencies.java
copy to maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerLoggerError.java
index e65464e..981f939 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedDependencies.java
+++ b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerLoggerError.java
@@ -16,25 +16,33 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer;
+package org.apache.maven.plugins.enforcer.internal;
 
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.plugins.enforcer.utils.ArtifactUtils;
+import java.util.function.Supplier;
+
+import org.apache.maven.plugin.logging.Log;
 
 /**
- * This rule checks that lists of dependencies are not included.
+ * EnforcerLogger implementation for {@code ERROR} execution level
  *
- * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
+ * @author Slawomir Jaranowski
+ * @since 3.2.0
  */
-public class BannedDependencies extends BannedDependenciesBase {
+public class EnforcerLoggerError extends AbstractEnforcerLogger {
+
+    public EnforcerLoggerError(Log log) {
+        super(log);
+    }
+
     @Override
-    protected boolean validate(Artifact artifact) {
-        return !ArtifactUtils.matchDependencyArtifact(artifact, excludes)
-                || ArtifactUtils.matchDependencyArtifact(artifact, includes);
+    public void warnOrError(CharSequence message) {
+        log.error(message);
     }
 
     @Override
-    protected String getErrorMessage() {
-        return "banned via the exclude/include list";
+    public void warnOrError(Supplier<CharSequence> messageSupplier) {
+        if (log.isErrorEnabled()) {
+            log.error(messageSupplier.get());
+        }
     }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedDependencies.java b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerLoggerWarn.java
similarity index 57%
copy from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedDependencies.java
copy to maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerLoggerWarn.java
index e65464e..3ec547a 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedDependencies.java
+++ b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerLoggerWarn.java
@@ -16,25 +16,33 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer;
+package org.apache.maven.plugins.enforcer.internal;
 
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.plugins.enforcer.utils.ArtifactUtils;
+import java.util.function.Supplier;
+
+import org.apache.maven.plugin.logging.Log;
 
 /**
- * This rule checks that lists of dependencies are not included.
+ * EnforcerLogger implementation for {@code WARN} execution level
  *
- * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
+ * @author Slawomir Jaranowski
+ * @since 3.2.0
  */
-public class BannedDependencies extends BannedDependenciesBase {
+public class EnforcerLoggerWarn extends AbstractEnforcerLogger {
+
+    public EnforcerLoggerWarn(Log log) {
+        super(log);
+    }
+
     @Override
-    protected boolean validate(Artifact artifact) {
-        return !ArtifactUtils.matchDependencyArtifact(artifact, excludes)
-                || ArtifactUtils.matchDependencyArtifact(artifact, includes);
+    public void warnOrError(CharSequence message) {
+        log.warn(message);
     }
 
     @Override
-    protected String getErrorMessage() {
-        return "banned via the exclude/include list";
+    public void warnOrError(Supplier<CharSequence> messageSupplier) {
+        if (log.isWarnEnabled()) {
+            log.warn(messageSupplier.get());
+        }
     }
 }
diff --git a/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleCache.java b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleCache.java
new file mode 100644
index 0000000..14595de
--- /dev/null
+++ b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleCache.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugins.enforcer.internal;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.enforcer.rule.api.AbstractEnforcerRule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Service for manage rules cache storage.
+ *
+ * @author Slawomir Jaranowski
+ * @since 3.2.0
+ */
+@Named
+@Singleton
+public class EnforcerRuleCache {
+
+    private final Logger logger = LoggerFactory.getLogger(EnforcerRuleCache.class);
+
+    private final Map<Class<? extends AbstractEnforcerRule>, List<String>> cache = new HashMap<>();
+
+    public boolean isCached(AbstractEnforcerRule rule) {
+
+        String cacheId = rule.getCacheId();
+
+        if (cacheId == null) {
+            return false;
+        }
+
+        Class<? extends AbstractEnforcerRule> ruleClass = rule.getClass();
+        logger.debug("Check cache for {} with id {}", ruleClass, cacheId);
+
+        synchronized (this) {
+            List<String> cacheIdList = cache.computeIfAbsent(ruleClass, (k) -> new ArrayList<>());
+            if (cacheIdList.contains(cacheId)) {
+                logger.debug("Already cached {} with id {}", ruleClass, cacheId);
+                return true;
+            }
+            logger.debug("Add cache {} with id {}", ruleClass, cacheId);
+            cacheIdList.add(cacheId);
+        }
+
+        return false;
+    }
+}
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EnforcerRuleDesc.java b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleDesc.java
similarity index 70%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EnforcerRuleDesc.java
rename to maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleDesc.java
index 84d5977..ec0f8ed 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EnforcerRuleDesc.java
+++ b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleDesc.java
@@ -16,24 +16,29 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer;
+package org.apache.maven.plugins.enforcer.internal;
 
-import org.apache.maven.enforcer.rule.api.EnforcerRule;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleBase;
 
 /**
- * Description of rule to eecute.
+ * Description of rule to execute.
+ *
+ * @author Slawomir Jaranowski
+ * @since 3.2.0
  */
 public class EnforcerRuleDesc {
 
     private final String name;
-    private final EnforcerRule rule;
+
+    private final EnforcerRuleBase rule;
 
     /**
      * Create a new Rule Description
+     *
      * @param name a rule name
      * @param rule a rule instance
      */
-    EnforcerRuleDesc(String name, EnforcerRule rule) {
+    public EnforcerRuleDesc(String name, EnforcerRuleBase rule) {
         this.name = name;
         this.rule = rule;
     }
@@ -42,7 +47,12 @@ public class EnforcerRuleDesc {
         return name;
     }
 
-    public EnforcerRule getRule() {
+    public EnforcerRuleBase getRule() {
         return rule;
     }
+
+    @Override
+    public String toString() {
+        return "EnforcerRuleDesc[name=" + name + ", rule=" + rule + "]";
+    }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EnforcerRuleManager.java b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleManager.java
similarity index 62%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EnforcerRuleManager.java
rename to maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleManager.java
index 07531c9..0b2cd72 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EnforcerRuleManager.java
+++ b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleManager.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer;
+package org.apache.maven.plugins.enforcer.internal;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -25,33 +25,52 @@ import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
-import org.apache.maven.enforcer.rule.api.EnforcerRule;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleBase;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
+import org.apache.maven.plugins.enforcer.EnforcerRuleManagerException;
+import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.classworlds.realm.ClassRealm;
 import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
 import org.codehaus.plexus.component.configurator.ComponentConfigurator;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.codehaus.plexus.configuration.PlexusConfiguration;
 
 /**
  * Manage enforcer rules.
+ *
+ * @author Slawomir Jaranowski
+ * @since 3.2.0
  */
 @Named
 @Singleton
 public class EnforcerRuleManager {
 
-    @Inject
-    private Provider<MavenSession> sessionProvider;
+    private final Provider<MavenSession> sessionProvider;
 
-    @Inject
-    private Provider<MojoExecution> mojoExecutionProvider;
+    private final Provider<MojoExecution> mojoExecutionProvider;
+
+    private final ComponentConfigurator componentConfigurator;
+
+    private final PlexusContainer plexusContainer;
 
     @Inject
-    @Named("basic")
-    private ComponentConfigurator componentConfigurator;
+    public EnforcerRuleManager(
+            Provider<MavenSession> sessionProvider,
+            Provider<MojoExecution> mojoExecutionProvider,
+            @Named("basic") ComponentConfigurator componentConfigurator,
+            PlexusContainer plexusContainer) {
+        this.sessionProvider = Objects.requireNonNull(sessionProvider, "sessionProvider must be not null");
+        this.mojoExecutionProvider =
+                Objects.requireNonNull(mojoExecutionProvider, "mojoExecutionProvider must be not null");
+        this.componentConfigurator =
+                Objects.requireNonNull(componentConfigurator, "componentConfigurator must be not null");
+        this.plexusContainer = Objects.requireNonNull(plexusContainer, "plexusContainer must be not null");
+    }
 
     /**
      * Create enforcer rules based on xml configuration.
@@ -93,6 +112,16 @@ public class EnforcerRuleManager {
 
     private EnforcerRuleDesc createRuleDesc(String name, String implementation) throws EnforcerRuleManagerException {
 
+        // component name should always start at lowercase character
+        String ruleName = Character.toLowerCase(name.charAt(0)) + name.substring(1);
+
+        try {
+            return new EnforcerRuleDesc(ruleName, plexusContainer.lookup(EnforcerRuleBase.class, ruleName));
+        } catch (ComponentLookupException e) {
+            // no component for rule
+            // process old way, by  class name
+        }
+
         String ruleClass;
         if (implementation != null && !implementation.isEmpty()) {
             ruleClass = implementation;
@@ -101,15 +130,16 @@ public class EnforcerRuleManager {
         }
 
         if (!ruleClass.contains(".")) {
-            ruleClass = getClass().getPackage().getName() + "." + Character.toUpperCase(ruleClass.charAt(0))
+            ruleClass = "org.apache.maven.plugins.enforcer." + Character.toUpperCase(ruleClass.charAt(0))
                     + ruleClass.substring(1);
         }
 
         try {
             return new EnforcerRuleDesc(
-                    name, (EnforcerRule) Class.forName(ruleClass).newInstance());
+                    name, (EnforcerRuleBase) Class.forName(ruleClass).newInstance());
         } catch (Exception e) {
-            throw new EnforcerRuleManagerException("Failed to create enforcer rules for class: " + ruleClass, e);
+            throw new EnforcerRuleManagerException(
+                    "Failed to create enforcer rules with name: " + ruleName + " or for class: " + ruleClass, e);
         }
     }
 }
diff --git a/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestDefaultEnforcementRuleHelper.java b/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestDefaultEnforcementRuleHelper.java
deleted file mode 100644
index a0ade16..0000000
--- a/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestDefaultEnforcementRuleHelper.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.maven.plugins.enforcer;
-
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
-/**
- * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
- */
-public class TestDefaultEnforcementRuleHelper {
-    @Test
-    public void testHelper() throws ExpressionEvaluationException {
-        DefaultEnforcementRuleHelper helper = (DefaultEnforcementRuleHelper) EnforcerTestUtils.getHelper();
-
-        assertNotNull(helper.getLog());
-        assertNotNull(helper.evaluate("${session}"));
-        assertNotNull(helper.evaluate("${project}"));
-    }
-}
diff --git a/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestEnforceMojo.java b/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestEnforceMojo.java
index cd25b7c..bead244 100644
--- a/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestEnforceMojo.java
+++ b/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestEnforceMojo.java
@@ -23,10 +23,15 @@ import java.util.Collections;
 import java.util.List;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRule;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleError;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.execution.MavenSession;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.plugins.enforcer.internal.EnforcerRuleDesc;
+import org.apache.maven.plugins.enforcer.internal.EnforcerRuleManager;
+import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.InjectMocks;
@@ -36,9 +41,13 @@ import org.mockito.junit.jupiter.MockitoExtension;
 import org.mockito.junit.jupiter.MockitoSettings;
 import org.mockito.quality.Strictness;
 
+import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 /**
@@ -53,22 +62,29 @@ class TestEnforceMojo {
     @Mock
     private EnforcerRuleManager ruleManager;
 
+    @Mock
+    private MavenSession session;
+
     @InjectMocks
     private EnforceMojo mojo;
 
     @Test
-    void testEnforceMojo() throws Exception {
-        setupBasics(false);
+    void emptyRuleListShouldThrowException() {
+        mojo.setFail(false);
 
-        Log logSpy = setupLogSpy();
+        assertThatCode(() -> mojo.execute())
+                .isInstanceOf(MojoExecutionException.class)
+                .hasMessage("No rules are configured. Use the skip flag if you want to disable execution.");
+    }
 
-        try {
-            mojo.execute();
-            fail("Expected a Mojo Execution Exception.");
-        } catch (MojoExecutionException e) {
-            System.out.println("Caught Expected Exception:" + e.getLocalizedMessage());
-        }
+    @Test
+    void failedRulesAndNoFailPassBuild() throws Exception {
+        // set fail to false
+        mojo.setFail(false);
+
+        Log logSpy = setupLogSpy();
 
+        // two rules which fail
         EnforcerRuleDesc[] rules = new EnforcerRuleDesc[2];
         rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(true));
         rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(true));
@@ -77,8 +93,51 @@ class TestEnforceMojo {
 
         mojo.execute();
 
-        Mockito.verify(logSpy, Mockito.times(2))
-                .info(Mockito.contains("Executing rule: " + MockEnforcerRule.class.getName()));
+        verify(logSpy)
+                .warn(Mockito.contains(
+                        "Rule 0: org.apache.maven.plugins.enforcer.MockEnforcerRule failed with message"));
+        verify(logSpy)
+                .warn(Mockito.contains(
+                        "Rule 1: org.apache.maven.plugins.enforcer.MockEnforcerRule failed with message"));
+    }
+
+    @Test
+    void breakBuildImmediately() throws Exception {
+        // set fail to false
+        mojo.setFail(false);
+
+        Log logSpy = setupLogSpy();
+
+        // this rule break build immediately
+        EnforcerRule ruleBreakBuild = Mockito.mock(EnforcerRule.class);
+        Mockito.doThrow(EnforcerRuleError.class).when(ruleBreakBuild).execute(any(EnforcerRuleHelper.class));
+
+        EnforcerRuleDesc[] rules = new EnforcerRuleDesc[3];
+        rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false));
+        rules[1] = new EnforcerRuleDesc("ruleBreakBuild", ruleBreakBuild);
+        rules[2] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false));
+
+        when(ruleManager.createRules(any())).thenReturn(Arrays.asList(rules));
+
+        Assertions.assertThatCode(() -> mojo.execute())
+                .isInstanceOf(MojoExecutionException.class)
+                .hasCauseInstanceOf(EnforcerRuleError.class);
+
+        assertTrue(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule to be executed.");
+        assertFalse(((MockEnforcerRule) rules[2].getRule()).executed, "Expected this rule to be not executed.");
+
+        verify(logSpy).info(Mockito.contains("Rule 0: org.apache.maven.plugins.enforcer.MockEnforcerRule executed"));
+    }
+
+    @Test
+    void testEnforceMojo() throws Exception {
+        mojo.setFail(true);
+
+        EnforcerRuleDesc[] rules = new EnforcerRuleDesc[2];
+        rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(true));
+        rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(true));
+
+        when(ruleManager.createRules(any())).thenReturn(Arrays.asList(rules));
 
         try {
             mojo.setFailFast(false);
@@ -105,7 +164,7 @@ class TestEnforceMojo {
 
     @Test
     void testCaching() throws Exception {
-        setupBasics(true);
+        mojo.setFail(true);
 
         EnforcerRuleDesc[] rules = new EnforcerRuleDesc[10];
 
@@ -174,7 +233,7 @@ class TestEnforceMojo {
 
     @Test
     void testCachePersistence1() throws Exception {
-        setupBasics(true);
+        mojo.setFail(true);
 
         EnforcerRuleDesc[] rules = new EnforcerRuleDesc[10];
 
@@ -192,7 +251,7 @@ class TestEnforceMojo {
 
     @Test
     void testCachePersistence2() throws Exception {
-        setupBasics(true);
+        mojo.setFail(true);
 
         EnforcerRuleDesc[] rules = new EnforcerRuleDesc[10];
 
@@ -216,7 +275,7 @@ class TestEnforceMojo {
         } catch (InterruptedException e) {
         }
 
-        setupBasics(true);
+        mojo.setFail(true);
 
         EnforcerRuleDesc[] rules = new EnforcerRuleDesc[10];
 
@@ -234,7 +293,7 @@ class TestEnforceMojo {
     @Test
     void testLoggingOnEnforcerRuleExceptionWithMessage() throws Exception {
         // fail=false because this is out of scope here (also allows for cleaner test code without catch block)
-        setupBasics(false);
+        mojo.setFail(false);
 
         // the regular kind of EnforcerRuleException:
         EnforcerRuleException ruleException = new EnforcerRuleException("testMessage");
@@ -248,18 +307,16 @@ class TestEnforceMojo {
 
         mojo.execute();
 
-        Mockito.verify(logSpy).debug(Mockito.anyString(), Mockito.same(ruleException));
+        verify(logSpy, Mockito.never()).warn(Mockito.anyString(), any(Throwable.class));
 
-        Mockito.verify(logSpy, Mockito.never()).warn(Mockito.anyString(), any(Throwable.class));
-
-        Mockito.verify(logSpy)
+        verify(logSpy)
                 .warn(Mockito.matches(".* failed with message:" + System.lineSeparator() + ruleException.getMessage()));
     }
 
     @Test
     void testLoggingOnEnforcerRuleExceptionWithoutMessage() throws Exception {
         // fail=false because this is out of scope here (also allows for cleaner test code without catch block)
-        setupBasics(false);
+        mojo.setFail(false);
 
         // emulate behaviour of various rules that just catch Exception and wrap into EnforcerRuleException:
         NullPointerException npe = new NullPointerException();
@@ -275,27 +332,25 @@ class TestEnforceMojo {
 
         mojo.execute();
 
-        Mockito.verify(logSpy).warn(Mockito.contains("failed without a message"), Mockito.same(enforcerRuleException));
-
-        Mockito.verify(logSpy).warn(Mockito.matches(".* failed with message:" + System.lineSeparator() + "null"));
+        Mockito.verify(logSpy).warn(Mockito.matches(".* failed without a message"));
     }
 
     @Test
     void testFailIfNoTests() throws MojoExecutionException {
-        setupBasics(false);
+        mojo.setFail(false);
         mojo.setFailIfNoRules(false);
 
         Log logSpy = setupLogSpy();
 
         mojo.execute();
 
-        Mockito.verify(logSpy).warn("No rules are configured.");
+        verify(logSpy).warn("No rules are configured.");
         Mockito.verifyNoMoreInteractions(logSpy);
     }
 
     @Test
     void testFailIfBothRuleOverridePropertiesAreSet() throws MojoExecutionException {
-        setupBasics(false);
+        mojo.setFail(false);
 
         Log logSpy = setupLogSpy();
         List<String> rules = Arrays.asList("rule1", "rule2");
@@ -309,7 +364,7 @@ class TestEnforceMojo {
 
     @Test
     void testShouldPrintWarnWhenUsingDeprecatedRulesProperty() throws MojoExecutionException {
-        setupBasics(false);
+        mojo.setFail(false);
 
         Log logSpy = setupLogSpy();
 
@@ -321,7 +376,7 @@ class TestEnforceMojo {
 
     @Test
     void testShouldNotPrintWarnWhenDeprecatedRulesPropertyIsEmpty() throws MojoExecutionException {
-        setupBasics(false);
+        mojo.setFail(false);
 
         Log logSpy = setupLogSpy();
 
@@ -330,12 +385,6 @@ class TestEnforceMojo {
         Mockito.verifyNoInteractions(logSpy);
     }
 
-    private void setupBasics(boolean fail) {
-        mojo.setFail(fail);
-        mojo.setSession(EnforcerTestUtils.getMavenSession());
-        mojo.setProject(new MockProject());
-    }
-
     private Log setupLogSpy() {
         Log spy = Mockito.spy(mojo.getLog());
         mojo.setLog(spy);
diff --git a/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy b/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestRule1.java
similarity index 70%
copy from maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy
copy to maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestRule1.java
index c05c677..fdef9a2 100644
--- a/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy
+++ b/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestRule1.java
@@ -16,8 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[WARNING] Rule 0: org.apache.maven.plugins.enforcer.AlwaysFail warned with message:' )
+package org.apache.maven.plugins.enforcer;
 
+import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
 
- 
\ No newline at end of file
+public class TestRule1 extends AbstractNonCacheableEnforcerRule {
+
+    @Override
+    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {}
+}
diff --git a/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy b/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestRule2.java
similarity index 70%
copy from maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy
copy to maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestRule2.java
index c05c677..4b2a2c5 100644
--- a/maven-enforcer-plugin/src/it/projects/always-fail-warn/verify.groovy
+++ b/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/TestRule2.java
@@ -16,8 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[WARNING] Rule 0: org.apache.maven.plugins.enforcer.AlwaysFail warned with message:' )
+package org.apache.maven.plugins.enforcer;
 
+import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
 
- 
\ No newline at end of file
+public class TestRule2 extends AbstractNonCacheableEnforcerRule {
+
+    @Override
+    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {}
+}
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/EnforcerRuleManagerTest.java b/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleManagerTest.java
similarity index 66%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/EnforcerRuleManagerTest.java
rename to maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleManagerTest.java
index 99626cd..a068e50 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/EnforcerRuleManagerTest.java
+++ b/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleManagerTest.java
@@ -16,31 +16,39 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer;
+package org.apache.maven.plugins.enforcer.internal;
 
 import javax.inject.Provider;
 
 import java.util.List;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRule;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleBase;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.plugins.enforcer.EnforcerRuleManagerException;
+import org.apache.maven.plugins.enforcer.TestRule1;
+import org.apache.maven.plugins.enforcer.TestRule2;
+import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
 import org.codehaus.plexus.component.configurator.ComponentConfigurator;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.codehaus.plexus.configuration.DefaultPlexusConfiguration;
 import org.codehaus.plexus.configuration.PlexusConfiguration;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.ArgumentCaptor;
-import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.junit.jupiter.MockitoExtension;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -58,10 +66,18 @@ class EnforcerRuleManagerTest {
     @Mock
     private ComponentConfigurator componentConfigurator;
 
-    @InjectMocks
+    @Mock
+    private PlexusContainer plexusContainer;
+
     private EnforcerRuleManager enforcerRuleManager;
 
-    void setupMocks() {
+    @BeforeEach
+    void setup() {
+        enforcerRuleManager =
+                new EnforcerRuleManager(sessionProvider, mojoExecutionProvider, componentConfigurator, plexusContainer);
+    }
+
+    void setupMocks() throws Exception {
         MojoExecution mojoExecution = mock(MojoExecution.class);
         when(mojoExecutionProvider.get()).thenReturn(mojoExecution);
 
@@ -71,10 +87,12 @@ class EnforcerRuleManagerTest {
         when(mojoDescriptor.getPluginDescriptor()).thenReturn(mock(PluginDescriptor.class));
 
         when(sessionProvider.get()).thenReturn(mock(MavenSession.class));
+
+        doThrow(ComponentLookupException.class).when(plexusContainer).lookup(any(Class.class), anyString());
     }
 
     @Test
-    void nulConfigReturnEmptyRules() throws Exception {
+    void nullConfigReturnEmptyRules() throws Exception {
 
         List<EnforcerRuleDesc> rules = enforcerRuleManager.createRules(null);
 
@@ -90,7 +108,7 @@ class EnforcerRuleManagerTest {
     }
 
     @Test
-    void unKnownRuleThrowException() {
+    void unKnownRuleThrowException() throws Exception {
 
         setupMocks();
 
@@ -98,17 +116,18 @@ class EnforcerRuleManagerTest {
 
         assertThatCode(() -> enforcerRuleManager.createRules(configuration))
                 .isInstanceOf(EnforcerRuleManagerException.class)
-                .hasMessage("Failed to create enforcer rules for class: org.apache.maven.plugins.enforcer.UnKnowRule")
+                .hasMessage(
+                        "Failed to create enforcer rules with name: unKnowRule or for class: org.apache.maven.plugins.enforcer.UnKnowRule")
                 .hasCauseInstanceOf(ClassNotFoundException.class);
     }
 
     @Test
-    void invalidConfigurationThrowException() throws ComponentConfigurationException {
+    void invalidConfigurationThrowException() throws Exception {
 
         setupMocks();
 
         PlexusConfiguration ruleConfig =
-                new DefaultPlexusConfiguration("alwaysPass").addChild("message", "messageValue");
+                new DefaultPlexusConfiguration("testRule1").addChild("message", "messageValue");
         PlexusConfiguration configuration = new DefaultPlexusConfiguration("rules");
         configuration.addChild(ruleConfig);
 
@@ -122,49 +141,70 @@ class EnforcerRuleManagerTest {
     }
 
     @Test
-    void createSimpleRule() throws EnforcerRuleManagerException {
+    void createSimpleRule() throws Exception {
+
+        setupMocks();
+
+        PlexusConfiguration configuration = new DefaultPlexusConfiguration("rules")
+                .addChild("TestRule1", null)
+                .addChild("testRule2", null);
+
+        List<EnforcerRuleDesc> rules = enforcerRuleManager.createRules(configuration);
+
+        assertThat(rules)
+                .hasSize(2)
+                .map(EnforcerRuleDesc::getRule)
+                .hasExactlyElementsOfTypes(TestRule1.class, TestRule2.class);
+
+        assertThat(rules).hasSize(2).map(EnforcerRuleDesc::getName).containsExactly("TestRule1", "testRule2");
+    }
+
+    @Test
+    void createSimpleRuleFromComponentAndClasses() throws Exception {
 
         setupMocks();
 
+        Mockito.doReturn(new TestRule1()).when(plexusContainer).lookup(EnforcerRuleBase.class, "testRule1");
+
         PlexusConfiguration configuration = new DefaultPlexusConfiguration("rules")
-                .addChild("AlwaysFail", null)
-                .addChild("alwaysPass", null);
+                .addChild("TestRule1", null)
+                .addChild("testRule2", null);
 
         List<EnforcerRuleDesc> rules = enforcerRuleManager.createRules(configuration);
 
         assertThat(rules)
                 .hasSize(2)
                 .map(EnforcerRuleDesc::getRule)
-                .hasExactlyElementsOfTypes(AlwaysFail.class, AlwaysPass.class);
+                .hasExactlyElementsOfTypes(TestRule1.class, TestRule2.class);
 
-        assertThat(rules).hasSize(2).map(EnforcerRuleDesc::getName).containsExactly("AlwaysFail", "alwaysPass");
+        assertThat(rules).hasSize(2).map(EnforcerRuleDesc::getName).containsExactly("testRule1", "testRule2");
     }
 
     @Test
-    void createRuleWithImplementation() throws EnforcerRuleManagerException {
+    void createRuleWithImplementation() throws Exception {
 
         setupMocks();
 
-        PlexusConfiguration ruleConfig = new DefaultPlexusConfiguration("alwaysPassWithImp");
-        ruleConfig.setAttribute("implementation", AlwaysPass.class.getName());
+        PlexusConfiguration ruleConfig = new DefaultPlexusConfiguration("testRuleWithImp");
+        ruleConfig.setAttribute("implementation", TestRule1.class.getName());
 
         PlexusConfiguration configuration = new DefaultPlexusConfiguration("rules");
         configuration.addChild(ruleConfig);
 
         List<EnforcerRuleDesc> rules = enforcerRuleManager.createRules(configuration);
 
-        assertThat(rules).hasSize(1).map(EnforcerRuleDesc::getRule).hasExactlyElementsOfTypes(AlwaysPass.class);
+        assertThat(rules).hasSize(1).map(EnforcerRuleDesc::getRule).hasExactlyElementsOfTypes(TestRule1.class);
 
-        assertThat(rules).hasSize(1).map(EnforcerRuleDesc::getName).containsExactly("alwaysPassWithImp");
+        assertThat(rules).hasSize(1).map(EnforcerRuleDesc::getName).containsExactly("testRuleWithImp");
     }
 
     @Test
-    void ruleShouldBeConfigured() throws EnforcerRuleManagerException, ComponentConfigurationException {
+    void ruleShouldBeConfigured() throws Exception {
 
         setupMocks();
 
         PlexusConfiguration ruleConfig =
-                new DefaultPlexusConfiguration("alwaysPass").addChild("message", "messageValue");
+                new DefaultPlexusConfiguration("testRule1").addChild("message", "messageValue");
         PlexusConfiguration configuration = new DefaultPlexusConfiguration("rules");
         configuration.addChild(ruleConfig);
 
@@ -177,7 +217,7 @@ class EnforcerRuleManagerTest {
         verify(componentConfigurator)
                 .configureComponent(ruleCaptor.capture(), configurationCaptor.capture(), any(), any());
 
-        assertThat(ruleCaptor.getValue()).isInstanceOf(AlwaysPass.class);
+        assertThat(ruleCaptor.getValue()).isInstanceOf(TestRule1.class);
         assertThat(configurationCaptor.getValue()).isSameAs(ruleConfig);
     }
 }