View Javadoc
1   package org.apache.maven.plugins.enforcer;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.artifact.Artifact;
23  import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
24  import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
25  import org.apache.maven.plugin.logging.Log;
26  import org.apache.maven.project.MavenProject;
27  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
28  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
29  import org.apache.maven.shared.dependency.graph.DependencyNode;
30  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
31  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
32  import java.util.HashSet;
33  import java.util.Set;
34  
35  /**
36   * Abstract Rule for banning dependencies.
37   *
38   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
39   * @version $Id: AbstractBanDependencies.java 1802595 2017-07-21 13:39:48Z rfscholte $
40   */
41  public abstract class AbstractBanDependencies
42      extends AbstractNonCacheableEnforcerRule
43  {
44  
45      /** Specify if transitive dependencies should be searched (default) or only look at direct dependencies. */
46      private boolean searchTransitive = true;
47  
48      private transient DependencyGraphBuilder graphBuilder;
49  
50      @Override
51      public void execute( EnforcerRuleHelper helper )
52          throws EnforcerRuleException
53      {
54  
55          // get the project
56          MavenProject project = null;
57          try
58          {
59              project = (MavenProject) helper.evaluate( "${project}" );
60          }
61          catch ( ExpressionEvaluationException eee )
62          {
63              throw new EnforcerRuleException( "Unable to retrieve the MavenProject: ", eee );
64          }
65  
66          try
67          {
68              graphBuilder = (DependencyGraphBuilder) helper.getComponent( DependencyGraphBuilder.class );
69          }
70          catch ( ComponentLookupException e )
71          {
72              // real cause is probably that one of the Maven3 graph builder could not be initiated and fails with a
73              // ClassNotFoundException
74              try
75              {
76                  graphBuilder =
77                      (DependencyGraphBuilder) helper.getComponent( DependencyGraphBuilder.class.getName(), "maven2" );
78              }
79              catch ( ComponentLookupException e1 )
80              {
81                  throw new EnforcerRuleException( "Unable to lookup DependencyGraphBuilder: ", e );
82              }
83          }
84  
85          // get the correct list of dependencies
86          Set<Artifact> dependencies = getDependenciesToCheck( project );
87  
88          // look for banned dependencies
89          Set<Artifact> foundExcludes = checkDependencies( dependencies, helper.getLog() );
90  
91          // if any are found, fail the check but list all of them
92          if ( foundExcludes != null && !foundExcludes.isEmpty() )
93          {
94              String message = getMessage();
95  
96              StringBuilder buf = new StringBuilder();
97              if ( message != null )
98              {
99                  buf.append( message + "\n" );
100             }
101             for ( Artifact artifact : foundExcludes )
102             {
103                 buf.append( getErrorMessage( artifact ) );
104             }
105             message = buf.toString() + "Use 'mvn dependency:tree' to locate the source of the banned dependencies.";
106 
107             throw new EnforcerRuleException( message );
108         }
109 
110     }
111 
112     protected CharSequence getErrorMessage( Artifact artifact )
113     {
114         return "Found Banned Dependency: " + artifact.getId() + "\n";
115     }
116 
117     protected Set<Artifact> getDependenciesToCheck( MavenProject project )
118     {
119         Set<Artifact> dependencies = null;
120         try
121         {
122             DependencyNode node = graphBuilder.buildDependencyGraph( project, null );
123             if ( searchTransitive )
124             {
125                 dependencies = getAllDescendants( node );
126             }
127             else if ( node.getChildren() != null )
128             {
129                 dependencies = new HashSet<Artifact>();
130                 for ( DependencyNode depNode : node.getChildren() )
131                 {
132                     dependencies.add( depNode.getArtifact() );
133                 }
134             }
135         }
136         catch ( DependencyGraphBuilderException e )
137         {
138             // otherwise we need to change the signature of this protected method
139             throw new RuntimeException( e );
140         }
141         return dependencies;
142     }
143 
144     private Set<Artifact> getAllDescendants( DependencyNode node )
145     {
146         Set<Artifact> children = null;
147         if ( node.getChildren() != null )
148         {
149             children = new HashSet<Artifact>();
150             for ( DependencyNode depNode : node.getChildren() )
151             {
152                 children.add( depNode.getArtifact() );
153                 Set<Artifact> subNodes = getAllDescendants( depNode );
154                 if ( subNodes != null )
155                 {
156                     children.addAll( subNodes );
157                 }
158             }
159         }
160         return children;
161     }
162 
163     /**
164      * Checks the set of dependencies against the list of excludes.
165      *
166      * @param dependencies the dependencies
167      * @param log the log
168      * @return the sets the
169      * @throws EnforcerRuleException the enforcer rule exception
170      */
171     protected abstract Set<Artifact> checkDependencies( Set<Artifact> dependencies, Log log )
172         throws EnforcerRuleException;
173 
174     /**
175      * Checks if is search transitive.
176      *
177      * @return the searchTransitive
178      */
179     public boolean isSearchTransitive()
180     {
181         return this.searchTransitive;
182     }
183 
184     /**
185      * Sets the search transitive.
186      *
187      * @param theSearchTransitive the searchTransitive to set
188      */
189     public void setSearchTransitive( boolean theSearchTransitive )
190     {
191         this.searchTransitive = theSearchTransitive;
192     }
193 
194 }