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