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