1+ /* Copyright (c) 2021 Chunky contributors
2+ *
3+ * This file is part of Chunky.
4+ *
5+ * Chunky is free software: you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published by
7+ * the Free Software Foundation, either version 3 of the License, or
8+ * (at your option) any later version.
9+ *
10+ * Chunky is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ * You should have received a copy of the GNU General Public License
15+ * along with Chunky. If not, see <http://www.gnu.org/licenses/>.
16+ */
117package se .llbit .chunky .launcher ;
218
319import java .io .File ;
420import java .io .IOException ;
521import java .lang .management .ManagementFactory ;
622import java .net .URISyntaxException ;
23+ import java .nio .file .DirectoryStream ;
24+ import java .nio .file .Files ;
725import java .nio .file .Path ;
26+ import java .nio .file .Paths ;
827import java .util .ArrayList ;
928import java .util .Arrays ;
10- import java .util .List ;
29+ import java .util .LinkedHashSet ;
1130
1231public class JavaFxLocator {
1332
33+ /**
34+ * Lazy set of absolute paths to JavaFX library folders.
35+ * Filled using {@link #scanForJavaFXLibs()}.
36+ */
37+ private static final LinkedHashSet <Path > javafxPathCandidates = new LinkedHashSet <>();
1438
15- private static final List <String > javafxPathCandidates ;
39+ private static void scanForJavaFXLibs () {
40+ // working directory (local lib overwrites installed system libs)
41+ addJavaFXPathIfValid (getJavaFXPathBySystemProperty ("user.dir" ));
42+ try {
43+ // directory of the .jar
44+ File executableFile = new File (
45+ ChunkyLauncher .class .getProtectionDomain ().getCodeSource ().getLocation ().toURI ());
46+ addJavaFXPathIfValid (executableFile .toPath ().getParent ());
47+ } catch (URISyntaxException ignored ) {
48+ }
49+
50+ // home directory installation
51+ Path userHomePath = getJavaFXPathBySystemProperty ("user.home" );
52+ if (userHomePath != null ) {
53+ addJavaFXPathIfValid (userHomePath .resolve (".chunky" ), true );
54+ }
1655
17- static {
18- javafxPathCandidates = new ArrayList <>();
19- javafxPathCandidates .add ("C:\\ Program Files\\ openjfx\\ lib" );
20- javafxPathCandidates .add ("/usr/share/openjfx/lib" );
21- javafxPathCandidates .add ("/usr/lib/jvm/java-11-openjdk/lib" );
22- javafxPathCandidates .add ("/usr/lib/jvm/java-12-openjdk/lib" );
23- javafxPathCandidates .add ("/usr/lib/jvm/java-13-openjdk/lib" );
24- javafxPathCandidates .add ("/usr/lib/jvm/java-14-openjdk/lib" );
25- javafxPathCandidates .add ("/usr/lib/jvm/java-15-openjdk/lib" );
56+ // java home
57+ Path javaHomePath = getJavaFXPathBySystemProperty ("java.home" );
58+ addJavaFXPathIfValid (javaHomePath );
59+
60+ if (System .getProperty ("os.name" ).startsWith ("Windows" )) {
61+ // windows paths
62+ if (javaHomePath != null &&
63+ (javaHomePath .endsWith ("jre" ) || javaHomePath .endsWith ("jdk" ))) {
64+ // if jre is in a subfolder of the jdk, try jdks lib path (example: OpenJDK from odjkbuild)
65+ addJavaFXPathIfValid (javaHomePath .getParent (), true );
66+ }
67+ addJavaFXPathIfValid ("C:\\ Program Files\\ openjfx" );
68+ } else {
69+ // linux paths
70+ addJavaFXPathIfValid ("/usr/share/openjfx" );
71+ for (int javaVersion = 11 ; javaVersion <= 17 ; javaVersion ++) {
72+ addJavaFXPathIfValid ("/usr/lib/jvm/java-" + javaVersion + "-openjdk" );
73+ }
74+ }
75+ }
2676
27- javafxPathCandidates .add (System .getProperty ("java.home" , "" ) + File .separator + "lib" ); // java home
28- javafxPathCandidates .add (System .getProperty ("user.dir" , "" ) + File .separator + "lib" ); // working directory
77+ private static Path getJavaFXPathBySystemProperty (String propertyName ) {
2978 try {
30- javafxPathCandidates .add (new File (ChunkyLauncher .class .getProtectionDomain ().getCodeSource ().getLocation ().toURI ())
31- .toPath ().getParent ().toAbsolutePath ().toString () + File .separator + "lib" ); // directory of the .jar
32- } catch (URISyntaxException e ) {
33- e .printStackTrace ();
79+ String propertyValue = System .getProperty (propertyName );
80+ if (propertyValue != null ) {
81+ return Paths .get (propertyValue );
82+ }
83+ } catch (SecurityException ignored ) {
84+ }
85+ return null ;
86+ }
87+
88+
89+ private static void addJavaFXPathIfValid (String path ) {
90+ addJavaFXPathIfValid (Paths .get (path ), false );
91+ }
92+
93+ private static void addJavaFXPathIfValid (Path path ) {
94+ addJavaFXPathIfValid (path , false );
95+ }
96+
97+ /**
98+ * Validates the path to contain the required JavaFX library files.
99+ * Retests the path with lib appended, if the initial test does not find the files.
100+ *
101+ * @param path path to library files, gets converted to absolute while following links
102+ * @return true if path contains required files
103+ */
104+ private static boolean addJavaFXPathIfValid (Path path , boolean searchJavaFXSDK ) {
105+ try {
106+ // get absolute path, follow links
107+ path = path .toRealPath ();
108+
109+ if (isValidJavaFXDirectory (path )) {
110+ javafxPathCandidates .add (path );
111+ return true ;
112+ }
113+ if (!path .endsWith ("lib" )) {
114+ if (addJavaFXPathIfValid (path .resolve ("lib" ), searchJavaFXSDK )) {
115+ return true ;
116+ }
117+ }
118+ if (searchJavaFXSDK ) {
119+ try (DirectoryStream <Path > directoryStream = Files .newDirectoryStream (path , subPath -> subPath .toFile ().isDirectory ())) {
120+ for (Path subPath : directoryStream ) {
121+ if (subPath .getFileName ().toString ().contains ("javafx" )) {
122+ addJavaFXPathIfValid (subPath );
123+ }
124+ }
125+ }
126+ }
127+ } catch (IOException ignored ) {
34128 }
129+ return false ;
35130 }
36131
37- private static boolean validJavafxDirectory (Path dir ) {
132+ private static boolean isValidJavaFXDirectory (Path dir ) {
38133 return dir .toFile ().exists ()
39134 && dir .resolve ("javafx.base.jar" ).toFile ().exists ()
40135 && dir .resolve ("javafx.controls.jar" ).toFile ().exists ()
@@ -48,7 +143,7 @@ private static void runWithJavafx(Path javafxDir, String[] args) {
48143 cmd .add (JreUtil .javaCommand ("" ));
49144 cmd .addAll (ManagementFactory .getRuntimeMXBean ().getInputArguments ());
50145 cmd .add ("--module-path" );
51- cmd .add (javafxDir .toAbsolutePath (). toString ());
146+ cmd .add (javafxDir .toString ());
52147 cmd .add ("--add-modules" );
53148 cmd .add ("javafx.controls,javafx.fxml" );
54149
@@ -61,16 +156,19 @@ private static void runWithJavafx(Path javafxDir, String[] args) {
61156 cmd .add ("--javaOptions" );
62157 StringBuilder javaOptions = new StringBuilder ();
63158 javaOptions .append ("--module-path " );
64- if (System .getProperty ("os.name" ).startsWith ("Windows" )) {
65- // Escape the path twice to make the second launcher pass the options to Chunky retaining the double speechmarks (fixes paths with spaces)
66- javaOptions .append ("\\ \" " + javafxDir .toAbsolutePath (). toString () + "\\ \" " );
159+ if (System .getProperty ("os.name" ).startsWith ("Windows" )) {
160+ // Escape the path twice to make the second launcher pass the options to Chunky retaining the double quotation marks (fixes paths with spaces)
161+ javaOptions .append ("\\ \" " ). append ( javafxDir .toAbsolutePath ()). append ( "\\ \" " );
67162 } else {
68- javaOptions .append (javafxDir . toAbsolutePath (). toString () );
163+ javaOptions .append (javafxDir );
69164 }
70165 javaOptions .append (" --add-modules " );
71166 javaOptions .append ("javafx.controls,javafx.fxml" );
72167 cmd .add (javaOptions .toString ());
73168
169+ System .out .println ("Trying to start the chunky process with the following arguments:" );
170+ System .out .println (String .join (" " , cmd ));
171+
74172 ProcessBuilder builder = new ProcessBuilder (cmd );
75173 builder .inheritIO ();
76174 try {
@@ -82,11 +180,13 @@ private static void runWithJavafx(Path javafxDir, String[] args) {
82180 }
83181
84182 public static void retryWithJavafx (String [] args ) {
85- for (String candiate : javafxPathCandidates ) {
86- Path directory = new File (candiate ).toPath ();
87- if (validJavafxDirectory (directory )) {
88- runWithJavafx (directory , args );
89- }
183+ if (javafxPathCandidates .isEmpty ()) {
184+ scanForJavaFXLibs ();
185+ System .out .println ("JavaFX scan found the following candidates:" );
186+ javafxPathCandidates .forEach (System .out ::println );
187+ }
188+ for (Path pathCandiate : javafxPathCandidates ) {
189+ runWithJavafx (pathCandiate , args );
90190 }
91191 }
92192
0 commit comments