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

com.codename1.impl.javase.Simulator Maven / Gradle / Ivy

There is a newer version: 7.0.167
Show newest version
/*
 * Copyright (c) 2008, 2010, Oracle 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.  Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores
 * CA 94065 USA or visit www.oracle.com if you need additional information or
 * have any questions.
 */
package com.codename1.impl.javase;

import com.codename1.impl.javase.util.MavenUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;

/**
 * A simple class that can invoke a lifecycle object to allow it to run a
 * Codename One application. Classes are loaded with a classloader so the UI
 * skin can be updated and the lifecycle objects reloaded.
 *
 * @author Shai Almog
 */
public class Simulator {
    
    private static final String DEFAULT_SKIN="/iPhoneX.skin";
    private static ClassPathLoader rootClassLoader;


    /**
     * Loads properties from the target/codenameone/simulator.properties file into the System properties.
     * This file is created by the PrepareSimulatorClasspathMojo
     * @param projectDir
     */
    private static void loadSimulatorProperties(File projectDir) {
       if (!MavenUtils.isRunningInMaven()) {
           // simulator.properties file is only for maven.
           // The PrepareSimulatorClassPathMojo writes the simulator.properties file in the target/codenameone folder.
           return;
       }
       if (System.getProperty("cn1.simulator.properties.loaded") != null) {
           // properties are already loaded.
           return;
       }
       System.setProperty("cn1.simulator.properties.loaded", "true");
       File simulatorProperties = new File(projectDir, "target" + File.separator + "codenameone" + File.separator + "simulator.properties");
       if (simulatorProperties.exists()) {
           Properties props = new Properties();
           try (FileInputStream fis = new FileInputStream(simulatorProperties)) {
               props.load(fis);
           } catch (IOException ex) {
               System.err.println("Failed to load simulator.properties file");
               ex.printStackTrace();
           }
           for (Object key : props.keySet()) {
               String stringKey = (String)key;
               if (stringKey.isEmpty()) continue;
               System.setProperty(stringKey, props.getProperty(stringKey));
           }


       }

   }

    /**
     * Accepts the classname to launch
     */
    public static void main(final String[] argv) throws Exception {

        try {
            // Load the sqlite database Engine JDBC driver in the top level classloader so it's shared
            // this works around the exception: java.lang.UnsatisfiedLinkError: Native Library sqlite already loaded in another classloader
            Class.forName("org.sqlite.JDBC");
        } catch (ClassNotFoundException ex) {
        }
        System.setProperty("NSHighResolutionCapable", "true");
        String skin = System.getProperty("dskin");
        if (skin == null) {
            System.setProperty("dskin", DEFAULT_SKIN);
        }
        
        for (int i = 0; i < argv.length; i++) {
            String argv1 = argv[i];
            if(argv1.equals("resetSkins")){
                System.setProperty("resetSkins", "true");
                System.setProperty("skin", DEFAULT_SKIN);
                System.setProperty("dskin", DEFAULT_SKIN);            
            }
        }
        
        if (System.getenv("CN1_SIMULATOR_SKIN") != null) {
            System.setProperty("skin", System.getenv("CN1_SIMULATOR_SKIN"));
        }

        String classPathStr = System.getProperty("java.class.path");
        if (System.getProperty("cn1.class.path") != null) {
            classPathStr += File.pathSeparator + System.getProperty("cn1.class.path");
        }
        StringTokenizer t = new StringTokenizer(classPathStr, File.pathSeparator);
        if(argv.length > 0) {
            System.setProperty("MainClass", argv[0]);
        }
        List files = new ArrayList();
        // Support for instant reload:
        // If running with HotswapAgent (https://github.com/HotswapProjects/HotswapAgent) in debug mode
        // we add special support for instant refresh when source files are changed.
        // The easiest way to enable this is to install DCEVM JDK https://github.com/TravaOpenJDK/trava-jdk-11-dcevm/releases
        // and use that as the project JDK.  Then add "-XX:HotswapAgent=core" to the java VM options.
        // 
        List inputArgs = java.lang.management.ManagementFactory.getRuntimeMXBean().getInputArguments();
        final boolean isDebug = inputArgs.toString().indexOf("-agentlib:jdwp") > 0;
        final boolean usingHotswapAgent = inputArgs.toString().indexOf("-XX:HotswapAgent") > 0;
        File cn1Props = new File("codenameone_settings.properties");
        if (!cn1Props.exists()) {
            cn1Props = new File("common" + File.separator + "codenameone_settings.properties");

        }
        if (!cn1Props.exists()) {
            cn1Props = new File(".." + File.separator + "common" + File.separator + "codenameone_settings.properties").getAbsoluteFile();

        }
        if (cn1Props.exists()) {
            File commonClasses = new File(cn1Props.getParentFile(), "target" + File.separator + "classes");
            if (commonClasses.exists()) {
                files.add(commonClasses.getAbsoluteFile());
            }
            loadSimulatorProperties(cn1Props.getParentFile());
        }
        if (isDebug && usingHotswapAgent) { 
            HotswapProperties hotswapProperties = new HotswapProperties();
            files.addAll(hotswapProperties.getExtraClasses());
        }
        int len = t.countTokens();
        for (int iter = 0; iter < len; iter++) {
            files.add(new File(t.nextToken()).getAbsoluteFile());
        }
        File javase = new File("native" + File.separator + "javase");
        File libJavase = new File("lib" + File.separator + "impl" + File.separator + "native" + File.separator + "javase");
        for (File dir : new File[]{javase, libJavase}) {
            if (dir.exists()) {
                
                for (File jar : dir.listFiles()) {
                    if (jar.getName().endsWith(".jar")) {
                        if (!files.contains(jar)) {
                            files.add(jar.getAbsoluteFile());
                            System.setProperty("java.class.path", System.getProperty("java.class.path")+File.pathSeparator+jar.getAbsolutePath());
                        }
                    }
                }
            }
        }
        boolean cefSupported = false;
        boolean fxSupported = false;
        try {
            Class.forName("javafx.embed.swing.JFXPanel");
            fxSupported = true;
        } catch (Throwable ex) {}
        boolean fxOnSystemPath = fxSupported;
        
        File cef = System.getProperty("cef.dir") != null ? new File(System.getProperty("cef.dir")) : new File(System.getProperty("user.home") + File.separator + ".codenameone" + File.separator + "cef");
        if (cef.exists()) {
            if (isUnix && !is64Bit) {
                System.out.println("Found CEF, but not using because CEF is only supported on 64 bit platforms.  Try running inside a 64 bit JVM");
            } else {
                
            
                cefSupported = true;
                System.out.println("Adding CEF to classpath");
                String cn1LibPath = System.getProperty("cn1.library.path", ".");
                String bitSuffix = is64Bit ? "64" : "32";
                String nativeDir = isMac ? "macos64" : isWindows ? ("lib" + File.separator + "win"+bitSuffix) : ("lib" + File.separator + "linux"+bitSuffix);
                System.setProperty("cn1.library.path", cn1LibPath + File.pathSeparator + cef.getAbsolutePath() + File.separator + nativeDir);

                // Necessary to modify java.libary.path property on windows as it is used by CefApp to locate jcef_helper.exe
                System.setProperty("java.library.path", cef.getAbsolutePath()+File.separator+nativeDir+File.pathSeparator+System.getProperty("java.library.path", "."));
                for (File jar : cef.listFiles()) {
                    if (jar.getName().endsWith(".jar") && !jar.getName().endsWith("-tests.jar")) {
                        files.add(jar.getAbsoluteFile());
                    }
                }
            }
        }
        
        File jmf = new File(System.getProperty("user.home") + File.separator + ".codenameone" + File.separator + "jmf-2.1.1e.jar");
        if (jmf.exists()) {
            System.setProperty("java.class.path", System.getProperty("java.class.path") + File.pathSeparator + jmf.getAbsolutePath());
            files.add(jmf.getAbsoluteFile());
        }
        
        String implementation = System.getProperty("cn1.javase.implementation", "");

        
        if (implementation.equalsIgnoreCase("cef") && !cefSupported) {
            // We will use CEF
            System.err.println("cn1.javase.implementation=cef but CEF was not found.  Please update your Codename One libraries and try again.\nAlternatively, you can try using a different implementation.");
            System.exit(1);
        }
        if (implementation.equalsIgnoreCase("fx") && !fxSupported) {
            System.err.println("cn1.javase.implementation=fx but JavaFX was not found.  Please use a JDK that has JavaFX such as ZuluFX.  https://www.azul.com/downloads/zulu-community/");
            System.exit(1);
        }
        if ("".equals(implementation)) {
            if (cefSupported) {
                System.setProperty("cn1.javase.implementation", "cef");
            } else if (fxSupported) {
                System.setProperty("cn1.javase.implementation", "fx");
            } else {
                System.setProperty("cn1.javase.implementation", "jmf");
            }
        }
        
        //loadFXRuntime();
        ClassLoader ldr = rootClassLoader == null ? 
                new ClassPathLoader( files.toArray(new File[files.size()])) :
                new ClassPathLoader(rootClassLoader, files.toArray(new File[files.size()]));
        if (rootClassLoader == null) {
            rootClassLoader = (ClassPathLoader)ldr;
            
            ldr = new ClassPathLoader(rootClassLoader, files.toArray(new File[files.size()]));
            
        }
        StringBuilder filesPath = new StringBuilder();
        for (File f : files) {
            if (filesPath.length() > 0) {
                filesPath.append(File.pathSeparator);
            }
            filesPath.append(f.getAbsolutePath());
        }
        System.setProperty("cn1.classPathLoader.Path", filesPath.toString());
        ((ClassPathLoader)ldr).addExclude("org.cef.");
        
        final ClassLoader fLdr = ldr;
        Thread.currentThread().setContextClassLoader(fLdr);
        Class c = Class.forName("com.codename1.impl.javase.Executor", true, ldr);
        Method m = c.getDeclaredMethod("main", String[].class);
        m.invoke(null, new Object[]{argv});
        new Thread() {
            public void run() {
                setContextClassLoader(fLdr);
                while (true) {
                    try {
                        sleep(500);
                    } catch (InterruptedException ex) {
                    }
                    String r = System.getProperty("reload.simulator");
                    if (r != null && r.equals("true")) {
                        System.setProperty("reload.simulator", "");
                        int version = Integer.parseInt(System.getProperty("reload.simulator.count", "0"));
                        System.setProperty("reload.simulator.count", String.valueOf(version+1));
                        try {
                            main(argv);
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                        return;
                    }
                }
            }
        }.start();
    }

    private static void addToSystemClassLoader(File f) {
        ClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        Class sysclass = URLClassLoader.class;
        try {
            Method method = sysclass.getDeclaredMethod("addURL", new Class[]{URL.class});
            method.setAccessible(true);
            method.invoke(sysloader, new Object[]{f.toURI().toURL()});
        } catch (Throwable t) {
            t.printStackTrace();
        }//end try catch    
    }
    
    static void loadFXRuntime() {
        String javahome = System.getProperty("java.home");
        String fx = javahome + "/lib/jfxrt.jar";
        File f = new File(fx);
        if (f.exists()) {
            addToSystemClassLoader(f);

        } 
    }
    
    private static String getJavaFXVersionStr() {
        return (getJavaVersion() == 8) ? "8" : "";
    }
    
    private static int cachedJavaVersion = -1;

    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;
    }
    
    private static String OS = System.getProperty("os.name").toLowerCase();
    private static boolean isWindows = (OS.indexOf("win") >= 0);
    

    private static boolean isMac =  (OS.indexOf("mac") >= 0);
    private static final String ARCH = System.getProperty("os.arch");

    private static boolean isUnix = (OS.indexOf("nux") >= 0);
    private static final boolean is64Bit = is64Bit();
    private static final boolean is64Bit() {
        
        String model = System.getProperty("sun.arch.data.model",
                                          System.getProperty("com.ibm.vm.bitmode"));
        if (model != null) {
            return "64".equals(model);
        }
        if ("x86-64".equals(ARCH)
            || "ia64".equals(ARCH)
            || "ppc64".equals(ARCH) || "ppc64le".equals(ARCH)
            || "sparcv9".equals(ARCH)
            || "mips64".equals(ARCH) || "mips64el".equals(ARCH)
            || "amd64".equals(ARCH)
            || "aarch64".equals(ARCH)) {
            return true;
        }
        return false;
    }
    
    /**
     * Encapsulates the hotswap-agent.properties file that is used when running with HotswapAgent.
     * See https://github.com/HotswapProjects/HotswapAgent
     */
    private static class HotswapProperties {
        Properties props;
        
        /**
         * Finds the hotswap-agent.properties file.
         * @return 
         */
        private File findHotswapPropertiesFile() {
        
            try {
                File currDir = new File(System.getProperty("user.dir")).getCanonicalFile();
                while (!new File(currDir, "javase").exists()) {
                    currDir = currDir.getParentFile();
                    if (currDir == null) {
                        return null;
                    }
                }

                //System.out.println("Curr Directory is "+currDir);
                File hotswapProps = new File(currDir, "javase" + File.separator + "src" + File.separator + "main" + File.separator + "resources" + File.separator + "hotswap-agent.properties");
                if (hotswapProps.exists()) {
                    return hotswapProps;
                }
            } catch (IOException ex){
                ex.printStackTrace();
            }

            return null;

        }


        /**
         * The hotswap-agent.properties file may be added to the root of the
         * classpath to tune the Hotswap Agent to support enhanced live
         * class-reloading.
         *
         * https://github.com/HotswapProjects/HotswapAgent
         *
         * @return
         */
        private Properties loadHotswapProperties() {
            Properties out = new Properties();
            File hotswapProps = findHotswapPropertiesFile();
            if (hotswapProps != null) {
                FileInputStream fis = null;
                try {
                   fis = new FileInputStream(hotswapProps);
                   out.load(fis);

                } catch (IOException ex) {
                    System.err.println("Failed to load hotswap properties file from "+hotswapProps);
                    ex.printStackTrace();
                } finally {
                    if (fis != null) {
                        try {
                            fis.close();
                        } catch (Exception ex){}
                    }
                }
            }
            return out;

        }
        
        private Properties getProperties() {
            if (props == null) {
                props = loadHotswapProperties();
            }
            return props;
        }
        
        /**
         * Gets the extraClasspath from the hotswap-agent.properties file.  These paths
         * are prepended to the classpath of the classloader to allow for live code refresh.
         * 
         * @return 
         */
        private List getExtraClasses() {
            String extraClasspath = getProperties().getProperty("extraClasspath");
            // NOTE: The hotswap-agent.properties file  uses semicolon to separate entries in extraClasspath on all
            // platforms - not just windows.
            if (extraClasspath == null || extraClasspath.trim().isEmpty()) {
                return new ArrayList();
            }
            String[] parts = extraClasspath.split(";");
            List files = new ArrayList();
            for (String part : parts) {
                part = part.trim();
                files.add(new File(part).getAbsoluteFile());
            }
            return files;
        }
    }
    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy