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.BufferedReader;
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.FileReader;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.lang.management.ManagementFactory;
28  import java.lang.reflect.Method;
29  import java.math.BigDecimal;
30  import java.util.Properties;
31  import java.util.StringTokenizer;
32  
33  import org.apache.maven.surefire.api.util.ReflectionUtils;
34  
35  import static java.lang.Thread.currentThread;
36  import static java.util.Objects.requireNonNull;
37  import static org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodChain;
38  import static org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray;
39  import static org.apache.maven.surefire.api.util.ReflectionUtils.tryLoadClass;
40  import static org.apache.maven.surefire.shared.lang3.JavaVersion.JAVA_9;
41  import static org.apache.maven.surefire.shared.lang3.JavaVersion.JAVA_RECENT;
42  import static org.apache.maven.surefire.shared.lang3.StringUtils.isNumeric;
43  import static org.apache.maven.surefire.shared.lang3.SystemUtils.IS_OS_FREE_BSD;
44  import static org.apache.maven.surefire.shared.lang3.SystemUtils.IS_OS_LINUX;
45  import static org.apache.maven.surefire.shared.lang3.SystemUtils.IS_OS_NET_BSD;
46  import static org.apache.maven.surefire.shared.lang3.SystemUtils.IS_OS_OPEN_BSD;
47  
48  
49  
50  
51  
52  
53  
54  public final class SystemUtils {
55      private static final BigDecimal JIGSAW_JAVA_VERSION = new BigDecimal(9).stripTrailingZeros();
56  
57      private static final int PROC_STATUS_PID_FIRST_CHARS = 20;
58  
59      private SystemUtils() {
60          throw new IllegalStateException("no instantiable constructor");
61      }
62  
63      
64  
65  
66  
67      public static boolean endsWithJavaPath(String jvmExecPath) {
68          File javaExec = new File(jvmExecPath).getAbsoluteFile();
69          File bin = javaExec.getParentFile();
70          String exec = javaExec.getName();
71          return exec.startsWith("java") && bin != null && bin.getName().equals("bin");
72      }
73  
74      
75  
76  
77  
78  
79  
80  
81  
82  
83      public static File toJdkHomeFromJvmExec(String jvmExecutable) {
84          File bin = new File(jvmExecutable).getAbsoluteFile().getParentFile();
85          if ("bin".equals(bin.getName())) {
86              File parent = bin.getParentFile();
87              if ("jre".equals(parent.getName())) {
88                  File jdk = parent.getParentFile();
89                  return new File(jdk, "bin").isDirectory() ? jdk : null;
90              }
91              return parent;
92          }
93          return null;
94      }
95  
96      
97  
98  
99  
100 
101 
102 
103     public static File toJdkHomeFromJre() {
104         return toJdkHomeFromJre(System.getProperty("java.home"));
105     }
106 
107     
108 
109 
110 
111 
112 
113 
114 
115 
116     static File toJdkHomeFromJre(String jreHome) {
117         File pathToJreOrJdk = new File(jreHome).getAbsoluteFile();
118         return "jre".equals(pathToJreOrJdk.getName()) ? pathToJreOrJdk.getParentFile() : pathToJreOrJdk;
119     }
120 
121     public static BigDecimal toJdkVersionFromReleaseFile(File jdkHome) {
122         File release = new File(requireNonNull(jdkHome).getAbsoluteFile(), "release");
123         if (!release.isFile()) {
124             return null;
125         }
126         Properties properties = new Properties();
127         try (InputStream is = new FileInputStream(release)) {
128             properties.load(is);
129             String javaVersion = properties.getProperty("JAVA_VERSION").replace("\"", "");
130             StringTokenizer versions = new StringTokenizer(javaVersion, "._");
131 
132             if (versions.countTokens() == 1) {
133                 javaVersion = versions.nextToken();
134             } else if (versions.countTokens() >= 2) {
135                 String majorVersion = versions.nextToken();
136                 String minorVersion = versions.nextToken();
137                 javaVersion = isNumeric(minorVersion) ? majorVersion + "." + minorVersion : majorVersion;
138             } else {
139                 return null;
140             }
141 
142             return new BigDecimal(javaVersion);
143         } catch (IOException e) {
144             return null;
145         }
146     }
147 
148     public static boolean isJava9AtLeast(String jvmExecutablePath) {
149         File externalJavaHome = toJdkHomeFromJvmExec(jvmExecutablePath);
150         File thisJavaHome = toJdkHomeFromJre();
151         if (thisJavaHome.equals(externalJavaHome)) {
152             return isBuiltInJava9AtLeast();
153         } else {
154             BigDecimal releaseFileVersion =
155                     externalJavaHome == null ? null : toJdkVersionFromReleaseFile(externalJavaHome);
156             return isJava9AtLeast(releaseFileVersion);
157         }
158     }
159 
160     public static boolean isBuiltInJava9AtLeast() {
161         return JAVA_RECENT.atLeast(JAVA_9);
162     }
163 
164     public static boolean isJava9AtLeast(BigDecimal version) {
165         return version != null && version.compareTo(JIGSAW_JAVA_VERSION) >= 0;
166     }
167 
168     public static ClassLoader platformClassLoader() {
169         if (isBuiltInJava9AtLeast()) {
170             return reflectClassLoader(ClassLoader.class, "getPlatformClassLoader");
171         }
172         return null;
173     }
174 
175     public static Long pid() {
176         if (isBuiltInJava9AtLeast()) {
177             Long pid = pidOnJava9();
178             if (pid != null) {
179                 return pid;
180             }
181         }
182 
183         if (IS_OS_LINUX) {
184             try {
185                 return pidStatusOnLinux();
186             } catch (Exception e) {
187                 
188             }
189         } else if (IS_OS_FREE_BSD || IS_OS_NET_BSD || IS_OS_OPEN_BSD) {
190             try {
191                 return pidStatusOnBSD();
192             } catch (Exception e) {
193                 
194             }
195         }
196 
197         return pidOnJMX();
198     }
199 
200     static Long pidOnJMX() {
201         String processName = ManagementFactory.getRuntimeMXBean().getName();
202         if (processName.contains("@")) {
203             String pid = processName.substring(0, processName.indexOf('@')).trim();
204             try {
205                 return Long.parseLong(pid);
206             } catch (NumberFormatException e) {
207                 return null;
208             }
209         }
210 
211         return null;
212     }
213 
214     
215 
216 
217 
218 
219 
220 
221 
222 
223 
224 
225 
226 
227 
228 
229 
230     static Long pidStatusOnLinux() throws Exception {
231         return pidStatusOnLinux("");
232     }
233 
234     
235 
236 
237 
238 
239 
240 
241     static Long pidStatusOnLinux(String root) throws Exception {
242         try (FileReader input = new FileReader(root + "/proc/self/stat")) {
243             
244             
245             char[] buffer = new char[PROC_STATUS_PID_FIRST_CHARS];
246             String startLine = new String(buffer, 0, input.read(buffer));
247             return Long.parseLong(startLine.substring(0, startLine.indexOf(' ')));
248         }
249     }
250 
251     
252 
253 
254 
255 
256 
257 
258 
259 
260 
261 
262 
263 
264 
265 
266 
267 
268 
269     static Long pidStatusOnBSD() throws Exception {
270         return pidStatusOnBSD("");
271     }
272 
273     
274 
275 
276 
277 
278 
279 
280     static Long pidStatusOnBSD(String root) throws Exception {
281         try (BufferedReader input = new BufferedReader(new FileReader(root + "/proc/curproc/status"))) {
282             String line = input.readLine();
283             int i1 = 1 + line.indexOf(' ');
284             int i2 = line.indexOf(' ', i1);
285             return Long.parseLong(line.substring(i1, i2));
286         }
287     }
288 
289     static Long pidOnJava9() {
290         ClassLoader classLoader = currentThread().getContextClassLoader();
291         Class<?> processHandle = tryLoadClass(classLoader, "java.lang.ProcessHandle");
292         Class<?>[] classesChain = {processHandle, processHandle};
293         String[] methodChain = {"current", "pid"};
294         return invokeMethodChain(classesChain, methodChain, null);
295     }
296 
297     static ClassLoader reflectClassLoader(Class<?> target, String getterMethodName) {
298         try {
299             Method getter = ReflectionUtils.getMethod(target, getterMethodName);
300             return invokeMethodWithArray(null, getter);
301         } catch (RuntimeException e) {
302             return null;
303         }
304     }
305 }