View Javadoc

1   package org.apache.maven.surefire.booter;
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.PrintStream;
24  import java.lang.reflect.Constructor;
25  import java.lang.reflect.InvocationHandler;
26  import java.lang.reflect.Method;
27  import java.util.List;
28  import java.util.Properties;
29  
30  import org.apache.maven.plugin.surefire.report.FileReporterFactory;
31  import org.apache.maven.surefire.providerapi.ProviderParameters;
32  import org.apache.maven.surefire.report.ReporterConfiguration;
33  import org.apache.maven.surefire.report.ReporterFactory;
34  import org.apache.maven.surefire.suite.RunResult;
35  import org.apache.maven.surefire.testset.DirectoryScannerParameters;
36  import org.apache.maven.surefire.testset.TestArtifactInfo;
37  import org.apache.maven.surefire.testset.TestRequest;
38  import org.apache.maven.surefire.util.ReflectionUtils;
39  import org.apache.maven.surefire.util.RunOrder;
40  import org.apache.maven.surefire.util.SurefireReflectionException;
41  
42  /**
43   * Does reflection based invocation of the surefire methods.
44   * <p/>
45   * This is to avoid compilications with linkage issues
46   *
47   * @author Kristian Rosenvold
48   */
49  public class SurefireReflector
50  {
51      private final ClassLoader surefireClassLoader;
52  
53      private final Class reporterConfiguration;
54  
55      private final Class testRequest;
56  
57      private final Class testArtifactInfo;
58  
59      private final Class testArtifactInfoAware;
60  
61      private final Class directoryScannerParameters;
62  
63      private final Class directoryScannerParametersAware;
64  
65      private final Class testSuiteDefinitionAware;
66  
67      private final Class testClassLoaderAware;
68  
69      private final Class reporterConfigurationAware;
70  
71      private final Class providerPropertiesAware;
72  
73      private final Class runResult;
74  
75      private final Class booterParameters;
76  
77      private final Class reporterFactory;
78  
79      private final Class startupReportConfiguration;
80  
81      public SurefireReflector( ClassLoader surefireClassLoader )
82      {
83          this.surefireClassLoader = surefireClassLoader;
84          try
85          {
86              reporterConfiguration = surefireClassLoader.loadClass( ReporterConfiguration.class.getName() );
87              startupReportConfiguration = surefireClassLoader.loadClass( StartupReportConfiguration.class.getName() );
88              testRequest = surefireClassLoader.loadClass( TestRequest.class.getName() );
89              testArtifactInfo = surefireClassLoader.loadClass( TestArtifactInfo.class.getName() );
90              testArtifactInfoAware = surefireClassLoader.loadClass( TestArtifactInfoAware.class.getName() );
91              directoryScannerParameters = surefireClassLoader.loadClass( DirectoryScannerParameters.class.getName() );
92              directoryScannerParametersAware =
93                  surefireClassLoader.loadClass( DirectoryScannerParametersAware.class.getName() );
94              testSuiteDefinitionAware = surefireClassLoader.loadClass( TestRequestAware.class.getName() );
95              testClassLoaderAware = surefireClassLoader.loadClass( SurefireClassLoadersAware.class.getName() );
96              reporterConfigurationAware = surefireClassLoader.loadClass( ReporterConfigurationAware.class.getName() );
97              providerPropertiesAware = surefireClassLoader.loadClass( ProviderPropertiesAware.class.getName() );
98              reporterFactory = surefireClassLoader.loadClass( ReporterFactory.class.getName() );
99              runResult = surefireClassLoader.loadClass( RunResult.class.getName() );
100             booterParameters = surefireClassLoader.loadClass( ProviderParameters.class.getName() );
101         }
102         catch ( ClassNotFoundException e )
103         {
104             throw new SurefireReflectionException( e );
105         }
106     }
107 
108     public Object convertIfRunResult( Object result )
109     {
110         if ( result == null || !isRunResult( result ) )
111         {
112             return result;
113         }
114         final Integer getCompletedCount1 = (Integer) ReflectionUtils.invokeGetter( result, "getCompletedCount" );
115         final Integer getErrors = (Integer) ReflectionUtils.invokeGetter( result, "getErrors" );
116         final Integer getSkipped = (Integer) ReflectionUtils.invokeGetter( result, "getSkipped" );
117         final Integer getFailures = (Integer) ReflectionUtils.invokeGetter( result, "getFailures" );
118         return new RunResult( getCompletedCount1.intValue(), getErrors.intValue(), getFailures.intValue(),
119                               getSkipped.intValue() );
120 
121     }
122 
123 
124     /**
125      * @noinspection UnusedDeclaration
126      */
127     class ClassLoaderProxy
128         implements InvocationHandler
129     {
130         private final Object target;
131 
132         /**
133          * @param delegate a target
134          * @noinspection UnusedDeclaration
135          */
136         public ClassLoaderProxy( Object delegate )
137         {
138             this.target = delegate;
139         }
140 
141         public Object invoke( Object proxy, Method method, Object[] args )
142             throws Throwable
143         {
144             Method delegateMethod = target.getClass().getMethod( method.getName(), method.getParameterTypes() );
145             return delegateMethod.invoke( target, args );
146         }
147     }
148 
149 
150     Object createTestRequest( TestRequest suiteDefinition )
151     {
152         if ( suiteDefinition == null )
153         {
154             return null;
155         }
156         Class[] arguments = { List.class, File.class, String.class, String.class };
157         Constructor constructor = ReflectionUtils.getConstructor( this.testRequest, arguments );
158         return ReflectionUtils.newInstance( constructor, new Object[]{ suiteDefinition.getSuiteXmlFiles(),
159             suiteDefinition.getTestSourceDirectory(), suiteDefinition.getRequestedTest(),
160             suiteDefinition.getRequestedTestMethod() } );
161     }
162 
163 
164     Object createDirectoryScannerParameters( DirectoryScannerParameters directoryScannerParameters )
165     {
166         if ( directoryScannerParameters == null )
167         {
168             return null;
169         }
170         //Can't use the constructor with the RunOrder parameter. Using it causes some integration tests to fail.
171         Class[] arguments = { File.class, List.class, List.class, Boolean.class, String.class };
172         Constructor constructor = ReflectionUtils.getConstructor( this.directoryScannerParameters, arguments );
173         return ReflectionUtils.newInstance( constructor,
174                                             new Object[]{ directoryScannerParameters.getTestClassesDirectory(),
175                                                 directoryScannerParameters.getIncludes(),
176                                                 directoryScannerParameters.getExcludes(),
177                                                 directoryScannerParameters.isFailIfNoTests(),
178                                                 directoryScannerParameters.getRunOrder().name() } );
179     }
180 
181     Object createTestArtifactInfo( TestArtifactInfo testArtifactInfo )
182     {
183         if ( testArtifactInfo == null )
184         {
185             return null;
186         }
187         Class[] arguments = { String.class, String.class };
188         Constructor constructor = ReflectionUtils.getConstructor( this.testArtifactInfo, arguments );
189         return ReflectionUtils.newInstance( constructor, new Object[]{ testArtifactInfo.getVersion(),
190             testArtifactInfo.getClassifier() } );
191     }
192 
193 
194     Object createReporterConfiguration( ReporterConfiguration reporterConfiguration )
195     {
196         Constructor constructor = ReflectionUtils.getConstructor( this.reporterConfiguration,
197                                                                   new Class[]{ File.class, Boolean.class } );
198         return ReflectionUtils.newInstance( constructor, new Object[]{ reporterConfiguration.getReportsDirectory(),
199             reporterConfiguration.isTrimStackTrace()} );
200     }
201 
202     Object createStartupReportConfiguration( StartupReportConfiguration reporterConfiguration )
203     {
204         Constructor constructor = ReflectionUtils.getConstructor( this.startupReportConfiguration,
205                                                                   new Class[]{ boolean.class, boolean.class,
206                                                                       String.class, boolean.class, boolean.class,
207                                                                       File.class, boolean.class, String.class } );
208         //noinspection BooleanConstructorCall
209         final Object[] params =
210             { new Boolean( reporterConfiguration.isUseFile() ), new Boolean( reporterConfiguration.isPrintSummary() ),
211                 reporterConfiguration.getReportFormat(),
212                 new Boolean( reporterConfiguration.isRedirectTestOutputToFile() ),
213                 new Boolean( reporterConfiguration.isDisableXmlReport() ),
214                 reporterConfiguration.getReportsDirectory(),
215                 new Boolean( reporterConfiguration.isTrimStackTrace()),
216                 reporterConfiguration.getReportNameSuffix()};
217         return ReflectionUtils.newInstance( constructor, params );
218     }
219 
220     public Object createForkingReporterFactory( Boolean trimStackTrace, PrintStream originalSystemOut )
221     {
222         Class[] args = new Class[]{ Boolean.class, PrintStream.class };
223         Object[] values = new Object[]{ trimStackTrace, originalSystemOut };
224         return ReflectionUtils.instantiateObject( ForkingReporterFactory.class.getName(), args, values,
225                                                   surefireClassLoader );
226     }
227 
228     public Object createReportingReporterFactory( StartupReportConfiguration startupReportConfiguration )
229     {
230         Class[] args =
231             new Class[]{ this.startupReportConfiguration };
232         Object src = createStartupReportConfiguration( startupReportConfiguration );
233         Object[] params = new Object[]{ src };
234         return ReflectionUtils.instantiateObject( FileReporterFactory.class.getName(), args, params,
235                                                   surefireClassLoader );
236 
237     }
238 
239     public Object createBooterConfiguration( ClassLoader surefireClassLoader, Object factoryInstance )
240     {
241         return ReflectionUtils.instantiateOneArg( surefireClassLoader, BaseProviderFactory.class.getName(),
242                                                   reporterFactory, factoryInstance );
243     }
244 
245     public Object instantiateProvider( String providerClassName, Object booterParameters )
246     {
247         return ReflectionUtils.instantiateOneArg( surefireClassLoader, providerClassName, this.booterParameters,
248                                                   booterParameters );
249     }
250 
251     public void setIfDirScannerAware( Object o, DirectoryScannerParameters dirScannerParams )
252     {
253         if ( directoryScannerParametersAware.isAssignableFrom( o.getClass() ) )
254         {
255             setDirectoryScannerParameters( o, dirScannerParams );
256         }
257     }
258 
259     public void setDirectoryScannerParameters( Object o, DirectoryScannerParameters dirScannerParams )
260     {
261         final Object param = createDirectoryScannerParameters( dirScannerParams );
262         ReflectionUtils.invokeSetter( o, "setDirectoryScannerParameters", this.directoryScannerParameters, param );
263     }
264 
265 
266     public void setTestSuiteDefinitionAware( Object o, TestRequest testSuiteDefinition2 )
267     {
268         if ( testSuiteDefinitionAware.isAssignableFrom( o.getClass() ) )
269         {
270             setTestSuiteDefinition( o, testSuiteDefinition2 );
271         }
272     }
273 
274     void setTestSuiteDefinition( Object o, TestRequest testSuiteDefinition1 )
275     {
276         final Object param = createTestRequest( testSuiteDefinition1 );
277         ReflectionUtils.invokeSetter( o, "setTestRequest", this.testRequest, param );
278     }
279 
280     public void setProviderPropertiesAware( Object o, Properties properties )
281     {
282         if ( providerPropertiesAware.isAssignableFrom( o.getClass() ) )
283         {
284             setProviderProperties( o, properties );
285         }
286     }
287 
288     void setProviderProperties( Object o, Properties providerProperties )
289     {
290         ReflectionUtils.invokeSetter( o, "setProviderProperties", Properties.class, providerProperties );
291     }
292 
293     public void setReporterConfigurationAware( Object o, ReporterConfiguration reporterConfiguration1 )
294     {
295         if ( reporterConfigurationAware.isAssignableFrom( o.getClass() ) )
296         {
297             setReporterConfiguration( o, reporterConfiguration1 );
298         }
299     }
300 
301 
302     void setReporterConfiguration( Object o, ReporterConfiguration reporterConfiguration )
303     {
304         final Object param = createReporterConfiguration( reporterConfiguration );
305         ReflectionUtils.invokeSetter( o, "setReporterConfiguration", this.reporterConfiguration, param );
306     }
307 
308     public void setTestClassLoaderAware( Object o, ClassLoader surefireClassLoader, ClassLoader testClassLoader )
309     {
310         if ( testClassLoaderAware.isAssignableFrom( o.getClass() ) )
311         {
312             setTestClassLoader( o, surefireClassLoader, testClassLoader );
313         }
314     }
315 
316     void setTestClassLoader( Object o, ClassLoader surefireClassLoader, ClassLoader testClassLoader )
317     {
318         final Method setter =
319             ReflectionUtils.getMethod( o, "setClassLoaders", new Class[]{ ClassLoader.class, ClassLoader.class } );
320         ReflectionUtils.invokeMethodWithArray( o, setter, new Object[]{ surefireClassLoader, testClassLoader } );
321     }
322 
323     public void setTestArtifactInfoAware( Object o, TestArtifactInfo testArtifactInfo1 )
324     {
325         if ( testArtifactInfoAware.isAssignableFrom( o.getClass() ) )
326         {
327             setTestArtifactInfo( o, testArtifactInfo1 );
328         }
329     }
330 
331     void setTestArtifactInfo( Object o, TestArtifactInfo testArtifactInfo )
332     {
333         final Object param = createTestArtifactInfo( testArtifactInfo );
334         ReflectionUtils.invokeSetter( o, "setTestArtifactInfo", this.testArtifactInfo, param );
335     }
336 
337     private boolean isRunResult( Object o )
338     {
339         return runResult.isAssignableFrom( o.getClass() );
340     }
341 }