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