View Javadoc

1   package org.apache.maven.plugin.surefire.util;
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  import static org.apache.maven.plugin.surefire.util.ScannerUtil.convertJarFileResourceToJavaClassName;
22  import static org.apache.maven.plugin.surefire.util.ScannerUtil.convertSlashToSystemFileSeparator;
23  import static org.apache.maven.plugin.surefire.util.ScannerUtil.processIncludesExcludes;
24  
25  import java.io.File;
26  import java.io.IOException;
27  import java.util.ArrayList;
28  import java.util.Enumeration;
29  import java.util.List;
30  import java.util.jar.JarEntry;
31  import java.util.jar.JarFile;
32  
33  import org.apache.maven.artifact.Artifact;
34  import org.apache.maven.plugin.MojoExecutionException;
35  import org.apache.maven.shared.utils.io.MatchPatterns;
36  import org.apache.maven.surefire.util.DefaultScanResult;
37  
38  import javax.annotation.Nonnull;
39  import javax.annotation.Nullable;
40  
41  /**
42   * Scans dependencies looking for tests.
43   * 
44   * @author Aslak Knutsen
45   */
46  public class DependencyScanner
47  {
48  
49      private final List<File> dependenciesToScan;
50  
51      protected final List<String> includes;
52  
53      protected final @Nonnull List<String> excludes;
54  
55      protected final List<String> specificTests;
56  
57      public DependencyScanner( List<File> dependenciesToScan, List<String> includes, @Nonnull List<String> excludes, List<String> specificTests )
58      {
59          this.dependenciesToScan = dependenciesToScan;
60          this.includes = includes;
61          this.excludes = excludes;
62          this.specificTests = specificTests;
63      }
64  
65      public DefaultScanResult scan()
66          throws MojoExecutionException
67      {
68          Matcher matcher = new Matcher( includes, excludes, specificTests );
69          List<String> found = new ArrayList<String>();
70          for ( File artifact : dependenciesToScan )
71          {
72              try
73              {
74                  found.addAll( scanArtifact( artifact, matcher ) );
75              }
76              catch ( IOException e )
77              {
78                  throw new MojoExecutionException( "Could not scan dependency " + artifact.toString(), e );
79              }
80          }
81          return new DefaultScanResult( found );
82      }
83  
84      private List<String> scanArtifact( File artifact, Matcher matcher )
85          throws IOException
86      {
87          List<String> found = new ArrayList<String>();
88  
89          if ( artifact != null )
90          {
91              if ( artifact.isFile() )
92              {
93                  JarFile jar = null;
94                  try
95                  {
96                      jar = new JarFile( artifact );
97                      Enumeration<JarEntry> entries = jar.entries();
98                      while ( entries.hasMoreElements() )
99                      {
100                         JarEntry entry = entries.nextElement();
101                         if ( matcher.shouldInclude( entry.getName() ) )
102                         {
103                             found.add( convertJarFileResourceToJavaClassName( entry.getName() ) );
104                         }
105                     }
106                 }
107                 finally
108                 {
109                     if ( jar != null )
110                     {
111                         jar.close();
112                     }
113                 }
114             }
115         }
116         return found;
117     }
118 
119     public static List<File> filter( List<Artifact> artifacts, List<String> groupArtifactIds )
120     {
121         List<File> matches = new ArrayList<File>();
122         if ( groupArtifactIds == null || artifacts == null )
123         {
124             return matches;
125         }
126         for ( Artifact artifact : artifacts )
127         {
128             for ( String groups : groupArtifactIds )
129             {
130                 String[] groupArtifact = groups.split( ":" );
131                 if ( groupArtifact.length != 2 )
132                 {
133                     throw new IllegalArgumentException(
134                                                         "dependencyToScan argument should be in format 'groupid:artifactid': "
135                                                             + groups );
136                 }
137                 if ( artifact.getGroupId().matches( groupArtifact[0] )
138                     && artifact.getArtifactId().matches( groupArtifact[1] ) )
139                 {
140                     matches.add( artifact.getFile() );
141                 }
142             }
143         }
144         return matches;
145     }
146 
147     private class Matcher
148     {
149 
150         private MatchPatterns includes;
151 
152         private MatchPatterns excludes;
153 
154         private SpecificFileFilter specificTestFilter;
155 
156         public Matcher( @Nullable List<String> includes, @Nonnull List<String> excludes, @Nullable List<String> specificTests )
157         {
158             String[] specific = specificTests == null ? new String[0] : processIncludesExcludes( specificTests );
159             specificTestFilter = new SpecificFileFilter( specific );
160 
161             if ( includes != null && includes.size() > 0 )
162             {
163                 this.includes = MatchPatterns.from( processIncludesExcludes( includes ) );
164             }
165             else
166             {
167                 this.includes = MatchPatterns.from( "**" );
168             }
169             this.excludes = MatchPatterns.from( processIncludesExcludes( excludes ) );
170         }
171 
172         public boolean shouldInclude( String name )
173         {
174             if ( !name.endsWith( ".class" ) )
175             {
176                 return false;
177             }
178             name = convertSlashToSystemFileSeparator( name );
179             boolean isIncluded = includes.matches( name, false );
180             boolean isExcluded = excludes.matches( name, false );
181 
182             return isIncluded && !isExcluded && specificTestFilter.accept( name );
183         }
184     }
185 }