All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.codename1.impl.javase.fx.JavaFXLoader Maven / Gradle / Ivy

/*
 * Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Codename One designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *  
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 * 
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 * 
 * Please contact Codename One through http://www.codenameone.com/ if you 
 * need additional information or have any questions.
 */
package com.codename1.impl.javase.fx;

import com.codename1.impl.javase.UnzipUtility;
import com.codename1.impl.javase.fx.JavaFXLoader.JavaFXNotLoadedException;

import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.lang.management.ManagementFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Properties;
import java.util.Scanner;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * A Simple utilty class that will add JavaFX to the classpath at runtime.  How it works is simple.  Just add the following to the
 * first line of your main() method:
 * 
 * 

{@code 
 * if (JavaFXLoader.main(MyMainClass.class, args)) { return };
 * }

* *

This will check to see if JavaFX is loaded. If so, it will call your main method again (don't worry about recursion as JavaFXLoader.main() * will only run once.. The second run you can view it like a NOP). If JavaFX is not loaded, it will download it (if necessary), add it to the classpath, * and re-run your main method using this new ClassLoader which includes JavafX. *

* @author Steve Hannah */ public class JavaFXLoader { private static String OS = System.getProperty("os.name").toLowerCase(); private File javafxDir = new File(System.getProperty("javafx.install.dir", new File(System.getProperty("user.home"), ".codenameone" + File.separator + "javafx" + getJavaFXVersionStr()).getAbsolutePath())); private String winUrl = System.getProperty("javafx.win.url", "https://github.com/codenameone/cn1-binaries/raw/master/javafx"+getJavaFXVersionStr()+"-win.zip"); private String macUrl = System.getProperty("javafx.mac.url", "https://github.com/codenameone/cn1-binaries/raw/master/javafx"+getJavaFXVersionStr()+"-mac.zip"); private String linuxUrl = System.getProperty("javafx.linux.url", "https://github.com/codenameone/cn1-binaries/raw/master/javafx"+getJavaFXVersionStr()+"-linux.zip"); private static boolean delTree(File f) throws IOException { if (f.isDirectory()) { for (File child : f.listFiles()) { if (!delTree(child)) { return false; } } } if (f.exists()) { if (!f.delete()) { return false; } } return true; } private static void downloadToFile(String url, File f) throws IOException { URL u = new URL(url); URLConnection conn = u.openConnection(); if (conn instanceof HttpURLConnection) { HttpURLConnection http = (HttpURLConnection)conn; http.setInstanceFollowRedirects(true); http.setDefaultUseCaches(false); } try (InputStream input = conn.getInputStream()) { try (FileOutputStream output = new FileOutputStream(f)) { byte[] buf = new byte[128 * 1024]; int len; while ((len = input.read(buf)) >= 0) { output.write(buf, 0, len); } } } } private static boolean isWindows() { return (OS.indexOf("win") >= 0); } private static boolean isMac() { return (OS.indexOf("mac") >= 0); } private static boolean isUnix() { return (OS.indexOf("nux") >= 0); } private String getJavaFXURL() { if (isWindows()) { return winUrl; } if (isMac()) { return macUrl; } if (isUnix()) { return linuxUrl; } return null; } private static File findDir(File root, String dirName) { if (root.getName().equals(dirName)) { return root; } if (root.isDirectory()) { for (File child : root.listFiles()) { File found = findDir(child, dirName); if (found != null) { return found; } } } return null; } private void downloadJavaFX() throws IOException { try { String url = getJavaFXURL(); if (url == null) { throw new RuntimeException("No JavaFX URL found for this platform"); } if (javafxDir.exists()) { delTree(javafxDir); } javafxDir.getParentFile().mkdirs(); File javafxZip = new File(javafxDir.getParentFile(), "javafx.zip"); downloadToFile(url, javafxZip); System.out.println("Downladed "+javafxZip+" "+javafxZip.length()+" bytes"); File tmpDir = new File(javafxZip.getParentFile(), "javafx.tmp."+System.currentTimeMillis()); try { new UnzipUtility().unzip(javafxZip.getAbsolutePath(), tmpDir.getAbsolutePath()); javafxDir.mkdir(); File libDirTmp = findDir(tmpDir, "lib"); File legalDirTmp = findDir(tmpDir, "legal"); File binDirTmp = findDir(tmpDir, "bin"); if (libDirTmp == null || !libDirTmp.exists()) { throw new IOException("No lib dir found within JavaFX zip"); } //System.out.println("Files:"); //for (File f : libDirTmp.listFiles()) { // System.out.println(f); // if (f.isDirectory()) { // for (File child : f.listFiles()) { // System.out.println(" "+child); // } // } //} //if (legalDirTmp == null || !legalDirTmp.exists()) { // throw new IOException("No legal dir found within JavaFX zip"); //} libDirTmp.renameTo(new File(javafxDir, "lib")); if (legalDirTmp != null && legalDirTmp.exists()) { legalDirTmp.renameTo(new File(javafxDir, "legal")); } if (binDirTmp != null && binDirTmp.exists()) { binDirTmp.renameTo(new File(javafxDir, "bin")); } } finally { delTree(tmpDir); javafxZip.delete(); } } catch (MalformedURLException ex) { Logger.getLogger(JavaFXLoader.class.getName()).log(Level.SEVERE, null, ex); throw new RuntimeException(ex); } } public URL[] getJavaFXJars() throws IOException { if (!javafxDir.exists()) { downloadJavaFX(); } if (!javafxDir.exists()) { throw new RuntimeException("Failed to download JavaFX"); } File javafxLibDir = new File(javafxDir, "lib"); if (!javafxLibDir.exists()) { throw new RuntimeException("JavaFX is missing. This application requires a JDK with JavaFX."); } File jarsDir = javafxLibDir; if ("8".equals(getJavaFXVersionStr())) { // JavaFX 8 jar files are in the lib/ext directory jarsDir = new File(javafxLibDir, "ext"); } java.util.List javafxUrls = new ArrayList(); for (File f : jarsDir.listFiles()) { if (!f.getName().endsWith(".jar")) { continue; } try { java.net.URL u = f.toURI().toURL(); javafxUrls.add(u); } catch (Exception ex2) { ex2.printStackTrace(); } } if (javafxUrls.isEmpty()) { throw new RuntimeException("JavaFX is missing. This application requires a JDK with JavaFX."); } try { javafxUrls.add(javafxLibDir.toURI().toURL()); // Necessary for loading native libs } catch (MalformedURLException mex) { throw new RuntimeException(mex); } return javafxUrls.toArray(new java.net.URL[javafxUrls.size()]); } public File[] getJavaFXJarFiles() throws IOException, URISyntaxException { URL[] urls = getJavaFXJars(); File[] files = new File[urls.length]; for (int i=0; i 0) { sb.append(File.pathSeparator); } sb.append(f.getAbsolutePath()); } return sb.toString(); } public static class JavaFXNotLoadedException extends Exception { public JavaFXNotLoadedException(Throwable cause) { super(cause); } } public static boolean isJavaFXLoaded() { boolean isJavaFX8 = "8".equals(getJavaFXVersionStr()); if (!isJavaFX8 && containsJavaFX8(System.getProperty("java.class.path"))) { // We're using javafx8 in jdk9 or higher... // we should claim that javafx isn't loaded so that we can fix it. return false; } try { ClassLoader.getSystemClassLoader().loadClass("javafx.scene.web.WebEngine"); return true; } catch (ClassNotFoundException ex) { return false; } catch (UnsupportedClassVersionError er) { return false; } } private File findEclipseLaunchFile() { for (File child : new File(".").listFiles()) { if (child.getName().startsWith("Simulator_") && child.getName().endsWith(".launch")) { return child; } } return null; } private void updateEclipseLaunchClasspath() { File launchFile = findEclipseLaunchFile(); if (launchFile == null || !launchFile.exists()) { return; } String contents = null; try { try (FileInputStream fos = new FileInputStream(launchFile)) { byte[] buf = new byte[(int)launchFile.length()]; fos.read(buf); contents = new String(buf, "UTF-8"); } boolean isJavaFX8 = "8".equals(getJavaFXVersionStr()); String javafxListEntry = ""; String javafx8ListEntry = ""; boolean changed = false; if (isJavaFX8 && containsJavaFX(contents)) { // This is javafx 8 but we have javafx11 on the classpath - REMOVE THEM System.out.println("Detected Incompatible version of JavaFX. Removing incompatible libs from the classpath"); contents = contents.replaceAll("", ""); changed = true; } else if (!isJavaFX8 && containsJavaFX8(contents)) { System.out.println("Detected Incompatible version of JavaFX. Removing incompatible libs from the classpath"); // This is javafx11 but we have javafx8 on the classpath - REMOVE THEM contents = contents.replaceAll("", ""); changed = true; } if (!isJavaFX8 && !containsJavaFX(contents)) { // This is JDK9 or higher and the javafx libs havent' been added to the classpath yet. System.out.println("Adding OpenJFX11 to the classpath"); int pos = contents.indexOf(""); if (pos < 0) { return; } String endTag = ""; int closingPos = contents.indexOf(endTag, pos); contents = contents.substring(0, closingPos) + " " + javafxListEntry + "\n " + endTag + contents.substring(closingPos + endTag.length()); changed = true; } else if (isJavaFX8 && !containsJavaFX8(contents)) { System.out.println("Adding OpenJFX8 to the classpath"); // This is JDK 8 and javafx libs haven't been added to the classpath yet. int pos = contents.indexOf(""); if (pos < 0) { return; } String endTag = ""; int closingPos = contents.indexOf(endTag, pos); contents = contents.substring(0, closingPos) + " " + javafx8ListEntry + "\n " + endTag + contents.substring(closingPos + endTag.length()); changed = true; } if (changed) { System.out.println("Adding JavaFX to your Eclipse launch classpath at "+launchFile); System.out.println("JavaFX should be correctly loaded the next time you run this project."); try (FileOutputStream fos = new FileOutputStream(launchFile)) { fos.write(contents.getBytes("UTF-8")); } } } catch (IOException ex) { System.err.println("Failed to update "+launchFile+" with JavaFX path"); ex.printStackTrace(System.err); } } private void updateNbProjectProperties() { // Update the nbProject properties file so that we don't have to do this every time. File nbProjectProperties = new File("nbproject" + File.separator + "project.properties"); if (nbProjectProperties.exists()) { String contents = null; try { try (FileInputStream fos = new FileInputStream(nbProjectProperties)) { byte[] buf = new byte[(int)nbProjectProperties.length()]; fos.read(buf); contents = new String(buf, "UTF-8"); } //System.out.println("Starting contents="+contents); boolean isJavaFX8 = "8".equals(getJavaFXVersionStr()); String jfxPath = isJavaFX8 ? "${user.home}/.codenameone/javafx8/lib/ext/*" : "${user.home}/.codenameone/javafx/lib/*"; boolean changed = false; if (contents != null) { if (contents.contains("cn1.javafx.path=")) { int pos = contents.indexOf("cn1.javafx.path="); String newContents = contents; if (pos > -1) { int eqPos = contents.indexOf("=", pos); int newlinePos = contents.indexOf("\n", pos); if (newlinePos < 0) { newlinePos = contents.length(); } newContents = contents.substring(0, pos) + contents.substring(newlinePos); } if (!newContents.equals(contents)) { contents = newContents; changed = true; } } else { String sep = System.getProperty("line.separator"); if (!contents.endsWith(sep)) { contents += sep; } contents += "cn1.javafx.path="+jfxPath; changed = true; } if (!contents.contains("${cn1.javafx.path}")) { int runClassPathPos = contents.indexOf("run.classpath="); if (runClassPathPos > 0) { int pos = contents.indexOf("${build.classes.dir}", runClassPathPos); if (pos > 0) { String before = contents.substring(0, pos); String after = contents.substring(pos + "${build.classes.dir}".length()); contents = before + "${build.classes.dir}:${cn1.javafx.path}" + after; contents = contents.replace("${cn1.javafx.path}:${cn1.javafx.path}", "${cn1.javafx.path}"); changed = true; } } runClassPathPos = contents.indexOf("run.test.classpath="); if (runClassPathPos > 0) { int pos = contents.indexOf("${build.classes.dir}", runClassPathPos); if (pos > 0) { String before = contents.substring(0, pos); String after = contents.substring(pos + "${build.classes.dir}".length()); contents = before + "${build.classes.dir}:${cn1.javafx.path}" + after; contents = contents.replace("${cn1.javafx.path}:${cn1.javafx.path}", "${cn1.javafx.path}"); changed = true; } } } } if (changed) { System.out.println("Adding JavaFX to your project properties file at "+nbProjectProperties); System.out.println("JavaFX should be correctly loaded the next time you run this project."); try (FileOutputStream fos = new FileOutputStream(nbProjectProperties)) { fos.write(contents.getBytes("UTF-8")); } } } catch (IOException ex) { System.err.println("Failed to update "+nbProjectProperties+" with JavaFX path"); ex.printStackTrace(System.err); } } } private static int cachedJavaVersion=-1; /** * Returns the Java version as an int value. * * @return the Java version as an int value (8, 9, etc.) * @since 12130 */ private static int getJavaVersion() { if (cachedJavaVersion < 0) { String version = System.getProperty("java.version"); if (version.startsWith("1.")) { version = version.substring(2); } // Allow these formats: // 1.8.0_72-ea // 9-ea // 9 // 9.0.1 int dotPos = version.indexOf('.'); int dashPos = version.indexOf('-'); if (dotPos < 0 && dashPos < 0) { cachedJavaVersion = Integer.parseInt(version); return cachedJavaVersion; } cachedJavaVersion = Integer.parseInt(version.substring(0, dotPos > -1 ? dotPos : dashPos > -1 ? dashPos : 1)); return cachedJavaVersion; } return cachedJavaVersion; } /** * Because of the historical order in which we supported sideloading JavaFX, JDK9, 10, and 11 * have an empty string for the version string. And JDK 8 has "8". The javafx libs * are downloaded to ${user.home}/.codenameone/javafx${versionstr}. E.g. * on JDK 8 it would be ${user.home}/.codenameone/javafx8, and oh 9, 10, 11, it would * just be ${user.home}/.codenameone/javafx * @return */ private static String getJavaFXVersionStr() { return (getJavaVersion() == 8) ? "8" : ""; } private static boolean containsJavaFX8(String classpath) { return classpath.contains(".codenameone/javafx8/lib/ext") || classpath.contains(".codenameone\\javafx8\\lib\\ext"); } private static boolean containsJavaFX(String classpath) { return classpath.contains(".codenameone/javafx/lib") || classpath.contains(".codenameone\\javafx\\lib"); } private static String p(String path) { if ("\\".equals(File.separator)) { return path.replace("/", "\\"); } else { return path.replace("\\", "/"); } } public boolean runWithJavaFX(Class launchClass, Class mainClass, String[] args) throws JavaFXNotLoadedException, InvocationTargetException { if(System.getProperty("skip.fx.test", "false").equalsIgnoreCase("true")) { System.out.println("Skipping JavaFX auto-install"); return false; } if (!JavaFXLoader.isJavaFXLoaded()) { System.out.println("JavaFX Not loaded. Classpath="+System.getProperty("java.class.path")+" . Adding to classpath"); try { getJavaFXJarFiles(); } catch (Exception ex) { ex.printStackTrace(); return false; } Properties props = new Properties(); boolean isJavaFX8 = "8".equals(getJavaFXVersionStr()); try { String cp = System.getProperty("java.class.path"); List cpParts = new ArrayList(Arrays.asList(cp.split(Pattern.quote(File.pathSeparator)))); if (isJavaFX8 && containsJavaFX(cp)) { //cp = cp.replace(".codenameone/javafx/lib/*", ".codenameone/javafx8/lib/ext/*"); ListIterator lit = cpParts.listIterator(); while (lit.hasNext()) { String nex = lit.next(); if (containsJavaFX(nex)) { lit.remove(); } } cp = String.join(File.pathSeparator, cpParts.toArray(new String[cpParts.size()])); cp += File.pathSeparator + System.getProperty("user.home")+p("/.codenameone/javafx8/lib/ext/*"); } else if (!isJavaFX8 && containsJavaFX8(cp)) { // cp = cp.replace(".codenameone/javafx8/lib/ext/*", ".codenameone/javafx/lib/*"); ListIterator lit = cpParts.listIterator(); while (lit.hasNext()) { String nex = lit.next(); if (containsJavaFX8(nex)) { lit.remove(); } } cp = String.join(File.pathSeparator, cpParts.toArray(new String[cpParts.size()])); cp += File.pathSeparator + System.getProperty("user.home")+p("/.codenameone/javafx/lib/*"); } else if (isJavaFX8 && !containsJavaFX8(cp)) { cp += File.pathSeparator + System.getProperty("user.home")+p("/.codenameone/javafx8/lib/ext/*"); } else if (!isJavaFX8 && !containsJavaFX(cp)) { cp += File.pathSeparator + System.getProperty("user.home") + p("/.codenameone/javafx/lib/*"); } else { String javafxPath = isJavaFX8 ? System.getProperty("user.home") + p("/.codenameone/javafx8") : System.getProperty("user.home") + p("/.codenameone/javafx"); System.err.println("Project could not be run because JavaFX is missing. It already has JavaFX in the class path so something else must be wrong. Ensure that the "+javafxPath+" directory exists and contains the proper files. You may want to try just deleting the entire directory and try running this project again, as it should autonmatically re-download it."); System.exit(1); } props.setProperty("java.class.path", cp); } catch (Exception ex) { throw new RuntimeException("Failed to load JavaFX", ex); } updateNbProjectProperties(); updateEclipseLaunchClasspath(); System.out.println("Restarting JVM with JavaFX in the classpath."); System.out.println("NOTE: If you are trying to debug the project, you'll need to cancel this run and try running debug on the project again. JavaFX should now be in your classpath."); restartJVM(launchClass, props, args); return true; } System.out.println("JavaFX is loaded"); return false; } public static boolean main(Class launchClass, Class mainClass, String[] argv) throws JavaFXNotLoadedException, InvocationTargetException { return new JavaFXLoader().runWithJavaFX(launchClass, mainClass, argv); } public static boolean restartJVM(Class launchClass, Properties props, String[] args) { String osName = System.getProperty("os.name"); // get current jvm process pid String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0]; // get environment variable on whether XstartOnFirstThread is enabled String env = System.getenv("JAVA_STARTED_ON_FIRST_THREAD_" + pid); // restart jvm with -XstartOnFirstThread String separator = System.getProperty("file.separator"); String classpath = props.getProperty("java.class.path", System.getProperty("java.class.path")); String mainClass = System.getenv("JAVA_MAIN_CLASS_" + pid); if (mainClass == null) { mainClass = launchClass.getName(); } String jvmPath = System.getProperty("java.home") + separator + "bin" + separator + "java"; List inputArguments = ManagementFactory.getRuntimeMXBean().getInputArguments(); ArrayList jvmArgs = new ArrayList(); jvmArgs.add(jvmPath); //jvmArgs.add("-XstartOnFirstThread"); jvmArgs.addAll(inputArguments); jvmArgs.add("-cp"); jvmArgs.add(classpath); jvmArgs.add(mainClass); for (String arg : args) { jvmArgs.add(arg); } try { ProcessBuilder processBuilder = new ProcessBuilder(jvmArgs); processBuilder.inheritIO(); Process process = processBuilder.start(); process.waitFor(); int exitCode = process.exitValue(); System.exit(exitCode); } catch (Exception e) { e.printStackTrace(); } return true; } public static void main(String[] args) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream out = new PrintStream(baos); PrintStream stdOut = System.out; PrintStream stdErr = System.err; System.setOut(out); System.setErr(out); JavaFXLoader jfxLoader = new JavaFXLoader(); if (!isJavaFXLoaded()) { try { jfxLoader.getJavaFXClassPath(); boolean isJavaFX8 = "8".equals(getJavaFXVersionStr()); String path = isJavaFX8 ? System.getProperty("user.home") + File.separator + ".codenameone" + File.separator + "javafx8" + File.separator + "lib" + File.separator + "ext" + File.separator + "*": System.getProperty("user.home") + File.separator + ".codenameone" + File.separator + "javafx" + File.separator + "lib" + File.separator + "*"; stdOut.print(path) ; } catch (Exception ex){ stdErr.print("Failed to load JavaFX jars"); ex.printStackTrace(stdErr); System.exit(1); } } else { //stdOut.print("."); } System.exit(0); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy