1 package org.apache.maven.plugin.surefire.booterclient;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.jar.JarEntry;
28 import java.util.jar.JarOutputStream;
29 import java.util.jar.Manifest;
30
31 import org.apache.maven.plugin.surefire.AbstractSurefireMojo;
32 import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.OutputStreamFlushableCommandline;
33 import org.apache.maven.plugin.surefire.util.Relocator;
34 import org.apache.maven.shared.utils.StringUtils;
35 import org.apache.maven.surefire.booter.Classpath;
36 import org.apache.maven.surefire.booter.ForkedBooter;
37 import org.apache.maven.surefire.booter.StartupConfiguration;
38 import org.apache.maven.surefire.booter.SurefireBooterForkException;
39 import org.apache.maven.surefire.util.UrlUtils;
40
41
42
43
44
45
46
47
48 public class ForkConfiguration
49 {
50 public static final String FORK_ONCE = "once";
51
52 public static final String FORK_ALWAYS = "always";
53
54 public static final String FORK_NEVER = "never";
55
56 public static final String FORK_PERTHREAD = "perthread";
57
58 private final int forkCount;
59
60 private final boolean reuseForks;
61
62 private final Classpath bootClasspathConfiguration;
63
64 private final String jvmExecutable;
65
66 private final String argLine;
67
68 private final Map<String, String> environmentVariables;
69
70 private final File workingDirectory;
71
72 private final File tempDirectory;
73
74 private final boolean debug;
75
76 private final String debugLine;
77
78 public ForkConfiguration( Classpath bootClasspathConfiguration, File tmpDir, String debugLine, String jvmExecutable,
79 File workingDirectory, String argLine, Map<String, String> environmentVariables,
80 boolean debugEnabled, int forkCount, boolean reuseForks )
81 {
82 this.bootClasspathConfiguration = bootClasspathConfiguration;
83 this.tempDirectory = tmpDir;
84 this.debugLine = debugLine;
85 this.jvmExecutable = jvmExecutable;
86 this.workingDirectory = workingDirectory;
87 this.argLine = argLine;
88 this.environmentVariables = environmentVariables;
89 this.debug = debugEnabled;
90 this.forkCount = forkCount;
91 this.reuseForks = reuseForks;
92 }
93
94 public Classpath getBootClasspath()
95 {
96 return bootClasspathConfiguration;
97 }
98
99 public static String getEffectiveForkMode( String forkMode )
100 {
101 if ( "pertest".equalsIgnoreCase( forkMode ) )
102 {
103 return FORK_ALWAYS;
104 }
105 else if ( "none".equalsIgnoreCase( forkMode ) )
106 {
107 return FORK_NEVER;
108 }
109 else if ( forkMode.equals( FORK_NEVER ) || forkMode.equals( FORK_ONCE ) ||
110 forkMode.equals( FORK_ALWAYS ) || forkMode.equals( FORK_PERTHREAD ) )
111 {
112 return forkMode;
113 }
114 else
115 {
116 throw new IllegalArgumentException( "Fork mode " + forkMode + " is not a legal value" );
117 }
118 }
119
120
121
122
123
124
125
126
127 public OutputStreamFlushableCommandline createCommandLine( List<String> classPath,
128 StartupConfiguration startupConfiguration,
129 int threadNumber )
130 throws SurefireBooterForkException
131 {
132 return createCommandLine( classPath,
133 startupConfiguration.getClassLoaderConfiguration().isManifestOnlyJarRequestedAndUsable(),
134 startupConfiguration.isShadefire(), startupConfiguration.isProviderMainClass()
135 ? startupConfiguration.getActualClassName()
136 : ForkedBooter.class.getName(), threadNumber );
137 }
138
139 OutputStreamFlushableCommandline createCommandLine( List<String> classPath, boolean useJar, boolean shadefire,
140 String providerThatHasMainMethod, int threadNumber )
141 throws SurefireBooterForkException
142 {
143 OutputStreamFlushableCommandline cli = new OutputStreamFlushableCommandline();
144
145 cli.setExecutable( jvmExecutable );
146
147 if ( argLine != null )
148 {
149 cli.createArg().setLine( replaceThreadNumberPlaceholder( stripNewLines( argLine ), threadNumber ) );
150 }
151
152 if ( environmentVariables != null )
153 {
154
155 for ( String key : environmentVariables.keySet() )
156 {
157 String value = environmentVariables.get( key );
158
159 cli.addEnvironment( key, value );
160 }
161 }
162
163 if ( getDebugLine() != null && !"".equals( getDebugLine() ) )
164 {
165 cli.createArg().setLine( getDebugLine() );
166 }
167
168 if ( useJar )
169 {
170 File jarFile;
171 try
172 {
173 jarFile = createJar( classPath, providerThatHasMainMethod );
174 }
175 catch ( IOException e )
176 {
177 throw new SurefireBooterForkException( "Error creating archive file", e );
178 }
179
180 cli.createArg().setValue( "-jar" );
181
182 cli.createArg().setValue( jarFile.getAbsolutePath() );
183 }
184 else
185 {
186 cli.addEnvironment( "CLASSPATH", StringUtils.join( classPath.iterator(), File.pathSeparator ) );
187
188 final String forkedBooter =
189 providerThatHasMainMethod != null ? providerThatHasMainMethod : ForkedBooter.class.getName();
190
191 cli.createArg().setValue( shadefire ? new Relocator().relocate( forkedBooter ) : forkedBooter );
192 }
193
194 cli.setWorkingDirectory( workingDirectory.getAbsolutePath() );
195
196 return cli;
197 }
198
199 private String replaceThreadNumberPlaceholder( String argLine, int threadNumber )
200 {
201 return argLine.replace( AbstractSurefireMojo.THREAD_NUMBER_PLACEHOLDER,
202 String.valueOf( threadNumber ) ).replace( AbstractSurefireMojo.FORK_NUMBER_PLACEHOLDER,
203 String.valueOf( threadNumber ) );
204 }
205
206
207
208
209
210
211
212
213
214
215 private File createJar( List<String> classPath, String startClassName )
216 throws IOException
217 {
218 File file = File.createTempFile( "surefirebooter", ".jar", tempDirectory );
219 if ( !debug )
220 {
221 file.deleteOnExit();
222 }
223 FileOutputStream fos = new FileOutputStream( file );
224 JarOutputStream jos = new JarOutputStream( fos );
225 jos.setLevel( JarOutputStream.STORED );
226 JarEntry je = new JarEntry( "META-INF/MANIFEST.MF" );
227 jos.putNextEntry( je );
228
229 Manifest man = new Manifest();
230
231
232
233 String cp = "";
234 for ( String el : classPath )
235 {
236
237 cp += UrlUtils.getURL( new File( el ) ).toExternalForm() + " ";
238 }
239
240 man.getMainAttributes().putValue( "Manifest-Version", "1.0" );
241 man.getMainAttributes().putValue( "Class-Path", cp.trim() );
242 man.getMainAttributes().putValue( "Main-Class", startClassName );
243
244 man.write( jos );
245 jos.close();
246
247 return file;
248 }
249
250 public boolean isDebug()
251 {
252 return debug;
253 }
254
255 public String stripNewLines( String argline )
256 {
257 return argline.replace( "\n", " " ).replace( "\r", " " );
258 }
259
260 public String getDebugLine()
261 {
262 return debugLine;
263 }
264
265 public File getTempDirectory()
266 {
267 return tempDirectory;
268 }
269
270 public int getForkCount()
271 {
272 return forkCount;
273 }
274
275
276 public boolean isReuseForks()
277 {
278 return reuseForks;
279 }
280 }