1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.surefire.booter;
20
21 import java.io.PrintStream;
22 import java.lang.reflect.InvocationTargetException;
23 import java.lang.reflect.Method;
24
25 import org.apache.maven.surefire.api.provider.SurefireProvider;
26 import org.apache.maven.surefire.api.report.ReporterException;
27 import org.apache.maven.surefire.api.suite.RunResult;
28 import org.apache.maven.surefire.api.testset.TestSetFailedException;
29
30 import static org.apache.maven.surefire.api.util.ReflectionUtils.getMethod;
31 import static org.apache.maven.surefire.api.util.ReflectionUtils.invokeGetter;
32 import static org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray;
33 import static org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray2;
34 import static org.apache.maven.surefire.api.util.internal.ObjectUtils.isSecurityManagerSupported;
35
36
37
38
39
40
41
42 public class ProviderFactory {
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 Object[] INVOKE_EMPTY_PARAMETERS = {};
58
59 public ProviderFactory(
60 StartupConfiguration startupConfiguration,
61 ProviderConfiguration providerConfiguration,
62 ClassLoader testsClassLoader,
63 Object reporterManagerFactory) {
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(
72 Object testSet,
73 ClassLoader testsClassLoader,
74 Object factory,
75 ProviderConfiguration providerConfiguration,
76 boolean insideFork,
77 StartupConfiguration startupConfig,
78 boolean restoreStreams)
79 throws TestSetFailedException, InvocationTargetException {
80 final PrintStream orgSystemOut = System.out;
81 final PrintStream orgSystemErr = System.err;
82
83
84
85 try {
86 return new ProviderFactory(startupConfig, providerConfiguration, testsClassLoader, factory)
87 .createProvider(insideFork)
88 .invoke(testSet);
89 } finally {
90 if (restoreStreams && (!isSecurityManagerSupported() || System.getSecurityManager() == null)) {
91 System.setOut(orgSystemOut);
92 System.setErr(orgSystemErr);
93 }
94 }
95 }
96
97 public SurefireProvider createProvider(boolean isInsideFork) {
98 final Thread currentThread = Thread.currentThread();
99 final ClassLoader systemClassLoader = currentThread.getContextClassLoader();
100 currentThread.setContextClassLoader(classLoader);
101
102 Object o = surefireReflector.createBooterConfiguration(classLoader, isInsideFork);
103 surefireReflector.setReporterFactoryAware(o, reporterManagerFactory);
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 surefireReflector.setMainCliOptions(o, providerConfiguration.getMainCliOptions());
112 surefireReflector.setSkipAfterFailureCount(o, providerConfiguration.getSkipAfterFailureCount());
113 if (isInsideFork) {
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 implements SurefireProvider {
124 private final Object providerInOtherClassLoader;
125
126 private final ClassLoader testsClassLoader;
127
128 private ProviderProxy(Object providerInOtherClassLoader, ClassLoader testsClassLoader) {
129 this.providerInOtherClassLoader = providerInOtherClassLoader;
130 this.testsClassLoader = testsClassLoader;
131 }
132
133 @Override
134 public Iterable<Class<?>> getSuites() {
135 ClassLoader current = swapClassLoader(testsClassLoader);
136 try {
137 return invokeGetter(providerInOtherClassLoader, "getSuites");
138 } finally {
139 Thread.currentThread().setContextClassLoader(current);
140 }
141 }
142
143 @Override
144 public RunResult invoke(Object forkTestSet) throws ReporterException, InvocationTargetException {
145 ClassLoader current = swapClassLoader(testsClassLoader);
146 try {
147 Method invoke = getMethod(providerInOtherClassLoader.getClass(), "invoke", INVOKE_PARAMETERS);
148 Object result = invokeMethodWithArray2(providerInOtherClassLoader, invoke, forkTestSet);
149 return (RunResult) surefireReflector.convertIfRunResult(result);
150 } finally {
151 if (System.getSecurityManager() == null) {
152 Thread.currentThread().setContextClassLoader(current);
153 }
154 }
155 }
156
157 private ClassLoader swapClassLoader(ClassLoader newClassLoader) {
158 ClassLoader current = Thread.currentThread().getContextClassLoader();
159 Thread.currentThread().setContextClassLoader(newClassLoader);
160 return current;
161 }
162
163 @Override
164 public void cancel() {
165 Class<?> providerType = providerInOtherClassLoader.getClass();
166 Method invoke = getMethod(providerType, "cancel", INVOKE_EMPTY_PARAMETER_TYPES);
167 invokeMethodWithArray(providerInOtherClassLoader, invoke, INVOKE_EMPTY_PARAMETERS);
168 }
169 }
170 }