1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  package org.apache.maven.plugin.compiler;
20  
21  import javax.lang.model.element.Modifier;
22  import javax.lang.model.element.NestingKind;
23  import javax.tools.FileObject;
24  import javax.tools.JavaFileObject;
25  import javax.tools.StandardJavaFileManager;
26  import javax.tools.StandardLocation;
27  
28  import java.io.File;
29  import java.io.IOException;
30  import java.io.InputStream;
31  import java.io.OutputStream;
32  import java.io.Reader;
33  import java.io.UncheckedIOException;
34  import java.io.Writer;
35  import java.net.URI;
36  import java.nio.charset.Charset;
37  import java.nio.file.Files;
38  import java.nio.file.Path;
39  import java.util.Arrays;
40  import java.util.Collection;
41  import java.util.HashMap;
42  import java.util.Iterator;
43  import java.util.List;
44  import java.util.Map;
45  import java.util.Optional;
46  import java.util.Set;
47  import java.util.StringJoiner;
48  import java.util.stream.Stream;
49  import java.util.stream.StreamSupport;
50  
51  import org.apache.maven.api.JavaPathType;
52  import org.apache.maven.api.PathType;
53  
54  
55  
56  
57  
58  
59  
60  
61  final class ForkedToolSources implements StandardJavaFileManager {
62      
63  
64  
65  
66      private enum SourcePathType implements PathType {
67          
68  
69  
70          SOURCES("--source-path"),
71  
72          
73  
74  
75          GENERATED_SOURCES("-s"),
76  
77          
78  
79  
80          OUTPUT("-d");
81  
82          
83  
84  
85          private final String option;
86  
87          SourcePathType(String option) {
88              this.option = option;
89          }
90  
91          @Override
92          public String id() {
93              return name();
94          }
95  
96          @Override
97          public Optional<String> option() {
98              return Optional.of(option);
99          }
100 
101         @Override
102         public String[] option(Iterable<? extends Path> paths) {
103             var builder = new StringJoiner(File.pathSeparator);
104             paths.forEach((path) -> builder.add(path.toString()));
105             return new String[] {option, builder.toString()};
106         }
107     };
108 
109     
110 
111 
112 
113 
114 
115 
116     private final Map<PathType, Collection<? extends Path>> locations;
117 
118     
119 
120 
121     final Charset encoding;
122 
123     
124 
125 
126     ForkedToolSources(Charset encoding) {
127         if (encoding == null) {
128             encoding = Charset.defaultCharset();
129         }
130         this.encoding = encoding;
131         locations = new HashMap<>();
132     }
133 
134     
135 
136 
137 
138     @Override
139     public int isSupportedOption(String option) {
140         return -1;
141     }
142 
143     
144 
145 
146     @Override
147     public boolean handleOption(String current, Iterator<String> remaining) {
148         return false;
149     }
150 
151     
152 
153 
154     @Override
155     public Path asPath(FileObject file) {
156         return (file instanceof Item) ? ((Item) file).path : Path.of(file.toUri());
157     }
158 
159     
160 
161 
162 
163     @Override
164     public boolean isSameFile(FileObject a, FileObject b) {
165         return asPath(a).equals(asPath(b));
166     }
167 
168     
169 
170 
171     @Override
172     public Iterable<? extends JavaFileObject> getJavaFileObjects(String... names) {
173         return fromNames(Arrays.stream(names));
174     }
175 
176     
177 
178 
179     @Override
180     public Iterable<? extends JavaFileObject> getJavaFileObjects(File... files) {
181         return fromFiles(Arrays.stream(files));
182     }
183 
184     
185 
186 
187     @Override
188     public Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) {
189         return fromNames(StreamSupport.stream(names.spliterator(), false));
190     }
191 
192     
193 
194 
195     @Override
196     public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) {
197         return fromFiles(StreamSupport.stream(files.spliterator(), false));
198     }
199 
200     
201 
202 
203     @Override
204     public Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths(Collection<? extends Path> paths) {
205         return paths.stream().map(Item::new).toList();
206     }
207 
208     
209 
210 
211     private Iterable<? extends JavaFileObject> fromFiles(Stream<? extends File> files) {
212         return files.map((file) -> new Item(file.toPath())).toList();
213     }
214 
215     
216 
217 
218     private Iterable<? extends JavaFileObject> fromNames(Stream<? extends String> names) {
219         return names.map((name) -> new Item(Path.of(name))).toList();
220     }
221 
222     
223 
224 
225 
226 
227     private final class Item implements JavaFileObject {
228         
229 
230 
231         final Path path;
232 
233         
234 
235 
236         Item(Path path) {
237             this.path = path;
238         }
239 
240         
241 
242 
243         @Override
244         public String getName() {
245             return path.toString();
246         }
247 
248         
249 
250 
251         @Override
252         public String toString() {
253             return getName();
254         }
255 
256         
257 
258 
259         @Override
260         public URI toUri() {
261             return path.toUri();
262         }
263 
264         
265 
266 
267         @Override
268         public Kind getKind() {
269             String filename = path.getFileName().toString();
270             for (Kind k : Kind.values()) {
271                 if (filename.endsWith(k.extension)) {
272                     return k;
273                 }
274             }
275             return Kind.OTHER;
276         }
277 
278         
279 
280 
281         @Override
282         public boolean isNameCompatible(String simpleName, Kind kind) {
283             return path.getFileName().toString().equals(simpleName.concat(kind.extension));
284         }
285 
286         
287 
288 
289         @Override
290         public NestingKind getNestingKind() {
291             return null;
292         }
293 
294         
295 
296 
297         @Override
298         public Modifier getAccessLevel() {
299             return null;
300         }
301 
302         
303 
304 
305         @Override
306         public long getLastModified() {
307             try {
308                 return Files.getLastModifiedTime(path).toMillis();
309             } catch (IOException e) {
310                 throw new UncheckedIOException(e);
311             }
312         }
313 
314         
315 
316 
317         @Override
318         public boolean delete() {
319             try {
320                 return Files.deleteIfExists(path);
321             } catch (IOException e) {
322                 throw new UncheckedIOException(e);
323             }
324         }
325 
326         
327 
328 
329 
330         @Override
331         public InputStream openInputStream() throws IOException {
332             return Files.newInputStream(path);
333         }
334 
335         
336 
337 
338 
339         @Override
340         public OutputStream openOutputStream() throws IOException {
341             return Files.newOutputStream(path);
342         }
343 
344         
345 
346 
347 
348         @Override
349         public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
350             return Files.newBufferedReader(path, encoding);
351         }
352 
353         
354 
355 
356 
357         @Override
358         public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
359             return Files.readString(path, encoding);
360         }
361 
362         
363 
364 
365 
366         @Override
367         public Writer openWriter() throws IOException {
368             return Files.newBufferedWriter(path, encoding);
369         }
370     }
371 
372     
373 
374 
375 
376 
377 
378     @Override
379     public void setLocation(Location location, Iterable<? extends File> files) {
380         List<Path> paths = null;
381         if (files != null) {
382             paths = StreamSupport.stream(files.spliterator(), false)
383                     .map(File::toPath)
384                     .toList();
385         }
386         setLocationFromPaths(location, paths);
387     }
388 
389     
390 
391 
392 
393 
394 
395     @Override
396     public Iterable<? extends File> getLocation(Location location) {
397         var paths = getLocationAsPaths(location);
398         if (paths != null) {
399             return paths.stream().map(Path::toFile).toList();
400         }
401         return null;
402     }
403 
404     
405 
406 
407 
408 
409     @Override
410     public void setLocationFromPaths(Location location, Collection<? extends Path> paths) {
411         PathType type = JavaPathType.valueOf(location).orElse(null);
412         if (type == null) {
413             if (location == StandardLocation.SOURCE_OUTPUT) {
414                 type = SourcePathType.GENERATED_SOURCES;
415             } else if (location == StandardLocation.SOURCE_PATH) {
416                 type = SourcePathType.SOURCES;
417             } else if (location == StandardLocation.CLASS_OUTPUT) {
418                 type = SourcePathType.OUTPUT;
419             } else {
420                 throw new IllegalArgumentException("Unsupported location: " + location);
421             }
422         }
423         if (paths == null || paths.isEmpty()) {
424             locations.remove(type);
425         } else {
426             locations.put(type, paths);
427         }
428     }
429 
430     
431 
432 
433     @Override
434     public Collection<? extends Path> getLocationAsPaths(Location location) {
435         return locations.get(JavaPathType.valueOf(location).orElse(null));
436     }
437 
438     
439 
440 
441 
442     @Override
443     public boolean hasLocation(Location location) {
444         return getLocationAsPaths(location) != null;
445     }
446 
447     
448 
449 
450 
451 
452     void addAllLocations(List<String> command) {
453         for (Map.Entry<PathType, Collection<? extends Path>> entry : locations.entrySet()) {
454             for (String element : entry.getKey().option(entry.getValue())) {
455                 command.add(element);
456             }
457         }
458     }
459 
460     
461 
462 
463     @Override
464     public Iterable<JavaFileObject> list(
465             Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse) throws IOException {
466         throw new UnsupportedOperationException("Not supported yet.");
467     }
468 
469     
470 
471 
472     @Override
473     public String inferBinaryName(Location location, JavaFileObject file) {
474         throw new UnsupportedOperationException("Not supported yet.");
475     }
476 
477     
478 
479 
480     @Override
481     public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind)
482             throws IOException {
483         throw new UnsupportedOperationException("Not supported yet.");
484     }
485 
486     
487 
488 
489     @Override
490     public JavaFileObject getJavaFileForOutput(
491             Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
492         throw new UnsupportedOperationException("Not supported yet.");
493     }
494 
495     
496 
497 
498     @Override
499     public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
500         throw new UnsupportedOperationException("Not supported yet.");
501     }
502 
503     
504 
505 
506     @Override
507     public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling)
508             throws IOException {
509         throw new UnsupportedOperationException("Not supported yet.");
510     }
511 
512     
513 
514 
515     @Override
516     public ClassLoader getClassLoader(Location location) {
517         return null;
518     }
519 
520     
521 
522 
523     @Override
524     public void flush() {}
525 
526     
527 
528 
529     @Override
530     public void close() {
531         locations.clear();
532     }
533 }