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/17 19:24:15 UTC

[maven-enforcer] branch master updated: [MENFORCER-458] Move Build-in rules to new 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 fba5896  [MENFORCER-458] Move Build-in rules to new API
fba5896 is described below

commit fba589678e44a4cb7ea9e0a729ca8575fe9ed3f0
Author: Slawomir Jaranowski <s....@gmail.com>
AuthorDate: Mon Jan 16 00:35:55 2023 +0100

    [MENFORCER-458] Move Build-in rules to new API
    
    Moved rules:
     - banDependencyManagementScope
     - banDistributionManagement
     - banDuplicatePomDependencyVersions
     - banDynamicVersions
     - bannedPlugins
     - bannedRepositories
     - evaluateBeanshell
     - reactorModuleConvergence
     - requireActiveProfile
     - requireExplicitDependencyScope
     - requirePluginVersions
     - requirePrerequisite
     - requireProfileIdsExist
     - requireReleaseVersion
     - requireSameVersions
     - requireSnapshotVersion
---
 .../rules/AbstractStandardEnforcerRule.java        |  64 +++++
 .../apache/maven/enforcer/rules/AlwaysFail.java    |   2 +-
 .../apache/maven/enforcer/rules/AlwaysPass.java    |   2 +-
 .../rules}/BanDependencyManagementScope.java       |  76 +++---
 .../enforcer/rules/BanDistributionManagement.java  | 159 +++++++++++
 .../rules}/BanDuplicatePomDependencyVersions.java  |  35 ++-
 .../rules}/BanDynamicVersions.java                 | 113 +++-----
 .../enforcer => enforcer/rules}/BannedPlugins.java |  65 +++--
 .../rules}/BannedRepositories.java                 |  70 ++---
 .../rules}/EvaluateBeanshell.java                  |  54 ++--
 .../apache/maven/enforcer/rules/ExternalRules.java |   2 +-
 .../rules}/ReactorModuleConvergence.java           |  72 ++---
 .../rules}/RequireActiveProfile.java               |  89 +++---
 .../rules/RequireExplicitDependencyScope.java      |  84 ++++++
 .../maven/enforcer/rules/RequireJavaVendor.java    |   3 +-
 .../enforcer/rules/RequireNoRepositories.java      |   3 +-
 .../org/apache/maven/enforcer/rules/RequireOS.java |  11 +-
 .../rules}/RequirePluginVersions.java              | 302 ++++++++-------------
 .../rules}/RequirePrerequisite.java                |  34 ++-
 .../enforcer/rules/RequireProfileIdsExist.java     |  91 +++++++
 .../rules}/RequireReleaseVersion.java              |  50 ++--
 .../rules}/RequireSameVersions.java                |  34 ++-
 .../rules}/RequireSnapshotVersion.java             |  48 ++--
 .../rules/checksum/RequireFileChecksum.java        |   4 +-
 .../rules/checksum/RequireTextFileChecksum.java    |   5 +-
 .../enforcer/rules/files/AbstractRequireFiles.java |   4 +-
 .../rules/property/RequireEnvironmentVariable.java |  14 +-
 .../enforcer/rules/property/RequireProperty.java   |   7 +-
 .../rules/utils/DistributionManagementCheck.java   |  71 -----
 .../enforcer/rules/utils/EnforcerRuleUtils.java    |  27 +-
 .../rules/version/AbstractVersionEnforcer.java     |   2 +-
 .../plugins/enforcer/AbstractBanDependencies.java  | 108 --------
 .../enforcer/BanDistributionManagement.java        | 104 -------
 .../enforcer/RequireExplicitDependencyScope.java   |  83 ------
 .../plugins/enforcer/RequireProfileIdsExist.java   |  86 ------
 .../src/site/apt/banDistributionManagement.apt.vm  |  10 +-
 .../apt/banDuplicatePomDependencyVersions.apt.vm   |   7 -
 .../src/site/apt/banDynamicVersions.apt.vm         |   5 +-
 enforcer-rules/src/site/apt/bannedPlugins.apt.vm   |   9 +-
 .../src/site/apt/bannedRepositories.apt.vm         |  12 +-
 .../src/site/apt/evaluateBeanshell.apt.vm          |   4 +-
 .../src/site/apt/reactorModuleConvergence.apt.vm   |  16 +-
 .../src/site/apt/requireActiveProfile.apt.vm       |   6 +-
 .../src/site/apt/requireNoRepositories.apt.vm      |  14 +-
 .../src/site/apt/requirePluginVersions.apt.vm      |  16 +-
 .../src/site/apt/requirePrerequisite.apt.vm        |   2 +-
 .../src/site/apt/requireSameVersions.apt.vm        |  10 +-
 .../src/site/apt/requireSnapshotVersion.apt.vm     |   4 +-
 .../rules}/BanDependencyManagementScopeTest.java   |  13 +-
 .../rules/BanDistributionManagementTest.java       | 219 +++++++++++++++
 .../rules}/ReactorModuleConvergenceTest.java       |  52 ++--
 .../rules}/RequireActiveProfileTest.java           |  63 ++---
 .../rules}/RequirePrerequisiteTest.java            |  94 +++----
 .../rules}/TestBannedRepositories.java             |  32 +--
 .../enforcer/rules/TestEvaluateBeanshell.java      | 122 +++++++++
 .../rules}/TestRequirePluginVersions.java          | 172 ++++++++----
 .../enforcer/rules/TestRequireReleaseVersion.java  | 104 +++++++
 .../enforcer/rules/TestRequireSnapshotVersion.java | 111 ++++++++
 .../enforcer/BanDistributionManagementTest.java    | 261 ------------------
 .../plugins/enforcer/TestEvaluateBeanshell.java    | 231 ----------------
 .../enforcer/TestRequireReleaseVersion.java        |  84 ------
 .../enforcer/TestRequireSnapshotVersion.java       |  91 -------
 .../verify.groovy                                  |   2 +-
 .../verify.groovy                                  |   2 +-
 .../ban-distribution-management/verify.groovy      |   2 +-
 .../verify.groovy                                  |   2 +-
 .../it/projects/ban-dynamic-versions/verify.groovy |   2 +-
 .../verify.groovy                                  |   2 +-
 .../ban-pom-dependency-version/verify.groovy       |   2 +-
 .../it/projects/banned-plugins-fails/verify.groovy |   2 +-
 .../src/it/projects/evaluate-beanshell/pom.xml     |   3 +
 .../verify.groovy                                  |   6 +-
 .../require-plugin-versions-ci/verify.groovy       |   2 +-
 .../verify.groovy                                  |   2 +-
 .../enforcer/internal/EnforcerRuleCache.java       |  10 +-
 .../enforcer/internal/EnforcerRuleManager.java     |  12 +-
 .../enforcer/internal/EnforcerRuleManagerTest.java |  26 +-
 77 files changed, 1837 insertions(+), 1982 deletions(-)

diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/AbstractStandardEnforcerRule.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/AbstractStandardEnforcerRule.java
index b426f6e..4fa5887 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/AbstractStandardEnforcerRule.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/AbstractStandardEnforcerRule.java
@@ -19,6 +19,8 @@
 package org.apache.maven.enforcer.rules;
 
 import org.apache.maven.enforcer.rule.api.AbstractEnforcerRule;
+import org.apache.maven.model.InputLocation;
+import org.apache.maven.project.MavenProject;
 
 /**
  * Abstract help rule.
@@ -37,4 +39,66 @@ public abstract class AbstractStandardEnforcerRule extends AbstractEnforcerRule
     public void setMessage(String message) {
         this.message = message;
     }
+
+    /**
+     * Returns an identifier of a given project.
+     * @param project the project
+     * @return the identifier of the project in the format {@code <groupId>:<artifactId>:<version>}
+     */
+    private static String getProjectId(MavenProject project) {
+        StringBuilder buffer = new StringBuilder(128);
+
+        buffer.append(
+                (project.getGroupId() != null && project.getGroupId().length() > 0)
+                        ? project.getGroupId()
+                        : "[unknown-group-id]");
+        buffer.append(':');
+        buffer.append(
+                (project.getArtifactId() != null && project.getArtifactId().length() > 0)
+                        ? project.getArtifactId()
+                        : "[unknown-artifact-id]");
+        buffer.append(':');
+        buffer.append(
+                (project.getVersion() != null && project.getVersion().length() > 0)
+                        ? project.getVersion()
+                        : "[unknown-version]");
+
+        return buffer.toString();
+    }
+
+    /**
+     * Creates a string with line/column information for problems originating directly from this POM. Inspired by
+     * {@code o.a.m.model.building.ModelProblemUtils.formatLocation(...)}.
+     *
+     * @param project the current project.
+     * @param location The location which should be formatted, must not be {@code null}.
+     * @return The formatted problem location or an empty string if unknown, never {@code null}.
+     */
+    protected static String formatLocation(MavenProject project, InputLocation location) {
+        StringBuilder buffer = new StringBuilder();
+
+        if (!location.getSource().getModelId().equals(getProjectId(project))) {
+            buffer.append(location.getSource().getModelId());
+
+            if (location.getSource().getLocation().length() > 0) {
+                if (buffer.length() > 0) {
+                    buffer.append(", ");
+                }
+                buffer.append(location.getSource().getLocation());
+            }
+        }
+        if (location.getLineNumber() > 0) {
+            if (buffer.length() > 0) {
+                buffer.append(", ");
+            }
+            buffer.append("line ").append(location.getLineNumber());
+        }
+        if (location.getColumnNumber() > 0) {
+            if (buffer.length() > 0) {
+                buffer.append(", ");
+            }
+            buffer.append("column ").append(location.getColumnNumber());
+        }
+        return buffer.toString();
+    }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/AlwaysFail.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/AlwaysFail.java
index 1e1f8cf..16a3c56 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/AlwaysFail.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/AlwaysFail.java
@@ -43,6 +43,6 @@ public final class AlwaysFail extends AbstractStandardEnforcerRule {
 
     @Override
     public String toString() {
-        return String.format("AlwaysFail[level=%s, message=%s]", getLevel(), getMessage());
+        return String.format("AlwaysFail[message=%s]", getMessage());
     }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/AlwaysPass.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/AlwaysPass.java
index 38f0daa..f3269cc 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/AlwaysPass.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/AlwaysPass.java
@@ -40,6 +40,6 @@ public final class AlwaysPass extends AbstractStandardEnforcerRule {
 
     @Override
     public String toString() {
-        return String.format("AlwaysPass[level=%s, message=%s]", getLevel(), getMessage());
+        return String.format("AlwaysPass[message=%s]", getMessage());
     }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDependencyManagementScope.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BanDependencyManagementScope.java
similarity index 59%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDependencyManagementScope.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BanDependencyManagementScope.java
index 2b3dd87..ed8848d 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDependencyManagementScope.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BanDependencyManagementScope.java
@@ -16,27 +16,28 @@
  * 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.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.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 
 /**
  * This rule bans all scope values except for {@code import} from dependencies within the dependency management.
  * There is a configuration option to ignore certain dependencies in this check.
  */
-public class BanDependencyManagementScope extends AbstractNonCacheableEnforcerRule implements EnforcerRule2 {
+@Named("banDependencyManagementScope")
+public final class BanDependencyManagementScope extends AbstractStandardEnforcerRule {
 
     /**
      * Specify the dependencies that will be ignored. This can be a list of artifacts in the format
@@ -54,40 +55,37 @@ public class BanDependencyManagementScope extends AbstractNonCacheableEnforcerRu
      */
     private boolean checkEffectivePom = false;
 
+    private final MavenProject project;
+
+    @Inject
+    public BanDependencyManagementScope(MavenProject project) {
+        this.project = Objects.requireNonNull(project);
+    }
+
     @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        Log logger = helper.getLog();
-        MavenProject project;
-        try {
-            project = (MavenProject) helper.evaluate("${project}");
-            if (project == null) {
-                throw new EnforcerRuleException("${project} is null");
-            }
-            // only evaluate local depMgmt, without taking into account inheritance and interpolation
-            DependencyManagement depMgmt = checkEffectivePom
-                    ? project.getModel().getDependencyManagement()
-                    : project.getOriginalModel().getDependencyManagement();
-            if (depMgmt != null && depMgmt.getDependencies() != null) {
-                List<Dependency> violatingDependencies = getViolatingDependencies(logger, depMgmt);
-                if (!violatingDependencies.isEmpty()) {
-                    String message = getMessage();
-                    StringBuilder buf = new StringBuilder();
-                    if (message == null) {
-                        message = "Scope other than 'import' is not allowed in 'dependencyManagement'";
-                    }
-                    buf.append(message + System.lineSeparator());
-                    for (Dependency violatingDependency : violatingDependencies) {
-                        buf.append(getErrorMessage(project, violatingDependency));
-                    }
-                    throw new EnforcerRuleException(buf.toString());
+    public void execute() throws EnforcerRuleException {
+        // only evaluate local depMgmt, without taking into account inheritance and interpolation
+        DependencyManagement depMgmt = checkEffectivePom
+                ? project.getModel().getDependencyManagement()
+                : project.getOriginalModel().getDependencyManagement();
+        if (depMgmt != null && depMgmt.getDependencies() != null) {
+            List<Dependency> violatingDependencies = getViolatingDependencies(depMgmt);
+            if (!violatingDependencies.isEmpty()) {
+                String message = getMessage();
+                StringBuilder buf = new StringBuilder();
+                if (message == null) {
+                    message = "Scope other than 'import' is not allowed in 'dependencyManagement'";
+                }
+                buf.append(message + System.lineSeparator());
+                for (Dependency violatingDependency : violatingDependencies) {
+                    buf.append(getErrorMessage(project, violatingDependency));
                 }
+                throw new EnforcerRuleException(buf.toString());
             }
-        } catch (ExpressionEvaluationException e) {
-            throw new EnforcerRuleException("Cannot resolve expression: " + e.getCause(), e);
         }
     }
 
-    protected List<Dependency> getViolatingDependencies(Log logger, DependencyManagement depMgmt) {
+    protected List<Dependency> getViolatingDependencies(DependencyManagement depMgmt) {
         final ArtifactMatcher excludesMatcher;
         if (excludes != null) {
             excludesMatcher = new ArtifactMatcher(excludes, Collections.emptyList());
@@ -98,7 +96,8 @@ public class BanDependencyManagementScope extends AbstractNonCacheableEnforcerRu
         for (Dependency dependency : depMgmt.getDependencies()) {
             if (dependency.getScope() != null && !"import".equals(dependency.getScope())) {
                 if (excludesMatcher != null && excludesMatcher.match(dependency)) {
-                    logger.debug("Skipping excluded dependency " + dependency + " with scope " + dependency.getScope());
+                    getLog().debug("Skipping excluded dependency " + dependency + " with scope "
+                            + dependency.getScope());
                     continue;
                 }
                 violatingDependencies.add(dependency);
@@ -118,7 +117,10 @@ public class BanDependencyManagementScope extends AbstractNonCacheableEnforcerRu
         this.excludes = theExcludes;
     }
 
-    public void setCheckEffectivePom(boolean checkEffectivePom) {
-        this.checkEffectivePom = checkEffectivePom;
+    @Override
+    public String toString() {
+        return String.format(
+                "BanDependencyManagementScope[message=%s, excludes=%s, checkEffectivePom=%b]",
+                getMessage(), excludes, checkEffectivePom);
     }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BanDistributionManagement.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BanDistributionManagement.java
new file mode 100644
index 0000000..f723af7
--- /dev/null
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BanDistributionManagement.java
@@ -0,0 +1,159 @@
+/*
+ * 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.rules;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import java.util.Objects;
+
+import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
+import org.apache.maven.model.DistributionManagement;
+import org.apache.maven.project.MavenProject;
+
+/**
+ * This rule will check if a pom contains a <code>distributionManagement</code> part. This should be by best practice
+ * only defined once. It could happen that you like to check the parent as well. This can be activated by using the
+ * <code>ignoreParent</code> which is by default turned off (<code>true</code>) which means not to check the parent.
+ *
+ * @author Karl Heinz Marbaise
+ * @since 1.4
+ */
+@Named("banDistributionManagement")
+public final class BanDistributionManagement extends AbstractStandardEnforcerRule {
+
+    /**
+     * Allow using a repository entry in the distributionManagement area.
+     */
+    private boolean allowRepository = false;
+
+    /**
+     * Allow snapshotRepository entry in the distributionManagement area.
+     */
+    private boolean allowSnapshotRepository = false;
+
+    /**
+     * Allow site entry in the distributionManagement area.
+     */
+    private boolean allowSite = false;
+
+    private final MavenProject project;
+
+    @Inject
+    public BanDistributionManagement(MavenProject project) {
+        this.project = Objects.requireNonNull(project);
+    }
+
+    @Override
+    public void execute() throws EnforcerRuleException {
+
+        if (project.isExecutionRoot()) {
+            if (project.getParent() == null) {
+                // Does it make sense to check something? If yes please make a JIRA ticket for it.
+                getLog().debug("We have no parent and in the root of a build we don't check anything,");
+                getLog().debug("because that is the location where we defined maven-enforcer-plugin.");
+            } else {
+                getLog().debug("We are in the root of the execution and we have a parent.");
+
+                DistributionManagementCheck check = new DistributionManagementCheck(project);
+                check.execute(isAllowRepository(), isAllowSnapshotRepository(), isAllowSite());
+            }
+        } else {
+            getLog().debug("We are in a deeper level.");
+            DistributionManagementCheck check = new DistributionManagementCheck(project);
+            check.execute(isAllowRepository(), isAllowSnapshotRepository(), isAllowSite());
+        }
+    }
+
+    public boolean isAllowRepository() {
+        return allowRepository;
+    }
+
+    public void setAllowRepository(boolean allowRepository) {
+        this.allowRepository = allowRepository;
+    }
+
+    public boolean isAllowSnapshotRepository() {
+        return allowSnapshotRepository;
+    }
+
+    public void setAllowSnapshotRepository(boolean allowSnapshotRepository) {
+        this.allowSnapshotRepository = allowSnapshotRepository;
+    }
+
+    public boolean isAllowSite() {
+        return allowSite;
+    }
+
+    public void setAllowSite(boolean allowSite) {
+        this.allowSite = allowSite;
+    }
+
+    private static class DistributionManagementCheck {
+        private DistributionManagement distributionManagement;
+
+        DistributionManagementCheck(MavenProject project) {
+            this.distributionManagement = project.getOriginalModel().getDistributionManagement();
+        }
+
+        public void execute(boolean isAllowRepository, boolean isAllowSnapshotRepository, boolean isAllowSite)
+                throws EnforcerRuleException {
+            if (hasDistributionManagement()) {
+                if (!isAllowRepository && hasRepository()) {
+                    throw new EnforcerRuleException("You have defined a repository in distributionManagement.");
+                } else if (!isAllowSnapshotRepository && hasSnapshotRepository()) {
+                    throw new EnforcerRuleException("You have defined a snapshotRepository in distributionManagement.");
+                } else if (!isAllowSite && hasSite()) {
+                    throw new EnforcerRuleException("You have defined a site in distributionManagement.");
+                }
+            }
+        }
+
+        private boolean hasRepository() {
+            return getDistributionManagement().getRepository() != null;
+        }
+
+        public DistributionManagement getDistributionManagement() {
+            return distributionManagement;
+        }
+
+        public void setDistributionManagement(DistributionManagement distributionManagement) {
+            this.distributionManagement = distributionManagement;
+        }
+
+        private boolean hasSnapshotRepository() {
+            return getDistributionManagement().getSnapshotRepository() != null;
+        }
+
+        private boolean hasSite() {
+            return getDistributionManagement().getSite() != null;
+        }
+
+        private boolean hasDistributionManagement() {
+            return getDistributionManagement() != null;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return String.format(
+                "BanDistributionManagement[allowRepository=%b, allowSnapshotRepository=%b, allowSite=%b]",
+                allowRepository, allowSnapshotRepository, allowSite);
+    }
+}
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDuplicatePomDependencyVersions.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BanDuplicatePomDependencyVersions.java
similarity index 87%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDuplicatePomDependencyVersions.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BanDuplicatePomDependencyVersions.java
index e985262..94bf49b 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDuplicatePomDependencyVersions.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BanDuplicatePomDependencyVersions.java
@@ -16,7 +16,10 @@
  * 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.io.FileInputStream;
 import java.io.IOException;
@@ -24,16 +27,16 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
+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.model.Dependency;
 import org.apache.maven.model.Model;
 import org.apache.maven.model.Profile;
 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 
 /**
@@ -43,16 +46,18 @@ import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
  * @author Robert Scholte
  * @since 1.3
  */
-public class BanDuplicatePomDependencyVersions extends AbstractNonCacheableEnforcerRule {
+@Named("banDuplicatePomDependencyVersions")
+public final class BanDuplicatePomDependencyVersions extends AbstractStandardEnforcerRule {
+
+    private final MavenProject project;
+
+    @Inject
+    public BanDuplicatePomDependencyVersions(MavenProject project) {
+        this.project = Objects.requireNonNull(project);
+    }
+
     @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        // get the project
-        MavenProject project;
-        try {
-            project = (MavenProject) helper.evaluate("${project}");
-        } catch (ExpressionEvaluationException eee) {
-            throw new EnforcerRuleException("Unable to retrieve the MavenProject: ", eee);
-        }
+    public void execute() throws EnforcerRuleException {
 
         // re-read model, because M3 uses optimized model
         MavenXpp3Reader modelReader = new MavenXpp3Reader();
@@ -61,7 +66,7 @@ public class BanDuplicatePomDependencyVersions extends AbstractNonCacheableEnfor
         try (FileInputStream pomInputStream = new FileInputStream(project.getFile())) {
             model = modelReader.read(pomInputStream, false);
         } catch (IOException | XmlPullParserException e) {
-            throw new EnforcerRuleException("Unable to retrieve the MavenProject: ", e);
+            throw new EnforcerRuleError("Unable to retrieve the MavenProject: ", e);
         }
 
         // @todo reuse ModelValidator when possible
@@ -78,14 +83,14 @@ public class BanDuplicatePomDependencyVersions extends AbstractNonCacheableEnfor
 
         // if( modelValidator == null )
         // {
-        maven2Validation(helper, model);
+        maven2Validation(model);
         // }
         // else
         // {
         // }
     }
 
-    private void maven2Validation(EnforcerRuleHelper helper, Model model) throws EnforcerRuleException {
+    private void maven2Validation(Model model) throws EnforcerRuleException {
         List<Dependency> dependencies = model.getDependencies();
         Map<String, Integer> duplicateDependencies = validateDependencies(dependencies);
 
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDynamicVersions.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BanDynamicVersions.java
similarity index 73%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDynamicVersions.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BanDynamicVersions.java
index aa684c0..6335f97 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDynamicVersions.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BanDynamicVersions.java
@@ -16,7 +16,10 @@
  * 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.text.ChoiceFormat;
 import java.util.ArrayDeque;
@@ -31,15 +34,12 @@ 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.execution.MavenSession;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.shared.utils.logging.MessageBuilder;
 import org.apache.maven.shared.utils.logging.MessageUtils;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
-import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.eclipse.aether.DefaultRepositorySystemSession;
 import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
@@ -50,7 +50,6 @@ import org.eclipse.aether.collection.DependencySelector;
 import org.eclipse.aether.graph.Dependency;
 import org.eclipse.aether.graph.DependencyNode;
 import org.eclipse.aether.graph.DependencyVisitor;
-import org.eclipse.aether.repository.RemoteRepository;
 import org.eclipse.aether.util.graph.selector.AndDependencySelector;
 import org.eclipse.aether.util.graph.selector.OptionalDependencySelector;
 import org.eclipse.aether.util.graph.selector.ScopeDependencySelector;
@@ -68,7 +67,8 @@ import org.eclipse.aether.version.VersionConstraint;
  *
  * @since 3.2.0
  */
-public class BanDynamicVersions extends AbstractNonCacheableEnforcerRule {
+@Named("banDynamicVersions")
+public final class BanDynamicVersions extends AbstractStandardEnforcerRule {
 
     private static final String RELEASE = "RELEASE";
 
@@ -118,43 +118,24 @@ public class BanDynamicVersions extends AbstractNonCacheableEnforcerRule {
      * Any of the sections can be a wildcard by using '*' (e.g. {@code group:*:1.0}).
      * <br>
      * Any of the ignored dependencies may have dynamic versions.
-     *
-     * @see {@link #setIgnores(List)}
      */
     private List<String> ignores = null;
 
-    public void setIgnores(List<String> ignores) {
-        this.ignores = ignores;
-    }
+    private final MavenProject project;
 
-    public void setAllowSnapshots(boolean allowSnapshots) {
-        this.allowSnapshots = allowSnapshots;
-    }
+    private final RepositorySystem repoSystem;
 
-    public void setAllowLatest(boolean allowLatest) {
-        this.allowLatest = allowLatest;
-    }
+    private final MavenSession mavenSession;
 
-    public void setAllowRelease(boolean allowRelease) {
-        this.allowRelease = allowRelease;
-    }
-
-    public void setAllowRanges(boolean allowRanges) {
-        this.allowRanges = allowRanges;
-    }
-
-    public void setExcludeOptionals(boolean excludeOptionals) {
-        this.excludeOptionals = excludeOptionals;
-    }
-
-    public void setExcludedScopes(String[] excludedScopes) {
-        this.excludedScopes = excludedScopes;
+    @Inject
+    public BanDynamicVersions(MavenProject project, RepositorySystem repoSystem, MavenSession mavenSession) {
+        this.project = Objects.requireNonNull(project);
+        this.repoSystem = Objects.requireNonNull(repoSystem);
+        this.mavenSession = Objects.requireNonNull(mavenSession);
     }
 
     private final class BannedDynamicVersionCollector implements DependencyVisitor {
 
-        private final Log log;
-
         private final Deque<DependencyNode> nodeStack; // all intermediate nodes (without the root node)
 
         private boolean isRoot = true;
@@ -167,8 +148,7 @@ public class BanDynamicVersions extends AbstractNonCacheableEnforcerRule {
             return numViolations;
         }
 
-        BannedDynamicVersionCollector(Log log, Predicate<DependencyNode> predicate) {
-            this.log = log;
+        BannedDynamicVersionCollector(Predicate<DependencyNode> predicate) {
             nodeStack = new ArrayDeque<>();
             this.predicate = predicate;
             this.isRoot = true;
@@ -193,7 +173,7 @@ public class BanDynamicVersions extends AbstractNonCacheableEnforcerRule {
                 }
                 return !allowRanges;
             } else {
-                log.warn("Unexpected version constraint found: " + versionConstraint);
+                getLog().warn("Unexpected version constraint found: " + versionConstraint);
             }
             return false;
         }
@@ -203,10 +183,10 @@ public class BanDynamicVersions extends AbstractNonCacheableEnforcerRule {
             if (isRoot) {
                 isRoot = false;
             } else {
-                log.debug("Found node " + node + " with version constraint " + node.getVersionConstraint());
+                getLog().debug("Found node " + node + " with version constraint " + node.getVersionConstraint());
                 if (predicate.test(node) && isBannedDynamicVersion(node.getVersionConstraint())) {
                     MessageBuilder msgBuilder = MessageUtils.buffer();
-                    log.warn(msgBuilder
+                    getLog().warn(msgBuilder
                             .a("Dependency ")
                             .strong(node.getDependency())
                             .mojo(dumpIntermediatePath(nodeStack))
@@ -229,27 +209,12 @@ public class BanDynamicVersions extends AbstractNonCacheableEnforcerRule {
         }
     }
 
-    @SuppressWarnings("unchecked")
     @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        MavenProject project;
-        DefaultRepositorySystemSession newRepoSession;
-        RepositorySystem repoSystem;
-        List<RemoteRepository> remoteRepositories;
-        try {
-            project = (MavenProject) Objects.requireNonNull(helper.evaluate("${project}"), "${project} is null");
-            RepositorySystemSession repoSession = (RepositorySystemSession) Objects.requireNonNull(
-                    helper.evaluate("${repositorySystemSession}"), "${repositorySystemSession} is null");
-            // get a new session to be able to tweak the dependency selector
-            newRepoSession = new DefaultRepositorySystemSession(repoSession);
-            remoteRepositories = (List<RemoteRepository>) helper.evaluate("${project.remoteProjectRepositories}");
-            repoSystem = helper.getComponent(RepositorySystem.class);
-        } catch (ExpressionEvaluationException eee) {
-            throw new EnforcerRuleException("Cannot resolve expression", eee);
-        } catch (ComponentLookupException cle) {
-            throw new EnforcerRuleException("Unable to retrieve component RepositorySystem", cle);
-        }
-        Log log = helper.getLog();
+    public void execute() throws EnforcerRuleException {
+
+        // get a new session to be able to tweak the dependency selector
+        DefaultRepositorySystemSession newRepoSession =
+                new DefaultRepositorySystemSession(mavenSession.getRepositorySession());
 
         Collection<DependencySelector> depSelectors = new ArrayList<>();
         depSelectors.add(new ScopeDependencySelector(excludedScopes));
@@ -261,8 +226,7 @@ public class BanDynamicVersions extends AbstractNonCacheableEnforcerRule {
         Dependency rootDependency = RepositoryUtils.toDependency(project.getArtifact(), null);
         try {
             // use root dependency with unresolved direct dependencies
-            int numViolations = emitDependenciesWithBannedDynamicVersions(
-                    rootDependency, repoSystem, newRepoSession, remoteRepositories, log);
+            int numViolations = emitDependenciesWithBannedDynamicVersions(rootDependency, newRepoSession);
             if (numViolations > 0) {
                 ChoiceFormat dependenciesFormat = new ChoiceFormat("1#dependency|1<dependencies");
                 throw new EnforcerRuleException("Found " + numViolations + " "
@@ -295,14 +259,9 @@ public class BanDynamicVersions extends AbstractNonCacheableEnforcerRule {
         }
     }
 
-    protected int emitDependenciesWithBannedDynamicVersions(
-            org.eclipse.aether.graph.Dependency rootDependency,
-            RepositorySystem repoSystem,
-            RepositorySystemSession repoSession,
-            List<RemoteRepository> remoteRepositories,
-            Log log)
-            throws DependencyCollectionException {
-        CollectRequest collectRequest = new CollectRequest(rootDependency, remoteRepositories);
+    private int emitDependenciesWithBannedDynamicVersions(
+            Dependency rootDependency, RepositorySystemSession repoSession) throws DependencyCollectionException {
+        CollectRequest collectRequest = new CollectRequest(rootDependency, project.getRemoteProjectRepositories());
         CollectResult collectResult = repoSystem.collectDependencies(repoSession, collectRequest);
         Predicate<DependencyNode> predicate;
         if (ignores != null && !ignores.isEmpty()) {
@@ -310,9 +269,23 @@ public class BanDynamicVersions extends AbstractNonCacheableEnforcerRule {
         } else {
             predicate = d -> true;
         }
-        BannedDynamicVersionCollector bannedDynamicVersionCollector = new BannedDynamicVersionCollector(log, predicate);
+        BannedDynamicVersionCollector bannedDynamicVersionCollector = new BannedDynamicVersionCollector(predicate);
         DependencyVisitor depVisitor = new TreeDependencyVisitor(bannedDynamicVersionCollector);
         collectResult.getRoot().accept(depVisitor);
         return bannedDynamicVersionCollector.getNumViolations();
     }
+
+    @Override
+    public String toString() {
+        return String.format(
+                "BanDynamicVersions[allowSnapshots=%b, allowLatest=%b, allowRelease=%b, allowRanges=%b, allowRangesWithIdenticalBounds=%b, excludeOptionals=%b, excludedScopes=%s, ignores=%s]",
+                allowSnapshots,
+                allowLatest,
+                allowRelease,
+                allowRanges,
+                allowRangesWithIdenticalBounds,
+                excludeOptionals,
+                excludedScopes,
+                ignores);
+    }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedPlugins.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BannedPlugins.java
similarity index 50%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedPlugins.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BannedPlugins.java
index 73db174..b9a48e4 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedPlugins.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BannedPlugins.java
@@ -16,39 +16,63 @@
  * 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.List;
+import java.util.Objects;
 
 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.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 
 /**
  * This rule checks that lists of plugins are not included.
  *
  * @author <a href="mailto:velo.br@gmail.com">Marvin Froeder</a>
  */
-public class BannedPlugins extends BannedDependenciesBase {
+@Named("bannedPlugins")
+public final class BannedPlugins extends AbstractStandardEnforcerRule {
+
+    /**
+     * Specify the banned plugins. This can be a list of plugins in the format
+     * <code>groupId[:artifactId][:version]</code>. Any of the sections can be a wildcard
+     * by using '*' (ie group:*:1.0) <br>
+     * The rule will fail if any plugin matches any exclude, unless it also matches
+     * an include rule.
+     */
+    private List<String> excludes = null;
+
+    /**
+     * Specify the allowed plugins. This can be a list of plugins in the format
+     * <code>groupId[:artifactId][:version]</code>. Any of the sections can be a wildcard
+     * by using '*' (ie group:*:1.0) <br>
+     * Includes override the exclude rules. It is meant to allow wide exclusion rules
+     * with wildcards and still allow a
+     * smaller set of includes. <br>
+     * For example, to ban all xerces except xerces-api -&gt; exclude "xerces", include "xerces:xerces-api"
+     */
+    private List<String> includes = null;
+
+    private final MavenSession session;
+
+    @Inject
+    public BannedPlugins(MavenSession session) {
+        this.session = Objects.requireNonNull(session);
+    }
 
     @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        MavenSession session;
-        try {
-            session = (MavenSession) helper.evaluate("${session}");
-        } catch (ExpressionEvaluationException e) {
-            throw new EnforcerRuleException("Cannot resolve MavenSession", e);
-        }
+    public void execute() throws EnforcerRuleException {
 
         String result = session.getCurrentProject().getPluginArtifacts().stream()
                 .filter(a -> !validate(a))
                 .collect(
                         StringBuilder::new,
-                        (messageBuilder, node) -> messageBuilder
-                                .append(node.getId())
-                                .append(" <--- ")
-                                .append(getErrorMessage()),
+                        (messageBuilder, node) ->
+                                messageBuilder.append(node.getId()).append(" <--- banned plugin"),
                         (m1, m2) -> m1.append(m2.toString()))
                 .toString();
         if (!result.isEmpty()) {
@@ -56,14 +80,13 @@ public class BannedPlugins extends BannedDependenciesBase {
         }
     }
 
-    @Override
-    protected String getErrorMessage() {
-        return "banned plugin";
+    private boolean validate(Artifact artifact) {
+        return !ArtifactUtils.matchDependencyArtifact(artifact, excludes)
+                || ArtifactUtils.matchDependencyArtifact(artifact, includes);
     }
 
     @Override
-    protected boolean validate(Artifact artifact) {
-        return !ArtifactUtils.matchDependencyArtifact(artifact, excludes)
-                || ArtifactUtils.matchDependencyArtifact(artifact, includes);
+    public String toString() {
+        return String.format("BannedPlugins[excludes=%s, includes=%s]", excludes, includes);
     }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedRepositories.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BannedRepositories.java
similarity index 75%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedRepositories.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BannedRepositories.java
index bb5b50c..9284f63 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BannedRepositories.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BannedRepositories.java
@@ -16,17 +16,19 @@
  * 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.artifact.repository.ArtifactRepository;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 import org.codehaus.plexus.util.StringUtils;
 
 /**
@@ -34,7 +36,8 @@ import org.codehaus.plexus.util.StringUtils;
  *
  * @author <a href="mailto:wangyf2010@gmail.com">Simon Wang</a>
  */
-public class BannedRepositories extends AbstractNonCacheableEnforcerRule {
+@Named("bannedRepositories")
+public final class BannedRepositories extends AbstractStandardEnforcerRule {
 
     // ----------------------------------------------------------------------
     // Mojo parameters
@@ -43,63 +46,53 @@ public class BannedRepositories extends AbstractNonCacheableEnforcerRule {
     /**
      * Specify explicitly banned non-plugin repositories. This is a list of repository url patterns. Support wildcard
      * "*".
-     *
-     * @see {@link #setBannedRepositories(List)}
      */
     private List<String> bannedRepositories = Collections.emptyList();
 
     /**
      * Specify explicitly banned plugin repositories. This is a list of repository url patterns. Support wildcard "*".
-     *
-     * @see {@link #setBannedPluginRepositories(List)}
      */
     private List<String> bannedPluginRepositories = Collections.emptyList();
 
     /**
      * Specify explicitly allowed non-plugin repositories, then all others repositories would be banned. This is a list
      * of repository url patterns. Support wildcard "*".
-     *
-     * @see {@link #setAllowedRepositories(List)}
      */
     private List<String> allowedRepositories = Collections.emptyList();
 
     /**
      * Specify explicitly allowed plugin repositories, then all others repositories would be banned. This is a list of
      * repository url patterns. Support wildcard "*".
-     *
-     * @see {@link #setAllowedPluginRepositories(List)}
      */
     private List<String> allowedPluginRepositories = Collections.emptyList();
 
+    private final MavenProject project;
+
+    @Inject
+    public BannedRepositories(MavenProject project) {
+        this.project = Objects.requireNonNull(project);
+    }
+
     // ----------------------------------------------------------------------
     // Public methods
     // ----------------------------------------------------------------------
 
     @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        MavenProject project;
-        try {
-            project = (MavenProject) helper.evaluate("${project}");
+    public void execute() throws EnforcerRuleException {
 
-            List<ArtifactRepository> resultBannedRepos = checkRepositories(
-                    project.getRemoteArtifactRepositories(), this.allowedRepositories, this.bannedRepositories);
+        List<ArtifactRepository> resultBannedRepos = checkRepositories(
+                project.getRemoteArtifactRepositories(), this.allowedRepositories, this.bannedRepositories);
 
-            List<ArtifactRepository> resultBannedPluginRepos = checkRepositories(
-                    project.getPluginArtifactRepositories(),
-                    this.allowedPluginRepositories,
-                    this.bannedPluginRepositories);
+        List<ArtifactRepository> resultBannedPluginRepos = checkRepositories(
+                project.getPluginArtifactRepositories(), this.allowedPluginRepositories, this.bannedPluginRepositories);
 
-            String repoErrMsg = populateErrorMessage(resultBannedRepos, " ");
-            String pluginRepoErrMsg = populateErrorMessage(resultBannedPluginRepos, " plugin ");
+        String repoErrMsg = populateErrorMessage(resultBannedRepos, " ");
+        String pluginRepoErrMsg = populateErrorMessage(resultBannedPluginRepos, " plugin ");
 
-            String errMsg = repoErrMsg + pluginRepoErrMsg;
+        String errMsg = repoErrMsg + pluginRepoErrMsg;
 
-            if (errMsg != null && !StringUtils.isEmpty(errMsg)) {
-                throw new EnforcerRuleException(errMsg);
-            }
-
-        } catch (ExpressionEvaluationException e) {
-            throw new EnforcerRuleException(e.getLocalizedMessage());
+        if (errMsg != null && !StringUtils.isEmpty(errMsg)) {
+            throw new EnforcerRuleException(errMsg);
         }
     }
 
@@ -111,10 +104,6 @@ public class BannedRepositories extends AbstractNonCacheableEnforcerRule {
         this.bannedRepositories = bannedRepositories;
     }
 
-    protected void setBannedPluginRepositories(List<String> bannedPluginRepositories) {
-        this.bannedPluginRepositories = bannedPluginRepositories;
-    }
-
     protected void setAllowedRepositories(List<String> allowedRepositories) {
         this.allowedRepositories = allowedRepositories;
     }
@@ -137,6 +126,10 @@ public class BannedRepositories extends AbstractNonCacheableEnforcerRule {
      */
     private List<ArtifactRepository> checkRepositories(
             List<ArtifactRepository> repositories, List<String> includes, List<String> excludes) {
+
+        getLog().debug(() -> String.format(
+                "Check repositories: %s, for includes=%s and excludes=%s", repositories, includes, excludes));
+
         List<ArtifactRepository> bannedRepos = new ArrayList<>();
 
         for (ArtifactRepository repo : repositories) {
@@ -186,4 +179,11 @@ public class BannedRepositories extends AbstractNonCacheableEnforcerRule {
         }
         return urls.toString();
     }
+
+    @Override
+    public String toString() {
+        return String.format(
+                "BannedRepositories[bannedRepositories=%s, bannedPluginRepositories=%s, allowedRepositories=%s, allowedPluginRepositories=%s",
+                bannedRepositories, bannedPluginRepositories, allowedRepositories, allowedPluginRepositories);
+    }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EvaluateBeanshell.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/EvaluateBeanshell.java
similarity index 63%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EvaluateBeanshell.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/EvaluateBeanshell.java
index 9adf525..07dfb7c 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EvaluateBeanshell.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/EvaluateBeanshell.java
@@ -16,14 +16,18 @@
  * 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.Objects;
 
 import bsh.EvalError;
 import bsh.Interpreter;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
-import org.apache.maven.plugin.logging.Log;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
 import org.codehaus.plexus.util.StringUtils;
 
 /**
@@ -31,36 +35,40 @@ import org.codehaus.plexus.util.StringUtils;
  *
  * @author hugonnem
  */
-public class EvaluateBeanshell extends AbstractNonCacheableEnforcerRule {
+@Named("evaluateBeanshell")
+public final class EvaluateBeanshell extends AbstractStandardEnforcerRule {
 
     /** Beanshell interpreter. */
-    private static final ThreadLocal<Interpreter> INTERPRETER = ThreadLocal.withInitial(Interpreter::new);
+    private final Interpreter interpreter = new Interpreter();
 
     /** The condition to be evaluated.
-     *
-     * @see {@link #setCondition(String)}
-     * @see {@link #getCondition()}
      * */
     private String condition;
 
-    public final void setCondition(String condition) {
+    private final ExpressionEvaluator evaluator;
+
+    @Inject
+    public EvaluateBeanshell(ExpressionEvaluator evaluator) {
+        this.evaluator = Objects.requireNonNull(evaluator);
+    }
+
+    public void setCondition(String condition) {
         this.condition = condition;
     }
 
-    public final String getCondition() {
+    public String getCondition() {
         return condition;
     }
 
     @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        Log log = helper.getLog();
+    public void execute() throws EnforcerRuleException {
 
         try {
-            log.debug("Echo condition : " + this.condition);
+            getLog().debug("Echo condition : " + condition);
             // Evaluate condition within Plexus Container
-            String script = (String) helper.evaluate(this.condition);
-            log.debug("Echo script : " + script);
-            if (!evaluateCondition(script, log)) {
+            String script = (String) evaluator.evaluate(condition);
+            getLog().debug("Echo script : " + script);
+            if (!evaluateCondition(script)) {
                 String message = getMessage();
                 if (StringUtils.isEmpty(message)) {
                     message = "The expression \"" + condition + "\" is not true.";
@@ -76,18 +84,22 @@ public class EvaluateBeanshell extends AbstractNonCacheableEnforcerRule {
      * Evaluate expression using Beanshell.
      *
      * @param script the expression to be evaluated
-     * @param log the logger
      * @return boolean the evaluation of the expression
      * @throws EnforcerRuleException if the script could not be evaluated
      */
-    protected boolean evaluateCondition(String script, Log log) throws EnforcerRuleException {
+    private boolean evaluateCondition(String script) throws EnforcerRuleException {
         Boolean evaluation;
         try {
-            evaluation = (Boolean) INTERPRETER.get().eval(script);
-            log.debug("Echo evaluating : " + evaluation);
+            evaluation = (Boolean) interpreter.eval(script);
+            getLog().debug("Echo evaluating : " + evaluation);
         } catch (EvalError ex) {
             throw new EnforcerRuleException("Couldn't evaluate condition: " + script, ex);
         }
-        return evaluation.booleanValue();
+        return evaluation;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("EvaluateBeanshell[message=%s, condition=%s]", getMessage(), condition);
     }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/ExternalRules.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/ExternalRules.java
index 4a436cb..35fdb4a 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/ExternalRules.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/ExternalRules.java
@@ -42,7 +42,7 @@ import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
  * @since 3.2.0
  */
 @Named("externalRules")
-public class ExternalRules extends AbstractEnforcerRuleConfigProvider {
+public final class ExternalRules extends AbstractEnforcerRuleConfigProvider {
     private static final String LOCATION_PREFIX_CLASSPATH = "classpath:";
 
     /**
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/ReactorModuleConvergence.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/ReactorModuleConvergence.java
similarity index 89%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/ReactorModuleConvergence.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/ReactorModuleConvergence.java
index b08479b..651f12f 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/ReactorModuleConvergence.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/ReactorModuleConvergence.java
@@ -16,21 +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.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 
 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.Dependency;
-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;
 
 /**
@@ -39,23 +40,21 @@ import org.codehaus.plexus.util.StringUtils;
  * @author Karl-Heinz Marbaise
  * @since 1.4
  */
-public class ReactorModuleConvergence extends AbstractNonCacheableEnforcerRule {
+@Named("reactorModuleConvergence")
+public final class ReactorModuleConvergence extends AbstractStandardEnforcerRule {
     private static final String MODULE_TEXT = " module: ";
 
     private boolean ignoreModuleDependencies = false;
 
-    private Log logger;
+    private final MavenSession session;
+
+    @Inject
+    public ReactorModuleConvergence(MavenSession session) {
+        this.session = Objects.requireNonNull(session);
+    }
 
     @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        logger = helper.getLog();
-
-        MavenSession session;
-        try {
-            session = (MavenSession) helper.evaluate("${session}");
-        } catch (ExpressionEvaluationException eee) {
-            throw new EnforcerRuleException("Unable to retrieve the MavenSession: ", eee);
-        }
+    public void execute() throws EnforcerRuleException {
 
         List<MavenProject> sortedProjects = session.getProjectDependencyGraph().getSortedProjects();
         if (sortedProjects != null && !sortedProjects.isEmpty()) {
@@ -182,12 +181,12 @@ public class ReactorModuleConvergence extends AbstractNonCacheableEnforcerRule {
         List<MavenProject> result = new ArrayList<>();
 
         for (MavenProject mavenProject : sortedProjects) {
-            logger.debug("Project: " + mavenProject.getId());
+            getLog().debug("Project: " + mavenProject.getId());
             if (hasParent(mavenProject)) {
                 if (!mavenProject.isExecutionRoot()) {
                     MavenProject parent = mavenProject.getParent();
                     if (!reactorVersion.equals(parent.getVersion())) {
-                        logger.debug("The project: " + mavenProject.getId()
+                        getLog().debug("The project: " + mavenProject.getId()
                                 + " has a parent which version does not match the other elements in reactor");
                         result.add(mavenProject);
                     }
@@ -204,7 +203,7 @@ public class ReactorModuleConvergence extends AbstractNonCacheableEnforcerRule {
         List<MavenProject> result = new ArrayList<>();
 
         for (MavenProject mavenProject : sortedProjects) {
-            logger.debug("Project: " + mavenProject.getId());
+            getLog().debug("Project: " + mavenProject.getId());
             if (hasParent(mavenProject)) {
                 if (!mavenProject.isExecutionRoot()) {
                     MavenProject parent = mavenProject.getParent();
@@ -222,7 +221,7 @@ public class ReactorModuleConvergence extends AbstractNonCacheableEnforcerRule {
      * This will check of the groupId/artifactId can be found in any reactor project. The version will be ignored cause
      * versions are checked before.
      *
-     * @param project The project which should be checked if it is contained in the sortedProjects.
+     * @param project        The project which should be checked if it is contained in the sortedProjects.
      * @param sortedProjects The list of existing projects.
      * @return true if the project has been found within the list false otherwise.
      */
@@ -237,8 +236,8 @@ public class ReactorModuleConvergence extends AbstractNonCacheableEnforcerRule {
     /**
      * This will check if the given <code>groupId/artifactId</code> is part of the current reactor.
      *
-     * @param groupId The groupId
-     * @param artifactId The artifactId
+     * @param groupId        The groupId
+     * @param artifactId     The artifactId
      * @param sortedProjects The list of projects within the reactor.
      * @return true if the groupId/artifactId is part of the reactor false otherwise.
      */
@@ -266,13 +265,13 @@ public class ReactorModuleConvergence extends AbstractNonCacheableEnforcerRule {
         List<MavenProject> result = new ArrayList<>();
 
         for (MavenProject mavenProject : sortedProjects) {
-            logger.debug("Project: " + mavenProject.getId());
+            getLog().debug("Project: " + mavenProject.getId());
             if (!hasParent(mavenProject)) {
                 // TODO: Should add an option to force having a parent?
                 if (mavenProject.isExecutionRoot()) {
-                    logger.debug("The root does not need having a parent.");
+                    getLog().debug("The root does not need having a parent.");
                 } else {
-                    logger.debug("The module: " + mavenProject.getId() + " has no parent.");
+                    getLog().debug("The module: " + mavenProject.getId() + " has no parent.");
                     result.add(mavenProject);
                 }
             }
@@ -284,8 +283,8 @@ public class ReactorModuleConvergence extends AbstractNonCacheableEnforcerRule {
     /**
      * Convenience method to handle adding a dependency to the Map of List.
      *
-     * @param result The result List which should be handled.
-     * @param project The MavenProject which will be added.
+     * @param result     The result List which should be handled.
+     * @param project    The MavenProject which will be added.
      * @param dependency The dependency which will be added.
      */
     private void addDep(Map<MavenProject, List<Dependency>> result, MavenProject project, Dependency dependency) {
@@ -319,12 +318,12 @@ public class ReactorModuleConvergence extends AbstractNonCacheableEnforcerRule {
             {
         Map<MavenProject, List<Dependency>> result = new HashMap<>();
         for (MavenProject mavenProject : sortedProjects) {
-            logger.debug("Project: " + mavenProject.getId());
+            getLog().debug("Project: " + mavenProject.getId());
 
             List<Dependency> dependencies = mavenProject.getDependencies();
             if (hasDependencies(dependencies)) {
                 for (Dependency dependency : dependencies) {
-                    logger.debug(" -> Dep:" + dependency.getGroupId() + ":" + dependency.getArtifactId() + ":"
+                    getLog().debug(" -> Dep:" + dependency.getGroupId() + ":" + dependency.getArtifactId() + ":"
                             + dependency.getVersion());
                     if (isDependencyPartOfTheReactor(dependency, sortedProjects)) {
                         if (!dependency.getVersion().equals(reactorVersion)) {
@@ -340,14 +339,12 @@ public class ReactorModuleConvergence extends AbstractNonCacheableEnforcerRule {
 
     /**
      * This method will check the following situation within a multi-module build.
-     *
      * <pre>
      *  &lt;parent&gt;
      *    &lt;groupId&gt;...&lt;/groupId&gt;
      *    &lt;artifactId&gt;...&lt;/artifactId&gt;
      *    &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;
      *  &lt;/parent&gt;
-     *
      *  &lt;version&gt;1.1-SNAPSHOT&lt;/version&gt;
      * </pre>
      *
@@ -360,9 +357,9 @@ public class ReactorModuleConvergence extends AbstractNonCacheableEnforcerRule {
 
         if (projectList != null && !projectList.isEmpty()) {
             String version = projectList.get(0).getVersion();
-            logger.debug("First version:" + version);
+            getLog().debug("First version:" + version);
             for (MavenProject mavenProject : projectList) {
-                logger.debug(" -> checking " + mavenProject.getId());
+                getLog().debug(" -> checking " + mavenProject.getId());
                 if (!version.equals(mavenProject.getVersion())) {
                     result.add(mavenProject);
                 }
@@ -383,10 +380,6 @@ public class ReactorModuleConvergence extends AbstractNonCacheableEnforcerRule {
         return ignoreModuleDependencies;
     }
 
-    public void setIgnoreModuleDependencies(boolean ignoreModuleDependencies) {
-        this.ignoreModuleDependencies = ignoreModuleDependencies;
-    }
-
     /**
      * This will add the given user message to the output.
      *
@@ -398,4 +391,11 @@ public class ReactorModuleConvergence extends AbstractNonCacheableEnforcerRule {
             sb.append(System.lineSeparator());
         }
     }
+
+    @Override
+    public String toString() {
+        return String.format(
+                "ReactorModuleConvergence[message=%s, ignoreModuleDependencies=%b]",
+                getMessage(), ignoreModuleDependencies);
+    }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireActiveProfile.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireActiveProfile.java
similarity index 50%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireActiveProfile.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireActiveProfile.java
index b804d58..58878ce 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireActiveProfile.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireActiveProfile.java
@@ -16,16 +16,18 @@
  * 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.List;
 import java.util.Map;
+import java.util.Objects;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 import org.codehaus.plexus.util.StringUtils;
 
 /**
@@ -33,75 +35,71 @@ import org.codehaus.plexus.util.StringUtils;
  *
  * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
  */
-public class RequireActiveProfile extends AbstractNonCacheableEnforcerRule {
+@Named("requireActiveProfile")
+public final class RequireActiveProfile extends AbstractStandardEnforcerRule {
 
     /** Comma separated list of profiles to check.
-     *
-     * @see {@link #setProfiles(String)}
-     * @see {@link #getProfiles()}
      */
     private String profiles = null;
 
     /** If all profiles must be active. If false, only one must be active
-     *
-     * @see {@link #setAll(boolean)}
-     * @see {@link #isAll()}
      */
     private boolean all = true;
 
-    public final String getProfiles() {
+    private final MavenProject project;
+
+    @Inject
+    public RequireActiveProfile(MavenProject project) {
+        this.project = Objects.requireNonNull(project);
+    }
+
+    public String getProfiles() {
         return profiles;
     }
 
-    public final void setProfiles(String profiles) {
+    public void setProfiles(String profiles) {
         this.profiles = profiles;
     }
 
-    public final boolean isAll() {
+    public boolean isAll() {
         return all;
     }
 
-    public final void setAll(boolean all) {
+    public void setAll(boolean all) {
         this.all = all;
     }
 
     @Override
-    public void execute(EnforcerRuleHelper theHelper) throws EnforcerRuleException {
+    public void execute() throws EnforcerRuleException {
         List<String> missingProfiles = new ArrayList<>();
-        try {
-            MavenProject project = (MavenProject) theHelper.evaluate("${project}");
-            if (StringUtils.isNotEmpty(profiles)) {
-                String[] profileIds = profiles.split(",");
-                for (String profileId : profileIds) {
-                    if (!isProfileActive(project, profileId)) {
-                        missingProfiles.add(profileId);
-                    }
+        if (StringUtils.isNotEmpty(profiles)) {
+            String[] profileIds = profiles.split(",");
+            for (String profileId : profileIds) {
+                if (!isProfileActive(project, profileId)) {
+                    missingProfiles.add(profileId);
                 }
+            }
 
-                boolean fail = false;
-                if (!missingProfiles.isEmpty()) {
-                    if (all || missingProfiles.size() == profileIds.length) {
-                        fail = true;
-                    }
+            boolean fail = false;
+            if (!missingProfiles.isEmpty()) {
+                if (all || missingProfiles.size() == profileIds.length) {
+                    fail = true;
                 }
+            }
 
-                if (fail) {
-                    String message = getMessage();
-                    StringBuilder buf = new StringBuilder();
-                    if (message != null) {
-                        buf.append(message + System.lineSeparator());
-                    }
-
-                    for (String profile : missingProfiles) {
-                        buf.append("Profile \"" + profile + "\" is not activated." + System.lineSeparator());
-                    }
+            if (fail) {
+                String message = getMessage();
+                StringBuilder buf = new StringBuilder();
+                if (message != null) {
+                    buf.append(message + System.lineSeparator());
+                }
 
-                    throw new EnforcerRuleException(buf.toString());
+                for (String profile : missingProfiles) {
+                    buf.append("Profile \"" + profile + "\" is not activated." + System.lineSeparator());
                 }
-            }
 
-        } catch (ExpressionEvaluationException e) {
-            throw new EnforcerRuleException("Unable to retrieve the project.", e);
+                throw new EnforcerRuleException(buf.toString());
+            }
         }
     }
 
@@ -112,7 +110,7 @@ public class RequireActiveProfile extends AbstractNonCacheableEnforcerRule {
      * @param profileId the profile name
      * @return <code>true</code> if profile is active, otherwise <code>false</code>
      */
-    protected boolean isProfileActive(MavenProject project, String profileId) {
+    private boolean isProfileActive(MavenProject project, String profileId) {
         for (Map.Entry<String, List<String>> entry :
                 project.getInjectedProfileIds().entrySet()) {
             if (entry.getValue().contains(profileId)) {
@@ -121,4 +119,9 @@ public class RequireActiveProfile extends AbstractNonCacheableEnforcerRule {
         }
         return false;
     }
+
+    @Override
+    public String toString() {
+        return String.format("RequireActiveProfile[message=%s, profiles=%s, all=%b]", getMessage(), profiles, all);
+    }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireExplicitDependencyScope.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireExplicitDependencyScope.java
new file mode 100644
index 0000000..11aeeb1
--- /dev/null
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireExplicitDependencyScope.java
@@ -0,0 +1,84 @@
+/*
+ * 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.rules;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import java.text.ChoiceFormat;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.maven.enforcer.rule.api.EnforcerLevel;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.shared.utils.logging.MessageBuilder;
+import org.apache.maven.shared.utils.logging.MessageUtils;
+
+/**
+ * Checks that all dependencies have an explicitly declared scope in the non-effective pom (i.e. without taking
+ * inheritance or dependency management into account).
+ */
+@Named("requireExplicitDependencyScope")
+public final class RequireExplicitDependencyScope extends AbstractStandardEnforcerRule {
+
+    private final MavenProject project;
+
+    @Inject
+    public RequireExplicitDependencyScope(MavenProject project) {
+        this.project = Objects.requireNonNull(project);
+    }
+
+    @Override
+    public void execute() throws EnforcerRuleException {
+        int numMissingDependencyScopes = 0;
+        List<Dependency> dependencies = project.getOriginalModel().getDependencies(); // this is the non-effective
+        // model but the original one
+        // without inheritance and
+        // interpolation resolved
+        // check scope without considering inheritance
+        for (Dependency dependency : dependencies) {
+            getLog().debug("Found dependency " + dependency);
+            if (dependency.getScope() == null) {
+                MessageBuilder msgBuilder = MessageUtils.buffer();
+                msgBuilder
+                        .a("Dependency ")
+                        .strong(dependency.getManagementKey())
+                        .a(" @ ")
+                        .strong(formatLocation(project, dependency.getLocation("")))
+                        .a(" does not have an explicit scope defined!")
+                        .toString();
+                if (getLevel() == EnforcerLevel.ERROR) {
+                    getLog().error(msgBuilder.toString());
+                } else {
+                    getLog().warn(msgBuilder.toString());
+                }
+                numMissingDependencyScopes++;
+            }
+        }
+        if (numMissingDependencyScopes > 0) {
+            ChoiceFormat scopesFormat = new ChoiceFormat("1#scope|1<scopes");
+            String logCategory = getLevel() == EnforcerLevel.ERROR ? "errors" : "warnings";
+            throw new EnforcerRuleException("Found " + numMissingDependencyScopes + " missing dependency "
+                    + scopesFormat.format(numMissingDependencyScopes)
+                    + ". Look at the " + logCategory + " emitted above for the details.");
+        }
+    }
+}
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireJavaVendor.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireJavaVendor.java
index dc94632..5b4dbd7 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireJavaVendor.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireJavaVendor.java
@@ -125,7 +125,6 @@ public final class RequireJavaVendor extends AbstractStandardEnforcerRule {
     @Override
     public String toString() {
         return String.format(
-                "RequireJavaVendor[level=%s, message=%s, includes=%s, excludes=%s]",
-                getLevel(), getMessage(), includes, excludes);
+                "RequireJavaVendor[message=%s, includes=%s, excludes=%s]", getMessage(), includes, excludes);
     }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireNoRepositories.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireNoRepositories.java
index 3a0fb36..df08c72 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireNoRepositories.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireNoRepositories.java
@@ -250,8 +250,9 @@ public final class RequireNoRepositories extends AbstractStandardEnforcerRule {
     @Override
     public String toString() {
         return String.format(
-                "RequireNoRepositories[banRepositories=%b, allowSnapshotRepositories=%b, allowedRepositories=%s, "
+                "RequireNoRepositories[message=%s, banRepositories=%b, allowSnapshotRepositories=%b, allowedRepositories=%s, "
                         + "banPluginRepositories=%b, allowSnapshotPluginRepositories=%b, allowedPluginRepositories=%s]",
+                getMessage(),
                 banRepositories,
                 allowSnapshotRepositories,
                 allowedRepositories,
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireOS.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireOS.java
index 7317cab..29738da 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireOS.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireOS.java
@@ -40,7 +40,7 @@ import org.codehaus.plexus.util.StringUtils;
  * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
  */
 @Named("requireOS")
-public class RequireOS extends AbstractStandardEnforcerRule {
+public final class RequireOS extends AbstractStandardEnforcerRule {
     private final ProfileActivator activator;
 
     /**
@@ -263,7 +263,7 @@ public class RequireOS extends AbstractStandardEnforcerRule {
     /**
      * @param display The value for the display.
      */
-    public final void setDisplay(boolean display) {
+    public void setDisplay(boolean display) {
         this.display = display;
     }
 
@@ -285,4 +285,11 @@ public class RequireOS extends AbstractStandardEnforcerRule {
         }
         return b.toString();
     }
+
+    @Override
+    public String toString() {
+        return String.format(
+                "RequireOS[message=%s, arch=%s, family=%s, name=%s, version=%s, display=%b]",
+                getMessage(), arch, family, name, version, display);
+    }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequirePluginVersions.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequirePluginVersions.java
similarity index 80%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequirePluginVersions.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequirePluginVersions.java
index a552f03..b7e5060 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequirePluginVersions.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequirePluginVersions.java
@@ -16,7 +16,10 @@
  * 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.Arrays;
@@ -25,6 +28,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 import org.apache.maven.BuildFailureException;
@@ -36,8 +40,8 @@ import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
 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.ExpressionEvaluator;
 import org.apache.maven.enforcer.rules.utils.PluginWrapper;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.lifecycle.DefaultLifecycles;
@@ -55,12 +59,12 @@ import org.apache.maven.plugin.PluginManager;
 import org.apache.maven.plugin.PluginManagerException;
 import org.apache.maven.plugin.PluginNotFoundException;
 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.project.MavenProject;
 import org.apache.maven.rtinfo.RuntimeInformation;
 import org.apache.maven.settings.Settings;
+import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.codehaus.plexus.util.StringUtils;
@@ -73,39 +77,26 @@ import org.eclipse.aether.resolution.ArtifactResolutionException;
  *
  * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
  */
-public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
-
-    private EnforcerRuleHelper helper;
+@Named("requirePluginVersions")
+public final class RequirePluginVersions extends AbstractStandardEnforcerRule {
 
     /**
      * Don't allow the LATEST identifier.
-     *
-     * @see {@link #setBanLatest(boolean)}
-     * @see {@link #isBanLatest()}
      */
     private boolean banLatest = true;
 
     /**
      * Don't allow the RELEASE identifier.
-     *
-     * @see {@link #setBanRelease(boolean)}
-     * @see {@link #isBanRelease()}
      */
     private boolean banRelease = true;
 
     /**
      * Don't allow snapshot plugins.
-     *
-     * @see {@link #setBanSnapshots(boolean)}
-     * @see {@link #isBanSnapshots()}
      */
     private boolean banSnapshots = true;
 
     /**
      * Don't allow timestamp snapshot plugins.
-     *
-     * @see {@link #setBanTimestamps(boolean)}
-     * @see {@link #isBanTimestamps()}
      */
     private boolean banTimestamps = true;
 
@@ -117,9 +108,6 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
     /**
      * The comma separated list of phases that should be used to find lifecycle plugin bindings. The default value is
      * "clean,deploy,site".
-     *
-     * @see {@link #setPhases(String)}
-     * @see {@link #getPhases()}
      */
     private String phases = "clean,deploy,site";
 
@@ -127,82 +115,87 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
      * Additional plugins to enforce have versions. These are plugins that may not be in the poms but are used anyway,
      * like help, eclipse etc. <br>
      * The plugins should be specified in the form: <code>group:artifactId</code>.
-     *
-     * @see {@link #setAdditionalPlugins(List)}
-     * @see {@link #getAdditionalPlugins()}
      */
     private List<String> additionalPlugins;
 
     /**
      * Plugins to skip for version enforcement. The plugins should be specified in the form:
      * <code>group:artifactId</code>. NOTE: This is deprecated, use unCheckedPluginList instead.
-     *
-     * @see {@link #setUnCheckedPlugins(List)}
-     * @see {@link #getUnCheckedPlugins()}
      */
     private List<String> unCheckedPlugins;
 
     /**
      * Same as unCheckedPlugins but as a comma list to better support properties. Sample form:
      * <code>group:artifactId,group2:artifactId2</code>
-     *
      * @since 1.0-beta-1
-     * @see {@link #setUnCheckedPlugins(List)}
-     * @see {@link #getUnCheckedPlugins()}
      */
     private String unCheckedPluginList;
 
-    /** The plugin manager. */
-    private PluginManager pluginManager;
-
     /** The phase to lifecycle map. */
     private Map<String, Lifecycle> phaseToLifecycleMap;
 
     /** The lifecycles. */
     private Collection<Lifecycle> lifecycles;
 
+    /** The plugin manager. */
+    private final PluginManager pluginManager;
+
     /** The factory. */
-    private ArtifactFactory factory;
+    private final ArtifactFactory factory;
 
-    private RepositorySystem repositorySystem;
+    private final RepositorySystem repositorySystem;
 
     /** The local. */
     private ArtifactRepository local;
 
-    /** The log. */
-    private Log log;
-
     /** The session. */
-    private MavenSession session;
+    private final MavenSession session;
 
     /** The utils. */
-    private EnforcerRuleUtils utils;
-
-    private RuntimeInformation runtimeInformation;
+    private final EnforcerRuleUtils utils;
+
+    private final RuntimeInformation runtimeInformation;
+
+    private final DefaultLifecycles defaultLifeCycles;
+
+    private final MavenProject project;
+
+    private final ExpressionEvaluator evaluator;
+
+    private final PlexusContainer container;
+
+    @Inject
+    public RequirePluginVersions(
+            PluginManager pluginManager,
+            ArtifactFactory factory,
+            RepositorySystem repositorySystem,
+            MavenSession session,
+            EnforcerRuleUtils utils,
+            RuntimeInformation runtimeInformation,
+            DefaultLifecycles defaultLifeCycles,
+            MavenProject project,
+            ExpressionEvaluator evaluator,
+            PlexusContainer container) {
+        this.pluginManager = Objects.requireNonNull(pluginManager);
+        this.factory = Objects.requireNonNull(factory);
+        this.repositorySystem = Objects.requireNonNull(repositorySystem);
+        this.session = Objects.requireNonNull(session);
+        this.utils = Objects.requireNonNull(utils);
+        this.runtimeInformation = Objects.requireNonNull(runtimeInformation);
+        this.defaultLifeCycles = Objects.requireNonNull(defaultLifeCycles);
+        this.project = Objects.requireNonNull(project);
+        this.evaluator = Objects.requireNonNull(evaluator);
+        this.container = Objects.requireNonNull(container);
+    }
 
     @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        this.log = helper.getLog();
-        this.helper = helper;
+    public void execute() throws EnforcerRuleException {
 
-        MavenProject project;
         try {
             // get the various expressions out of the helper.
 
-            project = (MavenProject) helper.evaluate("${project}");
-
-            runtimeInformation = helper.getComponent(RuntimeInformation.class);
-
-            DefaultLifecycles defaultLifeCycles = helper.getComponent(DefaultLifecycles.class);
             lifecycles = defaultLifeCycles.getLifeCycles();
-
-            session = (MavenSession) helper.evaluate("${session}");
-            pluginManager = helper.getComponent(PluginManager.class);
-            factory = helper.getComponent(ArtifactFactory.class);
-            repositorySystem = helper.getComponent(RepositorySystem.class);
-            local = (ArtifactRepository) helper.evaluate("${localRepository}");
-
-            utils = new EnforcerRuleUtils(helper);
+            local = session.getLocalRepository();
 
             // get all the plugins that are bound to the specified lifecycles
             Set<Plugin> allPlugins = getBoundPlugins(project, phases);
@@ -217,24 +210,24 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
 
             // there's nothing to do here
             if (allPlugins.isEmpty()) {
-                log.info("No plugin bindings found.");
+                getLog().info("No plugin bindings found.");
                 return;
             } else {
-                log.debug("All Plugins in use: " + allPlugins);
+                getLog().debug("All Plugins in use: " + allPlugins);
             }
 
             // get all the plugins that are mentioned in the pom (and parents)
             List<PluginWrapper> pluginWrappers = getAllPluginEntries(project);
 
             for (PluginWrapper pluginWrapper : pluginWrappers) {
-                log.debug("pluginWrappers: " + pluginWrapper.getGroupId() + ":" + pluginWrapper.getArtifactId() + ":"
-                        + pluginWrapper.getVersion() + " source: " + pluginWrapper.getSource());
+                getLog().debug("pluginWrappers: " + pluginWrapper.getGroupId() + ":" + pluginWrapper.getArtifactId()
+                        + ":" + pluginWrapper.getVersion() + " source: " + pluginWrapper.getSource());
             }
             // now look for the versions that aren't valid and add to a list.
             List<Plugin> failures = new ArrayList<>();
 
             for (Plugin plugin : allPlugins) {
-                if (!hasValidVersionSpecified(helper, plugin, pluginWrappers)) {
+                if (!hasValidVersionSpecified(plugin, pluginWrappers)) {
                     failures.add(plugin);
                 }
             }
@@ -243,10 +236,6 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
             if (!failures.isEmpty()) {
                 handleMessagesToTheUser(project, failures);
             }
-        } catch (ExpressionEvaluationException e) {
-            throw new EnforcerRuleException("Unable to Evaluate an Expression:" + e.getLocalizedMessage());
-        } catch (ComponentLookupException e) {
-            throw new EnforcerRuleException("Unable to lookup a component:" + e.getLocalizedMessage());
         } catch (Exception e) {
             throw new EnforcerRuleException(e.getLocalizedMessage(), e);
         }
@@ -288,7 +277,7 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
             } catch (Exception e) {
                 // lots can go wrong here. Don't allow any issues trying to
                 // determine the issue stop me
-                log.debug("Exception while determining plugin Version.", e);
+                getLog().debug("Exception while determining plugin Version " + e.getMessage());
                 newMsg.append(". Unable to determine the plugin version.");
             }
             newMsg.append("\n");
@@ -322,8 +311,8 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
      *
      * @param uncheckedPlugins
      * @param plugins
-     * @throws MojoExecutionException
      * @return The plugins which have been removed.
+     * @throws MojoExecutionException
      */
     public Set<Plugin> removeUncheckedPlugins(Collection<String> uncheckedPlugins, Set<Plugin> plugins)
             throws MojoExecutionException {
@@ -343,17 +332,15 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
      * @param uncheckedPluginsList
      * @return List of unchecked plugins.
      */
-    // CHECKSTYLE_OFF: LineLength
-    public Collection<String> combineUncheckedPlugins(Collection<String> uncheckedPlugins, String uncheckedPluginsList)
-                // CHECKSTYLE_ON: LineLength
-            {
+    public Collection<String> combineUncheckedPlugins(
+            Collection<String> uncheckedPlugins, String uncheckedPluginsList) {
         // if the comma list is empty, then there's nothing to do here.
         if (StringUtils.isNotEmpty(uncheckedPluginsList)) {
             // make sure there is a collection to add to.
             if (uncheckedPlugins == null) {
                 uncheckedPlugins = new HashSet<>();
-            } else if (!uncheckedPlugins.isEmpty() && log != null) {
-                log.warn("The parameter 'unCheckedPlugins' is deprecated. Use 'unCheckedPluginList' instead");
+            } else if (!uncheckedPlugins.isEmpty()) {
+                getLog().warn("The parameter 'unCheckedPlugins' is deprecated. Use 'unCheckedPluginList' instead");
             }
 
             uncheckedPlugins.addAll(Arrays.asList(uncheckedPluginsList.split(",")));
@@ -364,7 +351,7 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
     /**
      * Add the additional plugins if they don't exist yet.
      *
-     * @param existing the existing
+     * @param existing   the existing
      * @param additional the additional
      * @return the sets the
      * @throws MojoExecutionException the mojo execution exception
@@ -391,8 +378,8 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
      *
      * @param pluginString
      * @param field
-     * @throws MojoExecutionException
      * @return the plugin
+     * @throws MojoExecutionException
      */
     protected Plugin parsePluginString(String pluginString, String field) throws MojoExecutionException {
         if (pluginString != null) {
@@ -437,11 +424,11 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
     /**
      * Given a plugin, this will retrieve the matching plugin artifact from the model.
      *
-     * @param plugin plugin to lookup
+     * @param plugin  plugin to lookup
      * @param project project to search
      * @return matching plugin, <code>null</code> if not found.
      */
-    protected Plugin findCurrentPlugin(Plugin plugin, MavenProject project) throws EnforcerRuleException {
+    private Plugin findCurrentPlugin(Plugin plugin, MavenProject project) throws EnforcerRuleException {
         Plugin found = null;
         try {
             Model model = project.getModel();
@@ -477,13 +464,13 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
      * Gets the plugins that are bound to the defined phases. This does not find plugins bound in the pom to a phase
      * later than the plugin is executing.
      *
-     * @param project the project
+     * @param project   the project
      * @param thePhases the phases
      * @return the bound plugins
-     * @throws PluginNotFoundException the plugin not found exception
+     * @throws PluginNotFoundException     the plugin not found exception
      * @throws LifecycleExecutionException the lifecycle execution exception
      */
-    protected Set<Plugin> getBoundPlugins(MavenProject project, String thePhases)
+    private Set<Plugin> getBoundPlugins(MavenProject project, String thePhases)
             throws PluginNotFoundException, LifecycleExecutionException {
 
         Set<Plugin> allPlugins = new HashSet<>();
@@ -495,7 +482,8 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
             if (StringUtils.isNotEmpty(lifecyclePhase)) {
                 try {
                     Lifecycle lifecycle = getLifecycleForPhase(lifecyclePhase);
-                    log.debug("getBoundPlugins(): " + project.getId() + " " + lifecyclePhase + " " + lifecycle.getId());
+                    getLog().debug("getBoundPlugins(): " + project.getId() + " " + lifecyclePhase + " "
+                            + lifecycle.getId());
                     allPlugins.addAll(getAllPlugins(project, lifecycle));
                 } catch (BuildFailureException e) {
                     // i'm going to swallow this because the
@@ -511,13 +499,11 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
      * Checks for valid version specified. Checks to see if the version is specified for the plugin. Can optionally ban
      * "RELEASE" or "LATEST" even if specified.
      *
-     * @param helper the helper
-     * @param source the source
+     * @param source         the source
      * @param pluginWrappers the plugins
      * @return true, if successful
      */
-    protected boolean hasValidVersionSpecified(
-            EnforcerRuleHelper helper, Plugin source, List<PluginWrapper> pluginWrappers) {
+    public boolean hasValidVersionSpecified(Plugin source, List<PluginWrapper> pluginWrappers) {
         boolean found = false;
         boolean status = false;
         for (PluginWrapper plugin : pluginWrappers) {
@@ -527,13 +513,13 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
                 // found the entry. now see if the version is specified
                 String version = plugin.getVersion();
                 try {
-                    version = (String) helper.evaluate(version);
+                    version = (String) evaluator.evaluate(version);
                 } catch (ExpressionEvaluationException e) {
                     return false;
                 }
 
                 if (isValidVersion(version)) {
-                    helper.getLog().debug("checking for notEmpty and notIsWhitespace(): " + version);
+                    getLog().debug("checking for notEmpty and notIsWhitespace(): " + version);
                     if (banRelease && version.equals("RELEASE")) {
                         return false;
                     }
@@ -559,7 +545,7 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
             }
         }
         if (!found) {
-            helper.getLog().debug("plugin " + source.getGroupId() + ":" + source.getArtifactId() + " not found");
+            getLog().debug("plugin " + source.getGroupId() + ":" + source.getArtifactId() + " not found");
         }
         return status;
     }
@@ -579,7 +565,7 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
      * @param baseVersion the base version
      * @return true, if is snapshot
      */
-    protected boolean isSnapshot(String baseVersion) {
+    private boolean isSnapshot(String baseVersion) {
         if (banTimestamps) {
             return Artifact.VERSION_FILE_PATTERN.matcher(baseVersion).matches()
                     || baseVersion.endsWith(Artifact.SNAPSHOT_VERSION);
@@ -591,35 +577,36 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
     /*
      * Uses borrowed lifecycle code to get a list of all plugins bound to the lifecycle.
      */
+
     /**
      * Gets the all plugins.
      *
-     * @param project the project
+     * @param project   the project
      * @param lifecycle the lifecycle
      * @return the all plugins
-     * @throws PluginNotFoundException the plugin not found exception
+     * @throws PluginNotFoundException     the plugin not found exception
      * @throws LifecycleExecutionException the lifecycle execution exception
      */
     private Set<Plugin> getAllPlugins(MavenProject project, Lifecycle lifecycle)
             throws PluginNotFoundException, LifecycleExecutionException {
 
-        log.debug("RequirePluginVersions.getAllPlugins:");
+        getLog().debug("RequirePluginVersions.getAllPlugins:");
 
         Set<Plugin> plugins = new HashSet<>();
         // first, bind those associated with the packaging
         Map<String, String> mappings = findMappingsForLifecycle(project, lifecycle);
 
         for (Map.Entry<String, String> entry : mappings.entrySet()) {
-            log.debug("  lifecycleMapping = " + entry.getKey());
+            getLog().debug("  lifecycleMapping = " + entry.getKey());
             String pluginsForLifecycle = (String) entry.getValue();
-            log.debug("  plugins = " + pluginsForLifecycle);
+            getLog().debug("  plugins = " + pluginsForLifecycle);
             if (StringUtils.isNotEmpty(pluginsForLifecycle)) {
                 String pluginList[] = pluginsForLifecycle.split(",");
                 for (String plugin : pluginList) {
                     plugin = StringUtils.strip(plugin);
-                    log.debug("    plugin = " + plugin);
+                    getLog().debug("    plugin = " + plugin);
                     String tokens[] = plugin.split(":");
-                    log.debug("    GAV = " + Arrays.asList(tokens));
+                    getLog().debug("    GAV = " + Arrays.asList(tokens));
 
                     Plugin p = new Plugin();
                     p.setGroupId(tokens[0]);
@@ -638,6 +625,7 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
      * NOTE: All the code following this point was scooped from the DefaultLifecycleExecutor. There must be a better way
      * but for now it should work.
      */
+
     /**
      * Gets the phase to lifecycle map.
      *
@@ -651,7 +639,7 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
             for (Lifecycle lifecycle : lifecycles) {
                 List<String> phases = lifecycle.getPhases();
                 for (String phase : phases) {
-                    log.debug("getPhaseToLifecycleMap(): phase: " + phase);
+                    getLog().debug("getPhaseToLifecycleMap(): phase: " + phase);
                     if (phaseToLifecycleMap.containsKey(phase)) {
                         Lifecycle prevLifecycle = (Lifecycle) phaseToLifecycleMap.get(phase);
                         throw new LifecycleExecutionException("Phase '" + phase
@@ -671,7 +659,7 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
      *
      * @param phase the phase
      * @return the lifecycle for phase
-     * @throws BuildFailureException the build failure exception
+     * @throws BuildFailureException       the build failure exception
      * @throws LifecycleExecutionException the lifecycle execution exception
      */
     private Lifecycle getLifecycleForPhase(String phase) throws BuildFailureException, LifecycleExecutionException {
@@ -686,11 +674,11 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
     /**
      * Find mappings for lifecycle.
      *
-     * @param project the project
+     * @param project   the project
      * @param lifecycle the lifecycle
      * @return the map
      * @throws LifecycleExecutionException the lifecycle execution exception
-     * @throws PluginNotFoundException the plugin not found exception
+     * @throws PluginNotFoundException     the plugin not found exception
      */
     private Map<String, String> findMappingsForLifecycle(MavenProject project, Lifecycle lifecycle)
             throws LifecycleExecutionException, PluginNotFoundException {
@@ -707,7 +695,7 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
 
         if (mappings == null) {
             try {
-                m = helper.getComponent(LifecycleMapping.class, packaging);
+                m = container.lookup(LifecycleMapping.class, packaging);
                 mappings = m.getPhases(lifecycle.getId());
             } catch (ComponentLookupException e) {
                 if (defaultMappings == null) {
@@ -732,14 +720,14 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
     /**
      * Find extension.
      *
-     * @param project the project
-     * @param role the role
-     * @param roleHint the role hint
-     * @param settings the settings
+     * @param project         the project
+     * @param role            the role
+     * @param roleHint        the role hint
+     * @param settings        the settings
      * @param localRepository the local repository
      * @return the object
      * @throws LifecycleExecutionException the lifecycle execution exception
-     * @throws PluginNotFoundException the plugin not found exception
+     * @throws PluginNotFoundException     the plugin not found exception
      */
     private Object findExtension(
             MavenProject project, String role, String roleHint, Settings settings, ArtifactRepository localRepository)
@@ -762,7 +750,7 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
                         break;
                     }
                 } catch (ComponentLookupException e) {
-                    log.debug("Unable to find the lifecycle component in the extension", e);
+                    getLog().debug("Unable to find the lifecycle component in the extension " + e.getMessage());
                 } catch (PluginManagerException e) {
                     throw new LifecycleExecutionException(
                             "Error getting extensions from the plugin '" + plugin.getKey() + "': " + e.getMessage(), e);
@@ -775,13 +763,13 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
     /**
      * Verify plugin.
      *
-     * @param plugin the plugin
-     * @param project the project
-     * @param settings the settings
+     * @param plugin          the plugin
+     * @param project         the project
+     * @param settings        the settings
      * @param localRepository the local repository
      * @return the plugin descriptor
      * @throws LifecycleExecutionException the lifecycle execution exception
-     * @throws PluginNotFoundException the plugin not found exception
+     * @throws PluginNotFoundException     the plugin not found exception
      */
     private PluginDescriptor verifyPlugin(
             Plugin plugin, MavenProject project, Settings settings, ArtifactRepository localRepository)
@@ -811,7 +799,7 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
      * @param project the project
      * @return the all plugin entries wrapped in a PluginWrapper Object
      */
-    protected List<PluginWrapper> getAllPluginEntries(MavenProject project) {
+    private List<PluginWrapper> getAllPluginEntries(MavenProject project) {
         List<PluginWrapper> plugins = new ArrayList<>();
         // now find all the plugin entries, either in
         // build.plugins or build.pluginManagement.plugins, profiles.plugins and reporting
@@ -865,60 +853,24 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
         plugins.addAll(PluginWrapper.addAll(utils.resolveReportPlugins(modelReportPlugins), banMavenDefaults));
     }
 
-    /**
-     * Checks if is ban latest.
-     *
-     * @return the banLatest
-     */
-    protected boolean isBanLatest() {
-        return this.banLatest;
-    }
-
     /**
      * Sets the ban latest.
      *
      * @param theBanLatest the banLatest to set
      */
-    protected void setBanLatest(boolean theBanLatest) {
+    public void setBanLatest(boolean theBanLatest) {
         this.banLatest = theBanLatest;
     }
 
-    /**
-     * Checks if is ban release.
-     *
-     * @return the banRelease
-     */
-    protected boolean isBanRelease() {
-        return this.banRelease;
-    }
-
     /**
      * Sets the ban release.
      *
      * @param theBanRelease the banRelease to set
      */
-    protected void setBanRelease(boolean theBanRelease) {
+    public void setBanRelease(boolean theBanRelease) {
         this.banRelease = theBanRelease;
     }
 
-    /**
-     * Gets the utils.
-     *
-     * @return the utils
-     */
-    protected EnforcerRuleUtils getUtils() {
-        return this.utils;
-    }
-
-    /**
-     * Sets the utils.
-     *
-     * @param theUtils the utils to set
-     */
-    protected void setUtils(EnforcerRuleUtils theUtils) {
-        this.utils = theUtils;
-    }
-
     /**
      * Checks if is ban snapshots.
      *
@@ -937,15 +889,6 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
         this.banSnapshots = theBanSnapshots;
     }
 
-    /**
-     * Checks if is ban timestamps.
-     *
-     * @return the banTimestamps
-     */
-    public boolean isBanTimestamps() {
-        return this.banTimestamps;
-    }
-
     /**
      * Sets the ban timestamps.
      *
@@ -955,27 +898,18 @@ public class RequirePluginVersions extends AbstractNonCacheableEnforcerRule {
         this.banTimestamps = theBanTimestamps;
     }
 
-    public List<String> getUnCheckedPlugins() {
-        return unCheckedPlugins;
-    }
-
-    public void setUnCheckedPlugins(List<String> unCheckedPlugins) {
-        this.unCheckedPlugins = unCheckedPlugins;
-    }
-
-    public final void setPhases(String phases) {
-        this.phases = phases;
-    }
-
-    public final String getPhases() {
-        return phases;
-    }
-
-    public final void setAdditionalPlugins(List<String> additionalPlugins) {
-        this.additionalPlugins = additionalPlugins;
-    }
-
-    public final List<String> getAdditionalPlugins() {
-        return additionalPlugins;
+    @Override
+    public String toString() {
+        return String.format(
+                "RequirePluginVersions[message=%s, banLatest=%b, banRelease=%b, banSnapshots=%b, banTimestamps=%b, phases=%s, additionalPlugins=%s, unCheckedPluginList=%s, unCheckedPlugins=%s]",
+                getMessage(),
+                banLatest,
+                banRelease,
+                banSnapshots,
+                banTimestamps,
+                phases,
+                additionalPlugins,
+                unCheckedPluginList,
+                unCheckedPlugins);
     }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequirePrerequisite.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequirePrerequisite.java
similarity index 79%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequirePrerequisite.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequirePrerequisite.java
index 4d950aa..5af436c 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequirePrerequisite.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequirePrerequisite.java
@@ -16,23 +16,26 @@
  * 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.List;
+import java.util.Objects;
 
 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.model.Prerequisites;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 
 /**
  * @author Robert Scholte
  * @since 1.3
  */
-public class RequirePrerequisite extends AbstractNonCacheableEnforcerRule {
+@Named("requirePrerequisite")
+public final class RequirePrerequisite extends AbstractStandardEnforcerRule {
     /**
      * Only the projects with one of these packagings will be enforced to have the correct prerequisite.
      *
@@ -45,6 +48,13 @@ public class RequirePrerequisite extends AbstractNonCacheableEnforcerRule {
      */
     private String mavenVersion;
 
+    private final MavenProject project;
+
+    @Inject
+    public RequirePrerequisite(MavenProject project) {
+        this.project = Objects.requireNonNull(project);
+    }
+
     /**
      * Set the mavenVersion Can either be version or a range, e.g. {@code 2.2.1} or {@code [2.2.1,)}
      *
@@ -65,20 +75,17 @@ public class RequirePrerequisite extends AbstractNonCacheableEnforcerRule {
     }
 
     @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
+    public void execute() throws EnforcerRuleException {
         try {
-            MavenProject project = (MavenProject) helper.evaluate("${project}");
 
             if ("pom".equals(project.getPackaging())) {
-                helper.getLog().debug("Packaging is pom, skipping requirePrerequisite rule");
+                getLog().debug("Packaging is pom, skipping requirePrerequisite rule");
                 return;
             }
 
             if (packagings != null && !packagings.contains(project.getPackaging())) {
-                // CHECKSTYLE_OFF: LineLength
-                helper.getLog().debug("Packaging is " + project.getPackaging() + ", skipping requirePrerequisite rule");
+                getLog().debug("Packaging is " + project.getPackaging() + ", skipping requirePrerequisite rule");
                 return;
-                // CHECKSTYLE_ON: LineLength
             }
 
             Prerequisites prerequisites = project.getPrerequisites();
@@ -104,8 +111,13 @@ public class RequirePrerequisite extends AbstractNonCacheableEnforcerRule {
                             + " ) doesn't match the required version: " + mavenVersion);
                 }
             }
-        } catch (ExpressionEvaluationException | InvalidVersionSpecificationException e) {
+        } catch (InvalidVersionSpecificationException e) {
             throw new EnforcerRuleException(e.getMessage(), e);
         }
     }
+
+    @Override
+    public String toString() {
+        return String.format("RequirePrerequisite[packagings=%s, mavenVersion=%s]", packagings, mavenVersion);
+    }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireProfileIdsExist.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireProfileIdsExist.java
new file mode 100644
index 0000000..df832f0
--- /dev/null
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireProfileIdsExist.java
@@ -0,0 +1,91 @@
+/*
+ * 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.rules;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * Ensure that all profiles mentioned on the commandline do exist.
+ *
+ * @author Robert Scholte
+ * @author Gabriel Belingueres
+ */
+@Named("requireProfileIdsExist")
+public final class RequireProfileIdsExist extends AbstractStandardEnforcerRule {
+
+    private final MavenSession session;
+
+    @Inject
+    public RequireProfileIdsExist(MavenSession session) {
+        this.session = Objects.requireNonNull(session);
+    }
+
+    @Override
+    public void execute() throws EnforcerRuleException {
+
+        List<String> profileIds = new ArrayList<>();
+        profileIds.addAll(session.getProjectBuildingRequest().getActiveProfileIds());
+        profileIds.addAll(session.getProjectBuildingRequest().getInactiveProfileIds());
+
+        for (MavenProject project : session.getProjects()) {
+            // iterate over all parents
+            MavenProject currentProject = project;
+            do {
+                for (org.apache.maven.model.Profile profile :
+                        currentProject.getModel().getProfiles()) {
+                    profileIds.remove(profile.getId());
+
+                    if (profileIds.isEmpty()) {
+                        return;
+                    }
+                }
+
+                currentProject = currentProject.getParent();
+            } while (currentProject != null);
+        }
+
+        for (org.apache.maven.settings.Profile profile : session.getSettings().getProfiles()) {
+            profileIds.remove(profile.getId());
+        }
+
+        if (profileIds.isEmpty()) {
+            return;
+        }
+
+        StringBuilder sb = new StringBuilder();
+        if (profileIds.size() > 1) {
+            sb.append("The requested profiles don't exist: ");
+        } else {
+            sb.append("The requested profile doesn't exist: ");
+        }
+        sb.append(StringUtils.join(profileIds.iterator(), ", "));
+
+        throw new EnforcerRuleException(sb.toString());
+    }
+}
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireReleaseVersion.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireReleaseVersion.java
similarity index 64%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireReleaseVersion.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireReleaseVersion.java
index 4d16abe..47b2d3c 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireReleaseVersion.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireReleaseVersion.java
@@ -16,35 +16,39 @@
  * 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.Objects;
 
 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.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 
 /**
  * This rule checks that the current project is not a snapshot.
  *
  * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
  */
-public class RequireReleaseVersion extends AbstractNonCacheableEnforcerRule {
+@Named("requireReleaseVersion")
+public final class RequireReleaseVersion extends AbstractStandardEnforcerRule {
+
+    private final MavenProject project;
 
     /**
      * Allows this rule to fail when the parent is defined as a snapshot.
-     *
-     * @parameter
-     *
-     * @see {@link #setFailWhenParentIsSnapshot(boolean)}
-     * @see {@link #isFailWhenParentIsSnapshot()}
      */
     private boolean failWhenParentIsSnapshot = true;
 
-    @Override
-    public void execute(EnforcerRuleHelper theHelper) throws EnforcerRuleException {
+    @Inject
+    public RequireReleaseVersion(MavenProject project) {
+        this.project = Objects.requireNonNull(project);
+    }
 
-        MavenProject project = getProject(theHelper);
+    @Override
+    public void execute() throws EnforcerRuleException {
 
         if (project.getArtifact().isSnapshot()) {
             String message = getMessage();
@@ -64,24 +68,12 @@ public class RequireReleaseVersion extends AbstractNonCacheableEnforcerRule {
         }
     }
 
-    /**
-     * @param helper
-     * @return The evaluated {@link MavenProject}.
-     * @throws EnforcerRuleException
-     */
-    private MavenProject getProject(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        try {
-            return (MavenProject) helper.evaluate("${project}");
-        } catch (ExpressionEvaluationException eee) {
-            throw new EnforcerRuleException("Unable to retrieve the MavenProject: ", eee);
-        }
-    }
-
-    public final boolean isFailWhenParentIsSnapshot() {
-        return failWhenParentIsSnapshot;
+    public void setFailWhenParentIsSnapshot(boolean failWhenParentIsSnapshot) {
+        this.failWhenParentIsSnapshot = failWhenParentIsSnapshot;
     }
 
-    public final void setFailWhenParentIsSnapshot(boolean failWhenParentIsSnapshot) {
-        this.failWhenParentIsSnapshot = failWhenParentIsSnapshot;
+    @Override
+    public String toString() {
+        return String.format("RequireReleaseVersion[failWhenParentIsSnapshot=%b]", failWhenParentIsSnapshot);
     }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireSameVersions.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireSameVersions.java
similarity index 84%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireSameVersions.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireSameVersions.java
index 800e5ec..4e77e3e 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireSameVersions.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireSameVersions.java
@@ -16,7 +16,10 @@
  * 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.Collection;
@@ -24,20 +27,20 @@ import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.regex.Pattern;
 
 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.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 
 /**
  * @author Robert Scholte
  * @since 1.3
  */
-public class RequireSameVersions extends AbstractNonCacheableEnforcerRule {
+@Named("requireSameVersions")
+public final class RequireSameVersions extends AbstractStandardEnforcerRule {
     private boolean uniqueVersions;
 
     private Set<String> dependencies = new HashSet<>();
@@ -48,15 +51,15 @@ public class RequireSameVersions extends AbstractNonCacheableEnforcerRule {
 
     private Set<String> reportPlugins = new HashSet<>();
 
+    private final MavenProject project;
+
+    @Inject
+    public RequireSameVersions(MavenProject project) {
+        this.project = Objects.requireNonNull(project);
+    }
+
     @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        // get the project
-        MavenProject project;
-        try {
-            project = (MavenProject) helper.evaluate("${project}");
-        } catch (ExpressionEvaluationException eee) {
-            throw new EnforcerRuleException("Unable to retrieve the MavenProject: ", eee);
-        }
+    public void execute() throws EnforcerRuleException {
 
         // consider including profile based artifacts
         Map<String, List<String>> versionMembers = new LinkedHashMap<>();
@@ -112,4 +115,11 @@ public class RequireSameVersions extends AbstractNonCacheableEnforcerRule {
         }
         return versionMembers;
     }
+
+    @Override
+    public String toString() {
+        return String.format(
+                "RequireSameVersions[dependencies=%s, buildPlugins=%s, reportPlugins=%s, plugins=%s, uniqueVersions=%b]",
+                dependencies, buildPlugins, reportPlugins, plugins, uniqueVersions);
+    }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireSnapshotVersion.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireSnapshotVersion.java
similarity index 65%
rename from enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireSnapshotVersion.java
rename to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireSnapshotVersion.java
index 2a13c6c..4ff4b84 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireSnapshotVersion.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/RequireSnapshotVersion.java
@@ -16,28 +16,39 @@
  * 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.Objects;
+import java.util.Optional;
 
 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.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 
 /**
  * This rule checks that the current project is not a release.
  */
-public class RequireSnapshotVersion extends AbstractNonCacheableEnforcerRule {
+@Named("requireSnapshotVersion")
+public final class RequireSnapshotVersion extends AbstractStandardEnforcerRule {
 
     /**
      * Allows this rule to fail when the parent is defined as a release.
      */
     private boolean failWhenParentIsRelease = true;
 
+    private final MavenProject project;
+
+    @Inject
+    public RequireSnapshotVersion(MavenProject project) {
+        this.project = Objects.requireNonNull(project);
+    }
+
     @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
+    public void execute() throws EnforcerRuleException {
 
-        MavenProject project = getProject(false, helper);
         Artifact artifact = project.getArtifact();
 
         if (!artifact.isSnapshot()) {
@@ -50,28 +61,23 @@ public class RequireSnapshotVersion extends AbstractNonCacheableEnforcerRule {
             throw new EnforcerRuleException(sb.toString());
         }
         if (failWhenParentIsRelease && project.hasParent()) {
-            // project.getParentArtifact() does not work here if a "CI Friendly Version" is used (e.g. ${revision})
-            Artifact parentArtifact = getProject(true, helper).getArtifact();
+            Artifact parentArtifact = Optional.ofNullable(project.getParent())
+                    .map(MavenProject::getArtifact)
+                    .orElse(null);
             if (parentArtifact != null && !parentArtifact.isSnapshot()) {
                 throw new EnforcerRuleException("Parent cannot be a release: " + parentArtifact.getId());
             }
         }
     }
 
-    private MavenProject getProject(boolean parent, EnforcerRuleHelper helper) throws EnforcerRuleException {
-        String expression = parent ? "${project.parent}" : "${project}";
-        try {
-            return (MavenProject) helper.evaluate(expression);
-        } catch (ExpressionEvaluationException eee) {
-            throw new EnforcerRuleException("Unable to retrieve the MavenProject: ", eee);
-        }
-    }
-
-    public boolean isFailWhenParentIsRelease() {
-        return failWhenParentIsRelease;
-    }
-
     public void setFailWhenParentIsRelease(boolean failWhenParentIsRelease) {
         this.failWhenParentIsRelease = failWhenParentIsRelease;
     }
+
+    @Override
+    public String toString() {
+        return String.format(
+                "RequireSnapshotVersion[message=%s, failWhenParentIsRelease=%b]",
+                getMessage(), failWhenParentIsRelease);
+    }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/checksum/RequireFileChecksum.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/checksum/RequireFileChecksum.java
index 84b3753..bf3ddb8 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/checksum/RequireFileChecksum.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/checksum/RequireFileChecksum.java
@@ -171,7 +171,7 @@ public class RequireFileChecksum extends AbstractStandardEnforcerRule {
     @Override
     public String toString() {
         return String.format(
-                "RequireFileChecksum[file=%s, checksum=%s, type=%s, nonexistentFileMessage=%s, level=%s]",
-                file, checksum, type, nonexistentFileMessage, getLevel());
+                "RequireFileChecksum[message=%s, file=%s, checksum=%s, type=%s, nonexistentFileMessage=%s]",
+                getMessage(), file, checksum, type, nonexistentFileMessage);
     }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/checksum/RequireTextFileChecksum.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/checksum/RequireTextFileChecksum.java
index 8eadcdf..8454184 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/checksum/RequireTextFileChecksum.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/checksum/RequireTextFileChecksum.java
@@ -42,7 +42,7 @@ import org.apache.maven.project.MavenProject;
  * @see RequireFileChecksum
  */
 @Named("requireTextFileChecksum")
-public class RequireTextFileChecksum extends RequireFileChecksum {
+public final class RequireTextFileChecksum extends RequireFileChecksum {
 
     private NormalizeLineSeparatorReader.LineSeparator normalizeLineSeparatorTo = LineSeparator.UNIX;
 
@@ -97,7 +97,8 @@ public class RequireTextFileChecksum extends RequireFileChecksum {
     @Override
     public String toString() {
         return String.format(
-                "RequireFileChecksum[file=%s, checksum=%s, type=%s, encoding=%s, normalizeLineSeparatorTo=%s, nonexistentFileMessage=%s, level=%s]",
+                "RequireFileChecksum[message=%s, file=%s, checksum=%s, type=%s, encoding=%s, normalizeLineSeparatorTo=%s, nonexistentFileMessage=%s, level=%s]",
+                getMessage(),
                 getFile(),
                 getChecksum(),
                 getType(),
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/files/AbstractRequireFiles.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/files/AbstractRequireFiles.java
index 34988b4..da9019f 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/files/AbstractRequireFiles.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/files/AbstractRequireFiles.java
@@ -134,7 +134,7 @@ abstract class AbstractRequireFiles extends AbstractStandardEnforcerRule {
     @Override
     public String toString() {
         return String.format(
-                "%s[message=%s, files=%s, allowNulls=%b, satisfyAny=%b, level=%s]",
-                getClass().getSimpleName(), getMessage(), files, allowNulls, satisfyAny, getLevel());
+                "%s[message=%s, files=%s, allowNulls=%b, satisfyAny=%b]",
+                getClass().getSimpleName(), getMessage(), files, allowNulls, satisfyAny);
     }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/property/RequireEnvironmentVariable.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/property/RequireEnvironmentVariable.java
index 14c8389..c1b36d6 100755
--- a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/property/RequireEnvironmentVariable.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/property/RequireEnvironmentVariable.java
@@ -33,20 +33,10 @@ public final class RequireEnvironmentVariable extends AbstractPropertyEnforcerRu
      */
     private String variableName = null;
 
-    /**
-     * @param variableName the variable name
-     *
-     * @see #setVariableName(String)
-     * @see #getVariableName()
-     */
     public void setVariableName(String variableName) {
         this.variableName = variableName;
     }
 
-    public String getVariableName() {
-        return variableName;
-    }
-
     @Override
     public String resolveValue() {
         return System.getenv(variableName);
@@ -70,7 +60,7 @@ public final class RequireEnvironmentVariable extends AbstractPropertyEnforcerRu
     @Override
     public String toString() {
         return String.format(
-                "RequireEnvironmentVariable[variableName=%s, message=%s, regex=%s, regexMessage=%s]",
-                variableName, getMessage(), getRegex(), getRegexMessage());
+                "RequireEnvironmentVariable[message=%s, variableName=%s, regex=%s, regexMessage=%s]",
+                getMessage(), variableName, getRegex(), getRegexMessage());
     }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/property/RequireProperty.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/property/RequireProperty.java
index cdfe411..72bba44 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/property/RequireProperty.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/property/RequireProperty.java
@@ -37,9 +37,6 @@ public final class RequireProperty extends AbstractPropertyEnforcerRule {
 
     /**
      * Specify the required property.
-     *
-     * @see {@link #setProperty(String)}
-     * @see {@link #getPropertyName()}
      */
     private String property = null;
 
@@ -76,7 +73,7 @@ public final class RequireProperty extends AbstractPropertyEnforcerRule {
     @Override
     public String toString() {
         return String.format(
-                "RequireProperty[property=%s, message=%s, regex=%s, regexMessage=%s]",
-                property, getMessage(), getRegex(), getRegexMessage());
+                "RequireProperty[message=%s, property=%s, regex=%s, regexMessage=%s]",
+                getMessage(), property, getRegex(), getRegexMessage());
     }
 }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/DistributionManagementCheck.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/DistributionManagementCheck.java
deleted file mode 100644
index e294215..0000000
--- a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/DistributionManagementCheck.java
+++ /dev/null
@@ -1,71 +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.rules.utils;
-
-import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.model.DistributionManagement;
-import org.apache.maven.project.MavenProject;
-
-/**
- * @author Karl Heinz Marbaise <a href="mailto:khmarbaise@apache.org">khmarbaise@apache.org</a>
- */
-public class DistributionManagementCheck {
-    private DistributionManagement distributionManagement;
-
-    public DistributionManagementCheck(MavenProject project) {
-        this.distributionManagement = project.getOriginalModel().getDistributionManagement();
-    }
-
-    public void execute(boolean isAllowRepository, boolean isAllowSnapshotRepository, boolean isAllowSite)
-            throws EnforcerRuleException {
-        if (hasDistributionManagement()) {
-            if (!isAllowRepository && hasRepository()) {
-                throw new EnforcerRuleException("You have defined a repository in distributionManagement.");
-            } else if (!isAllowSnapshotRepository && hasSnapshotRepository()) {
-                throw new EnforcerRuleException("You have defined a snapshotRepository in distributionManagement.");
-            } else if (!isAllowSite && hasSite()) {
-                throw new EnforcerRuleException("You have defined a site in distributionManagement.");
-            }
-        }
-    }
-
-    private boolean hasRepository() {
-        return getDistributionManagement().getRepository() != null;
-    }
-
-    public DistributionManagement getDistributionManagement() {
-        return distributionManagement;
-    }
-
-    public void setDistributionManagement(DistributionManagement distributionManagement) {
-        this.distributionManagement = distributionManagement;
-    }
-
-    private boolean hasSnapshotRepository() {
-        return getDistributionManagement().getSnapshotRepository() != null;
-    }
-
-    private boolean hasSite() {
-        return getDistributionManagement().getSite() != null;
-    }
-
-    private boolean hasDistributionManagement() {
-        return getDistributionManagement() != null;
-    }
-}
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/EnforcerRuleUtils.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/EnforcerRuleUtils.java
index add55e1..5bb3d28 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/EnforcerRuleUtils.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/utils/EnforcerRuleUtils.java
@@ -18,9 +18,12 @@
  */
 package org.apache.maven.enforcer.rules.utils;
 
+import javax.inject.Inject;
+import javax.inject.Named;
+
 import java.util.List;
+import java.util.Objects;
 
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.model.ReportPlugin;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
@@ -30,23 +33,25 @@ import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluatio
  *
  * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
  */
+@Named
 public class EnforcerRuleUtils {
-    private EnforcerRuleHelper helper;
 
+    private final ExpressionEvaluator evaluator;
     /**
      * Instantiates a new enforcer rule utils.
      *
-     * @param helper the helper
+     * @param evaluator the expression evaluator
      */
-    public EnforcerRuleUtils(EnforcerRuleHelper helper) {
-        this.helper = helper;
+    @Inject
+    public EnforcerRuleUtils(ExpressionEvaluator evaluator) {
+        this.evaluator = Objects.requireNonNull(evaluator);
     }
 
     private void resolve(Plugin plugin) {
         try {
-            plugin.setGroupId((String) helper.evaluate(plugin.getGroupId()));
-            plugin.setArtifactId((String) helper.evaluate(plugin.getArtifactId()));
-            plugin.setVersion((String) helper.evaluate(plugin.getVersion()));
+            plugin.setGroupId((String) evaluator.evaluate(plugin.getGroupId()));
+            plugin.setArtifactId((String) evaluator.evaluate(plugin.getArtifactId()));
+            plugin.setVersion((String) evaluator.evaluate(plugin.getVersion()));
         } catch (ExpressionEvaluationException e) {
             // this should have gone already before
         }
@@ -54,9 +59,9 @@ public class EnforcerRuleUtils {
 
     private void resolve(ReportPlugin plugin) {
         try {
-            plugin.setGroupId((String) helper.evaluate(plugin.getGroupId()));
-            plugin.setArtifactId((String) helper.evaluate(plugin.getArtifactId()));
-            plugin.setVersion((String) helper.evaluate(plugin.getVersion()));
+            plugin.setGroupId((String) evaluator.evaluate(plugin.getGroupId()));
+            plugin.setArtifactId((String) evaluator.evaluate(plugin.getArtifactId()));
+            plugin.setVersion((String) evaluator.evaluate(plugin.getVersion()));
         } catch (ExpressionEvaluationException e) {
             // this should have gone already before
         }
diff --git a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/version/AbstractVersionEnforcer.java b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/version/AbstractVersionEnforcer.java
index bbae8ea..042bbc4 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/version/AbstractVersionEnforcer.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/version/AbstractVersionEnforcer.java
@@ -141,6 +141,6 @@ abstract class AbstractVersionEnforcer extends AbstractStandardEnforcerRule {
 
     @Override
     public String toString() {
-        return String.format("%s[version=%s]", getClass().getSimpleName(), version);
+        return String.format("%s[message=%s, version=%s]", getClass().getSimpleName(), getMessage(), version);
     }
 }
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
deleted file mode 100644
index 3910f6a..0000000
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/AbstractBanDependencies.java
+++ /dev/null
@@ -1,108 +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 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.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
-
-/**
- * Abstract Rule for banning dependencies.
- *
- * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
- */
-public abstract class AbstractBanDependencies extends AbstractNonCacheableEnforcerRule {
-
-    /** Specify if transitive dependencies should be searched (default) or only look at direct dependencies. */
-    private boolean searchTransitive = true;
-
-    @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        MavenSession session;
-        try {
-            session = (MavenSession) helper.evaluate("${session}");
-        } catch (ExpressionEvaluationException e) {
-            throw new EnforcerRuleException("Cannot resolve MavenSession", e);
-        }
-
-        // get the correct list of dependencies
-        Set<Artifact> dependencyArtifacts = searchTransitive
-                ? ArtifactUtils.getDependencyArtifacts(ArtifactUtils.resolveTransitiveDependencies(helper))
-                : session.getCurrentProject().getDependencyArtifacts();
-
-        // look for banned dependencies
-        Set<Artifact> bannedDependencies = checkDependencies(dependencyArtifacts, helper.getLog());
-
-        // if any are found, fail the check but list all of them
-        if (bannedDependencies != null && !bannedDependencies.isEmpty()) {
-            String message = getMessage();
-
-            StringBuilder buf = new StringBuilder();
-            if (message != null) {
-                buf.append(message).append(System.lineSeparator());
-            }
-            for (Artifact artifact : bannedDependencies) {
-                buf.append(getErrorMessage(artifact));
-            }
-            message = buf.append("Use 'mvn dependency:tree' to locate the source of the banned dependencies.")
-                    .toString();
-
-            throw new EnforcerRuleException(message);
-        }
-    }
-
-    protected CharSequence getErrorMessage(Artifact artifact) {
-        return "Found Banned Dependency: " + artifact.getId() + System.lineSeparator();
-    }
-
-    /**
-     * Checks the set of dependencies against the list of excludes.
-     *
-     * @param dependencies dependencies to be checked against the list of excludes
-     * @param log          the log
-     * @return the sets the
-     * @throws EnforcerRuleException the enforcer rule exception
-     */
-    protected abstract Set<Artifact> checkDependencies(Set<Artifact> dependencies, Log log)
-            throws EnforcerRuleException;
-
-    /**
-     * Checks if is search transitive.
-     *
-     * @return the searchTransitive
-     */
-    public boolean isSearchTransitive() {
-        return this.searchTransitive;
-    }
-
-    /**
-     * Sets the search transitive.
-     *
-     * @param theSearchTransitive the searchTransitive to set
-     */
-    public void setSearchTransitive(boolean theSearchTransitive) {
-        this.searchTransitive = theSearchTransitive;
-    }
-}
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
deleted file mode 100644
index 96df784..0000000
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/BanDistributionManagement.java
+++ /dev/null
@@ -1,104 +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.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.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
-
-/**
- * This rule will check if a pom contains a <code>distributionManagement</code> part. This should be by best practice
- * only defined once. It could happen that you like to check the parent as well. This can be activated by using the
- * <code>ignoreParent</code> which is by default turned off (<code>true</code>) which means not to check the parent.
- *
- * @author Karl Heinz Marbaise
- * @since 1.4
- */
-public class BanDistributionManagement extends AbstractNonCacheableEnforcerRule {
-
-    /**
-     * Allow using a repository entry in the distributionManagement area.
-     */
-    private boolean allowRepository = false;
-
-    /**
-     * Allow snapshotRepository entry in the distributionManagement area.
-     */
-    private boolean allowSnapshotRepository = false;
-
-    /**
-     * Allow site entry in the distributionManagement area.
-     */
-    private boolean allowSite = false;
-
-    @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        Log logger = helper.getLog();
-
-        try {
-            MavenProject project = (MavenProject) helper.evaluate("${project}");
-
-            if (project.isExecutionRoot()) {
-                if (project.getParent() == null) {
-                    // Does it make sense to check something? If yes please make a JIRA ticket for it.
-                    logger.debug("We have no parent and in the root of a build we don't check anything,");
-                    logger.debug("because that is the location where we defined maven-enforcer-plugin.");
-                } else {
-                    logger.debug("We are in the root of the execution and we have a parent.");
-
-                    DistributionManagementCheck check = new DistributionManagementCheck(project);
-                    check.execute(isAllowRepository(), isAllowSnapshotRepository(), isAllowSite());
-                }
-            } else {
-                logger.debug("We are in a deeper level.");
-                DistributionManagementCheck check = new DistributionManagementCheck(project);
-                check.execute(isAllowRepository(), isAllowSnapshotRepository(), isAllowSite());
-            }
-        } catch (ExpressionEvaluationException e) {
-            throw new EnforcerRuleException(e.getMessage(), e);
-        }
-    }
-
-    public boolean isAllowRepository() {
-        return allowRepository;
-    }
-
-    public void setAllowRepository(boolean allowRepository) {
-        this.allowRepository = allowRepository;
-    }
-
-    public boolean isAllowSnapshotRepository() {
-        return allowSnapshotRepository;
-    }
-
-    public void setAllowSnapshotRepository(boolean allowSnapshotRepository) {
-        this.allowSnapshotRepository = allowSnapshotRepository;
-    }
-
-    public boolean isAllowSite() {
-        return allowSite;
-    }
-
-    public void setAllowSite(boolean allowSite) {
-        this.allowSite = allowSite;
-    }
-}
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireExplicitDependencyScope.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireExplicitDependencyScope.java
deleted file mode 100644
index e3cea88..0000000
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireExplicitDependencyScope.java
+++ /dev/null
@@ -1,83 +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 java.text.ChoiceFormat;
-import java.util.List;
-
-import org.apache.maven.enforcer.rule.api.EnforcerLevel;
-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.model.Dependency;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.shared.utils.logging.MessageBuilder;
-import org.apache.maven.shared.utils.logging.MessageUtils;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
-
-/**
- * Checks that all dependencies have an explicitly declared scope in the non-effective pom (i.e. without taking
- * inheritance or dependency management into account).
- */
-public class RequireExplicitDependencyScope extends AbstractNonCacheableEnforcerRule implements EnforcerRule2 {
-
-    @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        try {
-            int numMissingDependencyScopes = 0;
-            MavenProject project = (MavenProject) helper.evaluate("${project}");
-            if (project == null) {
-                throw new ExpressionEvaluationException("${project} is null");
-            }
-            List<Dependency> dependencies = project.getOriginalModel().getDependencies(); // this is the non-effective
-            // model but the original one
-            // without inheritance and
-            // interpolation resolved
-            // check scope without considering inheritance
-            for (Dependency dependency : dependencies) {
-                helper.getLog().debug("Found dependency " + dependency);
-                if (dependency.getScope() == null) {
-                    MessageBuilder msgBuilder = MessageUtils.buffer();
-                    msgBuilder
-                            .a("Dependency ")
-                            .strong(dependency.getManagementKey())
-                            .a(" @ ")
-                            .strong(formatLocation(project, dependency.getLocation("")))
-                            .a(" does not have an explicit scope defined!")
-                            .toString();
-                    if (getLevel() == EnforcerLevel.ERROR) {
-                        helper.getLog().error(msgBuilder.toString());
-                    } else {
-                        helper.getLog().warn(msgBuilder.toString());
-                    }
-                    numMissingDependencyScopes++;
-                }
-            }
-            if (numMissingDependencyScopes > 0) {
-                ChoiceFormat scopesFormat = new ChoiceFormat("1#scope|1<scopes");
-                String logCategory = getLevel() == EnforcerLevel.ERROR ? "errors" : "warnings";
-                throw new EnforcerRuleException("Found " + numMissingDependencyScopes + " missing dependency "
-                        + scopesFormat.format(numMissingDependencyScopes)
-                        + ". Look at the " + logCategory + " emitted above for the details.");
-            }
-        } catch (ExpressionEvaluationException eee) {
-            throw new EnforcerRuleException("Cannot resolve expression: " + eee.getCause(), eee);
-        }
-    }
-}
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireProfileIdsExist.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireProfileIdsExist.java
deleted file mode 100644
index d58e638..0000000
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireProfileIdsExist.java
+++ /dev/null
@@ -1,86 +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 java.util.ArrayList;
-import java.util.List;
-
-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.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
-import org.codehaus.plexus.util.StringUtils;
-
-/**
- * Ensure that all profiles mentioned on the commandline do exist.
- *
- * @author Robert Scholte
- * @author Gabriel Belingueres
- */
-public class RequireProfileIdsExist extends AbstractNonCacheableEnforcerRule {
-    @Override
-    public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
-        try {
-            MavenSession session = (MavenSession) helper.evaluate("${session}");
-
-            List<String> profileIds = new ArrayList<>();
-            profileIds.addAll(session.getProjectBuildingRequest().getActiveProfileIds());
-            profileIds.addAll(session.getProjectBuildingRequest().getInactiveProfileIds());
-
-            for (MavenProject project : session.getProjects()) {
-                // iterate over all parents
-                MavenProject currentProject = project;
-                do {
-                    for (org.apache.maven.model.Profile profile :
-                            currentProject.getModel().getProfiles()) {
-                        profileIds.remove(profile.getId());
-
-                        if (profileIds.isEmpty()) {
-                            return;
-                        }
-                    }
-
-                    currentProject = currentProject.getParent();
-                } while (currentProject != null);
-            }
-
-            for (org.apache.maven.settings.Profile profile :
-                    session.getSettings().getProfiles()) {
-                profileIds.remove(profile.getId());
-            }
-
-            if (profileIds.isEmpty()) {
-                return;
-            }
-
-            StringBuilder sb = new StringBuilder();
-            if (profileIds.size() > 1) {
-                sb.append("The requested profiles don't exist: ");
-            } else {
-                sb.append("The requested profile doesn't exist: ");
-            }
-            sb.append(StringUtils.join(profileIds.iterator(), ", "));
-
-            throw new EnforcerRuleException(sb.toString());
-        } catch (ExpressionEvaluationException e) {
-            throw new EnforcerRuleException(e.getMessage());
-        }
-    }
-}
diff --git a/enforcer-rules/src/site/apt/banDistributionManagement.apt.vm b/enforcer-rules/src/site/apt/banDistributionManagement.apt.vm
index c0f4551..4fc0a46 100644
--- a/enforcer-rules/src/site/apt/banDistributionManagement.apt.vm
+++ b/enforcer-rules/src/site/apt/banDistributionManagement.apt.vm
@@ -29,14 +29,12 @@ Ban Distribution Management
   in your pom files.
 
   The following parameters are supported by this rule:
-  
-  * message - an optional message to the user if the rule fails.
-   
-  * allowRepository - You can allow repository entry (default: false).
 
-  * allowSnapshotRepository - you can allow snapshotRepository entry (default: false).
+  * <<allowRepository>> - You can allow repository entry (default: false).
+
+  * <<allowSnapshotRepository>> - you can allow snapshotRepository entry (default: false).
 
-  * allowSite - You can allow site entry (default: false).
+  * <<allowSite>> - You can allow site entry (default: false).
    
   []
 
diff --git a/enforcer-rules/src/site/apt/banDuplicatePomDependencyVersions.apt.vm b/enforcer-rules/src/site/apt/banDuplicatePomDependencyVersions.apt.vm
index 0ae6ba1..ccc9bc0 100644
--- a/enforcer-rules/src/site/apt/banDuplicatePomDependencyVersions.apt.vm
+++ b/enforcer-rules/src/site/apt/banDuplicatePomDependencyVersions.apt.vm
@@ -28,13 +28,6 @@ Ban Duplicate Pom Dependency Versions
   This rule checks that there are no duplicate dependencies declared in the POM of the project.
   Duplicate dependencies are dependencies which have the same group id, artifact id, type and classifier.
 
-  The following parameters are supported by this rule:
-   
-  * message - an optional supplemental message to the user if the rule fails.
-
-   []
-
-   
   Sample Plugin Configuration:
   
 +------+
diff --git a/enforcer-rules/src/site/apt/banDynamicVersions.apt.vm b/enforcer-rules/src/site/apt/banDynamicVersions.apt.vm
index 806bf27..44d49f4 100644
--- a/enforcer-rules/src/site/apt/banDynamicVersions.apt.vm
+++ b/enforcer-rules/src/site/apt/banDynamicVersions.apt.vm
@@ -68,12 +68,9 @@ Ban Dynamic Versions
         * <<<org.apache.*:maven-*:*>>>
         
         []
-   
-  * <<message>> - an optional message to the user if the rule fails.
-  
+
   []
 
-   
   Sample Plugin Configuration:
   
 +---+
diff --git a/enforcer-rules/src/site/apt/bannedPlugins.apt.vm b/enforcer-rules/src/site/apt/bannedPlugins.apt.vm
index dc0e23a..028e213 100644
--- a/enforcer-rules/src/site/apt/bannedPlugins.apt.vm
+++ b/enforcer-rules/src/site/apt/bannedPlugins.apt.vm
@@ -29,7 +29,7 @@ Banned Plugins
 
    The following parameters are supported by this rule:
    
-   * excludes - a list of plugin artifacts to ban. The format is groupId[:artifactId][:version] where artifactId and version are optional. Wildcards may be used to replace an entire section.
+   * <<excludes>> - a list of plugin artifacts to ban. The format is groupId[:artifactId][:version] where artifactId and version are optional. Wildcards may be used to replace an entire section.
       Examples:
        
         * org.apache.maven
@@ -42,14 +42,11 @@ Banned Plugins
                 
         []
 
-   * includes - a list of plugin artifacts to include. These are exceptions to the excludes. It is meant to allow wide exclusion rules with wildcards and fine tune using includes. 
+   * <<includes>> - a list of plugin artifacts to include. These are exceptions to the excludes. It is meant to allow wide exclusion rules with wildcards and fine tune using includes.
      If nothing has been excluded, then the includes have no effect. In other words, includes only subtract from artifacts that matched an exclude rule.
-      
-   * message - an optional message to the user if the rule fails.
-   
+
    []
 
-   
   Sample Plugin Configuration:
   
 +---+
diff --git a/enforcer-rules/src/site/apt/bannedRepositories.apt.vm b/enforcer-rules/src/site/apt/bannedRepositories.apt.vm
index ef6d41f..7cd64c2 100644
--- a/enforcer-rules/src/site/apt/bannedRepositories.apt.vm
+++ b/enforcer-rules/src/site/apt/bannedRepositories.apt.vm
@@ -35,18 +35,18 @@ Banned Specified Repositories
 
 * Support Parameters
 
-   * banRepositories - Specify banned non-plugin repositories. This is a black list of http/https url patterns.
+   * <<banRepositories>> - Specify banned non-plugin repositories. This is a black list of http/https url patterns.
 
-   * banPluginRepositories - Specify banned plugin repositories. This is a black list of http/https url patterns.
+   * <<banPluginRepositories>> - Specify banned plugin repositories. This is a black list of http/https url patterns.
 
-   * allowedRepositories - Specify explicitly allowed non-plugin repositories. This is a white list of http/https url patterns.
+   * <<allowedRepositories>> - Specify explicitly allowed non-plugin repositories. This is a white list of http/https url patterns.
 
-   * allowedPluginRepositories - Specify explicitly allowed plugin repositories. This is a white list of http/https url patternes.
+   * <<allowedPluginRepositories>> - Specify explicitly allowed plugin repositories. This is a white list of http/https url patternes.
 
 * Sample Configuration
 
    For example, one company want to limit repositories usage. But different developers might use different settings.xml.
-   Even their projects' pom defined different repostories too.
+   Even their projects' pom defined different repositories too.
    For this case, could leverage this enforcer rule to banned specified repositories or even use allowedRepositories/allowedPluginRepositories to banned others unexpected repositories.
    
    Ex. http://repo1/xyz is the repository that want to be banned.
@@ -106,7 +106,7 @@ Banned Specified Repositories
 
    * http/https url patterns support wildcard "*"
    
-   * This rule will detect banned repositories on maven session itself istead of pom or settings, so if users defined "mirrorOf" in settings.xml, even defined banned repositories in pom.xml, it won't be detected.
+   * This rule will detect banned repositories on maven session itself instead of pom or settings, so if users defined "mirrorOf" in settings.xml, even defined banned repositories in pom.xml, it won't be detected.
 
 +---+
 	<mirrors>
diff --git a/enforcer-rules/src/site/apt/evaluateBeanshell.apt.vm b/enforcer-rules/src/site/apt/evaluateBeanshell.apt.vm
index 2efabb5..8cf2e10 100644
--- a/enforcer-rules/src/site/apt/evaluateBeanshell.apt.vm
+++ b/enforcer-rules/src/site/apt/evaluateBeanshell.apt.vm
@@ -30,9 +30,9 @@ Beanshell
 
    The following parameters are supported by this rule:
    
-   * condition - the beanshell statement to evaluate.
+   * <<condition>> - the beanshell statement to evaluate.
    
-   * message - an optional message to the user if the rule fails.
+   * <<message>> - an optional message to the user if the rule fails.
    
    []
 
diff --git a/enforcer-rules/src/site/apt/reactorModuleConvergence.apt.vm b/enforcer-rules/src/site/apt/reactorModuleConvergence.apt.vm
index c2947f7..3bf2e5a 100644
--- a/enforcer-rules/src/site/apt/reactorModuleConvergence.apt.vm
+++ b/enforcer-rules/src/site/apt/reactorModuleConvergence.apt.vm
@@ -32,9 +32,9 @@ Reactor Module Convergence
 
   The following parameters are supported by this rule:
    
-  * message - an optional supplemental message to the user if the rule fails.
+  * <<message>> - an optional supplemental message to the user if the rule fails.
   
-  * ignoreModuleDependencies - Ignore module dependencies which references modules within the 
+  * <<ignoreModuleDependencies>> - Ignore module dependencies which references modules within the
     the reactor (default: false). 
 
   Note: The current state does not correctly handle a situation like this {{mvn -pl subproject validate}}.
@@ -131,7 +131,7 @@ Reactor Module Convergence
   with the following resulting output:
 
 +-----
-[WARNING] Rule 0: org.apache.maven.plugins.enforcer.ReactorModuleConvergence failed with message:
+[WARNING] Rule 0: org.apache.maven.enforcer.rules.ReactorModuleConvergence failed with message:
 The reactor contains different versions.
  --> com.mycompany.project:myproject:pom:1.1-SNAPSHOT
 +-----
@@ -154,7 +154,7 @@ The reactor contains different versions.
   This will prompted by the following message:
   
 +-----
-[WARNING] Rule 0: org.apache.maven.plugins.enforcer.ReactorModuleConvergence failed with message:
+[WARNING] Rule 0: org.apache.maven.enforcer.rules.ReactorModuleConvergence failed with message:
 Reactor modules have parents which contain a wrong version.
  --> com.mycompany.project:myproject:pom:1.1-SNAPSHOT parent:com.mycompany.project:myproject:pom:1.0-SNAPSHOT
 +-----
@@ -176,7 +176,7 @@ Reactor modules have parents which contain a wrong version.
   you will get the same message as above:
   
 +-----
-[WARNING] Rule 0: org.apache.maven.plugins.enforcer.ReactorModuleConvergence failed with message:
+[WARNING] Rule 0: org.apache.maven.enforcer.rules.ReactorModuleConvergence failed with message:
 The reactor contains different versions.
  --> com.mycompany.project:myproject:pom:1.1-SNAPSHOT
 +-----
@@ -185,7 +185,7 @@ The reactor contains different versions.
   produces a message like this:
 
 +----
-[WARNING] Rule 0: org.apache.maven.plugins.enforcer.ReactorModuleConvergence failed with message:
+[WARNING] Rule 0: org.apache.maven.enforcer.rules.ReactorModuleConvergence failed with message:
 Reactor contains modules without parents.
  module: com.mycompany.project:myproject:pom:1.2-SNAPSHOT
 +----
@@ -218,7 +218,7 @@ Reactor contains modules without parents.
   has the same version as the rest of the build which happens):
    
 +-----
-[WARNING] Rule 0: org.apache.maven.plugins.enforcer.ReactorModuleConvergence failed with message:
+[WARNING] Rule 0: org.apache.maven.enforcer.rules.ReactorModuleConvergence failed with message:
 Module parents have been found which could not be found in the reactor.
  module: org.apache.enforcer:something-different:pom:1.0.4-SNAPSHOT
 +-----
@@ -250,7 +250,7 @@ Module parents have been found which could not be found in the reactor.
   This will result in the following message:
 
 +-----
-[WARNING] Rule 0: org.apache.maven.plugins.enforcer.ReactorModuleConvergence failed with message:
+[WARNING] Rule 0: org.apache.maven.enforcer.rules.ReactorModuleConvergence failed with message:
 Reactor modules contains dependencies which do not reference the reactor.
  module: com.mycompany.project:myproject-x:jar:1.2-SNAPSHOT
     dependency: com.mycompany.project:myproject:1.1
diff --git a/enforcer-rules/src/site/apt/requireActiveProfile.apt.vm b/enforcer-rules/src/site/apt/requireActiveProfile.apt.vm
index f639223..307b6c9 100644
--- a/enforcer-rules/src/site/apt/requireActiveProfile.apt.vm
+++ b/enforcer-rules/src/site/apt/requireActiveProfile.apt.vm
@@ -30,11 +30,11 @@ Require Active Profile
 
    The following parameters are supported by this rule:
    
-   * message - an optional message to the user if the rule fails.
+   * <<message>> - an optional message to the user if the rule fails.
    
-   * profiles - A comma separated list of profile to check.
+   * <<profiles>> - A comma separated list of profile to check.
    
-   * all - Checks if all given profiles are active. Default is true.
+   * <<all>> - Checks if all given profiles are active. Default is true.
    
    []
 
diff --git a/enforcer-rules/src/site/apt/requireNoRepositories.apt.vm b/enforcer-rules/src/site/apt/requireNoRepositories.apt.vm
index 9ae3f39..5976dbe 100644
--- a/enforcer-rules/src/site/apt/requireNoRepositories.apt.vm
+++ b/enforcer-rules/src/site/apt/requireNoRepositories.apt.vm
@@ -29,17 +29,19 @@ Require No Repositories
 
    The following parameters are supported by this rule:
 
-   * banRepositories - Whether to ban non-plugin repositories. By default they are banned (true).
+   * <<banRepositories>> - Whether to ban non-plugin repositories. By default they are banned (true).
 
-   * banPluginRepositories - Whether to ban plugin repositories. By default they are banned (true).
+   * <<banPluginRepositories>> - Whether to ban plugin repositories. By default they are banned (true).
 
-   * allowedRepositories - Specify explicitly allowed non-plugin repositories. This is a list of ids.
+   * <<allowedRepositories>> - Specify explicitly allowed non-plugin repositories. This is a list of ids.
 
-   * allowedPluginRepositories - Specify explicitly allowed plugin repositories. This is a list of ids.
+   * <<allowedPluginRepositories>> - Specify explicitly allowed plugin repositories. This is a list of ids.
 
-   * allowSnapshotRepositories - Whether to allow repositories which only resolve snapshots. By default they are banned (false).
+   * <<allowSnapshotRepositories>> - Whether to allow repositories which only resolve snapshots. By default they are banned (false).
 
-   * allowSnapshotPluginRepositories - Whether to allow plugin repositories which only resolve snapshots. By default they are banned (false).
+   * <<allowSnapshotPluginRepositories>> - Whether to allow plugin repositories which only resolve snapshots. By default they are banned (false).
+
+   * <<message>> - an optional message to the user if the rule fails.
 
    []
 
diff --git a/enforcer-rules/src/site/apt/requirePluginVersions.apt.vm b/enforcer-rules/src/site/apt/requirePluginVersions.apt.vm
index e654b71..bd35874 100644
--- a/enforcer-rules/src/site/apt/requirePluginVersions.apt.vm
+++ b/enforcer-rules/src/site/apt/requirePluginVersions.apt.vm
@@ -29,24 +29,24 @@ Require Plugin Versions
 
    The following parameters are supported by this rule:
 
-   * message - an optional message to the user if the rule fails.
+   * <<message>> - an optional message to the user if the rule fails.
 
-   * banLatest - disallow any use of "LATEST" as a version for any plugin. Default = true.
+   * <<banLatest>> - disallow any use of "LATEST" as a version for any plugin. Default = true.
 
-   * banRelease - disallow any use of "RELEASE" as a version for any plugin. Default = true.
+   * <<banRelease>> - disallow any use of "RELEASE" as a version for any plugin. Default = true.
 
-   * banSnapshots - disallow any use of SNAPSHOT plugins. Default = true.
+   * <<banSnapshots>> - disallow any use of SNAPSHOT plugins. Default = true.
 
-   * banTimestamps - disallow any use of snapshot plugins with timestamp version (only enabled when banSnapshots is true). Default = true.
+   * <<banTimestamps>> - disallow any use of snapshot plugins with timestamp version (only enabled when banSnapshots is true). Default = true.
 
-   * phases - The comma separated list of phases that should be used to find 
+   * <<phases>> - The comma separated list of phases that should be used to find
      lifecycle plugin bindings. The default value is "clean,deploy,site".
 
-   * additionalPlugins - A list of additional plugins to enforce have versions. These
+   * <<additionalPlugins>> - A list of additional plugins to enforce have versions. These
      are plugins that may not be in the poms but are used anyway, like help, eclipse etc.
      The plugins should be specified in the form: group:artifactId.
 
-   * unCheckedPluginList - A comma separated list of plugins to skip version checking. Ie allow no version, or snapshots, etc. The plugins should be specified in the form: group:artifactId.
+   * <<unCheckedPluginList>> - A comma separated list of plugins to skip version checking. Ie allow no version, or snapshots, etc. The plugins should be specified in the form: group:artifactId.
 
 
    []
diff --git a/enforcer-rules/src/site/apt/requirePrerequisite.apt.vm b/enforcer-rules/src/site/apt/requirePrerequisite.apt.vm
index 8a07987..b6fe1cb 100644
--- a/enforcer-rules/src/site/apt/requirePrerequisite.apt.vm
+++ b/enforcer-rules/src/site/apt/requirePrerequisite.apt.vm
@@ -31,7 +31,7 @@
 
    The following parameters are supported by this rule:
    
-   * mavenVersion - an optional value contain a versionrange or the version at least required.
+   * <<mavenVersion>> - an optional value contain a versionrange or the version at least required.
    
    []
 
diff --git a/enforcer-rules/src/site/apt/requireSameVersions.apt.vm b/enforcer-rules/src/site/apt/requireSameVersions.apt.vm
index f3c99e1..e4e55a7 100644
--- a/enforcer-rules/src/site/apt/requireSameVersions.apt.vm
+++ b/enforcer-rules/src/site/apt/requireSameVersions.apt.vm
@@ -30,15 +30,15 @@
 
    The following parameters are supported by this rule:
    
-   * dependencies - an optional list of dependency patterns
+   * <<dependencies>> - an optional list of dependency patterns
    
-   * buildPlugins - an optional list of build plugin patterns
+   * <<buildPlugins>> - an optional list of build plugin patterns
    
-   * reportPlugins - an optional list of report plugin patterns
+   * <<reportPlugins>> - an optional list of report plugin patterns
    
-   * plugins - an optional list of both build and report plugin patterns
+   * <<plugins>> - an optional list of both build and report plugin patterns
     
-   * uniqueVersions - if SNAPSHOTs should be compared by their timestamped version or not. Default: false 
+   * <<uniqueVersions>> - if SNAPSHOTs should be compared by their timestamped version or not. Default: false
 
    []
 
diff --git a/enforcer-rules/src/site/apt/requireSnapshotVersion.apt.vm b/enforcer-rules/src/site/apt/requireSnapshotVersion.apt.vm
index 446acf5..03820f9 100644
--- a/enforcer-rules/src/site/apt/requireSnapshotVersion.apt.vm
+++ b/enforcer-rules/src/site/apt/requireSnapshotVersion.apt.vm
@@ -30,9 +30,9 @@ Require Snapshot Version
 
    The following parameters are supported by this rule:
    
-   * message - an optional message to the user if the rule fails.
+   * <<message>> - an optional message to the user if the rule fails.
     
-   * failWhenParentIsRelease - if the parent should be checked. Default: true 
+   * <<failWhenParentIsRelease>> - if the parent should be checked. Default: true
 
    []
 
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/BanDependencyManagementScopeTest.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/BanDependencyManagementScopeTest.java
similarity index 87%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/BanDependencyManagementScopeTest.java
rename to enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/BanDependencyManagementScopeTest.java
index c74fc3e..af9fd93 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/BanDependencyManagementScopeTest.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/BanDependencyManagementScopeTest.java
@@ -16,21 +16,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer;
+package org.apache.maven.enforcer.rules;
 
 import java.util.Collections;
 
+import org.apache.maven.enforcer.rule.api.EnforcerLogger;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.plugin.logging.SystemStreamLog;
+import org.apache.maven.project.MavenProject;
 import org.hamcrest.MatcherAssert;
 import org.hamcrest.Matchers;
 import org.junit.jupiter.api.Test;
 
+import static org.mockito.Mockito.mock;
+
 class BanDependencyManagementScopeTest {
     @Test
     void testGetViolatingDependencies() {
-        BanDependencyManagementScope rule = new BanDependencyManagementScope();
+        BanDependencyManagementScope rule = new BanDependencyManagementScope(new MavenProject());
         DependencyManagement depMgmt = new DependencyManagement();
         Dependency depWithoutScope = createDependency("myGroup", "artifact1", null);
         Dependency depWithScope = createDependency("myGroup", "artifact2", "1.1.0", "provided");
@@ -41,8 +44,8 @@ class BanDependencyManagementScopeTest {
         depMgmt.addDependency(depWithImportScope);
         depMgmt.addDependency(excludedDepWithScope);
         rule.setExcludes(Collections.singletonList("*:artifact4"));
-        MatcherAssert.assertThat(
-                rule.getViolatingDependencies(new SystemStreamLog(), depMgmt), Matchers.contains(depWithScope));
+        rule.setLog(mock(EnforcerLogger.class));
+        MatcherAssert.assertThat(rule.getViolatingDependencies(depMgmt), Matchers.contains(depWithScope));
     }
 
     static Dependency createDependency(String groupId, String artifactId, String version) {
diff --git a/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/BanDistributionManagementTest.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/BanDistributionManagementTest.java
new file mode 100644
index 0000000..210b4d1
--- /dev/null
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/BanDistributionManagementTest.java
@@ -0,0 +1,219 @@
+/*
+ * 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.rules;
+
+import org.apache.maven.enforcer.rule.api.EnforcerLogger;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
+import org.apache.maven.model.DeploymentRepository;
+import org.apache.maven.model.DistributionManagement;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Site;
+import org.apache.maven.project.MavenProject;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * This class is intended to test the {@link BanDistributionManagement} rule.
+ *
+ * @author <a href="mailto:khmarbaise@apache.org">Karl Heinz Marbaise</a>
+ */
+@ExtendWith(MockitoExtension.class)
+class BanDistributionManagementTest {
+
+    @Mock
+    private MavenProject project;
+
+    @Mock
+    private EnforcerLogger log;
+
+    @InjectMocks
+    private BanDistributionManagement rule;
+
+    @BeforeEach
+    void setup() {
+        rule.setLog(log);
+    }
+
+    @Test
+    void shouldNotFailWithoutDistributionManagement() throws Exception {
+        setupProjectWithoutDistributionManagement();
+        rule.execute();
+        // intentionally no assert cause in case of an exception the test will be red.
+    }
+
+    /**
+     * <pre>
+     * &lt;distributionManagement&gt;
+     *   &lt;repository&gt;
+     *    ...
+     *   &lt;/repository&gt;
+     * &lt;/distributionManagement&gt;
+     * </pre>
+     */
+    @Test
+    void shouldThrowExceptionIfDistributionManagementIsDefinedWithRepository() {
+        setupProjectWithDistributionManagement(new DeploymentRepository(), null, null);
+        assertThrows(EnforcerRuleException.class, () -> rule.execute());
+    }
+
+    /**
+     * <pre>
+     * &lt;distributionManagement&gt;
+     *   &lt;snapshotRepository&gt;
+     *    ...
+     *   &lt;/snapshotRepository&gt;
+     * &lt;/distributionManagement&gt;
+     * </pre>
+     */
+    @Test
+    void shouldThrowExceptionIfDistributionManagementIsDefinedWithRepositorySnapshotRepository() {
+        setupProjectWithDistributionManagement(null, new DeploymentRepository(), null);
+
+        assertThrows(EnforcerRuleException.class, () -> rule.execute());
+    }
+
+    /**
+     * <pre>
+     * &lt;distributionManagement&gt;
+     *   &lt;repository&gt;
+     *    ...
+     *   &lt;/repository&gt;
+     *   &lt;snapshotRepository&gt;
+     *    ...
+     *   &lt;/snapshotRepository&gt;
+     *   &lt;site&gt;
+     *    ...
+     *   &lt;/site&gt;
+     * &lt;/distributionManagement&gt;
+     * </pre>
+     */
+    @Test
+    void shouldThrowExceptionIfDistributionManagementIsDefinedWithRepositorySnapshotRepositorySite() {
+        setupProjectWithDistributionManagement(new DeploymentRepository(), null, null);
+
+        assertThrows(EnforcerRuleException.class, () -> rule.execute());
+    }
+
+    /**
+     * <pre>
+     * &lt;distributionManagement&gt;
+     *   &lt;repository&gt;
+     *    ...
+     *   &lt;/repository&gt;
+     * &lt;/distributionManagement&gt;
+     * </pre>
+     *
+     * @throws Exception if any occurs
+     */
+    @Test
+    void shouldAllowDistributionManagementHavingRepository() throws Exception {
+        setupProjectWithDistributionManagement(null, null, null);
+        rule.setAllowRepository(true);
+        rule.execute();
+        // intentionally no assert cause in case of an exception the test will be red.
+    }
+
+    /**
+     * <pre>
+     * &lt;distributionManagement&gt;
+     *   &lt;repository&gt;
+     *    ...
+     *   &lt;/repository&gt;
+     *   &lt;snapshotRepository&gt;
+     *    ...
+     *   &lt;/snapshotRepository&gt;
+     * &lt;/distributionManagement&gt;
+     * </pre>
+     *
+     * @throws Exception if any occurs
+     */
+    @Test
+    void shouldAllowDistributionManagementHavingRepositorySnapshotRepository() throws Exception {
+        setupProjectWithDistributionManagement(null, null, null);
+
+        rule.setAllowRepository(true);
+        rule.setAllowSnapshotRepository(true);
+        rule.execute();
+        // intentionally no assert cause in case of an exception the test will be red.
+    }
+
+    /**
+     * <pre>
+     * &lt;distributionManagement&gt;
+     *   &lt;repository&gt;
+     *    ...
+     *   &lt;/repository&gt;
+     *   &lt;snapshotRepository&gt;
+     *    ...
+     *   &lt;/snapshotRepository&gt;
+     *   &lt;site&gt;
+     *    ...
+     *   &lt;/site&gt;
+     * &lt;/distributionManagement&gt;
+     * </pre>
+     *
+     * @throws Exception if any occurs
+     */
+    @Test
+    void shouldAllowDistributionManagementHavingRepositorySnapshotRepositorySite() throws Exception {
+        setupProjectWithDistributionManagement(null, null, null);
+        rule.setAllowRepository(true);
+        rule.setAllowSnapshotRepository(true);
+        rule.setAllowSite(true);
+        rule.execute();
+        // intentionally no assert cause in case of an exception the test will be red.
+    }
+
+    private void setupProjectWithoutDistributionManagement() {
+        setupProject(null);
+    }
+
+    private void setupProjectWithDistributionManagement(
+            DeploymentRepository repository, DeploymentRepository snapshotRepository, Site site) {
+        DistributionManagement dm = mock(DistributionManagement.class);
+        if (repository != null) {
+            when(dm.getRepository()).thenReturn(repository);
+        }
+        if (snapshotRepository != null) {
+            when(dm.getSnapshotRepository()).thenReturn(snapshotRepository);
+        }
+        if (site != null) {
+            when(dm.getSite()).thenReturn(site);
+        }
+        setupProject(dm);
+
+        when(project.getParent()).thenReturn(mock(MavenProject.class));
+        when(project.isExecutionRoot()).thenReturn(true);
+    }
+
+    private void setupProject(DistributionManagement distributionManagement) {
+        //        when(project.getPackaging()).thenReturn("jar");
+        Model mavenModel = mock(Model.class);
+        when(project.getOriginalModel()).thenReturn(mavenModel);
+        when(mavenModel.getDistributionManagement()).thenReturn(distributionManagement);
+    }
+}
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/ReactorModuleConvergenceTest.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/ReactorModuleConvergenceTest.java
similarity index 89%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/ReactorModuleConvergenceTest.java
rename to enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/ReactorModuleConvergenceTest.java
index 365661e..e3b6bc5 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/ReactorModuleConvergenceTest.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/ReactorModuleConvergenceTest.java
@@ -16,18 +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 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.Dependency;
-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;
@@ -42,21 +41,16 @@ import static org.mockito.Mockito.when;
  *
  * @author <a href="mailto:khmarbaise@apache.org">Karl Heinz Marbaise</a>
  */
-public class ReactorModuleConvergenceTest {
+class ReactorModuleConvergenceTest {
     private MavenSession session;
 
-    private EnforcerRuleHelper helper;
-
     private ReactorModuleConvergence rule;
 
     @BeforeEach
     public void before() throws ExpressionEvaluationException {
         session = mock(MavenSession.class);
-        helper = mock(EnforcerRuleHelper.class);
-        when(helper.evaluate("${session}")).thenReturn(session);
-        when(helper.getLog()).thenReturn(mock(Log.class));
-
-        rule = new ReactorModuleConvergence();
+        rule = new ReactorModuleConvergence(session);
+        rule.setLog(mock(EnforcerLogger.class));
     }
 
     private void setupSortedProjects(List<MavenProject> projectList) {
@@ -66,14 +60,14 @@ public class ReactorModuleConvergenceTest {
     }
 
     @Test
-    public void shouldNotFailWithNoProject() throws EnforcerRuleException {
+    void shouldNotFailWithNoProject() throws EnforcerRuleException {
         setupSortedProjects(Collections.emptyList());
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
-    public void shouldNotFailWithAValidProject() throws EnforcerRuleException {
+    void shouldNotFailWithAValidProject() throws EnforcerRuleException {
         MavenProject mp1 = createProjectParent();
         MavenProject mp2 = createProjectChild1(mp1);
         MavenProject mp3 = createProjectChild2(mp1);
@@ -81,11 +75,11 @@ public class ReactorModuleConvergenceTest {
         List<MavenProject> theList = Arrays.asList(mp1, mp2, mp3);
         setupSortedProjects(theList);
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
-    public void shouldFailWithWrongVersionInOneChild() {
+    void shouldFailWithWrongVersionInOneChild() {
         assertThrows(EnforcerRuleException.class, () -> {
             MavenProject mp1 = createProjectParent();
             MavenProject mp2 = createProjectChild1(mp1);
@@ -94,7 +88,7 @@ public class ReactorModuleConvergenceTest {
             List<MavenProject> theList = Arrays.asList(mp1, mp2, mp3);
             setupSortedProjects(theList);
 
-            rule.execute(helper);
+            rule.execute();
 
             // intentionally no assertTrue() cause we expect getting an exception.
         });
@@ -103,7 +97,7 @@ public class ReactorModuleConvergenceTest {
     }
 
     @Test
-    public void shouldFailWithWrongParent() {
+    void shouldFailWithWrongParent() {
         assertThrows(EnforcerRuleException.class, () -> {
             MavenProject mp1 = createProjectParent();
 
@@ -120,7 +114,7 @@ public class ReactorModuleConvergenceTest {
             List<MavenProject> theList = Arrays.asList(mp1, mp2, mp3);
             setupSortedProjects(theList);
 
-            rule.execute(helper);
+            rule.execute();
 
             // intentionally no assertTrue() cause we expect getting an exception.
         });
@@ -129,7 +123,7 @@ public class ReactorModuleConvergenceTest {
     }
 
     @Test
-    public void shouldNotFailWithACompanyParent() throws EnforcerRuleException {
+    void shouldNotFailWithACompanyParent() throws EnforcerRuleException {
         MavenProject companyParent = createCompanyParent();
         MavenProject mp1 = createProjectParent(companyParent);
 
@@ -139,11 +133,11 @@ public class ReactorModuleConvergenceTest {
         List<MavenProject> theList = Arrays.asList(mp1, mp2, mp3);
         setupSortedProjects(theList);
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
-    public void shouldFailWithMissingParentsInReactory() {
+    void shouldFailWithMissingParentsInReactory() {
         assertThrows(EnforcerRuleException.class, () -> {
             MavenProject mp1 = createProjectParent();
             MavenProject mp2 = createProjectChild1(mp1);
@@ -152,12 +146,12 @@ public class ReactorModuleConvergenceTest {
             List<MavenProject> theList = Arrays.asList(mp1, mp2, mp3);
             setupSortedProjects(theList);
 
-            rule.execute(helper);
+            rule.execute();
         });
     }
 
     @Test
-    public void shouldFailWithAParentWhichIsNotPartOfTheReactory() {
+    void shouldFailWithAParentWhichIsNotPartOfTheReactory() {
         assertThrows(EnforcerRuleException.class, () -> {
             MavenProject mp1 = createProjectParent();
 
@@ -174,7 +168,7 @@ public class ReactorModuleConvergenceTest {
             List<MavenProject> theList = Arrays.asList(mp1, mp2, mp3);
             setupSortedProjects(theList);
 
-            rule.execute(helper);
+            rule.execute();
 
             // intentionally no assertTrue() cause we expect getting an exception.
         });
@@ -183,7 +177,7 @@ public class ReactorModuleConvergenceTest {
     }
 
     @Test
-    public void shouldNotFailWithDependencyInReactory() throws EnforcerRuleException {
+    void shouldNotFailWithDependencyInReactory() throws EnforcerRuleException {
         MavenProject mp1 = createProjectParent();
         MavenProject mp2 = createProjectChild1(mp1);
 
@@ -199,11 +193,11 @@ public class ReactorModuleConvergenceTest {
         List<MavenProject> theList = Arrays.asList(mp1, mp2, mp3);
         setupSortedProjects(theList);
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
-    public void shouldFailWithWrongDependencyInReactor() {
+    void shouldFailWithWrongDependencyInReactor() {
         assertThrows(EnforcerRuleException.class, () -> {
             MavenProject mp1 = createProjectParent();
             MavenProject mp2 = createProjectChild1(mp1);
@@ -219,7 +213,7 @@ public class ReactorModuleConvergenceTest {
             List<MavenProject> theList = Arrays.asList(mp1, mp2, mp3);
             setupSortedProjects(theList);
 
-            rule.execute(helper);
+            rule.execute();
 
             // intentionally no assertTrue() cause we expect getting an exception.
         });
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/RequireActiveProfileTest.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/RequireActiveProfileTest.java
similarity index 68%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/RequireActiveProfileTest.java
rename to enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/RequireActiveProfileTest.java
index 6046f90..7a00f1a 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/RequireActiveProfileTest.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/RequireActiveProfileTest.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 java.util.Arrays;
 import java.util.Collections;
@@ -24,14 +24,14 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
 
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 /**
@@ -39,79 +39,72 @@ import static org.mockito.Mockito.when;
  *
  * @author <a href="mailto:khmarbaise@apache.org">Karl Heinz Marbaise</a>
  */
-public class RequireActiveProfileTest {
-    private MavenProject project;
+@ExtendWith(MockitoExtension.class)
+class RequireActiveProfileTest {
 
-    private EnforcerRuleHelper helper;
+    @Mock
+    private MavenProject project;
 
+    @InjectMocks
     private RequireActiveProfile rule;
 
-    @BeforeEach
-    public void before() throws ExpressionEvaluationException {
-        project = mock(MavenProject.class);
-        helper = mock(EnforcerRuleHelper.class);
-        when(helper.evaluate("${project}")).thenReturn(project);
-        rule = new RequireActiveProfile();
-    }
-
     @Test
-    public void testNoActiveProfilesInProjectAndNoProfilesExpectedToBeActivated() throws EnforcerRuleException {
-        when(project.getInjectedProfileIds()).thenReturn(Collections.emptyMap());
+    void testNoActiveProfilesInProjectAndNoProfilesExpectedToBeActivated() throws EnforcerRuleException {
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
-    public void testActiveProfileAndExpectedActiveProfile() throws EnforcerRuleException {
+    void testActiveProfileAndExpectedActiveProfile() throws EnforcerRuleException {
         Map<String, List<String>> profiles = Collections.singletonMap("pom", Arrays.asList("profile-2"));
 
         when(project.getInjectedProfileIds()).thenReturn(profiles);
 
         rule.setProfiles("profile-2");
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
-    public void testNoActiveProfileButTheRuleRequestedAnActiveProfile() {
+    void testNoActiveProfileButTheRuleRequestedAnActiveProfile() {
         assertThrows(EnforcerRuleException.class, () -> {
             when(project.getInjectedProfileIds()).thenReturn(Collections.emptyMap());
 
             rule.setProfiles("profile-2");
 
-            rule.execute(helper);
+            rule.execute();
             // intentionally no assertTrue(...)
         });
         // intentionally no assertTrue(...)
     }
 
     @Test
-    public void testNoActiveProfileButWeExpectToGetAnExceptionWithAll() {
+    void testNoActiveProfileButWeExpectToGetAnExceptionWithAll() {
         assertThrows(EnforcerRuleException.class, () -> {
             when(project.getInjectedProfileIds()).thenReturn(Collections.emptyMap());
 
             rule.setProfiles("profile-2");
             rule.setAll(true);
 
-            rule.execute(helper);
+            rule.execute();
             // intentionally no assertTrue(...)
         });
         // intentionally no assertTrue(...)
     }
 
     @Test
-    public void testTwoActiveProfilesWithOneRequiredProfile() throws EnforcerRuleException {
+    void testTwoActiveProfilesWithOneRequiredProfile() throws EnforcerRuleException {
         Map<String, List<String>> profiles = Collections.singletonMap("pom", Arrays.asList("profile-1", "profile-2"));
 
         when(project.getInjectedProfileIds()).thenReturn(profiles);
 
         rule.setProfiles("profile-2");
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
-    public void testTwoActiveProfilesWhereOneProfileIsRequiredToBeActivated() throws EnforcerRuleException {
+    void testTwoActiveProfilesWhereOneProfileIsRequiredToBeActivated() throws EnforcerRuleException {
         Map<String, List<String>> profiles = Collections.singletonMap("pom", Arrays.asList("profile-1", "profile-2"));
 
         when(project.getInjectedProfileIds()).thenReturn(profiles);
@@ -119,11 +112,11 @@ public class RequireActiveProfileTest {
         rule.setProfiles("profile-2");
         rule.setAll(true);
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
-    public void testTwoActiveProfilesWithTwoRequiredProfilesWhereOneOfThemIsNotPartOfTheActiveProfiles() {
+    void testTwoActiveProfilesWithTwoRequiredProfilesWhereOneOfThemIsNotPartOfTheActiveProfiles() {
         assertThrows(EnforcerRuleException.class, () -> {
             Map<String, List<String>> profiles =
                     Collections.singletonMap("pom", Arrays.asList("profile-X", "profile-Y"));
@@ -133,14 +126,14 @@ public class RequireActiveProfileTest {
             rule.setProfiles("profile-Z,profile-X");
             rule.setAll(true);
 
-            rule.execute(helper);
+            rule.execute();
             // intentionally no assertTrue(..)
         });
         // intentionally no assertTrue(..)
     }
 
     @Test
-    public void testOneActiveProfilesWithTwoRequiredProfiles() {
+    void testOneActiveProfilesWithTwoRequiredProfiles() {
         assertThrows(EnforcerRuleException.class, () -> {
             Map<String, List<String>> profiles = Collections.singletonMap("pom", Arrays.asList("profile-X"));
 
@@ -149,14 +142,14 @@ public class RequireActiveProfileTest {
             rule.setProfiles("profile-X,profile-Y");
             rule.setAll(true);
 
-            rule.execute(helper);
+            rule.execute();
             // intentionally no assertTrue(..)
         });
         // intentionally no assertTrue(..)
     }
 
     @Test
-    public void testOneActiveProfileWithTwoProfilesButNotAll() throws EnforcerRuleException {
+    void testOneActiveProfileWithTwoProfilesButNotAll() throws EnforcerRuleException {
         Map<String, List<String>> profiles = Collections.singletonMap("pom", Arrays.asList("profile-X"));
 
         when(project.getInjectedProfileIds()).thenReturn(profiles);
@@ -164,7 +157,7 @@ public class RequireActiveProfileTest {
         rule.setProfiles("profile-X,profile-Y");
         rule.setAll(false);
 
-        rule.execute(helper);
+        rule.execute();
         // intentionally no assertTrue(..)
     }
 }
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/RequirePrerequisiteTest.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/RequirePrerequisiteTest.java
similarity index 55%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/RequirePrerequisiteTest.java
rename to enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/RequirePrerequisiteTest.java
index da1dcc4..97e96ee 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/RequirePrerequisiteTest.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/RequirePrerequisiteTest.java
@@ -16,137 +16,121 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.plugins.enforcer;
+package org.apache.maven.enforcer.rules;
 
 import java.util.Collections;
 
+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.model.Prerequisites;
-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;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
 
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-public class RequirePrerequisiteTest {
+@ExtendWith(MockitoExtension.class)
+class RequirePrerequisiteTest {
+
+    @Mock
     private MavenProject project;
 
-    private EnforcerRuleHelper helper;
+    @Mock
+    private EnforcerLogger log;
+
+    @InjectMocks
+    private RequirePrerequisite rule;
 
     @BeforeEach
-    public void before() throws ExpressionEvaluationException {
-        project = mock(MavenProject.class);
+    void before() {
+        rule.setLog(log);
         when(project.getPackaging()).thenReturn("maven-plugin");
-
-        helper = mock(EnforcerRuleHelper.class);
-        when(helper.evaluate("${project}")).thenReturn(project);
     }
 
     @Test
-    public void testNoPrerequisite() {
-        assertThrows(EnforcerRuleException.class, () -> {
-            RequirePrerequisite rule = new RequirePrerequisite();
-            rule.execute(helper);
-        });
+    void testNoPrerequisite() {
+        assertThrows(EnforcerRuleException.class, () -> rule.execute());
     }
 
     @Test
-    public void testNoSpecifiedPrerequisite() throws Exception {
+    void testNoSpecifiedPrerequisite() throws Exception {
         when(project.getPrerequisites()).thenReturn(new Prerequisites());
-
-        RequirePrerequisite rule = new RequirePrerequisite();
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
-    public void testLowerMavenPrerequisite() {
-        assertThrows(EnforcerRuleException.class, () -> {
-            when(project.getPrerequisites()).thenReturn(new Prerequisites());
+    void testLowerMavenPrerequisite() {
+        when(project.getPrerequisites()).thenReturn(new Prerequisites());
 
-            RequirePrerequisite rule = new RequirePrerequisite();
+        assertThrows(EnforcerRuleException.class, () -> {
             rule.setMavenVersion("3.0");
-            rule.execute(helper);
+            rule.execute();
         });
     }
 
     @Test
-    public void testLowerMavenRangePrerequisite() {
-        assertThrows(EnforcerRuleException.class, () -> {
-            when(project.getPrerequisites()).thenReturn(new Prerequisites());
+    void testLowerMavenRangePrerequisite() {
+        when(project.getPrerequisites()).thenReturn(new Prerequisites());
 
-            RequirePrerequisite rule = new RequirePrerequisite();
+        assertThrows(EnforcerRuleException.class, () -> {
             rule.setMavenVersion("[3.0,)");
-
-            rule.execute(helper);
+            rule.execute();
         });
     }
 
     @Test
-    public void testMavenRangesPrerequisite() {
+    void testMavenRangesPrerequisite() {
         assertThrows(EnforcerRuleException.class, () -> {
             Prerequisites prerequisites = new Prerequisites();
             prerequisites.setMaven("2.2.0");
             when(project.getPrerequisites()).thenReturn(prerequisites);
 
-            RequirePrerequisite rule = new RequirePrerequisite();
             rule.setMavenVersion("[2.0.6,2.1.0),(2.1.0,2.2.0),(2.2.0,)");
-
-            rule.execute(helper);
+            rule.execute();
         });
     }
 
     @Test
-    public void testValidPrerequisite() throws Exception {
+    void testValidPrerequisite() throws Exception {
         Prerequisites prerequisites = new Prerequisites();
         prerequisites.setMaven("3.0");
         when(project.getPrerequisites()).thenReturn(prerequisites);
 
-        RequirePrerequisite rule = new RequirePrerequisite();
         rule.setMavenVersion("2.2.1");
-
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
-    public void testPomPackaging() throws Exception {
+    void testPomPackaging() throws Exception {
         when(project.getPackaging()).thenReturn("pom");
 
-        Log log = mock(Log.class);
-        when(helper.getLog()).thenReturn(log);
-
-        RequirePrerequisite rule = new RequirePrerequisite();
-        rule.execute(helper);
+        rule.execute();
 
         verify(log).debug("Packaging is pom, skipping requirePrerequisite rule");
     }
 
     @Test
-    public void testMatchingPackagings() {
+    void testMatchingPackagings() {
         assertThrows(EnforcerRuleException.class, () -> {
             when(project.getPackaging()).thenReturn("maven-plugin");
 
-            RequirePrerequisite rule = new RequirePrerequisite();
             rule.setPackagings(Collections.singletonList("maven-plugin"));
-            rule.execute(helper);
+            rule.execute();
         });
     }
 
     @Test
-    public void testNotMatchingPackagings() throws Exception {
+    void testNotMatchingPackagings() throws Exception {
         when(project.getPackaging()).thenReturn("jar");
 
-        Log log = mock(Log.class);
-        when(helper.getLog()).thenReturn(log);
-
-        RequirePrerequisite rule = new RequirePrerequisite();
         rule.setPackagings(Collections.singletonList("maven-plugin"));
-        rule.execute(helper);
+        rule.execute();
 
         verify(log).debug("Packaging is jar, skipping requirePrerequisite rule");
     }
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestBannedRepositories.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestBannedRepositories.java
similarity index 87%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestBannedRepositories.java
rename to enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestBannedRepositories.java
index 4b8bb0c..094a614 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestBannedRepositories.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestBannedRepositories.java
@@ -16,27 +16,28 @@
  * 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.List;
 
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.MavenArtifactRepository;
+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.plugins.enforcer.MockProject;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.fail;
+import static org.mockito.Mockito.mock;
 
 /**
  * Test the "banned repositories" rule.
  *
  * @author <a href="mailto:wangyf2010@gmail.com">Simon Wang</a>
  */
-public class TestBannedRepositories {
-    private EnforcerRuleHelper helper;
+class TestBannedRepositories {
 
     private BannedRepositories rule;
 
@@ -44,18 +45,17 @@ public class TestBannedRepositories {
 
     @BeforeEach
     public void setUp() {
-        rule = new BannedRepositories();
-        rule.setMessage("my message");
-
         project = new MockProject();
         project.setGroupId("org.apache.maven.plugins.enforcer.test");
         project.setVersion("1.0-SNAPSHOT");
 
-        helper = EnforcerTestUtils.getHelper(project);
+        rule = new BannedRepositories(project);
+        rule.setMessage("my message");
+        rule.setLog(mock(EnforcerLogger.class));
     }
 
     @Test
-    public void testNoCheckRules() throws EnforcerRuleException {
+    void testNoCheckRules() throws EnforcerRuleException {
         ArtifactRepository repo1 = new MavenArtifactRepository("repo1", "http://repo1/", null, null, null);
         List<ArtifactRepository> repos = new ArrayList<>();
         repos.add(repo1);
@@ -63,11 +63,11 @@ public class TestBannedRepositories {
         project.setRemoteArtifactRepositories(repos);
         project.setPluginArtifactRepositories(repos);
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
-    public void testBannedRepositories() {
+    void testBannedRepositories() {
         ArtifactRepository repo1 = new MavenArtifactRepository("repo1", "http://repo1/", null, null, null);
         ArtifactRepository repo2 = new MavenArtifactRepository("repo1", "http://repo1/test", null, null, null);
         ArtifactRepository repo3 = new MavenArtifactRepository("repo1", "http://repo2/test", null, null, null);
@@ -87,14 +87,14 @@ public class TestBannedRepositories {
         rule.setBannedRepositories(bannedRepositories);
 
         try {
-            rule.execute(helper);
+            rule.execute();
             fail("should throw exception");
         } catch (EnforcerRuleException e) {
         }
     }
 
     @Test
-    public void testAllowedRepositoriesAllOK() throws EnforcerRuleException {
+    void testAllowedRepositoriesAllOK() throws EnforcerRuleException {
         ArtifactRepository repo1 = new MavenArtifactRepository("repo1", "http://repo1/", null, null, null);
         ArtifactRepository repo2 = new MavenArtifactRepository("repo1", "http://repo1/test", null, null, null);
 
@@ -113,11 +113,11 @@ public class TestBannedRepositories {
         rule.setAllowedRepositories(bannedRepositories);
         rule.setAllowedPluginRepositories(bannedRepositories);
 
-        rule.execute(helper);
+        rule.execute();
     }
 
     @Test
-    public void testAllowedRepositoriesException() {
+    void testAllowedRepositoriesException() {
         ArtifactRepository repo1 = new MavenArtifactRepository("repo1", "http://repo1/", null, null, null);
         ArtifactRepository repo2 = new MavenArtifactRepository("repo1", "http://repo1/test", null, null, null);
         ArtifactRepository repo3 = new MavenArtifactRepository("repo1", "http://repo2/test", null, null, null);
@@ -138,7 +138,7 @@ public class TestBannedRepositories {
         rule.setAllowedRepositories(patterns);
 
         try {
-            rule.execute(helper);
+            rule.execute();
             fail("should throw exception");
         } catch (EnforcerRuleException e) {
         }
diff --git a/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestEvaluateBeanshell.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestEvaluateBeanshell.java
new file mode 100644
index 0000000..ec39044
--- /dev/null
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestEvaluateBeanshell.java
@@ -0,0 +1,122 @@
+/*
+ * 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.rules;
+
+import org.apache.maven.enforcer.rule.api.EnforcerLogger;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
+import org.apache.maven.enforcer.rules.utils.ExpressionEvaluator;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
+
+/**
+ * The Class TestEvaluateBeanshell.
+ *
+ * @author hugonnem
+ */
+@ExtendWith(MockitoExtension.class)
+class TestEvaluateBeanshell {
+
+    @Mock
+    private ExpressionEvaluator evaluator;
+
+    @InjectMocks
+    private EvaluateBeanshell rule;
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        rule.setLog(Mockito.mock(EnforcerLogger.class));
+
+        // we need not testing ExpressionEvaluator
+        when(evaluator.evaluate(anyString())).thenAnswer(i -> i.getArgument(0));
+    }
+
+    /**
+     * Test rule.
+     */
+    @Test
+    void testRulePass() throws Exception {
+
+        rule.setCondition("\"This is a test.\" == \"This is a test.\"");
+        rule.execute();
+    }
+
+    @Test
+    void testRuleFail() {
+        rule.setCondition("\"Test\" == null");
+        rule.setMessage("We have a variable : ${env}");
+
+        try {
+            rule.execute();
+            fail("Expected an exception.");
+        } catch (EnforcerRuleException e) {
+            assertEquals(e.getMessage(), rule.getMessage());
+        }
+    }
+
+    @Test
+    void testRuleFailNoMessage() {
+        rule.setCondition("\"Test\" == null");
+        try {
+            rule.execute();
+            fail("Expected an exception.");
+        } catch (EnforcerRuleException e) {
+            assertEquals("The expression \"\"Test\" == null\" is not true.", e.getLocalizedMessage());
+            assertTrue(e.getLocalizedMessage().length() > 0);
+        }
+    }
+
+    @Test
+    void testRuleInvalidExpression() throws Exception {
+        rule.setCondition("${env} == null");
+        rule.setMessage("We have a variable : ${env}");
+
+        when(evaluator.evaluate(rule.getCondition())).thenThrow(new ExpressionEvaluationException("expected error"));
+        try {
+            rule.execute();
+            fail("Expected an exception.");
+        } catch (EnforcerRuleException e) {
+            assertNotEquals(e.getLocalizedMessage(), rule.getMessage());
+        }
+    }
+
+    @Test
+    void testRuleInvalidBeanshell() {
+        rule.setCondition("this is not valid beanshell");
+        rule.setMessage("We have a variable : ${env}");
+        try {
+            rule.execute();
+            fail("Expected an exception.");
+        } catch (EnforcerRuleException e) {
+            assertNotEquals(e.getLocalizedMessage(), rule.getMessage());
+        }
+    }
+}
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequirePluginVersions.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestRequirePluginVersions.java
similarity index 74%
rename from enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequirePluginVersions.java
rename to enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestRequirePluginVersions.java
index c1bd3f1..a410e26 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequirePluginVersions.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestRequirePluginVersions.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 java.util.ArrayList;
 import java.util.Collection;
@@ -24,26 +24,93 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.enforcer.rule.api.EnforcerLogger;
+import org.apache.maven.enforcer.rules.utils.EnforcerRuleUtils;
+import org.apache.maven.enforcer.rules.utils.ExpressionEvaluator;
 import org.apache.maven.enforcer.rules.utils.PluginWrapper;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.DefaultLifecycles;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.PluginManager;
+import org.apache.maven.plugins.enforcer.EnforcerTestUtils;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.rtinfo.RuntimeInformation;
+import org.codehaus.plexus.PlexusContainer;
+import org.eclipse.aether.RepositorySystem;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.when;
 
 /**
  * The Class TestRequirePluginVersions.
  *
  * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
  */
-public class TestRequirePluginVersions {
+@ExtendWith(MockitoExtension.class)
+class TestRequirePluginVersions {
+
+    @Mock
+    private PluginManager pluginManager;
+
+    @Mock
+    private ArtifactFactory factory;
+
+    @Mock
+    private RepositorySystem repositorySystem;
+
+    @Mock
+    private MavenSession session;
+
+    @Mock
+    private EnforcerRuleUtils utils;
+
+    @Mock
+    private RuntimeInformation runtimeInformation;
+
+    @Mock
+    private DefaultLifecycles defaultLifeCycles;
+
+    @Mock
+    private MavenProject project;
+
+    @Mock
+    private ExpressionEvaluator evaluator;
+
+    @Mock
+    private PlexusContainer container;
+
+    @InjectMocks
+    private RequirePluginVersions rule;
+
+    @BeforeEach
+    void setup() {
+        rule.setLog(Mockito.mock(EnforcerLogger.class));
+    }
 
     /**
      * Test has version specified.
      */
     @Test
-    public void testHasVersionSpecified() {
+    void testHasVersionSpecified() throws Exception {
+
+        when(evaluator.evaluate(anyString())).thenAnswer(i -> i.getArgument(0));
+        when(evaluator.evaluate(isNull())).thenReturn(null);
+
         Plugin source = new Plugin();
         source.setArtifactId("foo");
         source.setGroupId("group");
@@ -73,55 +140,55 @@ public class TestRequirePluginVersions {
 
         List<PluginWrapper> pluginWrappers = PluginWrapper.addAll(plugins, false);
 
-        RequirePluginVersions rule = new RequirePluginVersions();
         rule.setBanLatest(false);
         rule.setBanRelease(false);
         rule.setBanSnapshots(false);
 
-        EnforcerRuleHelper helper = EnforcerTestUtils.getHelper();
-
-        assertTrue(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertTrue(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         // check that LATEST is allowed
         source.setArtifactId("c-artifact");
-        assertTrue(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertTrue(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         // check that LATEST is banned
         rule.setBanLatest(true);
-        assertFalse(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertFalse(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         // check that LATEST is exhaustively checked
         rule.setBanSnapshots(false);
         source.setArtifactId("f-artifact");
-        assertFalse(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertFalse(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         rule.setBanLatest(false);
         rule.setBanSnapshots(true);
-        assertFalse(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertFalse(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         // check that TIMESTAMP is allowed
         rule.setBanTimestamps(false);
         source.setArtifactId("g-artifact");
-        assertTrue(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertTrue(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         // check that RELEASE is allowed
         source.setArtifactId("d-artifact");
-        assertTrue(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertTrue(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         // check that RELEASE is banned
         rule.setBanRelease(true);
-        assertFalse(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertFalse(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         // check that RELEASE is exhaustively checked
         source.setArtifactId("e-artifact");
-        assertFalse(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertFalse(rule.hasValidVersionSpecified(source, pluginWrappers));
     }
 
     /**
      * Test has version specified with properties.
      */
     @Test
-    public void testHasVersionSpecifiedWithProperties() {
+    void testHasVersionSpecifiedWithProperties() throws Exception {
+
+        when(evaluator.evaluate(anyString())).thenAnswer(i -> ((String) i.getArgument(0)).replaceAll("\\$\\{|}", ""));
+
         Plugin source = new Plugin();
         source.setGroupId("group");
 
@@ -136,48 +203,45 @@ public class TestRequirePluginVersions {
 
         List<PluginWrapper> pluginWrappers = PluginWrapper.addAll(plugins, false);
 
-        RequirePluginVersions rule = new RequirePluginVersions();
         rule.setBanLatest(false);
         rule.setBanRelease(false);
         rule.setBanSnapshots(false);
 
-        EnforcerRuleHelper helper = EnforcerTestUtils.getHelper(true);
-
         source.setArtifactId("a-artifact");
-        assertTrue(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertTrue(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         source.setArtifactId("b-artifact");
-        assertTrue(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertTrue(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         source.setArtifactId("c-artifact");
-        assertTrue(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertTrue(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         source.setArtifactId("d-artifact");
-        assertTrue(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertTrue(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         // this one checks empty property values
         source.setArtifactId("e-artifact");
-        assertFalse(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertFalse(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         // this one checks empty property values
         source.setArtifactId("f-artifact");
-        assertFalse(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertFalse(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         rule.setBanLatest(true);
         source.setArtifactId("c-artifact");
-        assertFalse(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertFalse(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         rule.setBanRelease(true);
         source.setArtifactId("d-artifact");
-        assertFalse(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertFalse(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         rule.setBanSnapshots(true);
         source.setArtifactId("a-artifact");
-        assertFalse(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertFalse(rule.hasValidVersionSpecified(source, pluginWrappers));
 
         // release versions should pass everything
         source.setArtifactId("b-artifact");
-        assertTrue(rule.hasValidVersionSpecified(helper, source, pluginWrappers));
+        assertTrue(rule.hasValidVersionSpecified(source, pluginWrappers));
     }
 
     /**
@@ -186,8 +250,7 @@ public class TestRequirePluginVersions {
      * @throws MojoExecutionException the mojo execution exception
      */
     @Test
-    public void testGetAdditionalPluginsNull() throws MojoExecutionException {
-        RequirePluginVersions rule = new RequirePluginVersions();
+    void testGetAdditionalPluginsNull() throws MojoExecutionException {
         rule.addAdditionalPlugins(null, null);
     }
 
@@ -195,8 +258,7 @@ public class TestRequirePluginVersions {
      * Test get additional plugins invalid format.
      */
     @Test
-    public void testGetAdditionalPluginsInvalidFormat() {
-        RequirePluginVersions rule = new RequirePluginVersions();
+    void testGetAdditionalPluginsInvalidFormat() {
 
         List<String> additional = new ArrayList<>();
 
@@ -226,8 +288,7 @@ public class TestRequirePluginVersions {
      * @throws MojoExecutionException the mojo execution exception
      */
     @Test
-    public void testGetAdditionalPluginsEmptySet() throws MojoExecutionException {
-        RequirePluginVersions rule = new RequirePluginVersions();
+    void testGetAdditionalPluginsEmptySet() throws MojoExecutionException {
 
         Set<Plugin> plugins = new HashSet<>();
         plugins.add(EnforcerTestUtils.newPlugin("group", "a-artifact", "1.0"));
@@ -252,8 +313,7 @@ public class TestRequirePluginVersions {
      * @throws MojoExecutionException the mojo execution exception
      */
     @Test
-    public void testGetAdditionalPlugins() throws MojoExecutionException {
-        RequirePluginVersions rule = new RequirePluginVersions();
+    void testGetAdditionalPlugins() throws MojoExecutionException {
 
         Set<Plugin> plugins = new HashSet<>();
         plugins.add(EnforcerTestUtils.newPlugin("group", "a-artifact", "1.0"));
@@ -279,8 +339,7 @@ public class TestRequirePluginVersions {
      * @throws MojoExecutionException the mojo execution exception
      */
     @Test
-    public void testGetUncheckedPlugins() throws MojoExecutionException {
-        RequirePluginVersions rule = new RequirePluginVersions();
+    void testGetUncheckedPlugins() throws MojoExecutionException {
 
         Set<Plugin> plugins = new HashSet<>();
         plugins.add(EnforcerTestUtils.newPlugin("group", "a-artifact", "1.0"));
@@ -305,8 +364,7 @@ public class TestRequirePluginVersions {
      * Test combining values from both lists
      */
     @Test
-    public void testCombinePlugins() {
-        RequirePluginVersions rule = new RequirePluginVersions();
+    void testCombinePlugins() {
 
         Set<String> plugins = new HashSet<>();
         plugins.add("group:a-artifact");
@@ -329,8 +387,7 @@ public class TestRequirePluginVersions {
      * Test combining with an empty list
      */
     @Test
-    public void testCombinePlugins1() {
-        RequirePluginVersions rule = new RequirePluginVersions();
+    void testCombinePlugins1() {
 
         Set<String> plugins = new HashSet<>();
         Collection<String> results = rule.combineUncheckedPlugins(plugins, "group2:a,group3:b");
@@ -346,8 +403,7 @@ public class TestRequirePluginVersions {
      * Test combining with a null list
      */
     @Test
-    public void testCombinePlugins2() {
-        RequirePluginVersions rule = new RequirePluginVersions();
+    void testCombinePlugins2() {
 
         Collection<String> results = rule.combineUncheckedPlugins(null, "group2:a,group3:b");
 
@@ -362,8 +418,7 @@ public class TestRequirePluginVersions {
      * Test combining with an empty string
      */
     @Test
-    public void testCombinePlugins3() {
-        RequirePluginVersions rule = new RequirePluginVersions();
+    void testCombinePlugins3() {
 
         Set<String> plugins = new HashSet<>();
         plugins.add("group:a-artifact");
@@ -382,8 +437,7 @@ public class TestRequirePluginVersions {
      * Test combining with a null string
      */
     @Test
-    public void testCombinePlugins4() {
-        RequirePluginVersions rule = new RequirePluginVersions();
+    void testCombinePlugins4() {
 
         Set<String> plugins = new HashSet<>();
         plugins.add("group:a-artifact");
@@ -402,8 +456,7 @@ public class TestRequirePluginVersions {
      * Test combining with an invalid plugin string
      */
     @Test
-    public void testCombinePlugins5() {
-        RequirePluginVersions rule = new RequirePluginVersions();
+    void testCombinePlugins5() {
 
         Set<String> plugins = new HashSet<>();
         plugins.add("group:a-artifact");
@@ -422,9 +475,9 @@ public class TestRequirePluginVersions {
     /**
      * Assert contains plugin.
      *
-     * @param group the group
+     * @param group    the group
      * @param artifact the artifact
-     * @param theSet the the set
+     * @param theSet   the the set
      */
     private void assertContainsPlugin(String group, String artifact, Collection<Plugin> theSet) {
         Plugin p = new Plugin();
@@ -436,9 +489,9 @@ public class TestRequirePluginVersions {
     /**
      * Assert doesn't contain plugin.
      *
-     * @param group the group
+     * @param group    the group
      * @param artifact the artifact
-     * @param theSet the the set
+     * @param theSet   the the set
      */
     private void assertNotContainPlugin(String group, String artifact, Collection<Plugin> theSet) {
         Plugin p = new Plugin();
@@ -451,8 +504,7 @@ public class TestRequirePluginVersions {
      * Test id.
      */
     @Test
-    public void testId() {
-        RequirePluginVersions rule = new RequirePluginVersions();
+    void testId() {
         rule.getCacheId();
     }
 }
diff --git a/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestRequireReleaseVersion.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestRequireReleaseVersion.java
new file mode 100644
index 0000000..8c0501d
--- /dev/null
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestRequireReleaseVersion.java
@@ -0,0 +1,104 @@
+/*
+ * 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.rules;
+
+import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
+import org.apache.maven.plugin.testing.ArtifactStubFactory;
+import org.apache.maven.project.MavenProject;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+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.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * The Class TestRequireReleaseVersion.
+ *
+ * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
+ */
+@ExtendWith(MockitoExtension.class)
+class TestRequireReleaseVersion {
+
+    @Mock
+    private MavenProject project;
+
+    @InjectMocks
+    private RequireReleaseVersion rule;
+
+    @Test
+    void testProjectWithReleaseVersion() throws Exception {
+        ArtifactStubFactory factory = new ArtifactStubFactory();
+
+        when(project.getArtifact()).thenReturn(factory.getReleaseArtifact());
+
+        assertThatCode(rule::execute).doesNotThrowAnyException();
+    }
+
+    @Test
+    void testProjectWithSnapshotVersion() throws Exception {
+        ArtifactStubFactory factory = new ArtifactStubFactory();
+
+        when(project.getArtifact()).thenReturn(factory.getSnapshotArtifact());
+
+        assertThatCode(rule::execute)
+                .isInstanceOf(EnforcerRuleException.class)
+                .hasMessageContaining("This project cannot be a snapshot");
+    }
+
+    @Test
+    void shouldFailWhenParentIsSnapshot() throws Exception {
+        ArtifactStubFactory factory = new ArtifactStubFactory();
+
+        when(project.getArtifact()).thenReturn(factory.getReleaseArtifact());
+        when(project.getParentArtifact()).thenReturn(factory.getSnapshotArtifact());
+
+        rule.setFailWhenParentIsSnapshot(true);
+
+        assertThatCode(rule::execute)
+                .isInstanceOf(EnforcerRuleException.class)
+                .hasMessageContaining("Parent Cannot be a snapshot");
+    }
+
+    @Test
+    void shouldAllowParentSnapshot() throws Exception {
+        ArtifactStubFactory factory = new ArtifactStubFactory();
+
+        when(project.getArtifact()).thenReturn(factory.getReleaseArtifact());
+
+        rule.setFailWhenParentIsSnapshot(false);
+
+        assertThatCode(rule::execute).doesNotThrowAnyException();
+
+        verify(project, never()).getParentArtifact();
+    }
+
+    /**
+     * Test cache.
+     */
+    @Test
+    void testCache() {
+        assertThat(rule.getCacheId()).isNull();
+    }
+}
diff --git a/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestRequireSnapshotVersion.java b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestRequireSnapshotVersion.java
new file mode 100644
index 0000000..ec2f703
--- /dev/null
+++ b/enforcer-rules/src/test/java/org/apache/maven/enforcer/rules/TestRequireSnapshotVersion.java
@@ -0,0 +1,111 @@
+/*
+ * 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.rules;
+
+import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
+import org.apache.maven.plugin.testing.ArtifactStubFactory;
+import org.apache.maven.project.MavenProject;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * Test class for the RequireSnapshotVersion rule.
+ */
+@ExtendWith(MockitoExtension.class)
+class TestRequireSnapshotVersion {
+
+    @Mock
+    private MavenProject project;
+
+    private ArtifactStubFactory factory;
+
+    @InjectMocks
+    private RequireSnapshotVersion rule;
+
+    @BeforeEach
+    public void before() {
+        factory = new ArtifactStubFactory();
+    }
+
+    @Test
+    void shouldFailForRelease() throws Exception {
+        when(project.getArtifact()).thenReturn(factory.getReleaseArtifact());
+
+        assertThatCode(rule::execute).isInstanceOf(EnforcerRuleException.class);
+    }
+
+    @Test
+    void shouldPassForSnapshot() throws Exception {
+        when(project.getArtifact()).thenReturn(factory.getSnapshotArtifact());
+
+        assertThatCode(rule::execute).doesNotThrowAnyException();
+    }
+
+    @Test
+    void shouldFailForReleaseParent() throws Exception {
+        when(project.getArtifact()).thenReturn(factory.getSnapshotArtifact());
+
+        MavenProject parent = mock(MavenProject.class);
+        when(parent.getArtifact()).thenReturn(factory.getReleaseArtifact());
+
+        when(project.getParent()).thenReturn(parent);
+        when(project.hasParent()).thenReturn(true);
+
+        rule.setFailWhenParentIsRelease(true);
+
+        assertThatCode(rule::execute).isInstanceOf(EnforcerRuleException.class);
+    }
+
+    @Test
+    void shouldPassForSnapshotParent() throws Exception {
+        when(project.getArtifact()).thenReturn(factory.getSnapshotArtifact());
+
+        MavenProject parent = mock(MavenProject.class);
+        when(parent.getArtifact()).thenReturn(factory.getSnapshotArtifact());
+
+        when(project.getParent()).thenReturn(parent);
+        when(project.hasParent()).thenReturn(true);
+
+        rule.setFailWhenParentIsRelease(true);
+
+        assertThatCode(rule::execute).doesNotThrowAnyException();
+    }
+
+    @Test
+    void parentShouldNotBeChecked() throws Exception {
+        when(project.getArtifact()).thenReturn(factory.getSnapshotArtifact());
+
+        rule.setFailWhenParentIsRelease(false);
+
+        assertThatCode(rule::execute).doesNotThrowAnyException();
+
+        verify(project).getArtifact();
+        verifyNoMoreInteractions(project);
+    }
+}
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/BanDistributionManagementTest.java b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/BanDistributionManagementTest.java
deleted file mode 100644
index d17a071..0000000
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/BanDistributionManagementTest.java
+++ /dev/null
@@ -1,261 +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.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
-import org.apache.maven.model.DeploymentRepository;
-import org.apache.maven.model.DistributionManagement;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.Site;
-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.Test;
-
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-/**
- * This class is intended to test the {@link BanDistributionManagement} rule.
- *
- * @author <a href="mailto:khmarbaise@apache.org">Karl Heinz Marbaise</a>
- */
-public class BanDistributionManagementTest {
-    private MavenProject project;
-
-    private EnforcerRuleHelper helper;
-
-    @Test
-    public void shouldNotFailWithoutDistributionManagement() throws Exception {
-        BanDistributionManagement rule = setupProjectWithoutDistributionManagement();
-        rule.execute(helper);
-        // intentionally no assert cause in case of an exception the test will be red.
-    }
-
-    /**
-     * <pre>
-     * &lt;distributionManagement&gt;
-     *   &lt;repository&gt;
-     *    ...
-     *   &lt;/repository&gt;
-     * &lt;/distributionManagement&gt;
-     * </pre>
-     *
-     */
-    @Test
-    public void shouldThrowExceptionIfDistributionManagementIsDefinedWithRepository() {
-        assertThrows(EnforcerRuleException.class, () -> {
-            BanDistributionManagement rule =
-                    setupProjectWithDistributionManagement(new DeploymentRepository(), null, null);
-            rule.execute(helper);
-        });
-        // intentionally no assert cause we expect an exception.
-    }
-
-    /**
-     * <pre>
-     * &lt;distributionManagement&gt;
-     *   &lt;repository&gt;
-     *    ...
-     *   &lt;/repository&gt;
-     *   &lt;snapshotRepository&gt;
-     *    ...
-     *   &lt;/snapshotRepository&gt;
-     * &lt;/distributionManagement&gt;
-     * </pre>
-     *
-     */
-    @Test
-    public void shouldThrowExceptionIfDistributionManagementIsDefinedWithRepositorySnapshotRepository() {
-        assertThrows(EnforcerRuleException.class, () -> {
-            BanDistributionManagement rule = setupProjectWithDistributionManagement(
-                    new DeploymentRepository(), new DeploymentRepository(), null);
-            rule.execute(helper);
-        });
-        // intentionally no assert cause we expect an exception.
-    }
-
-    /**
-     * <pre>
-     * &lt;distributionManagement&gt;
-     *   &lt;repository&gt;
-     *    ...
-     *   &lt;/repository&gt;
-     *   &lt;snapshotRepository&gt;
-     *    ...
-     *   &lt;/snapshotRepository&gt;
-     *   &lt;site&gt;
-     *    ...
-     *   &lt;/site&gt;
-     * &lt;/distributionManagement&gt;
-     * </pre>
-     *
-     */
-    @Test
-    public void shouldThrowExceptionIfDistributionManagementIsDefinedWithRepositorySnapshotRepositorySite() {
-        assertThrows(EnforcerRuleException.class, () -> {
-            BanDistributionManagement rule = setupProjectWithDistributionManagement(
-                    new DeploymentRepository(), new DeploymentRepository(), new Site());
-            rule.execute(helper);
-            // intentionally no assert cause we expect an exception.
-        });
-        // intentionally no assert cause we expect an exception.
-    }
-
-    /**
-     * <pre>
-     * &lt;distributionManagement&gt;
-     *   &lt;repository&gt;
-     *    ...
-     *   &lt;/repository&gt;
-     * &lt;/distributionManagement&gt;
-     * </pre>
-     *
-     * @throws Exception if any occurs
-     */
-    @Test
-    public void shouldAllowDistributionManagementHavingRepository() throws Exception {
-        BanDistributionManagement rule = setupProjectWithDistributionManagement(new DeploymentRepository(), null, null);
-        rule.setAllowRepository(true);
-        rule.execute(helper);
-        // intentionally no assert cause in case of an exception the test will be red.
-    }
-
-    /**
-     * <pre>
-     * &lt;distributionManagement&gt;
-     *   &lt;repository&gt;
-     *    ...
-     *   &lt;/repository&gt;
-     *   &lt;snapshotRepository&gt;
-     *    ...
-     *   &lt;/snapshotRepository&gt;
-     * &lt;/distributionManagement&gt;
-     * </pre>
-     *
-     * @throws Exception if any occurs
-     */
-    @Test
-    public void shouldAllowDistributionManagementHavingRepositorySnapshotRepository() throws Exception {
-        BanDistributionManagement rule =
-                setupProjectWithDistributionManagement(new DeploymentRepository(), new DeploymentRepository(), null);
-        rule.setAllowRepository(true);
-        rule.setAllowSnapshotRepository(true);
-        rule.execute(helper);
-        // intentionally no assert cause in case of an exception the test will be red.
-    }
-
-    /**
-     * <pre>
-     * &lt;distributionManagement&gt;
-     *   &lt;repository&gt;
-     *    ...
-     *   &lt;/repository&gt;
-     *   &lt;snapshotRepository&gt;
-     *    ...
-     *   &lt;/snapshotRepository&gt;
-     *   &lt;site&gt;
-     *    ...
-     *   &lt;/site&gt;
-     * &lt;/distributionManagement&gt;
-     * </pre>
-     *
-     * @throws Exception if any occurs
-     */
-    @Test
-    public void shouldAllowDistributionManagementHavingRepositorySnapshotRepositorySite() throws Exception {
-        BanDistributionManagement rule = setupProjectWithDistributionManagement(
-                new DeploymentRepository(), new DeploymentRepository(), new Site());
-        rule.setAllowRepository(true);
-        rule.setAllowSnapshotRepository(true);
-        rule.setAllowSite(true);
-        rule.execute(helper);
-        // intentionally no assert cause in case of an exception the test will be red.
-    }
-
-    @Test
-    public void shouldThrowExceptionCauseParentProjectHasDistributionManagementSnapshotRepository() throws Exception {
-        BanDistributionManagement rule =
-                setupProjectWithParentDistributionManagement(null, new DeploymentRepository(), null);
-
-        rule.setAllowSnapshotRepository(true);
-
-        rule.execute(helper);
-    }
-
-    private BanDistributionManagement setupProjectWithParentDistributionManagement(
-            DeploymentRepository repository, DeploymentRepository snapshotRepository, Site site)
-            throws ExpressionEvaluationException {
-        project = setupProject(null);
-
-        DistributionManagement dmParent = mock(DistributionManagement.class);
-        when(dmParent.getRepository()).thenReturn(repository);
-        when(dmParent.getSnapshotRepository()).thenReturn(snapshotRepository);
-        when(dmParent.getSite()).thenReturn(site);
-
-        MavenProject parentProject = mock(MavenProject.class);
-        Model model = mock(Model.class);
-        when(model.getDistributionManagement()).thenReturn(dmParent);
-        when(parentProject.getOriginalModel()).thenReturn(model);
-        when(project.getParent()).thenReturn(parentProject);
-
-        return setupEnforcerRule();
-    }
-
-    private BanDistributionManagement setupProjectWithoutDistributionManagement() throws ExpressionEvaluationException {
-        project = setupProject(null);
-        return setupEnforcerRule();
-    }
-
-    private BanDistributionManagement setupProjectWithDistributionManagement(
-            DeploymentRepository repository, DeploymentRepository snapshotRepository, Site site)
-            throws ExpressionEvaluationException {
-        DistributionManagement dm = mock(DistributionManagement.class);
-        when(dm.getRepository()).thenReturn(repository);
-        when(dm.getSnapshotRepository()).thenReturn(snapshotRepository);
-        when(dm.getSite()).thenReturn(site);
-
-        project = setupProject(dm);
-
-        when(project.getParent()).thenReturn(mock(MavenProject.class));
-        when(project.isExecutionRoot()).thenReturn(true);
-
-        return setupEnforcerRule();
-    }
-
-    private MavenProject setupProject(DistributionManagement distributionManagement) {
-        MavenProject project = mock(MavenProject.class);
-        when(project.getPackaging()).thenReturn("jar");
-        Model mavenModel = mock(Model.class);
-        when(project.getOriginalModel()).thenReturn(mavenModel);
-        when(mavenModel.getDistributionManagement()).thenReturn(distributionManagement);
-        return project;
-    }
-
-    private BanDistributionManagement setupEnforcerRule() throws ExpressionEvaluationException {
-        helper = mock(EnforcerRuleHelper.class);
-        when(helper.evaluate("${project}")).thenReturn(project);
-        BanDistributionManagement rule = new BanDistributionManagement();
-
-        when(helper.getLog()).thenReturn(mock(Log.class));
-        return rule;
-    }
-}
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestEvaluateBeanshell.java b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestEvaluateBeanshell.java
deleted file mode 100644
index 214201e..0000000
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestEvaluateBeanshell.java
+++ /dev/null
@@ -1,231 +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 java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
-import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
-import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-/**
- * The Class TestEvaluateBeanshell.
- *
- * @author hugonnem
- */
-public class TestEvaluateBeanshell {
-    private MockProject project;
-
-    @BeforeEach
-    public void setUp() {
-        project = new MockProject();
-        project.setProperty("env", "\"This is a test.\"");
-    }
-
-    /**
-     * Test rule.
-     */
-    @Test
-    public void testRulePass() throws Exception {
-        EvaluateBeanshell rule = new EvaluateBeanshell();
-        // this property should not be set
-        rule.setCondition("${env} == \"This is a test.\"");
-        rule.setMessage("We have a variable : ${env}");
-
-        EnforcerRuleHelper helper = EnforcerTestUtils.getHelper(project);
-        rule.execute(helper);
-    }
-
-    @Test
-    public void testRuleFail() {
-        EvaluateBeanshell rule = new EvaluateBeanshell();
-        // this property should be set by the surefire
-        // plugin
-        rule.setCondition("${env} == null");
-        rule.setMessage("We have a variable : ${env}");
-
-        try {
-            EnforcerRuleHelper helper = EnforcerTestUtils.getHelper(project);
-            rule.execute(helper);
-            fail("Expected an exception.");
-        } catch (EnforcerRuleException e) {
-            assertEquals(e.getLocalizedMessage(), rule.getMessage());
-        }
-    }
-
-    @Test
-    public void testRuleFailNoMessage() {
-        EvaluateBeanshell rule = new EvaluateBeanshell();
-        // this property should be set by the surefire
-        // plugin
-        rule.setCondition("${env} == null");
-        try {
-            EnforcerRuleHelper helper = EnforcerTestUtils.getHelper(project);
-            rule.execute(helper);
-            fail("Expected an exception.");
-        } catch (EnforcerRuleException e) {
-            assertEquals(e.getLocalizedMessage(), "The expression \"${env} == null\" is not true.");
-            assertTrue(e.getLocalizedMessage().length() > 0);
-        }
-    }
-
-    @Test
-    public void testRuleInvalidExpression() throws Exception {
-        EvaluateBeanshell rule = new EvaluateBeanshell();
-        rule.setCondition("${env} == null");
-        rule.setMessage("We have a variable : ${env}");
-
-        ExpressionEvaluator eval = mock(ExpressionEvaluator.class);
-        when(eval.evaluate(rule.getCondition())).thenThrow(new ExpressionEvaluationException("expected error"));
-        try {
-            EnforcerRuleHelper helper = EnforcerTestUtils.getHelper(project, eval);
-            rule.execute(helper);
-            fail("Expected an exception.");
-        } catch (EnforcerRuleException e) {
-            assertNotEquals(e.getLocalizedMessage(), rule.getMessage());
-        }
-    }
-
-    @Test
-    public void testRuleInvalidBeanshell() {
-        EvaluateBeanshell rule = new EvaluateBeanshell();
-        rule.setCondition("this is not valid beanshell");
-        rule.setMessage("We have a variable : ${env}");
-        try {
-            EnforcerRuleHelper helper = EnforcerTestUtils.getHelper(project);
-            rule.execute(helper);
-            fail("Expected an exception.");
-        } catch (EnforcerRuleException e) {
-            assertNotEquals(e.getLocalizedMessage(), rule.getMessage());
-        }
-    }
-
-    @Test
-    public void testRuleCanExecuteMultipleThreads() throws Exception {
-        final String condition = "String property1 = \"${property1}\";\n"
-                + "(property1.equals(\"prop0\") && \"${property2}\".equals(\"prop0\"))\n"
-                + "|| (property1.equals(\"prop1\") && \"${property2}\".equals(\"prop1\"))\n"
-                + "|| (property1.equals(\"prop2\") && \"${property2}\".equals(\"prop2\"))\n";
-
-        final List<Runnable> runnables = new ArrayList<>();
-
-        runnables.add(() -> {
-            final int threadNumber = 0;
-            MockProject multiProject = new MockProject();
-            multiProject.setProperty("property1", "prop" + threadNumber);
-            multiProject.setProperty("property2", "prop" + threadNumber);
-
-            EvaluateBeanshell rule = new EvaluateBeanshell();
-            rule.setCondition(condition);
-            rule.setMessage("Race condition in thread " + threadNumber);
-            EnforcerRuleHelper helper = EnforcerTestUtils.getHelper(multiProject);
-            try {
-                rule.execute(helper);
-
-            } catch (EnforcerRuleException e) {
-                throw new RuntimeException(e);
-            }
-        });
-        runnables.add(() -> {
-            final int threadNumber = 1;
-            MockProject multiProject = new MockProject();
-            multiProject.setProperty("property1", "prop" + threadNumber);
-            multiProject.setProperty("property2", "prop" + threadNumber);
-
-            EvaluateBeanshell rule = new EvaluateBeanshell();
-            rule.setCondition(condition);
-            rule.setMessage("Race condition in thread " + threadNumber);
-            EnforcerRuleHelper helper = EnforcerTestUtils.getHelper(multiProject);
-            try {
-                rule.execute(helper);
-
-            } catch (EnforcerRuleException e) {
-                throw new RuntimeException(e);
-            }
-        });
-        runnables.add(() -> {
-            final int threadNumber = 2;
-            MockProject multiProject = new MockProject();
-            multiProject.setProperty("property1", "prop" + threadNumber);
-            multiProject.setProperty("property2", "prop" + threadNumber);
-
-            EvaluateBeanshell rule = new EvaluateBeanshell();
-            rule.setCondition(condition);
-            rule.setMessage("Race condition in thread " + threadNumber);
-            EnforcerRuleHelper helper = EnforcerTestUtils.getHelper(multiProject);
-            try {
-                rule.execute(helper);
-            } catch (EnforcerRuleException e) {
-                throw new RuntimeException(e);
-            }
-        });
-
-        assertConcurrent(runnables, 4);
-    }
-
-    private static void assertConcurrent(final List<? extends Runnable> runnables, final int maxTimeoutSeconds)
-            throws InterruptedException {
-        final int numThreads = runnables.size();
-        final List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<>());
-        final ExecutorService threadPool = Executors.newFixedThreadPool(numThreads);
-        try {
-            final CountDownLatch allExecutorThreadsReady = new CountDownLatch(numThreads);
-            final CountDownLatch afterInitBlocker = new CountDownLatch(1);
-            final CountDownLatch allDone = new CountDownLatch(numThreads);
-            for (final Runnable submittedTestRunnable : runnables) {
-                threadPool.submit(() -> {
-                    allExecutorThreadsReady.countDown();
-                    try {
-                        afterInitBlocker.await();
-                        submittedTestRunnable.run();
-                    } catch (final Throwable e) {
-                        exceptions.add(e);
-                    } finally {
-                        allDone.countDown();
-                    }
-                });
-            }
-            // wait until all threads are ready
-            assertTrue(
-                    allExecutorThreadsReady.await(runnables.size() * 10, TimeUnit.MILLISECONDS),
-                    "Timeout initializing threads! Perform long lasting initializations before passing runnables to assertConcurrent");
-            // start all test runners
-            afterInitBlocker.countDown();
-            assertTrue(
-                    allDone.await(maxTimeoutSeconds, TimeUnit.SECONDS),
-                    "Timeout! More than" + maxTimeoutSeconds + "seconds");
-        } finally {
-            threadPool.shutdownNow();
-        }
-        assertTrue(exceptions.isEmpty(), "Failed with exception(s)" + exceptions);
-    }
-}
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
deleted file mode 100644
index bf8da0b..0000000
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireReleaseVersion.java
+++ /dev/null
@@ -1,84 +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 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.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-
-/**
- * The Class TestRequireReleaseVersion.
- *
- * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
- */
-public class TestRequireReleaseVersion {
-
-    /**
-     * Test mojo.
-     *
-     * @throws IOException Signals that an I/O exception has occurred.
-     */
-    @Test
-    public void testMojo() throws IOException {
-        ArtifactStubFactory factory = new ArtifactStubFactory();
-        MockProject project = new MockProject();
-        EnforcerRuleHelper helper = EnforcerTestUtils.getHelper(project);
-
-        project.setArtifact(factory.getReleaseArtifact());
-
-        RequireReleaseVersion rule = new RequireReleaseVersion();
-
-        EnforcerRuleUtilsHelper.execute(rule, helper, false);
-
-        project.setArtifact(factory.getSnapshotArtifact());
-
-        EnforcerRuleUtilsHelper.execute(rule, helper, true);
-
-        project.setArtifact(factory.getReleaseArtifact());
-
-        MockProject parent = new MockProject();
-        parent.setArtifact(factory.getSnapshotArtifact());
-        project.setParent(parent);
-        helper = EnforcerTestUtils.getHelper(project);
-
-        rule.setFailWhenParentIsSnapshot(true);
-        EnforcerRuleUtilsHelper.execute(rule, helper, true);
-
-        rule.setFailWhenParentIsSnapshot(false);
-        EnforcerRuleUtilsHelper.execute(rule, helper, false);
-    }
-
-    /**
-     * Test cache.
-     */
-    @Test
-    public void testCache() {
-        EnforcerRule rule = new RequireReleaseVersion();
-        assertFalse(rule.isCacheable());
-        assertFalse(rule.isResultValid(null));
-        assertEquals("0", rule.getCacheId());
-    }
-}
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
deleted file mode 100644
index 1da0d7b..0000000
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestRequireSnapshotVersion.java
+++ /dev/null
@@ -1,91 +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 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.project.MavenProject;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-/**
- * Test class for the RequireSnapshotVersion rule.
- */
-public class TestRequireSnapshotVersion {
-
-    private MavenProject project;
-
-    private EnforcerRuleHelper helper;
-
-    private ArtifactStubFactory factory;
-
-    private RequireSnapshotVersion rule;
-
-    @BeforeEach
-    public void before() {
-        project = new MockProject();
-        helper = EnforcerTestUtils.getHelper(project);
-        factory = new ArtifactStubFactory();
-        rule = new RequireSnapshotVersion();
-    }
-
-    @Test
-    public void testRequireSnapshot() throws IOException {
-        project.setArtifact(factory.getReleaseArtifact());
-        EnforcerRuleUtilsHelper.execute(rule, helper, true);
-
-        project.setArtifact(factory.getSnapshotArtifact());
-        EnforcerRuleUtilsHelper.execute(rule, helper, false);
-    }
-
-    @Test
-    public void testWithParentShouldFail() throws IOException {
-        project.setArtifact(factory.getSnapshotArtifact());
-        rule.setFailWhenParentIsRelease(true);
-
-        MockProject parent = new MockProject();
-        parent.setArtifact(factory.getReleaseArtifact());
-        project.setParent(parent);
-        EnforcerRuleUtilsHelper.execute(rule, helper, true);
-
-        parent = new MockProject();
-        parent.setArtifact(factory.getSnapshotArtifact());
-        project.setParent(parent);
-        EnforcerRuleUtilsHelper.execute(rule, helper, false);
-    }
-
-    @Test
-    public void testWithParentShouldPass() throws IOException {
-        project.setArtifact(factory.getSnapshotArtifact());
-        rule.setFailWhenParentIsRelease(false);
-
-        MockProject parent = new MockProject();
-        parent.setArtifact(factory.getReleaseArtifact());
-        project.setParent(parent);
-        EnforcerRuleUtilsHelper.execute(rule, helper, false);
-
-        parent = new MockProject();
-        parent.setArtifact(factory.getSnapshotArtifact());
-        project.setParent(parent);
-        EnforcerRuleUtilsHelper.execute(rule, helper, false);
-    }
-}
diff --git a/maven-enforcer-plugin/src/it/projects/ban-dependency-management-scope-fail/verify.groovy b/maven-enforcer-plugin/src/it/projects/ban-dependency-management-scope-fail/verify.groovy
index 67651ac..5f78f44 100644
--- a/maven-enforcer-plugin/src/it/projects/ban-dependency-management-scope-fail/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/ban-dependency-management-scope-fail/verify.groovy
@@ -17,7 +17,7 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.plugins.enforcer.BanDependencyManagementScope failed with message:' )
+assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.BanDependencyManagementScope failed with message:' )
 assert buildLog.text.contains( 'Scope other than \'import\' is not allowed in \'dependencyManagement\'' )
 assert buildLog.text.contains( 'Banned scope \'provided\' used on dependency \'org.apache.maven.plugins.enforcer.its:menforcer138_archiver:jar\' @ line 65, column 19' )
 assert buildLog.text.contains( 'Banned scope \'test\' used on dependency \'org.apache.maven.plugins.enforcer.its:menforcer138_utils:jar\' @ line 71, column 19' )
\ No newline at end of file
diff --git a/maven-enforcer-plugin/src/it/projects/ban-distribution-management-multi-module-build/verify.groovy b/maven-enforcer-plugin/src/it/projects/ban-distribution-management-multi-module-build/verify.groovy
index 95d7a1c..331c97b 100644
--- a/maven-enforcer-plugin/src/it/projects/ban-distribution-management-multi-module-build/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/ban-distribution-management-multi-module-build/verify.groovy
@@ -18,5 +18,5 @@
  */
 File buildLog = new File( basedir, 'build.log' )
 assert buildLog.text.contains( '[INFO] BUILD FAILURE' )
-assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.plugins.enforcer.BanDistributionManagement failed with message:' )
+assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.BanDistributionManagement failed with message:' )
 assert buildLog.text.contains( 'You have defined a repository in distributionManagement.' )
diff --git a/maven-enforcer-plugin/src/it/projects/ban-distribution-management/verify.groovy b/maven-enforcer-plugin/src/it/projects/ban-distribution-management/verify.groovy
index 6db67a7..99dcdeb 100644
--- a/maven-enforcer-plugin/src/it/projects/ban-distribution-management/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/ban-distribution-management/verify.groovy
@@ -17,4 +17,4 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[INFO] BUILD SUCCESS' )
+assert buildLog.text.contains( '[INFO] Rule 0: org.apache.maven.enforcer.rules.BanDistributionManagement executed' )
diff --git a/maven-enforcer-plugin/src/it/projects/ban-duplicate-dependencies-versions/verify.groovy b/maven-enforcer-plugin/src/it/projects/ban-duplicate-dependencies-versions/verify.groovy
index c273942..e1b25c1 100644
--- a/maven-enforcer-plugin/src/it/projects/ban-duplicate-dependencies-versions/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/ban-duplicate-dependencies-versions/verify.groovy
@@ -17,7 +17,7 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.plugins.enforcer.BanDuplicatePomDependencyVersions failed with message:' )
+assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.BanDuplicatePomDependencyVersions failed with message:' )
 assert buildLog.text.contains( 'Found 1 duplicate dependency declarations in this project:' )
 assert buildLog.text.contains( '- dependencyManagement.dependencies.dependency[org.apache.maven.plugins.enforcer.its:menforcer128_api:jar] ( 2 times )' )
 
diff --git a/maven-enforcer-plugin/src/it/projects/ban-dynamic-versions/verify.groovy b/maven-enforcer-plugin/src/it/projects/ban-dynamic-versions/verify.groovy
index c26be3e..11abb38 100644
--- a/maven-enforcer-plugin/src/it/projects/ban-dynamic-versions/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/ban-dynamic-versions/verify.groovy
@@ -21,5 +21,5 @@ assert buildLog.text.contains( '[WARNING] Dependency org.apache.maven.plugins.en
 assert buildLog.text.contains( '[WARNING] Dependency org.apache.maven.plugins.enforcer.its:menforcer138_io:jar:LATEST (compile) is referenced with a banned dynamic version LATEST' )
 assert buildLog.text.contains( '[WARNING] Dependency org.apache.maven.plugins.enforcer.its:menforcer134_model:jar:1.0-SNAPSHOT (compile) is referenced with a banned dynamic version 1.0-SNAPSHOT' )
 assert buildLog.text.contains( '[WARNING] Dependency org.apache.maven.plugins.enforcer.its:menforcer427-a:jar:1.0 (compile) via org.apache.maven.plugins.enforcer.its:menforcer427:jar:1.0 is referenced with a banned dynamic version [1.0,2)' )
-assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.plugins.enforcer.BanDynamicVersions failed with message' )
+assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.BanDynamicVersions failed with message' )
 assert buildLog.text.contains( 'Found 4 dependencies with dynamic versions. Look at the warnings emitted above for the details.' )
diff --git a/maven-enforcer-plugin/src/it/projects/ban-pom-dependency-version-utf8-with-bom/verify.groovy b/maven-enforcer-plugin/src/it/projects/ban-pom-dependency-version-utf8-with-bom/verify.groovy
index e1e4696..67cda3b 100644
--- a/maven-enforcer-plugin/src/it/projects/ban-pom-dependency-version-utf8-with-bom/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/ban-pom-dependency-version-utf8-with-bom/verify.groovy
@@ -17,7 +17,7 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.plugins.enforcer.BanDuplicatePomDependencyVersions failed with message:' )
+assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.BanDuplicatePomDependencyVersions failed with message:' )
 assert buildLog.text.contains( 'Found 1 duplicate dependency declaration in this project:' )
 assert buildLog.text.contains( '- dependencies.dependency[org.apache.maven.plugins.enforcer.its:menforcer152:jar] ( 2 times )' )
 
diff --git a/maven-enforcer-plugin/src/it/projects/ban-pom-dependency-version/verify.groovy b/maven-enforcer-plugin/src/it/projects/ban-pom-dependency-version/verify.groovy
index 8f3fd23..50d2b17 100644
--- a/maven-enforcer-plugin/src/it/projects/ban-pom-dependency-version/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/ban-pom-dependency-version/verify.groovy
@@ -17,7 +17,7 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.plugins.enforcer.BanDuplicatePomDependencyVersions failed with message:' )
+assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.BanDuplicatePomDependencyVersions failed with message:' )
 assert buildLog.text.contains( 'Found 1 duplicate dependency declaration in this project:' )
 assert buildLog.text.contains( '- dependencies.dependency[org.apache.maven.plugins.enforcer.its:menforcer152:jar] ( 2 times )' )
 
diff --git a/maven-enforcer-plugin/src/it/projects/banned-plugins-fails/verify.groovy b/maven-enforcer-plugin/src/it/projects/banned-plugins-fails/verify.groovy
index 7fd3256..857383c 100644
--- a/maven-enforcer-plugin/src/it/projects/banned-plugins-fails/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/banned-plugins-fails/verify.groovy
@@ -17,5 +17,5 @@
  * under the License.
  */
 def buildLog = new File( basedir, 'build.log' ).text
-assert buildLog.contains( '[ERROR] Rule 0: org.apache.maven.plugins.enforcer.BannedPlugins failed with message:' )
+assert buildLog.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.BannedPlugins failed with message:' )
 assert buildLog =~ /org.codehaus.mojo:build-helper-maven-plugin:maven-plugin:.* <--- banned plugin/
diff --git a/maven-enforcer-plugin/src/it/projects/evaluate-beanshell/pom.xml b/maven-enforcer-plugin/src/it/projects/evaluate-beanshell/pom.xml
index fd6dcea..c99f6e6 100644
--- a/maven-enforcer-plugin/src/it/projects/evaluate-beanshell/pom.xml
+++ b/maven-enforcer-plugin/src/it/projects/evaluate-beanshell/pom.xml
@@ -46,6 +46,9 @@ under the License.
                 <evaluateBeanshell>
                   <condition>${project.artifactId} == test</condition>
                 </evaluateBeanshell>
+                <evaluateBeanshell>
+                  <condition>${project.version} == 1.0</condition>
+                </evaluateBeanshell>
               </rules>
             </configuration>
           </execution>
diff --git a/maven-enforcer-plugin/src/it/projects/ban-distribution-management/verify.groovy b/maven-enforcer-plugin/src/it/projects/evaluate-beanshell/verify.groovy
similarity index 75%
copy from maven-enforcer-plugin/src/it/projects/ban-distribution-management/verify.groovy
copy to maven-enforcer-plugin/src/it/projects/evaluate-beanshell/verify.groovy
index 6db67a7..64c5dc6 100644
--- a/maven-enforcer-plugin/src/it/projects/ban-distribution-management/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/evaluate-beanshell/verify.groovy
@@ -16,5 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[INFO] BUILD SUCCESS' )
+
+File buildLog = new File(basedir, 'build.log')
+assert buildLog.text.contains('[INFO] Rule 0: org.apache.maven.enforcer.rules.EvaluateBeanshell executed')
+assert buildLog.text.contains('[INFO] Rule 1: org.apache.maven.enforcer.rules.EvaluateBeanshell executed')
diff --git a/maven-enforcer-plugin/src/it/projects/require-plugin-versions-ci/verify.groovy b/maven-enforcer-plugin/src/it/projects/require-plugin-versions-ci/verify.groovy
index 4377c86..f2d5288 100644
--- a/maven-enforcer-plugin/src/it/projects/require-plugin-versions-ci/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/require-plugin-versions-ci/verify.groovy
@@ -17,5 +17,5 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.plugins.enforcer.RequirePluginVersions failed with message:' )
+assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.RequirePluginVersions failed with message:' )
 assert buildLog.text.contains( "Some plugins are missing valid versions or depend on Maven ${mavenVersion} defaults: (LATEST RELEASE SNAPSHOT are not allowed)" )
diff --git a/maven-enforcer-plugin/src/it/projects/require-plugin-versions-ci/verify.groovy b/maven-enforcer-plugin/src/it/projects/require-plugin-versions_failure/verify.groovy
similarity index 94%
copy from maven-enforcer-plugin/src/it/projects/require-plugin-versions-ci/verify.groovy
copy to maven-enforcer-plugin/src/it/projects/require-plugin-versions_failure/verify.groovy
index 4377c86..f2d5288 100644
--- a/maven-enforcer-plugin/src/it/projects/require-plugin-versions-ci/verify.groovy
+++ b/maven-enforcer-plugin/src/it/projects/require-plugin-versions_failure/verify.groovy
@@ -17,5 +17,5 @@
  * under the License.
  */
 File buildLog = new File( basedir, 'build.log' )
-assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.plugins.enforcer.RequirePluginVersions failed with message:' )
+assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.RequirePluginVersions failed with message:' )
 assert buildLog.text.contains( "Some plugins are missing valid versions or depend on Maven ${mavenVersion} defaults: (LATEST RELEASE SNAPSHOT are not allowed)" )
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
index 14595de..60750d1 100644
--- 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
@@ -18,6 +18,7 @@
  */
 package org.apache.maven.plugins.enforcer.internal;
 
+import javax.annotation.PreDestroy;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
@@ -56,7 +57,7 @@ public class EnforcerRuleCache {
         logger.debug("Check cache for {} with id {}", ruleClass, cacheId);
 
         synchronized (this) {
-            List<String> cacheIdList = cache.computeIfAbsent(ruleClass, (k) -> new ArrayList<>());
+            List<String> cacheIdList = cache.computeIfAbsent(ruleClass, k -> new ArrayList<>());
             if (cacheIdList.contains(cacheId)) {
                 logger.debug("Already cached {} with id {}", ruleClass, cacheId);
                 return true;
@@ -67,4 +68,11 @@ public class EnforcerRuleCache {
 
         return false;
     }
+
+    @PreDestroy
+    public void cleanup() {
+        synchronized (this) {
+            cache.clear();
+        }
+    }
 }
diff --git a/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleManager.java b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleManager.java
index a374f2b..2787e50 100644
--- a/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleManager.java
+++ b/maven-enforcer-plugin/src/main/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleManager.java
@@ -146,11 +146,13 @@ public class EnforcerRuleManager {
         // 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), ruleLevel);
-        } catch (ComponentLookupException e) {
-            // no component for rule
-            // process old way, by  class name
+        if (plexusContainer.hasComponent(EnforcerRuleBase.class, ruleName)) {
+            try {
+                return new EnforcerRuleDesc(
+                        ruleName, plexusContainer.lookup(EnforcerRuleBase.class, ruleName), ruleLevel);
+            } catch (ComponentLookupException e) {
+                throw new EnforcerRuleManagerException(e);
+            }
         }
 
         String ruleClass;
diff --git a/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleManagerTest.java b/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleManagerTest.java
index 4b62bd1..a31cca7 100644
--- a/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleManagerTest.java
+++ b/maven-enforcer-plugin/src/test/java/org/apache/maven/plugins/enforcer/internal/EnforcerRuleManagerTest.java
@@ -50,6 +50,7 @@ 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.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -82,6 +83,10 @@ class EnforcerRuleManagerTest {
     }
 
     void setupMocks() throws Exception {
+        setupMocks(false);
+    }
+
+    void setupMocks(Boolean hasComponent) {
         MojoExecution mojoExecution = mock(MojoExecution.class);
         when(mojoExecutionProvider.get()).thenReturn(mojoExecution);
 
@@ -92,11 +97,11 @@ class EnforcerRuleManagerTest {
 
         when(sessionProvider.get()).thenReturn(mock(MavenSession.class));
 
-        doThrow(ComponentLookupException.class).when(plexusContainer).lookup(any(Class.class), anyString());
+        when(plexusContainer.hasComponent(any(Class.class), anyString())).thenReturn(hasComponent);
     }
 
     @Test
-    void nullConfigReturnEmptyRules() throws Exception {
+    void nullConfigReturnEmptyRules() {
 
         List<EnforcerRuleDesc> rules = enforcerRuleManager.createRules(null, mojoLog);
 
@@ -104,7 +109,7 @@ class EnforcerRuleManagerTest {
     }
 
     @Test
-    void emptyConfigReturnEmptyRules() throws Exception {
+    void emptyConfigReturnEmptyRules() {
 
         List<EnforcerRuleDesc> rules =
                 enforcerRuleManager.createRules(new DefaultPlexusConfiguration("rules"), mojoLog);
@@ -169,6 +174,7 @@ class EnforcerRuleManagerTest {
 
         setupMocks();
 
+        when(plexusContainer.hasComponent(any(Class.class), eq("testRule1"))).thenReturn(true);
         Mockito.doReturn(new TestRule1()).when(plexusContainer).lookup(EnforcerRuleBase.class, "testRule1");
 
         PlexusConfiguration configuration = new DefaultPlexusConfiguration("rules")
@@ -185,6 +191,20 @@ class EnforcerRuleManagerTest {
         assertThat(rules).hasSize(2).map(EnforcerRuleDesc::getName).containsExactly("testRule1", "testRule2");
     }
 
+    @Test
+    void shouldThrowExceptionFormComponentCreation() throws Exception {
+
+        setupMocks(true);
+
+        doThrow(ComponentLookupException.class).when(plexusContainer).lookup(any(Class.class), anyString());
+
+        PlexusConfiguration configuration = new DefaultPlexusConfiguration("rules").addChild("TestRule1", null);
+
+        assertThatCode(() -> enforcerRuleManager.createRules(configuration, mojoLog))
+                .isInstanceOf(EnforcerRuleManagerException.class)
+                .hasCauseInstanceOf(ComponentLookupException.class);
+    }
+
     @Test
     void createRuleWithImplementation() throws Exception {