-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathToolFinder.java
More file actions
153 lines (133 loc) · 4.02 KB
/
ToolFinder.java
File metadata and controls
153 lines (133 loc) · 4.02 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
/*
* Copyright (c) 2024 Christian Stein
* Licensed under the Universal Permissive License v 1.0 -> https://opensource.org/license/upl
*/
package run.bach;
import java.lang.module.ModuleFinder;
import java.util.List;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.spi.ToolProvider;
import java.util.stream.Stream;
import run.bach.internal.ModulesSupport;
/**
* A finder of tools.
*
* <p>Usage example:
*
* <pre>{@code
* ToolFinder.compose(
* ToolFinder.of("jar", "javac", "javadoc"),
* ToolFinder.of("java", "jfr")
* )
* }</pre>
*/
@FunctionalInterface
public interface ToolFinder {
/** {@return a list of tool instances of this finder, possibly empty} */
List<Tool> tools();
/**
* {@return an instance of a tool for the given tool-identifying name}
*
* @param name the name of the tool to lookup
*/
default Optional<Tool> find(String name) {
return tools().stream().filter(tool -> tool.identifier().matches(name)).findFirst();
}
/**
* {@return an instance of a tool for the given tool-identifying name}
*
* @param name the name of the tool to lookup
* @throws ToolNotFoundException when a tool could not be found the given name
*/
default Tool get(String name) {
var tool = find(name);
if (tool.isPresent()) return tool.get();
throw new ToolNotFoundException("Tool not found for name: " + name);
}
/**
* {@return a tool finder composed all tools specified by their names}
*
* @param tools the names of the tools to be looked-up
* @throws ToolNotFoundException if any tool could not be found
*/
static ToolFinder of(String... tools) {
return of(Stream.of(tools).map(Tool::of).toArray(Tool[]::new));
}
/**
* {@return a tool finder composed of a sequence of zero or more tools}
*
* @param tools the array of tools
*/
static ToolFinder of(Tool... tools) {
return new DefaultFinder(List.of(tools));
}
static ToolFinder of(ModuleFinder finder) {
var layer = ModulesSupport.buildModuleLayer(finder);
return of(layer);
}
static ToolFinder of(ModuleLayer layer) {
var tools =
ServiceLoader.load(layer, ToolProvider.class).stream()
.filter(service -> service.type().getModule().getLayer() == layer)
.map(ServiceLoader.Provider::get)
.map(Tool::of)
.toList();
return new DefaultFinder(tools);
}
static ToolInstaller.Finder ofInstaller() {
return ToolInstaller.finder(ToolInstaller.Mode.INSTALL_ON_DEMAND);
}
static ToolInstaller.Finder ofInstaller(ToolInstaller.Mode mode) {
return ToolInstaller.finder(mode);
}
static ToolFinder ofSystem() {
return new SystemFinder();
}
/**
* {@return a tool finder that is composed of a sequence of zero or more tool finders}
*
* @param finders the array of tool finders
*/
static ToolFinder compose(ToolFinder... finders) {
return new CompositeFinder(List.of(finders));
}
record CompositeFinder(List<ToolFinder> finders) implements ToolFinder {
public CompositeFinder {
finders = List.copyOf(finders);
}
@Override
public List<Tool> tools() {
return finders.stream().flatMap(finder -> finder.tools().stream()).toList();
}
@Override
public Optional<Tool> find(String name) {
for (var finder : finders) {
var tool = finder.find(name);
if (tool.isPresent()) return tool;
}
return Optional.empty();
}
}
record DefaultFinder(List<Tool> tools) implements ToolFinder {
public DefaultFinder {
tools = List.copyOf(tools);
}
}
record SystemFinder() implements ToolFinder {
@Override
public List<Tool> tools() {
// TODO Load tool providers using the context class loader.
// TODO List tool programs of the current JDK's bin folder.
return List.of();
}
@Override
public Optional<Tool> find(String name) {
try {
return Optional.of(Tool.of(name));
} catch (ToolNotFoundException exception) {
return Optional.empty();
}
}
}
}