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