1 package org.apache.maven.surefire.booter;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.surefire.util.ReflectionUtils;
23
24 import java.io.BufferedReader;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.FileReader;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.lang.management.ManagementFactory;
31 import java.lang.reflect.Method;
32 import java.math.BigDecimal;
33 import java.util.Properties;
34 import java.util.StringTokenizer;
35
36 import static java.lang.Character.isDigit;
37 import static java.lang.Thread.currentThread;
38 import static org.apache.commons.io.IOUtils.closeQuietly;
39 import static org.apache.commons.lang3.StringUtils.isNumeric;
40 import static org.apache.commons.lang3.SystemUtils.IS_OS_FREE_BSD;
41 import static org.apache.commons.lang3.SystemUtils.IS_OS_LINUX;
42 import static org.apache.commons.lang3.SystemUtils.IS_OS_NET_BSD;
43 import static org.apache.commons.lang3.SystemUtils.IS_OS_OPEN_BSD;
44 import static org.apache.maven.surefire.util.ReflectionUtils.invokeMethodChain;
45 import static org.apache.maven.surefire.util.ReflectionUtils.tryLoadClass;
46 import static org.apache.maven.surefire.util.internal.ObjectUtils.requireNonNull;
47
48
49
50
51
52
53
54 public final class SystemUtils
55 {
56 public static final BigDecimal JAVA_SPECIFICATION_VERSION = getJavaSpecificationVersion();
57
58 private static final BigDecimal JAVA_VERSION_7 = new BigDecimal( "1.7" ).stripTrailingZeros();
59
60 private static final BigDecimal JIGSAW_JAVA_VERSION = new BigDecimal( 9 ).stripTrailingZeros();
61
62 private static final int PROC_STATUS_PID_FIRST_CHARS = 20;
63
64 private SystemUtils()
65 {
66 throw new IllegalStateException( "no instantiable constructor" );
67 }
68
69
70
71
72
73 public static boolean endsWithJavaPath( String jvmExecPath )
74 {
75 File javaExec = new File( jvmExecPath ).getAbsoluteFile();
76 File bin = javaExec.getParentFile();
77 String exec = javaExec.getName();
78 return exec.startsWith( "java" ) && bin != null && bin.getName().equals( "bin" );
79 }
80
81
82
83
84
85
86
87
88
89
90 public static File toJdkHomeFromJvmExec( String jvmExecutable )
91 {
92 File bin = new File( jvmExecutable ).getAbsoluteFile().getParentFile();
93 if ( "bin".equals( bin.getName() ) )
94 {
95 File parent = bin.getParentFile();
96 if ( "jre".equals( parent.getName() ) )
97 {
98 File jdk = parent.getParentFile();
99 return new File( jdk, "bin" ).isDirectory() ? jdk : null;
100 }
101 return parent;
102 }
103 return null;
104 }
105
106
107
108
109
110
111
112
113 public static File toJdkHomeFromJre()
114 {
115 return toJdkHomeFromJre( System.getProperty( "java.home" ) );
116 }
117
118
119
120
121
122
123
124
125
126
127 static File toJdkHomeFromJre( String jreHome )
128 {
129 File pathToJreOrJdk = new File( jreHome ).getAbsoluteFile();
130 return "jre".equals( pathToJreOrJdk.getName() ) ? pathToJreOrJdk.getParentFile() : pathToJreOrJdk;
131 }
132
133 public static BigDecimal toJdkVersionFromReleaseFile( File jdkHome )
134 {
135 File release = new File( requireNonNull( jdkHome ).getAbsoluteFile(), "release" );
136 if ( !release.isFile() )
137 {
138 return null;
139 }
140 InputStream is = null;
141 try
142 {
143 Properties properties = new Properties();
144 is = new FileInputStream( release );
145 properties.load( is );
146 String javaVersion = properties.getProperty( "JAVA_VERSION" ).replace( "\"", "" );
147 StringTokenizer versions = new StringTokenizer( javaVersion, "._" );
148
149 if ( versions.countTokens() == 1 )
150 {
151 javaVersion = versions.nextToken();
152 }
153 else if ( versions.countTokens() >= 2 )
154 {
155 String majorVersion = versions.nextToken();
156 String minorVersion = versions.nextToken();
157 javaVersion = isNumeric( minorVersion ) ? majorVersion + "." + minorVersion : majorVersion;
158 }
159 else
160 {
161 return null;
162 }
163
164 return new BigDecimal( javaVersion );
165 }
166 catch ( IOException e )
167 {
168 return null;
169 }
170 finally
171 {
172 closeQuietly( is );
173 }
174 }
175
176
177
178
179
180
181
182
183
184
185
186
187 private static BigDecimal getJavaSpecificationVersion()
188 {
189 StringBuilder fractionalVersion = new StringBuilder( "0" );
190 for ( char c : org.apache.commons.lang3.SystemUtils.JAVA_SPECIFICATION_VERSION.toCharArray() )
191 {
192 if ( isDigit( c ) )
193 {
194 fractionalVersion.append( c );
195 }
196 else if ( c == '.' )
197 {
198 if ( fractionalVersion.indexOf( "." ) == -1 )
199 {
200 fractionalVersion.append( '.' );
201 }
202 else
203 {
204 break;
205 }
206 }
207 }
208 String majorMinorVersion = fractionalVersion.toString();
209 return new BigDecimal( majorMinorVersion.endsWith( "." ) ? majorMinorVersion + "0" : majorMinorVersion )
210 .stripTrailingZeros();
211 }
212
213 public static boolean isJava9AtLeast( String jvmExecutablePath )
214 {
215 File externalJavaHome = toJdkHomeFromJvmExec( jvmExecutablePath );
216 File thisJavaHome = toJdkHomeFromJre();
217 if ( thisJavaHome.equals( externalJavaHome ) )
218 {
219 return isBuiltInJava9AtLeast();
220 }
221 else
222 {
223 BigDecimal releaseFileVersion =
224 externalJavaHome == null ? null : toJdkVersionFromReleaseFile( externalJavaHome );
225 return isJava9AtLeast( releaseFileVersion );
226 }
227 }
228
229 public static boolean isBuiltInJava9AtLeast()
230 {
231 return JAVA_SPECIFICATION_VERSION.compareTo( JIGSAW_JAVA_VERSION ) >= 0;
232 }
233
234 public static boolean isBuiltInJava7AtLeast()
235 {
236 return JAVA_SPECIFICATION_VERSION.compareTo( JAVA_VERSION_7 ) >= 0;
237 }
238
239 public static boolean isJava9AtLeast( BigDecimal version )
240 {
241 return version != null && version.compareTo( JIGSAW_JAVA_VERSION ) >= 0;
242 }
243
244 public static ClassLoader platformClassLoader()
245 {
246 if ( isBuiltInJava9AtLeast() )
247 {
248 return reflectClassLoader( ClassLoader.class, "getPlatformClassLoader" );
249 }
250 return null;
251 }
252
253 public static Long pid()
254 {
255 if ( isBuiltInJava9AtLeast() )
256 {
257 Long pid = pidOnJava9();
258 if ( pid != null )
259 {
260 return pid;
261 }
262 }
263
264 if ( IS_OS_LINUX )
265 {
266 try
267 {
268 return pidStatusOnLinux();
269 }
270 catch ( Exception e )
271 {
272
273 }
274 }
275 else if ( IS_OS_FREE_BSD || IS_OS_NET_BSD || IS_OS_OPEN_BSD )
276 {
277 try
278 {
279 return pidStatusOnBSD();
280 }
281 catch ( Exception e )
282 {
283
284 }
285 }
286
287 return pidOnJMX();
288 }
289
290 static Long pidOnJMX()
291 {
292 String processName = ManagementFactory.getRuntimeMXBean().getName();
293 if ( processName.contains( "@" ) )
294 {
295 String pid = processName.substring( 0, processName.indexOf( '@' ) ).trim();
296 try
297 {
298 return Long.parseLong( pid );
299 }
300 catch ( NumberFormatException e )
301 {
302 return null;
303 }
304 }
305
306 return null;
307 }
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325 static Long pidStatusOnLinux() throws Exception
326 {
327 return pidStatusOnLinux( "" );
328 }
329
330
331
332
333
334
335
336
337 static Long pidStatusOnLinux( String root ) throws Exception
338 {
339 FileReader input = new FileReader( root + "/proc/self/stat" );
340 try
341 {
342
343
344 char[] buffer = new char[PROC_STATUS_PID_FIRST_CHARS];
345 String startLine = new String( buffer, 0, input.read( buffer ) );
346 return Long.parseLong( startLine.substring( 0, startLine.indexOf( ' ' ) ) );
347 }
348 finally
349 {
350 input.close();
351 }
352 }
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372 static Long pidStatusOnBSD() throws Exception
373 {
374 return pidStatusOnBSD( "" );
375 }
376
377
378
379
380
381
382
383
384 static Long pidStatusOnBSD( String root ) throws Exception
385 {
386 BufferedReader input = new BufferedReader( new FileReader( root + "/proc/curproc/status" ) );
387 try
388 {
389 String line = input.readLine();
390 int i1 = 1 + line.indexOf( ' ' );
391 int i2 = line.indexOf( ' ', i1 );
392 return Long.parseLong( line.substring( i1, i2 ) );
393 }
394 finally
395 {
396 input.close();
397 }
398 }
399
400 static Long pidOnJava9()
401 {
402 ClassLoader classLoader = currentThread().getContextClassLoader();
403 Class<?> processHandle = tryLoadClass( classLoader, "java.lang.ProcessHandle" );
404 Class<?>[] classesChain = { processHandle, processHandle };
405 String[] methodChain = { "current", "pid" };
406 return (Long) invokeMethodChain( classesChain, methodChain, null );
407 }
408
409 static ClassLoader reflectClassLoader( Class<?> target, String getterMethodName )
410 {
411 try
412 {
413 Method getter = ReflectionUtils.getMethod( target, getterMethodName );
414 return (ClassLoader) ReflectionUtils.invokeMethodWithArray( null, getter );
415 }
416 catch ( RuntimeException e )
417 {
418 return null;
419 }
420 }
421 }