View Javadoc

1   package org.apache.rat.mp;
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.io.File;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.Writer;
26  import java.lang.reflect.UndeclaredThrowableException;
27  import java.util.ArrayList;
28  import java.util.Arrays;
29  import java.util.Iterator;
30  import java.util.List;
31  
32  import javax.xml.transform.TransformerConfigurationException;
33  
34  import org.apache.maven.plugin.AbstractMojo;
35  import org.apache.maven.plugin.MojoExecutionException;
36  import org.apache.maven.plugin.MojoFailureException;
37  import org.apache.maven.project.MavenProject;
38  import org.apache.rat.Defaults;
39  import org.apache.rat.Report;
40  import org.apache.rat.ReportConfiguration;
41  import org.apache.rat.analysis.IHeaderMatcher;
42  import org.apache.rat.analysis.util.HeaderMatcherMultiplexer;
43  import org.apache.rat.api.RatException;
44  import org.apache.rat.license.ILicenseFamily;
45  import org.apache.rat.report.IReportable;
46  import org.apache.rat.report.claim.ClaimStatistic;
47  import org.codehaus.plexus.util.DirectoryScanner;
48  
49  
50  /**
51   * Abstract base class for Mojos, which are running RAT.
52   */
53  public abstract class AbstractRatMojo extends AbstractMojo
54  {
55      /**
56       * The Maven specific default excludes.
57       */
58      public static final String[] MAVEN_DEFAULT_EXCLUDES = new String[] {
59          "target/**/*", "cobertura.ser", "release.properties",
60          "pom.xml.releaseBackup"
61      };
62  
63      /**
64       * The Eclipse specific default excludes.
65       */
66      public static final String[] ECLIPSE_DEFAULT_EXCLUDES = new String[] { ".classpath", ".project", ".settings/**/*" };
67  
68      /**
69       * The IDEA specific default excludes.
70       */
71      public static final String[] IDEA_DEFAULT_EXCLUDES = new String[] { "*.iml", "*.ipr", "*.iws" };
72  
73      /**
74       * The base directory, in which to search for files.
75       * 
76       * @parameter expression="${rat.basedir}" default-value="${basedir}"
77       * @required
78       */
79      protected File basedir;
80  
81      /**
82       * The licenses we want to match on.
83       * 
84       * @parameter
85       */
86      private HeaderMatcherSpecification[] licenseMatchers;
87  
88      /**
89       * The set of approved license family names.
90       */
91      private LicenseFamilySpecification[] licenseFamilyNames;
92  
93      /**
94       * Whether to add the default list of license matchers.
95       * 
96       * @parameter expression="${rat.addDefaultLicenseMatchers}" default-value="true"
97       */
98      private boolean addDefaultLicenseMatchers;
99  
100     /**
101      * Specifies files, which are included in the report. By default, all files are included.
102      * 
103      * @parameter
104      */
105     private String[] includes;
106 
107     /**
108      * Specifies files, which are excluded in the report. By default, no files are excluded.
109      * 
110      * @parameter
111      */
112     private String[] excludes;
113 
114     /**
115      * Whether to use the default excludes when scanning for files.
116      * 
117      * @parameter expression="${rat.useDefaultExcludes}" default-value="true"
118      */
119     private boolean useDefaultExcludes;
120 
121     /**
122      * Whether to use the Maven specific default excludes when scanning for files. Maven specific default excludes are
123      * given by the constant MAVEN_DEFAULT_EXCLUDES: The target directory, the cobertura.ser file, and so on.
124      * 
125      * @parameter expression="${rat.useMavenDefaultExcludes}" default-value="true"
126      */
127     private boolean useMavenDefaultExcludes;
128 
129     /**
130      * Whether to use the Eclipse specific default excludes when scanning for files. Eclipse specific default excludes
131      * are given by the constant ECLIPSE_DEFAULT_EXCLUDES: The .classpath and .project files, the .settings directory,
132      * and so on.
133      * 
134      * @parameter expression="${rat.useEclipseDefaultExcludes}" default-value="true"
135      */
136     private boolean useEclipseDefaultExcludes;
137 
138     /**
139      * Whether to use the IDEA specific default excludes when scanning for files. IDEA specific default excludes are
140      * given by the constant IDEA_DEFAULT_EXCLUDES: The *.iml, *.ipr and *.iws files.
141      * 
142      * @parameter expression="${rat.useIdeaDefaultExcludes}" default-value="true"
143      */
144     private boolean useIdeaDefaultExcludes;
145 
146     /**
147      * Whether to exclude subprojects. This is recommended, if you want a
148      * separate apache-rat-plugin report for each subproject.
149      * 
150      * @parameter expression="${rat.excludeSubprojects}" default-value="true"
151      */
152     private boolean excludeSubProjects;
153     
154     /**
155      * @parameter default-value="${project}"
156      * @required
157      * @readonly
158      */
159     private MavenProject project;
160 
161     /**
162      * Returns the Maven project.
163      */
164     protected MavenProject getProject()
165     {
166         return project;
167     }
168 
169     /**
170      * Returns the set of {@link IHeaderMatcher header matchers} to use.
171      * 
172      * @throws MojoFailureException
173      *             An error in the plugin configuration was detected.
174      * @throws MojoExecutionException
175      *             An error occurred while calculating the result.
176      * @return Array of license matchers to use
177      */
178     protected IHeaderMatcher[] getLicenseMatchers() throws MojoFailureException, MojoExecutionException
179     {
180         final List list = new ArrayList();
181         if ( licenseMatchers != null )
182         {
183             for ( int i = 0; i < licenseMatchers.length; i++ )
184             {
185                 final HeaderMatcherSpecification spec = licenseMatchers[i];
186                 final String className = spec.getClassName();
187                 final IHeaderMatcher headerMatcher = (IHeaderMatcher) newInstance( IHeaderMatcher.class, className );
188                 list.add( headerMatcher );
189             }
190         }
191 
192         if ( addDefaultLicenseMatchers )
193         {
194             list.addAll( Arrays.asList( Defaults.DEFAULT_MATCHERS ) );
195         }
196         return (IHeaderMatcher[]) list.toArray( new IHeaderMatcher[list.size()] );
197     }
198 
199     private Object newInstance( final Class clazz, final String className )
200         throws MojoExecutionException, MojoFailureException
201     {
202         final Object o;
203         try
204         {
205             final ClassLoader cl = Thread.currentThread().getContextClassLoader();
206             o = cl.loadClass( className ).newInstance();
207         }
208         catch ( InstantiationException e )
209         {
210             throw new MojoExecutionException( "Failed to instantiate class " + className + ": " + e.getMessage(), e );
211         }
212         catch ( ClassCastException e )
213         {
214             throw new MojoExecutionException( "The class " + className + " is not implementing " + clazz.getName()
215                             + ": " + e.getMessage(), e );
216         }
217         catch ( IllegalAccessException e )
218         {
219             throw new MojoExecutionException( "Illegal access to class " + className + ": " + e.getMessage(), e );
220         }
221         catch ( ClassNotFoundException e )
222         {
223             throw new MojoExecutionException( "Class " + className + " not found: " + e.getMessage(), e );
224         }
225 
226         if ( !clazz.isAssignableFrom( o.getClass() ) )
227         {
228             throw new MojoFailureException( "The class " + o.getClass().getName() + " does not implement "
229                             + clazz.getName() );
230         }
231         return o;
232     }
233 
234     /**
235      * Adds the given string array to the list.
236      * 
237      * @param pList
238      *            The list to which the array elements are being added.
239      * @param pArray
240      *            The strings to add to the list.
241      */
242     private void add( List pList, String[] pArray )
243     {
244         if ( pArray != null )
245         {
246             for ( int i = 0; i < pArray.length; i++ )
247             {
248                 pList.add( pArray[i] );
249             }
250         }
251     }
252 
253     /**
254      * Creates an iterator over the files to check.
255      * 
256      * @return A container of files, which are being checked.
257      */
258     protected IReportable getResources()
259     {
260         DirectoryScanner ds = new DirectoryScanner();
261         ds.setBasedir( basedir );
262         setExcludes( ds );
263         setIncludes( ds );
264         ds.scan();
265         final String[] files = ds.getIncludedFiles();
266         try
267         {
268             return new FilesReportable( basedir, files );
269         }
270         catch ( IOException e )
271         {
272             throw new UndeclaredThrowableException( e );
273         }
274     }
275 
276     private void setIncludes( DirectoryScanner ds )
277     {
278         if ( includes != null )
279         {
280             ds.setIncludes( includes );
281         }
282     }
283 
284     private void setExcludes( DirectoryScanner ds )
285     {
286         final List excludeList1 = new ArrayList();
287         if ( useDefaultExcludes )
288         {
289             add( excludeList1, DirectoryScanner.DEFAULTEXCLUDES );
290         }
291         if ( useMavenDefaultExcludes )
292         {
293             add( excludeList1, MAVEN_DEFAULT_EXCLUDES );
294         }
295         if ( useEclipseDefaultExcludes )
296         {
297             add( excludeList1, ECLIPSE_DEFAULT_EXCLUDES );
298         }
299         if ( useIdeaDefaultExcludes )
300         {
301             add( excludeList1, IDEA_DEFAULT_EXCLUDES );
302         }
303         if ( excludeSubProjects && project != null && project.getModules() != null )
304         {
305             for ( Iterator it = project.getModules().iterator(); it.hasNext(); )
306             {
307                 String moduleSubPath = (String) it.next();
308                 excludeList1.add( moduleSubPath + "/**/*" );
309             }
310         }
311         final List excludeList = excludeList1;
312         if ( excludes == null  ||  excludes.length == 0 )
313         {
314             getLog().info( "No excludes" );
315         }
316         else
317         {
318             for ( int i = 0;  i < excludes.length;  i++ )
319             {
320                 getLog().info( "Exclude: " + excludes[i] );
321             }
322         }
323         add( excludeList, excludes );
324         if ( !excludeList.isEmpty() )
325         {
326             String[] allExcludes = (String[]) excludeList.toArray( new String[excludeList.size()] );
327             ds.setExcludes( allExcludes );
328         }
329     }
330 
331     /**
332      * Writes the report to the given stream.
333      * 
334      * @param out The target writer, to which the report is being written.
335      * @param style The stylesheet to use, or <code>null</code> for raw XML
336      * @throws MojoFailureException
337      *             An error in the plugin configuration was detected.
338      * @throws MojoExecutionException
339      *             Another error occurred while creating the report.
340      */
341     protected ClaimStatistic createReport( Writer out, InputStream style ) throws MojoExecutionException, MojoFailureException
342     {
343         final ReportConfiguration configuration = getConfiguration();
344         try
345         {
346             if (style != null) {
347                 return Report.report( out, getResources(), style, configuration );
348             } else {
349                 return Report.report( getResources(), out, configuration );
350             }
351         }
352         catch ( TransformerConfigurationException e )
353         {
354             throw new MojoExecutionException( e.getMessage(), e );
355         }
356         catch ( IOException e )
357         {
358             throw new MojoExecutionException( e.getMessage(), e );
359         }
360         catch ( InterruptedException e )
361         {
362             throw new MojoExecutionException( e.getMessage(), e );
363         }
364         catch ( RatException e )
365         {
366             throw new MojoExecutionException( e.getMessage(), e );
367         }
368     }
369 
370     protected ReportConfiguration getConfiguration() throws MojoFailureException,
371             MojoExecutionException {
372         final ReportConfiguration configuration = new ReportConfiguration();
373         configuration.setHeaderMatcher( new HeaderMatcherMultiplexer( getLicenseMatchers() ) );
374         configuration.setApprovedLicenseNames(getApprovedLicenseNames());
375         return configuration;
376     }
377 
378     private ILicenseFamily[] getApprovedLicenseNames() throws MojoExecutionException, MojoFailureException
379     {
380         if ( licenseFamilyNames == null || licenseFamilyNames.length == 0 )
381         {
382             return null;
383         }
384         ILicenseFamily[] results = new ILicenseFamily[licenseFamilyNames.length];
385         for ( int i = 0; i < licenseFamilyNames.length; i++ )
386         {
387             LicenseFamilySpecification spec = licenseFamilyNames[i];
388             ILicenseFamily licenseFamily = (ILicenseFamily) newInstance( ILicenseFamily.class, spec.getClassName() );
389             results[i] = licenseFamily;
390         }
391         return results;
392     }
393 }