-
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathJdk.java
More file actions
384 lines (323 loc) · 9.06 KB
/
Jdk.java
File metadata and controls
384 lines (323 loc) · 9.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
package dev.jbang.devkitman;
import static dev.jbang.devkitman.util.FileUtils.realPath;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Predicate;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import dev.jbang.devkitman.jdkproviders.ExternalJdkProvider;
import dev.jbang.devkitman.util.JavaUtils;
public interface Jdk extends Comparable<Jdk> {
/**
* Returns the provider that is responsible for this JDK
*/
@NonNull
JdkProvider provider();
/**
* Returns the id that is used to uniquely identify this JDK across all
* providers
*/
@NonNull
String id();
/**
* Returns the JDK's version
*/
@NonNull
String version();
/**
* Returns the tags that are associated with this JDK
*/
@NonNull
Set<String> tags();
/**
* Returns the major version of the JDK
*/
default int majorVersion() {
return JavaUtils.parseJavaVersion(version());
}
/**
* Determines if this JDK is currently installed
*/
boolean isInstalled();
interface AvailableJdk extends Jdk {
@Override
default boolean isInstalled() {
return false;
}
/**
* Installs the JDK if it isn't already installed. If already installed it will
* simply return the current object, if not it will return a new copy with
* updated information (e.g. the home path will be set)
*
* @return A <code>Jdk</code> object
*/
@NonNull
InstalledJdk install();
class Default extends Jdk.Default implements AvailableJdk {
public Default(
@NonNull JdkProvider provider,
@NonNull String id,
@NonNull String version,
@Nullable Set<String> tags) {
super(provider, id, version, tags);
}
@Override
@NonNull
public InstalledJdk install() {
return provider.manager().installJdk(this);
}
@Override
public String toString() {
return majorVersion() + " (" + version + ", " + id + ", " + tags + "))";
}
}
}
interface InstalledJdk extends Jdk {
/**
* The path to where the JDK is installed. Can be <code>null</code> which means
* the JDK isn't currently installed by that provider
*/
@NonNull
Path home();
@Override
default boolean isInstalled() {
return true;
}
/**
* Uninstalls the JDK. If the JDK isn't installed it will do nothing
*/
void uninstall();
class Default extends Jdk.Default implements InstalledJdk {
@Nullable
private final Path home;
enum Tags {
Jre, Jdk, Graalvm, Native, Javafx
}
public Default(
@NonNull JdkProvider provider,
@NonNull String id,
@Nullable Path home,
@NonNull String version,
@Nullable Set<String> tags) {
super(provider, id, version, tags != null ? tags : determineTagsFromJdkHome(home));
this.home = home;
}
@Override
@NonNull
public Path home() {
if (home == null) {
throw new IllegalStateException(
"Trying to retrieve home folder for uninstalled JDK");
}
return home;
}
@Override
public void uninstall() {
provider.manager().uninstallJdk(this);
}
@Override
public boolean isInstalled() {
return home != null;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
InstalledJdk.Default jdk = (InstalledJdk.Default) o;
return id.equals(jdk.id) && Objects.equals(home, jdk.home);
}
@Override
public int hashCode() {
return Objects.hash(home, id);
}
@Override
public int compareTo(Jdk o) {
return Integer.compare(majorVersion(), o.majorVersion());
}
@Override
public String toString() {
return majorVersion() + " (" + version + (provider.hasFixedVersions() ? " [fixed]" : " [dynamic]")
+ ", " + id + ", " + home + ", " + tags + "))";
}
@NonNull
public static Set<String> determineTagsFromJdkHome(@Nullable Path home) {
if (home == null) {
return Collections.emptySet();
}
Set<String> tags = new HashSet<>();
if (JavaUtils.hasJavacCmd(home)) {
tags.add(Jdk.Default.Tags.Jdk.name());
} else if (JavaUtils.hasJavaCmd(home)) {
tags.add(Jdk.Default.Tags.Jre.name());
}
Optional<String> version = JavaUtils.resolveJavaVersionStringFromPath(home);
if (version.isPresent()) {
if (version.get().matches(".*\\b(ea|EA)\\b.*")) {
tags.add(Jdk.Default.Tags.Ea.name());
} else {
tags.add(Jdk.Default.Tags.Ga.name());
}
}
Optional<String> graalVersion = JavaUtils.readGraalVMVersionStringFromReleaseFile(home);
if (graalVersion.isPresent()) {
tags.add(Jdk.Default.Tags.Graalvm.name());
if (JavaUtils.hasNativeImageCmd(home)) {
tags.add(Jdk.Default.Tags.Native.name());
}
}
Path javafxProps = home.resolve("lib").resolve("javafx.properties");
if (Files.exists(javafxProps)) {
tags.add(Jdk.Default.Tags.Javafx.name());
}
return tags;
}
}
}
interface LinkedJdk extends InstalledJdk {
@NonNull
InstalledJdk linked();
class Default extends InstalledJdk.Default implements LinkedJdk {
public Default(
@NonNull JdkProvider provider,
@NonNull String id,
@Nullable Path home,
@NonNull String version,
@Nullable Set<String> tags) {
super(provider, id, home, version, tags);
}
@Override
@NonNull
public InstalledJdk linked() {
Path jdkHome;
try {
jdkHome = home().toRealPath();
} catch (Exception e) {
jdkHome = home().toAbsolutePath();
}
// First look for a Jdk in updatable non-linking providers
InstalledJdk linkedJdk = getLinkedJdk(jdkHome, p -> p.canUpdate() && !p.hasLinkedVersions());
if (linkedJdk == null) {
// Then check the non-updatable non-linking providers
linkedJdk = getLinkedJdk(jdkHome, p -> !p.canUpdate() && !p.hasLinkedVersions());
}
if (linkedJdk == null) {
// Finally fall back to the "external" provider
linkedJdk = (new ExternalJdkProvider()).getInstalledByPath(jdkHome);
assert linkedJdk != null;
}
return linkedJdk;
}
private InstalledJdk getLinkedJdk(Path jdkHome, Predicate<JdkProvider> providerFilter) {
return provider().manager()
.providers()
.stream()
.filter(providerFilter)
.map(p -> p.getInstalledByPath(jdkHome))
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
}
}
abstract class Default implements Jdk {
@NonNull
protected final transient JdkProvider provider;
@NonNull
protected final String id;
@NonNull
protected final String version;
@NonNull
protected final Set<String> tags;
public enum Tags {
Jre, Jdk, Graalvm, Native, Javafx, Ea, Ga
}
Default(
@NonNull JdkProvider provider,
@NonNull String id,
@NonNull String version,
@Nullable Set<String> tags) {
this.provider = provider;
this.id = id;
this.version = version;
TreeSet<String> ts = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
if (tags != null) {
ts.addAll(tags);
}
this.tags = Collections.unmodifiableSet(ts);
}
@Override
@NonNull
public JdkProvider provider() {
return provider;
}
@Override
@NonNull
public String id() {
return id;
}
@Override
@NonNull
public String version() {
return version;
}
@Override
@NonNull
public Set<String> tags() {
return tags;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Default jdk = (Default) o;
return id.equals(jdk.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public int compareTo(Jdk o) {
return Integer.compare(majorVersion(), o.majorVersion());
}
}
class Predicates {
public static final Predicate<? extends Jdk> all = provider -> true;
public static <T extends Jdk> Predicate<T> exactVersion(int version) {
return jdk -> jdk.majorVersion() == version;
}
public static <T extends Jdk> Predicate<T> openVersion(int version) {
return jdk -> jdk.majorVersion() >= version;
}
public static <T extends Jdk> Predicate<T> minVersion(int version) {
return jdk -> jdk.majorVersion() >= version;
}
public static <T extends Jdk> Predicate<T> maxVersion(int version) {
return jdk -> jdk.majorVersion() <= version;
}
public static <T extends Jdk> Predicate<T> forVersion(String version) {
int v = JavaUtils.parseJavaVersion(version);
return forVersion(v, JavaUtils.isOpenVersion(version));
}
public static <T extends Jdk> Predicate<T> forVersion(int version, boolean openVersion) {
return openVersion ? openVersion(version) : exactVersion(version);
}
public static <T extends Jdk> Predicate<T> id(String id) {
return jdk -> jdk.id().equals(id);
}
public static <T extends Jdk> Predicate<T> allTags(Set<String> tags) {
return jdk -> jdk.tags().containsAll(tags);
}
public static <T extends InstalledJdk> Predicate<T> fixedVersion() {
return jdk -> jdk.provider().hasFixedVersions();
}
public static <T extends InstalledJdk> Predicate<T> path(Path jdkPath) {
return jdk -> realPath(jdkPath).startsWith(realPath(jdk.home()));
}
}
}