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.PrintStream;
23  import java.lang.reflect.InvocationTargetException;
24  import java.lang.reflect.Method;
25  
26  import org.apache.maven.surefire.api.provider.SurefireProvider;
27  import org.apache.maven.surefire.api.report.ReporterException;
28  import org.apache.maven.surefire.api.suite.RunResult;
29  import org.apache.maven.surefire.api.testset.TestSetFailedException;
30  
31  import static org.apache.maven.surefire.api.util.ReflectionUtils.getMethod;
32  import static org.apache.maven.surefire.api.util.ReflectionUtils.invokeGetter;
33  import static org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray;
34  import static org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray2;
35  import static org.apache.maven.surefire.api.util.internal.ObjectUtils.isSecurityManagerSupported;
36  
37  /**
38   * Creates the surefire provider.
39   * <br>
40   *
41   * @author Kristian Rosenvold
42   */
43  public class ProviderFactory
44  {
45      private final StartupConfiguration startupConfiguration;
46  
47      private final ProviderConfiguration providerConfiguration;
48  
49      private final ClassLoader classLoader;
50  
51      private final SurefireReflector surefireReflector;
52  
53      private final Object reporterManagerFactory;
54  
55      private static final Class<?>[] INVOKE_PARAMETERS = { Object.class };
56  
57      private static final Class<?>[] INVOKE_EMPTY_PARAMETER_TYPES = { };
58  
59      private static final Object[] INVOKE_EMPTY_PARAMETERS = { };
60  
61      public ProviderFactory( StartupConfiguration startupConfiguration, ProviderConfiguration providerConfiguration,
62                              ClassLoader testsClassLoader, Object reporterManagerFactory )
63      {
64          this.providerConfiguration = providerConfiguration;
65          this.startupConfiguration = startupConfiguration;
66          this.surefireReflector = new SurefireReflector( testsClassLoader );
67          this.classLoader = testsClassLoader;
68          this.reporterManagerFactory = reporterManagerFactory;
69      }
70  
71      public static RunResult invokeProvider( Object testSet, ClassLoader testsClassLoader, Object factory,
72                                              ProviderConfiguration providerConfiguration, boolean insideFork,
73                                              StartupConfiguration startupConfig, boolean restoreStreams )
74          throws TestSetFailedException, InvocationTargetException
75      {
76          final PrintStream orgSystemOut = System.out;
77          final PrintStream orgSystemErr = System.err;
78          // Note that System.out/System.err are also read in the "ReporterConfiguration" instantiation
79          // in createProvider below. These are the same values as here.
80  
81          try
82          {
83              return new ProviderFactory( startupConfig, providerConfiguration, testsClassLoader, factory )
84                  .createProvider( insideFork )
85                  .invoke( testSet );
86          }
87          finally
88          {
89              if ( restoreStreams && ( !isSecurityManagerSupported() || System.getSecurityManager() == null ) )
90              {
91                  System.setOut( orgSystemOut );
92                  System.setErr( orgSystemErr );
93              }
94          }
95      }
96  
97      public SurefireProvider createProvider( boolean isInsideFork )
98      {
99          final Thread currentThread = Thread.currentThread();
100         final ClassLoader systemClassLoader = currentThread.getContextClassLoader();
101         currentThread.setContextClassLoader( classLoader );
102         // Note: Duplicated in ForkedBooter#createProviderInCurrentClassloader
103         Object o = surefireReflector.createBooterConfiguration( classLoader, isInsideFork );
104         surefireReflector.setReporterFactoryAware( o, reporterManagerFactory );
105         surefireReflector.setTestSuiteDefinitionAware( o, providerConfiguration.getTestSuiteDefinition() );
106         surefireReflector.setProviderPropertiesAware( o, providerConfiguration.getProviderProperties() );
107         surefireReflector.setReporterConfigurationAware( o, providerConfiguration.getReporterConfiguration() );
108         surefireReflector.setTestClassLoaderAware( o, classLoader );
109         surefireReflector.setTestArtifactInfoAware( o, providerConfiguration.getTestArtifact() );
110         surefireReflector.setRunOrderParameters( o, providerConfiguration.getRunOrderParameters() );
111         surefireReflector.setIfDirScannerAware( o, providerConfiguration.getDirScannerParams() );
112         surefireReflector.setMainCliOptions( o, providerConfiguration.getMainCliOptions() );
113         surefireReflector.setSkipAfterFailureCount( o, providerConfiguration.getSkipAfterFailureCount() );
114         if ( isInsideFork )
115         {
116             surefireReflector.setSystemExitTimeout( o, providerConfiguration.getSystemExitTimeout() );
117         }
118 
119         Object provider = surefireReflector.instantiateProvider( startupConfiguration.getActualClassName(), o );
120         currentThread.setContextClassLoader( systemClassLoader );
121 
122         return new ProviderProxy( provider, classLoader );
123     }
124 
125     private final class ProviderProxy
126         implements SurefireProvider
127     {
128         private final Object providerInOtherClassLoader;
129 
130         private final ClassLoader testsClassLoader;
131 
132 
133         private ProviderProxy( Object providerInOtherClassLoader, ClassLoader testsClassLoader )
134         {
135             this.providerInOtherClassLoader = providerInOtherClassLoader;
136             this.testsClassLoader = testsClassLoader;
137         }
138 
139         @Override
140         public Iterable<Class<?>> getSuites()
141         {
142             ClassLoader current = swapClassLoader( testsClassLoader );
143             try
144             {
145                 return invokeGetter( providerInOtherClassLoader, "getSuites" );
146             }
147             finally
148             {
149                 Thread.currentThread().setContextClassLoader( current );
150             }
151         }
152 
153         @Override
154         public RunResult invoke( Object forkTestSet )
155             throws ReporterException, InvocationTargetException
156         {
157             ClassLoader current = swapClassLoader( testsClassLoader );
158             try
159             {
160                 Method invoke = getMethod( providerInOtherClassLoader.getClass(), "invoke", INVOKE_PARAMETERS );
161                 Object result = invokeMethodWithArray2( providerInOtherClassLoader, invoke, forkTestSet );
162                 return (RunResult) surefireReflector.convertIfRunResult( result );
163             }
164             finally
165             {
166                 if ( System.getSecurityManager() == null )
167                 {
168                     Thread.currentThread().setContextClassLoader( current );
169                 }
170             }
171         }
172 
173         private ClassLoader swapClassLoader( ClassLoader newClassLoader )
174         {
175             ClassLoader current = Thread.currentThread().getContextClassLoader();
176             Thread.currentThread().setContextClassLoader( newClassLoader );
177             return current;
178         }
179 
180         @Override
181         public void cancel()
182         {
183             Class<?> providerType = providerInOtherClassLoader.getClass();
184             Method invoke = getMethod( providerType, "cancel", INVOKE_EMPTY_PARAMETER_TYPES );
185             invokeMethodWithArray( providerInOtherClassLoader, invoke, INVOKE_EMPTY_PARAMETERS );
186         }
187     }
188 }