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 java.util.HashSet;
23  import java.util.Set;
24  
25  import org.apache.maven.artifact.Artifact;
26  import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
27  import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
28  import org.apache.maven.plugin.logging.Log;
29  import org.apache.maven.project.MavenProject;
30  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
31  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
32  import org.apache.maven.shared.dependency.graph.DependencyNode;
33  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
34  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
35  
36  /**
37   * Abstract Rule for banning dependencies.
38   *
39   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
40   * @version $Id: AbstractBanDependencies.java 1495697 2013-06-22 10:05:58Z rfscholte $
41   */
42  public abstract class AbstractBanDependencies
43      extends AbstractNonCacheableEnforcerRule
44  {
45  
46      /** Specify if transitive dependencies should be searched (default) or only look at direct dependencies. */
47      private boolean searchTransitive = true;
48      
49      private transient DependencyGraphBuilder graphBuilder;
50  
51      /**
52       * Execute the rule.
53       *
54       * @param helper the helper
55       * @throws EnforcerRuleException the enforcer rule exception
56       */
57      public void execute( EnforcerRuleHelper helper )
58          throws EnforcerRuleException
59      {
60  
61          // get the project
62          MavenProject project = null;
63          try
64          {
65              project = (MavenProject) helper.evaluate( "${project}" );
66          }
67          catch ( ExpressionEvaluationException eee )
68          {
69              throw new EnforcerRuleException( "Unable to retrieve the MavenProject: ", eee );
70          }
71  
72          try
73          {
74              graphBuilder = (DependencyGraphBuilder) helper.getComponent( DependencyGraphBuilder.class );
75          }
76          catch ( ComponentLookupException e )
77          {
78              // real cause is probably that one of the Maven3 graph builder could not be initiated and fails with a ClassNotFoundException
79              try
80              {
81                  graphBuilder = (DependencyGraphBuilder) helper.getComponent( DependencyGraphBuilder.class.getName(), "maven2" );
82              }
83              catch ( ComponentLookupException e1 )
84              {
85                  throw new EnforcerRuleException( "Unable to lookup DependencyGraphBuilder: ", e );
86              }
87          }
88          
89          // get the correct list of dependencies
90          Set<Artifact> dependencies = getDependenciesToCheck( project );
91  
92          // look for banned dependencies
93          Set<Artifact> foundExcludes = checkDependencies( dependencies, helper.getLog() );
94  
95          // if any are found, fail the check but list all of them
96          if ( foundExcludes != null && !foundExcludes.isEmpty() )
97          {
98              String message = getMessage();
99              
100             StringBuilder buf = new StringBuilder();
101             if ( message != null )
102             {
103                 buf.append( message + "\n" );
104             }
105             for ( Artifact artifact : foundExcludes )
106             {
107                 buf.append( getErrorMessage( artifact ) );
108             }
109             message = buf.toString() + "Use 'mvn dependency:tree' to locate the source of the banned dependencies.";
110 
111             throw new EnforcerRuleException( message );
112         }
113 
114     }
115 
116     protected CharSequence getErrorMessage( Artifact artifact )
117     {
118         return "Found Banned Dependency: " + artifact.getId() + "\n";
119     }
120 
121     protected Set<Artifact> getDependenciesToCheck( MavenProject project )
122     {
123         Set<Artifact> dependencies = null;
124         try
125         {
126             DependencyNode node = graphBuilder.buildDependencyGraph( project, null );
127             if( searchTransitive )
128             {
129                 dependencies  = getAllDescendants( node );
130             }
131             else if ( node.getChildren() != null )
132             {
133                 dependencies = new HashSet<Artifact>();
134                 for( DependencyNode depNode : node.getChildren() )
135                 {
136                     dependencies.add( depNode.getArtifact() );
137                 }
138             }
139         }
140         catch ( DependencyGraphBuilderException e )
141         {
142             // otherwise we need to change the signature of this protected method
143             throw new RuntimeException( e );
144         }
145         return dependencies;
146     }
147 
148     private Set<Artifact> getAllDescendants( DependencyNode node )
149     {
150         Set<Artifact> children = null; 
151         if( node.getChildren() != null )
152         {
153             children = new HashSet<Artifact>();
154             for( DependencyNode depNode : node.getChildren() )
155             {
156                 children.add( depNode.getArtifact() );
157                 Set<Artifact> subNodes = getAllDescendants( depNode );
158                 if( subNodes != null )
159                 {
160                     children.addAll( subNodes );
161                 }
162             }
163         }
164         return children;
165     }
166 
167     /**
168      * Checks the set of dependencies against the list of excludes.
169      *
170      * @param dependencies the dependencies
171      * @param log the log
172      * @return the sets the
173      * @throws EnforcerRuleException the enforcer rule exception
174      */
175     protected abstract Set<Artifact> checkDependencies( Set<Artifact> dependencies, Log log )
176         throws EnforcerRuleException;
177 
178     /**
179      * Checks if is search transitive.
180      *
181      * @return the searchTransitive
182      */
183     public boolean isSearchTransitive()
184     {
185         return this.searchTransitive;
186     }
187 
188     /**
189      * Sets the search transitive.
190      *
191      * @param theSearchTransitive the searchTransitive to set
192      */
193     public void setSearchTransitive( boolean theSearchTransitive )
194     {
195         this.searchTransitive = theSearchTransitive;
196     }
197 
198 }