1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.jar;
20
21 import javax.inject.Named;
22 import javax.inject.Singleton;
23
24 import java.io.BufferedReader;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.io.UncheckedIOException;
29 import java.nio.file.Path;
30 import java.nio.file.Paths;
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Optional;
36
37 import org.apache.maven.toolchain.Toolchain;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41
42
43
44 @Named
45 @Singleton
46 class ToolchainsJdkSpecification {
47
48 private final Logger logger = LoggerFactory.getLogger(ToolchainsJdkSpecification.class);
49
50 private final Map<Path, String> cache = new HashMap<>();
51
52 public synchronized Optional<String> getJDKSpecification(Toolchain toolchain) {
53 Optional<Path> javacPath = getJavacPath(toolchain);
54 return javacPath.map(path -> cache.computeIfAbsent(path, this::getSpecForPath));
55 }
56
57 private Optional<Path> getJavacPath(Toolchain toolchain) {
58 return Optional.ofNullable(toolchain.findTool("javac")).map(Paths::get).map(this::getCanonicalPath);
59 }
60
61 private Path getCanonicalPath(Path path) {
62 try {
63 return path.toRealPath();
64 } catch (IOException e) {
65 if (path.getParent() != null) {
66 return getCanonicalPath(path.getParent()).resolve(path.getFileName());
67 } else {
68 throw new UncheckedIOException(e);
69 }
70 }
71 }
72
73 private String getSpecForPath(Path path) {
74 try {
75 ProcessBuilder processBuilder = new ProcessBuilder(path.toString(), "-version");
76 processBuilder.redirectErrorStream(false);
77 Process process = processBuilder.start();
78 List<String> stdout = readOutput(process.getInputStream());
79 List<String> stderr = readOutput(process.getErrorStream());
80 process.waitFor();
81
82 String version = tryParseVersion(stdout);
83 if (version == null) {
84 version = tryParseVersion(stderr);
85 }
86
87 if (version == null) {
88 logger.warn(
89 "Unrecognized output from {}: stdout: {}, stderr: {}",
90 processBuilder.command(),
91 stdout,
92 stderr);
93 }
94
95 return version;
96 } catch (IndexOutOfBoundsException | IOException e) {
97 logger.warn("Failed to execute: {} - {}", path, e.getMessage());
98 } catch (InterruptedException e) {
99 Thread.currentThread().interrupt();
100 }
101
102 return null;
103 }
104
105 private String tryParseVersion(List<String> versions) {
106 for (String version : versions) {
107 if (version.startsWith("javac ")) {
108 version = version.substring(6);
109 if (version.startsWith("1.")) {
110 version = version.substring(0, 3);
111 } else {
112 version = version.substring(0, 2);
113 }
114 return version;
115 }
116 }
117 return null;
118 }
119
120 private List<String> readOutput(InputStream inputstream) throws IOException {
121 BufferedReader br = new BufferedReader(new InputStreamReader(inputstream));
122
123 List<String> result = new ArrayList<>();
124 String line;
125 while ((line = br.readLine()) != null) {
126 result.add(line);
127 }
128
129 return result;
130 }
131 }