1 package org.apache.maven.surefire.booter;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.lang.reflect.Constructor;
24 import java.lang.reflect.InvocationHandler;
25 import java.lang.reflect.Method;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.List;
29 import java.util.Map;
30
31 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
32 import org.apache.maven.plugin.surefire.log.api.ConsoleLoggerDecorator;
33 import org.apache.maven.surefire.cli.CommandLineOption;
34 import org.apache.maven.surefire.providerapi.ProviderParameters;
35 import org.apache.maven.surefire.report.ReporterConfiguration;
36 import org.apache.maven.surefire.report.ReporterFactory;
37 import org.apache.maven.surefire.suite.RunResult;
38 import org.apache.maven.surefire.testset.DirectoryScannerParameters;
39 import org.apache.maven.surefire.testset.RunOrderParameters;
40 import org.apache.maven.surefire.testset.TestArtifactInfo;
41 import org.apache.maven.surefire.testset.TestListResolver;
42 import org.apache.maven.surefire.testset.TestRequest;
43 import org.apache.maven.surefire.util.RunOrder;
44 import org.apache.maven.surefire.util.SurefireReflectionException;
45
46 import javax.annotation.Nonnull;
47
48 import static java.util.Collections.checkedList;
49
50 import static org.apache.maven.surefire.util.ReflectionUtils.getConstructor;
51 import static org.apache.maven.surefire.util.ReflectionUtils.getMethod;
52 import static org.apache.maven.surefire.util.ReflectionUtils.invokeGetter;
53 import static org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray;
54 import static org.apache.maven.surefire.util.ReflectionUtils.instantiateOneArg;
55 import static org.apache.maven.surefire.util.ReflectionUtils.invokeSetter;
56 import static org.apache.maven.surefire.util.ReflectionUtils.instantiateTwoArgs;
57 import static org.apache.maven.surefire.util.ReflectionUtils.newInstance;
58
59
60
61
62
63
64
65
66 public class SurefireReflector
67 {
68 private final ClassLoader surefireClassLoader;
69
70 private final Class<?> reporterConfiguration;
71
72 private final Class<?> testRequest;
73
74 private final Class<?> testArtifactInfo;
75
76 private final Class<?> testArtifactInfoAware;
77
78 private final Class<?> directoryScannerParameters;
79
80 private final Class<?> runOrderParameters;
81
82 private final Class<?> directoryScannerParametersAware;
83
84 private final Class<?> testSuiteDefinitionAware;
85
86 private final Class<?> testClassLoaderAware;
87
88 private final Class<?> reporterConfigurationAware;
89
90 private final Class<?> providerPropertiesAware;
91
92 private final Class<?> runResult;
93
94 private final Class<?> booterParameters;
95
96 private final Class<?> reporterFactory;
97
98 private final Class<?> testListResolver;
99
100 private final Class<?> mainCliOptions;
101
102 private final Class<Enum> commandLineOptionsClass;
103
104 private final Class<?> shutdownAwareClass;
105
106 private final Class<Enum> shutdownClass;
107
108 @SuppressWarnings( "unchecked" )
109 public SurefireReflector( ClassLoader surefireClassLoader )
110 {
111 this.surefireClassLoader = surefireClassLoader;
112 try
113 {
114 reporterConfiguration = surefireClassLoader.loadClass( ReporterConfiguration.class.getName() );
115 testRequest = surefireClassLoader.loadClass( TestRequest.class.getName() );
116 testArtifactInfo = surefireClassLoader.loadClass( TestArtifactInfo.class.getName() );
117 testArtifactInfoAware = surefireClassLoader.loadClass( TestArtifactInfoAware.class.getName() );
118 directoryScannerParameters = surefireClassLoader.loadClass( DirectoryScannerParameters.class.getName() );
119 runOrderParameters = surefireClassLoader.loadClass( RunOrderParameters.class.getName() );
120 directoryScannerParametersAware =
121 surefireClassLoader.loadClass( DirectoryScannerParametersAware.class.getName() );
122 testSuiteDefinitionAware = surefireClassLoader.loadClass( TestRequestAware.class.getName() );
123 testClassLoaderAware = surefireClassLoader.loadClass( SurefireClassLoadersAware.class.getName() );
124 reporterConfigurationAware = surefireClassLoader.loadClass( ReporterConfigurationAware.class.getName() );
125 providerPropertiesAware = surefireClassLoader.loadClass( ProviderPropertiesAware.class.getName() );
126 reporterFactory = surefireClassLoader.loadClass( ReporterFactory.class.getName() );
127 runResult = surefireClassLoader.loadClass( RunResult.class.getName() );
128 booterParameters = surefireClassLoader.loadClass( ProviderParameters.class.getName() );
129 testListResolver = surefireClassLoader.loadClass( TestListResolver.class.getName() );
130 mainCliOptions = surefireClassLoader.loadClass( MainCliOptionsAware.class.getName() );
131 commandLineOptionsClass = (Class<Enum>) surefireClassLoader.loadClass( CommandLineOption.class.getName() );
132 shutdownAwareClass = surefireClassLoader.loadClass( ShutdownAware.class.getName() );
133 shutdownClass = (Class<Enum>) surefireClassLoader.loadClass( Shutdown.class.getName() );
134 }
135 catch ( ClassNotFoundException e )
136 {
137 throw new SurefireReflectionException( e );
138 }
139 }
140
141 public Object convertIfRunResult( Object result )
142 {
143 if ( result == null || !isRunResult( result ) )
144 {
145 return result;
146 }
147 int getCompletedCount1 = (Integer) invokeGetter( result, "getCompletedCount" );
148 int getErrors = (Integer) invokeGetter( result, "getErrors" );
149 int getSkipped = (Integer) invokeGetter( result, "getSkipped" );
150 int getFailures = (Integer) invokeGetter( result, "getFailures" );
151 return new RunResult( getCompletedCount1, getErrors, getFailures, getSkipped );
152
153 }
154
155
156
157
158 class ClassLoaderProxy
159 implements InvocationHandler
160 {
161 private final Object target;
162
163
164
165
166
167 public ClassLoaderProxy( Object delegate )
168 {
169 this.target = delegate;
170 }
171
172 public Object invoke( Object proxy, Method method, Object[] args )
173 throws Throwable
174 {
175 Method delegateMethod = target.getClass().getMethod( method.getName(), method.getParameterTypes() );
176 return delegateMethod.invoke( target, args );
177 }
178 }
179
180 Object createTestRequest( TestRequest suiteDefinition )
181 {
182 if ( suiteDefinition == null )
183 {
184 return null;
185 }
186 else
187 {
188 Object resolver = createTestListResolver( suiteDefinition.getTestListResolver() );
189 Class<?>[] arguments = { List.class, File.class, testListResolver, int.class };
190 Constructor constructor = getConstructor( testRequest, arguments );
191 return newInstance( constructor,
192 suiteDefinition.getSuiteXmlFiles(),
193 suiteDefinition.getTestSourceDirectory(),
194 resolver,
195 suiteDefinition.getRerunFailingTestsCount() );
196 }
197 }
198
199 Object createTestListResolver( TestListResolver resolver )
200 {
201 if ( resolver == null )
202 {
203 return null;
204 }
205 else
206 {
207 Constructor constructor = getConstructor( testListResolver, String.class );
208 return newInstance( constructor, resolver.getPluginParameterTest() );
209 }
210 }
211
212 Object createDirectoryScannerParameters( DirectoryScannerParameters directoryScannerParameters )
213 {
214 if ( directoryScannerParameters == null )
215 {
216 return null;
217 }
218
219 Class<?>[] arguments = { File.class, List.class, List.class, List.class, boolean.class, String.class };
220 Constructor constructor = getConstructor( this.directoryScannerParameters, arguments );
221 return newInstance( constructor,
222 directoryScannerParameters.getTestClassesDirectory(),
223 directoryScannerParameters.getIncludes(),
224 directoryScannerParameters.getExcludes(),
225 directoryScannerParameters.getSpecificTests(),
226 directoryScannerParameters.isFailIfNoTests(),
227 RunOrder.asString( directoryScannerParameters.getRunOrder() ) );
228 }
229
230
231 Object createRunOrderParameters( RunOrderParameters runOrderParameters )
232 {
233 if ( runOrderParameters == null )
234 {
235 return null;
236 }
237
238 Class<?>[] arguments = { String.class, File.class };
239 Constructor constructor = getConstructor( this.runOrderParameters, arguments );
240 File runStatisticsFile = runOrderParameters.getRunStatisticsFile();
241 return newInstance( constructor, RunOrder.asString( runOrderParameters.getRunOrder() ), runStatisticsFile );
242 }
243
244 Object createTestArtifactInfo( TestArtifactInfo testArtifactInfo )
245 {
246 if ( testArtifactInfo == null )
247 {
248 return null;
249 }
250 Class<?>[] arguments = { String.class, String.class };
251 Constructor constructor = getConstructor( this.testArtifactInfo, arguments );
252 return newInstance( constructor, testArtifactInfo.getVersion(), testArtifactInfo.getClassifier() );
253 }
254
255 Object createReporterConfiguration( ReporterConfiguration reporterConfig )
256 {
257 Constructor constructor = getConstructor( reporterConfiguration, File.class, boolean.class );
258 return newInstance( constructor, reporterConfig.getReportsDirectory(), reporterConfig.isTrimStackTrace() );
259 }
260
261 public Object createBooterConfiguration( ClassLoader surefireClassLoader, Object factoryInstance,
262 boolean insideFork )
263 {
264 return instantiateTwoArgs( surefireClassLoader, BaseProviderFactory.class.getName(),
265 reporterFactory, factoryInstance, boolean.class, insideFork );
266 }
267
268 public Object instantiateProvider( String providerClassName, Object booterParameters )
269 {
270 return instantiateOneArg( surefireClassLoader, providerClassName, this.booterParameters, booterParameters );
271 }
272
273 public void setIfDirScannerAware( Object o, DirectoryScannerParameters dirScannerParams )
274 {
275 if ( directoryScannerParametersAware.isAssignableFrom( o.getClass() ) )
276 {
277 setDirectoryScannerParameters( o, dirScannerParams );
278 }
279 }
280
281 public void setMainCliOptions( Object o, List<CommandLineOption> options )
282 {
283 if ( mainCliOptions.isAssignableFrom( o.getClass() ) )
284 {
285 List<Enum> newOptions = checkedList( new ArrayList<Enum>( options.size() ), commandLineOptionsClass );
286 Collection<Integer> ordinals = toOrdinals( options );
287 for ( Enum e : commandLineOptionsClass.getEnumConstants() )
288 {
289 if ( ordinals.contains( e.ordinal() ) )
290 {
291 newOptions.add( e );
292 }
293 }
294 invokeSetter( o, "setMainCliOptions", List.class, newOptions );
295 }
296 }
297
298 public void setSkipAfterFailureCount( Object o, int skipAfterFailureCount )
299 {
300 invokeSetter( o, "setSkipAfterFailureCount", int.class, skipAfterFailureCount );
301 }
302
303 public void setShutdown( Object o, Shutdown shutdown )
304 {
305 if ( shutdownAwareClass.isAssignableFrom( o.getClass() ) )
306 {
307 for ( Enum e : shutdownClass.getEnumConstants() )
308 {
309 if ( shutdown.ordinal() == e.ordinal() )
310 {
311 invokeSetter( o, "setShutdown", shutdownClass, e );
312 break;
313 }
314 }
315 }
316 }
317
318 public void setSystemExitTimeout( Object o, Integer systemExitTimeout )
319 {
320 invokeSetter( o, "setSystemExitTimeout", Integer.class, systemExitTimeout );
321 }
322
323 public void setDirectoryScannerParameters( Object o, DirectoryScannerParameters dirScannerParams )
324 {
325 Object param = createDirectoryScannerParameters( dirScannerParams );
326 invokeSetter( o, "setDirectoryScannerParameters", directoryScannerParameters, param );
327 }
328
329 public void setRunOrderParameters( Object o, RunOrderParameters runOrderParameters )
330 {
331 Object param = createRunOrderParameters( runOrderParameters );
332 invokeSetter( o, "setRunOrderParameters", this.runOrderParameters, param );
333 }
334
335 public void setTestSuiteDefinitionAware( Object o, TestRequest testSuiteDefinition2 )
336 {
337 if ( testSuiteDefinitionAware.isAssignableFrom( o.getClass() ) )
338 {
339 setTestSuiteDefinition( o, testSuiteDefinition2 );
340 }
341 }
342
343 void setTestSuiteDefinition( Object o, TestRequest testSuiteDefinition1 )
344 {
345 Object param = createTestRequest( testSuiteDefinition1 );
346 invokeSetter( o, "setTestRequest", testRequest, param );
347 }
348
349 public void setProviderPropertiesAware( Object o, Map<String, String> properties )
350 {
351 if ( providerPropertiesAware.isAssignableFrom( o.getClass() ) )
352 {
353 setProviderProperties( o, properties );
354 }
355 }
356
357 void setProviderProperties( Object o, Map<String, String> providerProperties )
358 {
359 invokeSetter( o, "setProviderProperties", Map.class, providerProperties );
360 }
361
362 public void setReporterConfigurationAware( Object o, ReporterConfiguration reporterConfiguration1 )
363 {
364 if ( reporterConfigurationAware.isAssignableFrom( o.getClass() ) )
365 {
366 setReporterConfiguration( o, reporterConfiguration1 );
367 }
368 }
369
370
371 void setReporterConfiguration( Object o, ReporterConfiguration reporterConfiguration )
372 {
373 Object param = createReporterConfiguration( reporterConfiguration );
374 invokeSetter( o, "setReporterConfiguration", this.reporterConfiguration, param );
375 }
376
377 public void setTestClassLoaderAware( Object o, ClassLoader testClassLoader )
378 {
379 if ( testClassLoaderAware.isAssignableFrom( o.getClass() ) )
380 {
381 setTestClassLoader( o, testClassLoader );
382 }
383 }
384
385 void setTestClassLoader( Object o, ClassLoader testClassLoader )
386 {
387 Method setter = getMethod( o, "setClassLoaders", ClassLoader.class );
388 invokeMethodWithArray( o, setter, testClassLoader );
389 }
390
391 public void setTestArtifactInfoAware( Object o, TestArtifactInfo testArtifactInfo1 )
392 {
393 if ( testArtifactInfoAware.isAssignableFrom( o.getClass() ) )
394 {
395 setTestArtifactInfo( o, testArtifactInfo1 );
396 }
397 }
398
399 void setTestArtifactInfo( Object o, TestArtifactInfo testArtifactInfo )
400 {
401 Object param = createTestArtifactInfo( testArtifactInfo );
402 invokeSetter( o, "setTestArtifactInfo", this.testArtifactInfo, param );
403 }
404
405 private boolean isRunResult( Object o )
406 {
407 return runResult.isAssignableFrom( o.getClass() );
408 }
409
410 public Object createConsoleLogger( @Nonnull ConsoleLogger consoleLogger )
411 {
412 return createConsoleLogger( consoleLogger, surefireClassLoader );
413 }
414
415 private static Collection<Integer> toOrdinals( Collection<? extends Enum> enums )
416 {
417 Collection<Integer> ordinals = new ArrayList<Integer>( enums.size() );
418 for ( Enum e : enums )
419 {
420 ordinals.add( e.ordinal() );
421 }
422 return ordinals;
423 }
424
425 public static Object createConsoleLogger( ConsoleLogger consoleLogger, ClassLoader cl )
426 {
427 try
428 {
429 Class<?> decoratorClass = cl.loadClass( ConsoleLoggerDecorator.class.getName() );
430 return getConstructor( decoratorClass, Object.class ).newInstance( consoleLogger );
431 }
432 catch ( Exception e )
433 {
434 throw new SurefireReflectionException( e );
435 }
436 }
437
438 }