Skip to content

Commit ecf5245

Browse files
authored
Add ModuleExplorer to explore custom controls in modules (#778)
1 parent bb3b5bb commit ecf5245

File tree

4 files changed

+122
-36
lines changed

4 files changed

+122
-36
lines changed

kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/library/LibraryUtil.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,38 @@
3535
import java.io.File;
3636
import java.io.FileNotFoundException;
3737
import java.io.IOException;
38+
import java.lang.module.ModuleReference;
39+
import java.lang.module.ResolvedModule;
3840
import java.nio.file.Files;
3941
import java.nio.file.Path;
4042
import java.util.List;
4143
import java.util.Locale;
44+
import java.util.Optional;
45+
import java.util.Set;
4246
import java.util.stream.Collectors;
4347

4448
public class LibraryUtil {
4549

4650
public static final String FOLDERS_LIBRARY_FILENAME = "library.folders"; //NOI18N
51+
private static Set<ResolvedModule> MODULES;
4752

4853
LibraryUtil() {
4954
// no-op
5055
}
5156

57+
public static Optional<ModuleReference> getModuleReference(Path path) {
58+
if (path == null) {
59+
return Optional.empty();
60+
}
61+
if (MODULES == null) {
62+
MODULES = ModuleLayer.boot().configuration().modules();
63+
}
64+
return MODULES.stream()
65+
.map(ResolvedModule::reference)
66+
.filter(r -> path.equals(r.location().map(Path::of).orElse(null)))
67+
.findFirst();
68+
}
69+
5270
public static boolean isJarPath(Path path) {
5371
final String pathString = path.toString().toLowerCase(Locale.ROOT);
5472
return pathString.endsWith(".jar"); //NOI18N

kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/user/LibraryFolderWatcher.java

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2021, Gluon and/or its affiliates.
2+
* Copyright (c) 2017, 2024, Gluon and/or its affiliates.
33
* Copyright (c) 2012, 2014, Oracle and/or its affiliates.
44
* All rights reserved. Use is subject to license terms.
55
*
@@ -36,6 +36,7 @@
3636
import java.io.IOException;
3737
import java.io.InputStreamReader;
3838
import java.io.LineNumberReader;
39+
import java.lang.module.ModuleReference;
3940
import java.net.MalformedURLException;
4041
import java.net.URL;
4142
import java.net.URLClassLoader;
@@ -53,6 +54,7 @@
5354
import java.util.Date;
5455
import java.util.HashSet;
5556
import java.util.List;
57+
import java.util.Optional;
5658
import java.util.Set;
5759
import java.util.logging.Logger;
5860
import java.util.stream.Collectors;
@@ -66,6 +68,7 @@
6668
import com.oracle.javafx.scenebuilder.kit.library.util.JarExplorer;
6769
import com.oracle.javafx.scenebuilder.kit.library.util.JarReport;
6870
import com.oracle.javafx.scenebuilder.kit.library.util.JarReportEntry;
71+
import com.oracle.javafx.scenebuilder.kit.library.util.ModuleExplorer;
6972

7073
/**
7174
*
@@ -348,49 +351,55 @@ private LibraryItem makeLibraryItem(Path path) throws IOException {
348351
}
349352

350353

351-
private void exploreAndUpdateLibrary(Collection<Path> jarsOrFolders) throws IOException {
354+
private void exploreAndUpdateLibrary(Collection<Path> modulesOrJarsOrFolders) throws IOException {
352355

353356
// 1) we create a classloader
354-
// 2) we explore all the jars and folders
357+
// 2) we explore all the modules, jars, and folders
355358
// 3) we construct a list of library items
356359
// 4) we update the user library with the class loader and items
357360
// 5) on startup only, we allow opening files that may/may not rely on the user library
358361

359362
// 1)
360363
final ClassLoader classLoader;
361-
if (jarsOrFolders.isEmpty()) {
364+
if (modulesOrJarsOrFolders.isEmpty()) {
362365
classLoader = null;
363366
} else {
364-
classLoader = new URLClassLoader(makeURLArrayFromPaths(jarsOrFolders));
367+
classLoader = new URLClassLoader(makeURLArrayFromPaths(modulesOrJarsOrFolders));
365368
}
366369

367370
// 2)
368-
final List<JarReport> jarOrFolderReports = new ArrayList<>();
369-
// boolean shouldShowImportGluonJarAlert = false;
370-
for (Path currentJarOrFolder : jarsOrFolders) {
371-
String jarName = currentJarOrFolder.getName(currentJarOrFolder.getNameCount() - 1).toString();
371+
final List<JarReport> moduleOrJarOrFolderReports = new ArrayList<>();
372+
for (Path currentModuleOrJarOrFolder : modulesOrJarsOrFolders) {
373+
String jarName = currentModuleOrJarOrFolder.getName(currentModuleOrJarOrFolder.getNameCount() - 1).toString();
372374
if (JAVAFX_MODULES.stream().anyMatch(jarName::startsWith)) {
373375
continue;
374376
}
375377

376378
JarReport jarReport;
377379
String resultText = "";
378-
if (LibraryUtil.isJarPath(currentJarOrFolder)) {
379-
LOGGER.info(I18N.getString("log.info.explore.jar", currentJarOrFolder));
380-
final JarExplorer explorer = new JarExplorer(currentJarOrFolder);
380+
Optional<ModuleReference> moduleReference = LibraryUtil.getModuleReference(currentModuleOrJarOrFolder);
381+
if (moduleReference.isPresent()) {
382+
LOGGER.info(I18N.getString("log.info.explore.module", moduleReference.get().descriptor()));
383+
final ModuleExplorer explorer = new ModuleExplorer(moduleReference.get());
384+
jarReport = explorer.explore();
385+
resultText = I18N.getString("log.info.explore.module.results", jarName);
386+
}
387+
else if (LibraryUtil.isJarPath(currentModuleOrJarOrFolder)) {
388+
LOGGER.info(I18N.getString("log.info.explore.jar", currentModuleOrJarOrFolder));
389+
final JarExplorer explorer = new JarExplorer(currentModuleOrJarOrFolder);
381390
jarReport = explorer.explore(classLoader);
382391
resultText = I18N.getString("log.info.explore.jar.results", jarName);
383392
}
384-
else if (Files.isDirectory(currentJarOrFolder)) {
385-
LOGGER.info(I18N.getString("log.info.explore.folder", currentJarOrFolder));
386-
final FolderExplorer explorer = new FolderExplorer(currentJarOrFolder);
393+
else if (Files.isDirectory(currentModuleOrJarOrFolder)) {
394+
LOGGER.info(I18N.getString("log.info.explore.folder", currentModuleOrJarOrFolder));
395+
final FolderExplorer explorer = new FolderExplorer(currentModuleOrJarOrFolder);
387396
jarReport = explorer.explore(classLoader);
388397
resultText = I18N.getString("log.info.explore.folder.results", jarName);
389398
} else {
390399
continue;
391400
}
392401

393-
jarOrFolderReports.add(jarReport);
402+
moduleOrJarOrFolderReports.add(jarReport);
394403

395404
StringBuilder sb = new StringBuilder(resultText).append("\n");
396405
if (jarReport.getEntries().isEmpty()) {
@@ -400,26 +409,13 @@ else if (Files.isDirectory(currentJarOrFolder)) {
400409
}
401410
LOGGER.info(sb.toString());
402411

403-
LOGGER.info(I18N.getString("log.info.explore.end", currentJarOrFolder));
404-
405-
// if (jarReport.hasGluonControls()) {
406-
// // We check if the jar has already been imported to avoid showing the import gluon jar
407-
// // alert every time Scene Builder starts for jars that have already been imported
408-
// if (!hasGluonJarBeenImported(jarReport.getJar().getFileName().toString())) {
409-
// shouldShowImportGluonJarAlert = true;
410-
// }
411-
//
412-
// }
412+
LOGGER.info(I18N.getString("log.info.explore.end", currentModuleOrJarOrFolder));
413413
}
414414

415-
// if (shouldShowImportGluonJarAlert && onImportingGluonControls != null) {
416-
// onImportingGluonControls.run();
417-
// }
418-
419415
// 3)
420416
final List<LibraryItem> newItems = new ArrayList<>();
421-
for (JarReport jarOrFolderReport : jarOrFolderReports) {
422-
newItems.addAll(makeLibraryItems(jarOrFolderReport));
417+
for (JarReport moduleOrJarOrFolderReport : moduleOrJarOrFolderReports) {
418+
newItems.addAll(makeLibraryItems(moduleOrJarOrFolderReport));
423419
}
424420

425421
// 4)
@@ -429,8 +425,8 @@ else if (Files.isDirectory(currentJarOrFolder)) {
429425
.stream()
430426
.distinct()
431427
.collect(Collectors.toList()));
432-
library.updateJarReports(new ArrayList<>(jarOrFolderReports));
433-
library.getOnFinishedUpdatingJarReports().accept(jarOrFolderReports);
428+
library.updateJarReports(new ArrayList<>(moduleOrJarOrFolderReports));
429+
library.getOnFinishedUpdatingJarReports().accept(moduleOrJarOrFolderReports);
434430
library.updateExplorationDate(new Date());
435431

436432
// 5
@@ -471,9 +467,9 @@ private URL[] makeURLArrayFromPaths(Collection<Path> paths) {
471467
if (url.toString().endsWith(".jar")) {
472468
result[i++] = new URL("jar", "", url + "!/"); // <-- jar:file/path/to/jar!/
473469
} else {
474-
result[i++] = url; // <-- file:/path/to/folder/
470+
result[i++] = url; // <-- file:/path/to/folder/ or jrt:/module.name
475471
}
476-
} catch(MalformedURLException x) {
472+
} catch (MalformedURLException x) {
477473
throw new RuntimeException("Bug in " + getClass().getSimpleName(), x); //NOI18N
478474
}
479475
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright (c) 2024, Gluon and/or its affiliates.
3+
* All rights reserved. Use is subject to license terms.
4+
*
5+
* This file is available and licensed under the following license:
6+
*
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions
9+
* are met:
10+
*
11+
* - Redistributions of source code must retain the above copyright
12+
* notice, this list of conditions and the following disclaimer.
13+
* - Redistributions in binary form must reproduce the above copyright
14+
* notice, this list of conditions and the following disclaimer in
15+
* the documentation and/or other materials provided with the distribution.
16+
* - Neither the name of Oracle Corporation nor the names of its
17+
* contributors may be used to endorse or promote products derived
18+
* from this software without specific prior written permission.
19+
*
20+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
*/
32+
package com.oracle.javafx.scenebuilder.kit.library.util;
33+
34+
import com.oracle.javafx.scenebuilder.kit.library.util.JarReportEntry.Status;
35+
36+
import java.io.IOException;
37+
import java.lang.module.ModuleReader;
38+
import java.lang.module.ModuleReference;
39+
import java.nio.file.Path;
40+
41+
public class ModuleExplorer extends ExplorerBase {
42+
43+
private final ModuleReference moduleReference;
44+
private final Module module;
45+
46+
public ModuleExplorer(ModuleReference moduleReference) {
47+
assert moduleReference != null;
48+
this.moduleReference = moduleReference;
49+
this.module = ModuleLayer.boot().findModule(moduleReference.descriptor().name()).orElseThrow();
50+
}
51+
52+
public JarReport explore() throws IOException {
53+
ClassLoader classLoader = module.getClassLoader();
54+
final JarReport result = new JarReport(moduleReference.location().map(Path::of).orElse(null));
55+
try (ModuleReader reader = moduleReference.open()) {
56+
reader.list().forEach(cl -> {
57+
if (cl.endsWith(".class")) {
58+
String className = cl.substring(0, cl.length() - ".class".length()).replaceAll("/", ".");
59+
JarReportEntry explored = super.exploreEntry(cl, classLoader, className);
60+
if (explored.getStatus() != Status.IGNORED) {
61+
result.getEntries().add(explored);
62+
}
63+
}
64+
});
65+
}
66+
67+
return result;
68+
}
69+
70+
}

kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,10 @@ label.qualifier.vertical = (vertical)
7171
# -----------------------------------------------------------------------------
7272
log.info.explore.end = End exploring {0}
7373
log.info.explore.folder = Start exploring FOLDER {0}
74+
log.info.explore.module = Start exploring MODULE {0}
7475
log.info.explore.jar = Start exploring JAR {0}
7576
log.info.explore.jar.results = Results of exploring JAR {0}
77+
log.info.explore.module.results = Results of exploring MODULE {0}
7678
log.info.explore.folder.results = Results of exploring FOLDER {0}
7779
log.info.explore.no.results = No custom controls found
7880
log.warning.inline.edit.internationalized.strings = Can''t inline edit internationalized strings

0 commit comments

Comments
 (0)