Java tutorial
/* * Copyright (c) 2016 - sikulix.com - MIT license */ package com.sikulix.core; import com.sikulix.api.Location; import com.sikulix.scripting.JythonHelper; import org.apache.commons.cli.*; import org.apache.commons.configuration2.PropertiesConfiguration; import org.apache.commons.configuration2.builder.fluent.Configurations; import org.apache.commons.configuration2.ex.ConfigurationException; import org.sikuli.util.SysJNA; import java.awt.*; import java.io.*; import java.lang.reflect.Field; import java.net.MalformedURLException; import java.net.URL; import java.security.CodeSource; import java.util.*; import java.util.List; import static com.sikulix.core.SX.NATIVES.HOTKEY; import static com.sikulix.core.SX.NATIVES.OPENCV; import static com.sikulix.core.SX.NATIVES.SYSUTIL; public class SX { private static long startTime = new Date().getTime(); //<editor-fold desc="*** logging"> public static final int INFO = 1; public static final int DEBUG = 3; public static final int TRACE = 4; public static final int ERROR = -1; public static final int FATAL = -2; private static final SXLog log = new SXLog(); private static void info(String message, Object... args) { log.info(message, args); } public static void debug(String message, Object... args) { log.debug(message, args); } public static void trace(String message, Object... args) { log.trace(message, args); } public static void error(String message, Object... args) { log.error(message, args); } public static void terminate(int retval, String message, Object... args) { if (retval != 0) { log.fatal(message, args); } else { info(message, args); } System.exit(retval); } public static void p(String msg, Object... args) { log.p(msg, args); } public static SXLog getLogger(String className) { return getLogger(className, null, -1); } public static SXLog getLogger(String className, int level) { return getLogger(className, null, level); } public static SXLog getLogger(String className, String[] args) { return getLogger(className, args, -1); } public static SXLog getLogger(String className, String[] args, int level) { return new SXLog(className, args, level); } //</editor-fold> //<editor-fold desc="*** init"> private static String sxInstance = null; private static boolean shouldLock = false; private static FileOutputStream isRunningFile = null; static final Class sxGlobalClassReference = SX.class; static void sxinit(String[] args) { if (null == sxInstance) { sxInstance = "SX INIT DONE"; //<editor-fold desc="*** shutdown hook"> Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { if (shouldLock && isSet(isRunningFile)) { try { isRunningFile.close(); } catch (IOException ex) { } } for (File f : getFile(getSYSTEMP()).listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { File aFile = new File(dir, name); boolean isObsolete = false; long lastTime = aFile.lastModified(); if (lastTime == 0) { return false; } if (lastTime < ((new Date().getTime()) - 7 * 24 * 60 * 60 * 1000)) { isObsolete = true; } if (name.contains("BridJExtractedLibraries") && isObsolete) { return true; } if (name.toLowerCase().contains("sikuli")) { if (name.contains("Sikulix_")) { if (isObsolete || aFile.equals(getFile(getSXTEMP()))) { return true; } } else { return true; } } return false; } })) { trace("cleanTemp: " + f.getName()); Content.deleteFileOrFolder("#" + f.getAbsolutePath()); } } }); //</editor-fold> // TODO Content class must be initialized for use in shutdown Content.start(); //<editor-fold desc="*** sx lock (not active)"> if (shouldLock) { File fLock = new File(getSYSTEMP(), "SikuliX2-i-s-r-u-n-n-i-n-g"); String shouldTerminate = ""; try { fLock.createNewFile(); isRunningFile = new FileOutputStream(fLock); if (isNull(isRunningFile.getChannel().tryLock())) { shouldTerminate = "SikuliX2 already running"; isRunningFile = null; } } catch (Exception ex) { shouldTerminate = "cannot access SX2 lock: " + ex.toString(); isRunningFile = null; } if (isSet(shouldTerminate)) { terminate(1, shouldTerminate); } } //</editor-fold> // *** command line args if (!isNull(args)) { checkArgs(args); } trace("!sxinit: entry"); // *** get SX options loadOptions(); // *** get the version info getSXVERSION(); // *** check how we are running sxRunningAs(); // *** get monitor setup globalGetMonitors(); //TODO i18n SXGlobal_sxinit_complete=complete %.3f trace("!sxinit: exit %.3f", (new Date().getTime() - startTime) / 1000.0f); } } //</editor-fold> //<editor-fold desc="*** command line args"> private static List<String> sxArgs = new ArrayList<String>(); private static List<String> userArgs = new ArrayList<String>(); private static CommandLine sxCommandArgs = null; static void checkArgs(String[] args) { boolean hasUserArgs = false; for (String arg : args) { if ("--".equals(arg)) { hasUserArgs = true; continue; } if (hasUserArgs) { trace("checkargs: user: %s", arg); userArgs.add(arg); } else { trace("checkargs: --sx: %s", arg); sxArgs.add(arg); } } if (sxArgs.size() > 0) { CommandLineParser parser = new PosixParser(); Options opts = new Options(); opts.addOption(OptionBuilder.hasOptionalArg().create('d')); opts.addOption(OptionBuilder.hasArg().create('o')); opts.addOption(OptionBuilder.hasArgs().create('r')); opts.addOption(OptionBuilder.hasArgs().create('t')); opts.addOption(OptionBuilder.hasArg(false).create('c')); opts.addOption(OptionBuilder.hasArg(false).create('q')); try { sxCommandArgs = parser.parse(opts, sxArgs.toArray(new String[0])); } catch (ParseException e) { terminate(1, "checkArgs: %s", e.getMessage()); } if (!isNull(sxCommandArgs)) { if (isArg("q")) { log.globalStop(); } else if (isArg("d")) { log.globalOn(log.DEBUG); } } } //TODO make options from SX args } private static boolean isArg(String arg) { return sxCommandArgs != null && sxCommandArgs.hasOption(arg); } private static String getArg(String arg) { if (sxCommandArgs != null && sxCommandArgs.hasOption(arg)) { String val = sxCommandArgs.getOptionValue(arg); return val == null ? "" : val; } return null; } public static String[] getUserArgs() { return userArgs.toArray(new String[0]); } //</editor-fold> //<editor-fold desc="*** check how we are running"> public static String sxGlobalClassNameIDE = ""; private static boolean isJythonReady = false; static String appType = "?appType?"; static File fSxBaseJar; static File fSxBase; //TODO getter public static File fSxProject; static boolean runningInProject = false; static final String fpContent = "sikulixcontent"; static String sxJythonMaven; static String sxJython; static String sxJRubyMaven; static String sxJRuby; static Map<String, String> tessData = new HashMap<String, String>(); static String dlMavenRelease = "https://repo1.maven.org/maven2/"; static String dlMavenSnapshot = "https://oss.sonatype.org/content/groups/public/"; private static boolean runningJar = true; static void sxRunningAs() { CodeSource codeSrc = sxGlobalClassReference.getProtectionDomain().getCodeSource(); String base = null; if (codeSrc != null && codeSrc.getLocation() != null) { base = Content.slashify(codeSrc.getLocation().getPath(), false); } appType = "from a jar"; if (base != null) { fSxBaseJar = new File(base); String jn = fSxBaseJar.getName(); fSxBase = fSxBaseJar.getParentFile(); debug("sxRunningAs: runs as %s in: %s", jn, fSxBase.getAbsolutePath()); if (jn.contains("classes")) { runningJar = false; fSxProject = fSxBase.getParentFile().getParentFile(); debug("sxRunningAs: not jar - supposing Maven project: %s", fSxProject); appType = "in Maven project from classes"; runningInProject = true; } else if ("target".equals(fSxBase.getName())) { fSxProject = fSxBase.getParentFile().getParentFile(); debug("sxRunningAs: folder target detected - supposing Maven project: %s", fSxProject); appType = "in Maven project from some jar"; runningInProject = true; } else { if (isWindows()) { if (jn.endsWith(".exe")) { setSXASAPP(true); runningJar = false; appType = "as application .exe"; } } else if (isMac()) { if (fSxBase.getAbsolutePath().contains("SikuliX.app/Content")) { setSXASAPP(true); appType = "as application .app"; if (!fSxBase.getAbsolutePath().startsWith("/Applications")) { appType += " (not from /Applications folder)"; } } } } } else { terminate(1, "sxRunningAs: no valid Java context for SikuliX available " + "(java.security.CodeSource.getLocation() is null)"); } } //</editor-fold> //<editor-fold desc="*** get SX options at startup"> private static File fOptions = null; private static String fnOptions = "sxoptions.txt"; private static PropertiesConfiguration sxOptions = null; private static void loadOptions() { boolean success = true; URL urlOptions = SX.class.getClassLoader().getResource("Settings/sxoptions.txt"); if (!isNull(urlOptions)) { Configurations configs = new Configurations(); try { sxOptions = configs.properties(urlOptions); } catch (ConfigurationException cex) { success = false; } } else { success = false; } if (!success) { terminate(1, "loadOptions: SX Options not available: %s", urlOptions); } setOptions(sxOptions); PropertiesConfiguration extraOptions = null; File aFile = null; String argFile = getArg("o"); if (!isNull(argFile)) { aFile = getFile(argFile); if (!aFile.isDirectory()) { if (aFile.exists()) { fOptions = aFile; trace("loadOptions: arg: %s (from arg -o)", aFile); } else { fnOptions = aFile.getName(); trace("loadOptions: file name given: %s (from arg -o)", fnOptions); } } } if (isNull(fOptions)) { for (String sFile : new String[] { getUSERWORK(), getUSERHOME(), getSXSTORE() }) { if (isNull(sFile)) { continue; } aFile = getFile(sFile); trace("loadOptions: check: %s", aFile); fOptions = new File(aFile, fnOptions); if (fOptions.exists()) { break; } else { fOptions = null; } } } if (fOptions != null) { trace("loadOptions: found Options file at: %s", fOptions); Configurations configs = new Configurations(); try { extraOptions = configs.properties(fOptions); } catch (ConfigurationException cex) { error("loadOptions: Options not valid: %s", cex.getMessage()); } if (!isNull(extraOptions)) { setOptions(extraOptions); mergeExtraOptions(sxOptions, extraOptions); } } else { trace("loadOptions: no extra Options file found"); } } private static void setOptions(PropertiesConfiguration someOptions) { if (isNull(someOptions) || someOptions.size() == 0) { return; } Iterator<String> allKeys = someOptions.getKeys(); List<String> sxSettings = new ArrayList<>(); while (allKeys.hasNext()) { String key = allKeys.next(); if (key.startsWith("Settings.")) { sxSettings.add(key); continue; } trace("!setOptions: %s = %s", key, someOptions.getProperty(key)); } if (sxSettings.size() > 0) { Class cClass = null; try { cClass = Class.forName("org.sikuli.basics.Settings"); } catch (ClassNotFoundException e) { error("!setOptions: %s", cClass); } if (!isNull(cClass)) { for (String sKey : sxSettings) { String sAttr = sKey.substring("Settings.".length()); Field cField = null; Class ccField = null; try { cField = cClass.getField(sAttr); ccField = cField.getType(); if (ccField.getName() == "boolean") { cField.setBoolean(null, someOptions.getBoolean(sKey)); } else if (ccField.getName() == "int") { cField.setInt(null, someOptions.getInt(sKey)); } else if (ccField.getName() == "float") { cField.setFloat(null, someOptions.getFloat(sKey)); } else if (ccField.getName() == "double") { cField.setDouble(null, someOptions.getDouble(sKey)); } else if (ccField.getName() == "String") { cField.set(null, someOptions.getString(sKey)); } trace("!setOptions: %s = %s", sAttr, someOptions.getProperty(sKey)); someOptions.clearProperty(sKey); } catch (Exception ex) { error("!setOptions: %s = %s", sKey, sxOptions.getProperty(sKey)); } } } } } private static void mergeExtraOptions(PropertiesConfiguration baseOptions, PropertiesConfiguration extraOptions) { trace("loadOptions: have to merge extra Options"); if (isNull(extraOptions) || extraOptions.size() == 0) { return; } Iterator<String> allKeys = extraOptions.getKeys(); while (allKeys.hasNext()) { String key = allKeys.next(); if (isNull(baseOptions.getProperty(key))) { baseOptions.addProperty(key, extraOptions.getProperty(key)); trace("Option added: %s", key); } else { baseOptions.addProperty(key, extraOptions.getProperty(key)); trace("Option changed: %s", key); } } } //</editor-fold> at start //<editor-fold desc="*** handle options at runtime"> public static void loadOptions(String fpOptions) { error("loadOptions: not yet implemented"); } public static boolean saveOptions(String fpOptions) { error("saveOptions: not yet implemented"); return false; } public static boolean saveOptions() { error("saveOptions: not yet implemented"); return false; } public static boolean hasOptions() { return sxOptions != null && sxOptions.size() > 0; } public static boolean isOption(String pName) { return isOption(pName, false); } public static boolean isOption(String pName, Boolean bDefault) { if (sxOptions == null) { return bDefault; } String pVal = sxOptions.getString(pName, bDefault.toString()).toLowerCase(); if (pVal.contains("yes") || pVal.contains("true") || pVal.contains("on")) { return true; } return false; } public static String getOption(String pName) { return getOption(pName, ""); } public static String getOption(String pName, String sDefault) { if (!hasOptions()) { return ""; } return sxOptions.getString(pName, sDefault); } public static void setOption(String pName, String sValue) { sxOptions.setProperty(pName, sValue); } public static double getOptionNumber(String pName) { return getOptionNumber(pName, 0); } public static double getOptionNumber(String pName, double nDefault) { double nVal = sxOptions.getDouble(pName, nDefault); return nVal; } public static Map<String, String> getOptions() { Map<String, String> mapOptions = new HashMap<String, String>(); if (hasOptions()) { Iterator<String> allKeys = sxOptions.getKeys(); while (allKeys.hasNext()) { String key = allKeys.next(); mapOptions.put(key, getOption(key)); } } return mapOptions; } public static void dumpOptions() { if (hasOptions()) { p("*** options dump"); for (String sOpt : getOptions().keySet()) { p("%s = %s", sOpt, getOption(sOpt)); } p("*** options dump end"); } } //</editor-fold> //<editor-fold desc="*** system/java version info"> static enum theSystem { WIN, MAC, LUX, FOO } /** * @return path seperator : or ; */ public String getSeparator() { if (isWindows()) { return ";"; } return ":"; } /** * ***** Property SXSYSTEM ***** * * @return info about the system running on */ public static String getSYSTEM() { if (isNotSet(SXSYSTEM)) { String osName = System.getProperty("os.name"); String osVersion = System.getProperty("os.version"); if (osName.toLowerCase().startsWith("windows")) { SXSYS = theSystem.WIN; osName = "Windows"; SXSYSshort = "windows"; } else if (osName.toLowerCase().startsWith("mac")) { SXSYS = theSystem.MAC; osName = "Mac OSX"; SXSYSshort = "mac"; } else if (osName.toLowerCase().startsWith("linux")) { SXSYS = theSystem.LUX; osName = "Linux"; SXSYSshort = "linux"; } else { terminate(-1, "running on not supported System: %s (%s)", osName, osVersion); } SYSTEMVERSION = osVersion; SXSYSTEM = String.format("%s (%s)", osName, SYSTEMVERSION); } return SXSYSTEM; } static String SXSYSTEM = ""; static theSystem SXSYS = theSystem.FOO; static String SXSYSshort = ""; /** * ***** Property SXSYSTEMVERSION ***** * * @return the running system's version info */ public static String getSYSTEMVERSION() { if (isNotSet(SYSTEMVERSION)) { getSYSTEM(); } return SYSTEMVERSION; } static String SYSTEMVERSION = ""; /** * @return true/false */ public static boolean isWindows() { getSYSTEM(); return theSystem.WIN.equals(SXSYS); } /** * @return true/false */ public static boolean isLinux() { getSYSTEM(); return theSystem.LUX.equals(SXSYS); } /** * @return true/false */ public static boolean isMac() { getSYSTEM(); return theSystem.MAC.equals(SXSYS); } public static boolean isOSX10() { return getSYSTEMVERSION().startsWith("10.10.") || getSYSTEMVERSION().startsWith("10.11."); } /** * ***** Property SXASAPP ***** * * @return to know wether running as .exe/.app */ public static boolean isSXASAPP() { if (isNotSet(SXASAPP)) { //TODO isSXASAPP detect running as .exe/.app setSXASAPP(false); } return SXASAPP; } static Boolean SXASAPP = null; public static boolean setSXASAPP(boolean val) { SXASAPP = val; return SXASAPP; } /** * ***** Property JHOME ***** * * @return the Java installation path */ public static String getJHOME() { if (isNotSet(JHOME)) { String jhome = System.getProperty("java.home"); if (isSet(jhome)) { JHOME = jhome; } } return JHOME; } static String JHOME = ""; /** * ***** Property JVERSION ***** * * @return Java version info */ public static String getJVERSION() { if (isNotSet(JVERSION)) { String vJava = System.getProperty("java.runtime.version"); String vVM = System.getProperty("java.vm.version"); String vClass = System.getProperty("java.class.version"); String vSysArch = System.getProperty("os.arch"); int javaVersion = 0; if (vSysArch == null || !vSysArch.contains("64")) { terminate(1, "Java arch not 64-Bit or not detected: JavaSystemProperty::os.arch = %s", vSysArch); } try { javaVersion = Integer.parseInt(vJava.substring(2, 3)); JVERSION = String.format("Java %s vm %s class %s arch %s", vJava, vVM, vClass, vSysArch); } catch (Exception ex) { terminate(1, "Java version not detected: JavaSystemProperty::java.runtime.version = %s", vJava); } if (javaVersion < 7 || javaVersion > 8) { terminate(1, "Java version must be 7 or 8"); } } return JVERSION; } static String JVERSION = ""; /** * ***** Property JVERSIONint ***** * * @return Java version number */ public static int getJVERSIONint() { if (isNotSet(JVERSIONint)) { JVERSIONint = Integer.parseInt(getJVERSION().substring(5, 6)); } return JVERSIONint; } static Integer JVERSIONint = null; public static boolean isJava8() { return getJVERSIONint() > 7; } public static boolean isJava7() { return getJVERSIONint() > 6; } //</editor-fold> //<editor-fold desc="*** temp folders"> /** * ***** Property SYSTEMP ***** * * @return the path for temporary stuff according to JavaSystemProperty::java.io.tmpdir */ public static String getSYSTEMP() { if (isNotSet(SYSTEMP)) { String tmpdir = System.getProperty("java.io.tmpdir"); if (tmpdir == null || tmpdir.isEmpty() || !getFile(tmpdir).exists()) { terminate(1, "JavaSystemProperty::java.io.tmpdir not valid"); } SYSTEMP = getFile(tmpdir).getAbsolutePath(); } return SYSTEMP; } static String SYSTEMP = ""; /** * ***** Property SXTEMP ***** * * @return the path to the area where Sikulix stores temporary stuff (located in SYSTEMP) */ public static String getSXTEMP() { if (isNotSet(SXTEMP)) { File fSXTempPath = getFile(getSYSTEMP(), String.format("Sikulix_%d", getRandomInt())); for (String aFile : getFile(SYSTEMP).list()) { if ((aFile.startsWith("Sikulix") && (new File(aFile).isFile())) || (aFile.startsWith("jffi") && aFile.endsWith(".tmp"))) { Content.deleteFileOrFolder(new File(getSYSTEMP(), aFile)); } } fSXTempPath.mkdirs(); if (!fSXTempPath.exists()) { terminate(1, "getSXTEMP: could not create: %s", fSXTempPath.getAbsolutePath()); } SXTEMP = fSXTempPath.getAbsolutePath(); } return SXTEMP; } static String SXTEMP = ""; /** * @return a positive random int > 0 using Java's Random().nextInt() */ static int getRandomInt() { int rand = 1 + new Random().nextInt(); return (rand < 0 ? rand * -1 : rand); } //</editor-fold> //<editor-fold desc="*** user/work/appdata folder"> /** * ***** Property USERHOME ***** * * @return the system specific User's home folder */ public static String getUSERHOME() { if (isNotSet(USERHOME)) { String aFolder = System.getProperty("user.home"); if (aFolder == null || aFolder.isEmpty() || !getFile(aFolder).exists()) { terminate(-1, "getUSERHOME: JavaSystemProperty::user.home not valid"); } USERHOME = getFile(aFolder).getAbsolutePath(); } return USERHOME; } static String USERHOME = ""; /** * ***** Property USERWORK ***** * * @return the working folder from JavaSystemProperty::user.dir */ public static String getUSERWORK() { if (isNotSet(USERWORK)) { String aFolder = System.getProperty("user.dir"); if (aFolder == null || aFolder.isEmpty() || !new File(aFolder).exists()) { terminate(-1, "getUSERWORK: JavaSystemProperty::user.dir not valid"); } USERWORK = getFolder(aFolder).getAbsolutePath(); } return USERWORK; } static String USERWORK = ""; /** * ***** Property SYSAPP ***** * * @return the system specific path to the users application storage area */ public static String getSYSAPP() { if (isNotSet(SYSAPP)) { String appDataMsg = ""; File fSysAppPath = null; if (isWindows()) { String sDir = System.getenv("APPDATA"); if (sDir == null || sDir.isEmpty()) { terminate(1, "setSYSAPP: Windows: %s not valid", "%APPDATA%"); } fSysAppPath = getFile(sDir); } else if (isMac()) { fSysAppPath = getFile(getUSERHOME(), "Library/Application Support"); } else if (isLinux()) { fSysAppPath = getFile(getUSERHOME()); SXAPPdefault = ".Sikulix/SX2"; } SYSAPP = fSysAppPath.getAbsolutePath(); } return SYSAPP; } static String SYSAPP = ""; //</editor-fold> //<editor-fold desc="*** SX app data folder"> /** * ***** Property SXAPP ***** * * @return the path to the area in SYSAPP where Sikulix stores all stuff */ public static String getSXAPP() { if (isNotSet(SXAPP)) { File fDir = getFile(getSYSAPP(), SXAPPdefault); fDir.mkdirs(); if (!fDir.exists()) { terminate(1, "setSXAPP: folder not available or cannot be created: %s", fDir); } SXAPP = fDir.getAbsolutePath(); } return SXAPP; } static String SXAPP = ""; static String SXAPPdefault = "Sikulix/SX2"; /** * ***** Property SXDOWNLOADS ***** * * @return path where Sikulix stores downloaded stuff */ public static String getSXDOWNLOADS() { if (isNotSet(SXDOWNLOADS)) { String fBase = getSXAPP(); File fDir = getFile(fBase, SXDOWNLOADSdefault); setSXDOWNLOADS(fDir); } return SXDOWNLOADS; } static String SXDOWNLOADS = ""; static String SXDOWNLOADSdefault = "Downloads"; public static String setSXDOWNLOADS(Object oDir) { File fDir = getFile(oDir, null); if (isSet(fDir)) { fDir.mkdirs(); } if (isNotSet(fDir) || !existsFile(fDir) || !fDir.isDirectory()) { terminate(1, "setSXDOWNLOADS: not posssible or not valid: %s", fDir); } SXDOWNLOADS = fDir.getAbsolutePath(); return SXDOWNLOADS; } /** * ***** Property SXNATIVE ***** * * @return path where Sikulix stores the native stuff */ public static String getSXNATIVE() { if (isNotSet(SXNATIVE)) { String fBase = getSXAPP(); File fDir = getFolder(fBase, SXNATIVEdefault); setSXNATIVE(fDir); } return SXNATIVE; } static String SXNATIVE = ""; static String SXNATIVEdefault = "Native"; public static String setSXNATIVE(Object oDir) { File fDir = getFolder(oDir); if (isNotSet(fDir) || !existsFile(fDir) || !fDir.isDirectory()) { terminate(1, "setSXNATIVE: not posssible or not valid: %s", fDir); } SXNATIVE = fDir.getAbsolutePath(); return SXNATIVE; } /** * ***** Property SXLIB ***** * * @return path to folder containing complementary stuff for scripting languages */ public static String getSXLIB() { if (isNotSet(SXLIB)) { String fBase = getSXAPP(); File fDir = getFile(fBase, SXLIBdefault); setSXLIB(fDir); } return SXLIB; } static String SXLIB = ""; static String SXLIBdefault = "LIB"; public static String setSXLIB(Object oDir) { File fDir = getFile(oDir, null); if (isSet(fDir)) { fDir.mkdirs(); } if (isNotSet(fDir) || !existsFile(fDir) || !fDir.isDirectory()) { terminate(1, "setSXLIB: not posssible or not valid: %s", fDir); } SXLIB = fDir.getAbsolutePath(); return SXLIB; } /** * ***** Property SXSTORE ***** * * @return path where other stuff is found or stored at runtime (options, logs, ...) */ public static String getSXSTORE() { if (isNotSet(SXSTORE)) { String fBase = getSXAPP(); File fDir = getFile(fBase, SXSTOREdefault); setSXSTORE(fDir); } return SXSTORE; } static String SXSTORE = ""; static String SXSTOREdefault = "Store"; public static String setSXSTORE(Object oDir) { File fDir = getFolder(oDir); if (isNotSet(fDir) || !existsFile(fDir) || !fDir.isDirectory()) { terminate(1, "setSXSTORE: not posssible or not valid: %s", fDir); } SXSTORE = fDir.getAbsolutePath(); return SXSTORE; } /** * ***** Property SXEDITOR ***** * * @return path to folder containing supporting stuff for Sikulix IDE */ public static String getSXEDITOR() { if (isNotSet(SXEDITOR)) { String fBase = getSXAPP(); File fDir = getFolder(fBase, SXEDITORdefault); setSXEDITOR(fDir); } return SXEDITOR; } static String SXEDITOR = ""; static String SXEDITORdefault = "Extensions/SXEditor"; public static String setSXEDITOR(Object oDir) { File fDir = getFile(oDir); if (isSet(fDir)) { fDir.mkdirs(); } if (isNotSet(fDir) || !existsFile(fDir) || !fDir.isDirectory()) { terminate(1, "setSXEDITOR: not posssible or not valid: %s", fDir); } SXEDITOR = fDir.getAbsolutePath(); return SXEDITOR; } /** * ***** Property SXTESSERACT ***** * * @return path to folder for stuff supporting Tesseract */ public static String getSXTESSERACT() { if (isNotSet(SXTESSERACT)) { String fBase = getSXAPP(); File fDir = getFile(fBase, SXTESSERACTdefault); setSXTESSERACT(fDir); } return SXTESSERACT; } static String SXTESSERACT = ""; static String SXTESSERACTdefault = "TESSERACT"; public static String setSXTESSERACT(Object oDir) { File fDir = getFile(oDir, null); if (isSet(fDir)) { fDir.mkdirs(); } if (isNotSet(fDir) || !existsFile(fDir) || !fDir.isDirectory()) { terminate(1, "setSXTESSERACT: not posssible or not valid: %s", fDir); } SXTESSERACT = fDir.getAbsolutePath(); return SXTESSERACT; } /** * ***** Property SXEXTENSIONS ***** * * @return path to folder containg extensions or plugins */ public static String getSXEXTENSIONS() { if (isNotSet(SXEXTENSIONS)) { String fBase = getSXAPP(); File fDir = getFile(fBase, SXEXTENSIONSdefault); setSXEXTENSIONS(fDir); } return SXEXTENSIONS; } static String SXEXTENSIONS = ""; static String SXEXTENSIONSdefault = "Extensions"; static String[] theExtensions = new String[] { "selenium4sikulix" }; public static String setSXEXTENSIONS(Object oDir) { File fDir = getFile(oDir, null); if (isSet(fDir)) { fDir.mkdirs(); } if (isNotSet(fDir) || !existsFile(fDir) || !fDir.isDirectory()) { terminate(1, "setSXEXTENSIONS: not posssible or not valid: %s", fDir); } SXEXTENSIONS = fDir.getAbsolutePath(); return SXEXTENSIONS; } public static File asExtension(String fpJar) { File fJarFound = new File(Content.normalizeAbsolute(fpJar, false)); if (!fJarFound.exists()) { String fpCPEntry = Content.isOnClasspath(fJarFound.getName()); if (fpCPEntry == null) { fJarFound = new File(getSXEXTENSIONS(), fpJar); if (!fJarFound.exists()) { fJarFound = new File(getSXLIB(), fpJar); if (!fJarFound.exists()) { fJarFound = null; } } } else { fJarFound = new File(fpCPEntry, fJarFound.getName()); } } else { return null; } return fJarFound; } /** * ***** Property SXIMAGES ***** * * @return */ public static String getSXIMAGES() { if (isNotSet(SXIMAGES)) { String fBase = getSXAPP(); File fDir = getFolder(fBase, SXIMAGESdefault); setSXIMAGES(fDir); } return SXIMAGES; } static String SXIMAGES = ""; static String SXIMAGESdefault = "Images"; public static String setSXIMAGES(Object oDir) { File fDir = getFile(oDir, null); if (isSet(fDir)) { fDir.mkdirs(); } if (isNotSet(fDir) || !existsFile(fDir) || !fDir.isDirectory()) { terminate(1, "setSXIMAGES: not posssible or not valid: %s", fDir); } SXIMAGES = fDir.getAbsolutePath(); return SXIMAGES; } //</editor-fold> //<editor-fold desc="*** SX version info"> /** * ***** Property SXVERSION ***** * * @return Sikulix version */ public static String getSXVERSION() { if (isNotSet(SXVERSION)) { String sxVersion = "?sxVersion?"; String sxBuild = "?sxBuild?"; String sxVersionShow = "?sxVersionShow?"; String sxStamp = "?sxStamp?"; sxVersion = sxOptions.getString("sxversion"); sxBuild = sxOptions.getString("sxbuild"); sxBuild = sxBuild.replaceAll("\\-", ""); sxBuild = sxBuild.replaceAll("_", ""); sxBuild = sxBuild.replaceAll("\\:", ""); String sxlocalrepo = Content.slashify(sxOptions.getString("sxlocalrepo"), true); String sxJythonVersion = sxOptions.getString("sxjython"); String sxJRubyVersion = sxOptions.getString("sxjruby"); debug("getSXVERSION: version: %s build: %s", sxVersion, sxBuild); sxStamp = String.format("%s_%s", sxVersion, sxBuild); // used for download of production versions String dlProdLink = "https://launchpad.net/raiman/sikulix2013+/"; String dlProdLinkSuffix = "/+download/"; // used for download of development versions (nightly builds) String dlDevLink = "http://nightly.sikuli.de/"; sxJythonMaven = "org/python/jython-standalone/" + sxJythonVersion + "/jython-standalone-" + sxJythonVersion + ".jar"; sxJython = sxlocalrepo + sxJythonMaven; sxJRubyMaven = "org/jruby/jruby-complete/" + sxJRubyVersion + "/jruby-complete-" + sxJRubyVersion + ".jar"; sxJRuby = sxlocalrepo + sxJRubyMaven; tessData.put("eng", "http://download.sikulix.com/tesseract-ocr-3.02.eng.tar.gz"); sxLibsCheckName = String.format(sxLibsCheckStamp, sxStamp); SXVERSION = sxVersion; SXBUILD = sxBuild; SXVERSIONSHOW = String.format("%s (%s)", sxVersion, sxBuild); SXSTAMP = sxStamp; } return SXVERSION; } static String SXVERSION = ""; /** * ***** Property SXBUILD ***** * * @return Sikulix build timestamp */ public static String getSXBUILD() { if (isNotSet(SXBUILD)) { getSXVERSION(); } return SXBUILD; } static String SXBUILD = ""; /** * ***** Property SXVERSIONSHOW ***** * * @return Version (Build) */ public static String getSXVERSIONSHOW() { if (isNotSet(SXVERSIONSHOW)) { getSXVERSION(); } return SXVERSIONSHOW; } static String SXVERSIONSHOW = ""; /** * ***** Property SXSTAMP ***** * * @return Version_Build */ public static String getSXSTAMP() { if (isNotSet(SXSTAMP)) { getSXVERSION(); } return SXSTAMP; } static String SXSTAMP = ""; //</editor-fold> //<editor-fold desc="*** monitor info"> private static GraphicsEnvironment genv = null; private static GraphicsDevice[] gdevs; private static Rectangle[] monitorBounds = null; private static Rectangle rAllMonitors; private static int mainMonitor = -1; private static int nMonitors = 0; /** * checks, whether Java runs with a valid GraphicsEnvironment (usually means real screens connected) * * @return false if Java thinks it has access to screen(s), true otherwise */ public static boolean isHeadless() { return GraphicsEnvironment.isHeadless(); } private static void globalGetMonitors() { if (!isHeadless()) { genv = GraphicsEnvironment.getLocalGraphicsEnvironment(); gdevs = genv.getScreenDevices(); nMonitors = gdevs.length; if (nMonitors == 0) { terminate(1, "globalGetMonitors: GraphicsEnvironment has no ScreenDevices"); } monitorBounds = new Rectangle[nMonitors]; rAllMonitors = null; Rectangle currentBounds; for (int i = 0; i < nMonitors; i++) { currentBounds = new Rectangle(gdevs[i].getDefaultConfiguration().getBounds()); if (null != rAllMonitors) { rAllMonitors = rAllMonitors.union(currentBounds); } else { rAllMonitors = currentBounds; } if (currentBounds.contains(new Point())) { if (mainMonitor < 0) { mainMonitor = i; debug("globalGetMonitors: 1#ScreenDevice %d has (0,0) --- will be primary Screen(0)", i); } else { debug("globalGetMonitors: 2#ScreenDevice %d too contains (0,0)!", i); } } debug("globalGetMonitors: Monitor %d: (%d, %d) %d x %d", i, currentBounds.x, currentBounds.y, currentBounds.width, currentBounds.height); monitorBounds[i] = currentBounds; } if (mainMonitor < 0) { debug("globalGetMonitors: No ScreenDevice has (0,0) --- using 0 as primary: %s", monitorBounds[0]); mainMonitor = 0; } } else { error("running in headless environment"); } } public static int getNumberOfMonitors() { return nMonitors; } public static Rectangle getMonitor(int n) { if (isHeadless() || mainMonitor < 0) { return new Rectangle(); } n = (n < 0 || n >= nMonitors) ? mainMonitor : n; return new Rectangle(monitorBounds[n]); } public static Rectangle getMonitor() { return getMonitor(mainMonitor); } public static int getMainMonitorID() { return mainMonitor; } public static Rectangle getAllMonitors() { return rAllMonitors; } public static GraphicsDevice getGraphicsDevice(int id) { return gdevs[id]; } //</editor-fold> //<editor-fold desc="*** handle native libs"> public static File fLibsProvided; public static boolean useLibsProvided; public static String linuxNeededLibs = ""; public static String linuxAppSupport = ""; static boolean areLibsExported = false; static String fpJarLibs = null; static Map<NATIVES, Boolean> libsLoaded = new HashMap<NATIVES, Boolean>(); static String sxLibsCheckStamp = "MadeForSikuliX_%s"; static String sflibsCheckFileStored = "MadeForSikuliX2"; public static String sxLibsCheckName = ""; public static String sfLibOpencvJava = "_ext_opencv_java"; public static String sfLibJXGrabKey = "_ext_JXGrabKey"; public static String sfLibJIntellitype = "_ext_JIntellitype"; public static String sfLibWinUtil = "_ext_WinUtil"; public static String sfLibMacUtil = "_ext_MacUtil"; public static String sfLibMacHotkey = "_ext_MacHotkeyManager"; static class LibsFilter implements FilenameFilter { String sAccept = ""; public LibsFilter(String toAccept) { sAccept = toAccept; } @Override public boolean accept(File dir, String name) { if (dir.getPath().contains(sAccept)) { return true; } return false; } } static void addToWindowsSystemPath(File fLibsFolder) { String syspath = SysJNA.WinKernel32.getEnvironmentVariable("PATH"); if (syspath == null) { terminate(1, "addToWindowsSystemPath: cannot access system path"); } else { String libsPath = (fLibsFolder.getAbsolutePath()).replaceAll("/", "\\"); if (!syspath.toUpperCase().contains(libsPath.toUpperCase())) { if (!SysJNA.WinKernel32.setEnvironmentVariable("PATH", libsPath + ";" + syspath)) { terminate(999, "", ""); } syspath = SysJNA.WinKernel32.getEnvironmentVariable("PATH"); if (!syspath.toUpperCase().contains(libsPath.toUpperCase())) { terminate(1, "addToWindowsSystemPath: did not work: %s", syspath); } debug("addToWindowsSystemPath: added: %s", libsPath); } } } static boolean checkJavaUsrPath(File fLibsFolder) { String fpLibsFolder = fLibsFolder.getAbsolutePath(); Field usrPathsField = null; boolean contained = false; try { usrPathsField = ClassLoader.class.getDeclaredField("usr_paths"); } catch (NoSuchFieldException ex) { error("checkJavaUsrPath: get (%s)", ex); } catch (SecurityException ex) { error("checkJavaUsrPath: get (%s)", ex); } if (usrPathsField != null) { usrPathsField.setAccessible(true); try { //get array of paths String[] javapaths = (String[]) usrPathsField.get(null); //check if the path to add is already present for (String p : javapaths) { if (new File(p).equals(fLibsFolder)) { contained = true; break; } } //add the new path if (!contained) { final String[] newPaths = Arrays.copyOf(javapaths, javapaths.length + 1); newPaths[newPaths.length - 1] = fpLibsFolder; usrPathsField.set(null, newPaths); debug("checkJavaUsrPath: added to ClassLoader.usrPaths"); contained = true; } } catch (IllegalAccessException ex) { error("checkJavaUsrPath: set (%s)", ex); } catch (IllegalArgumentException ex) { error("checkJavaUsrPath: set (%s)", ex); } return contained; } return false; } static void exportNativeLibraries() { if (areLibsExported) { return; } File fSXNative = getFile(getSXNATIVE()); if (!new File(fSXNative, sxLibsCheckName).exists()) { debug("exportNativeLibraries: folder empty or has wrong content"); Content.deleteFileOrFolder(fSXNative); } if (fSXNative.exists()) { debug("exportNativeLibraries: folder exists: %s", fSXNative); } else { fSXNative.mkdirs(); if (!fSXNative.exists()) { terminate(1, "exportNativeLibraries: folder not available: %s", fSXNative); } debug("exportNativeLibraries: new folder: %s", fSXNative); fpJarLibs = "/Native/" + SXSYSshort; URL uLibsFrom = sxGlobalClassReference.getResource(fpJarLibs); if (uLibsFrom == null) { Content.dumpClassPath("sikulix"); terminate(1, "exportNativeLibraries: libs not on classpath: " + fpJarLibs); } debug("exportNativeLibraries: from: %s", uLibsFrom); Content.extractResourcesToFolder(fpJarLibs, fSXNative, null); if (!new File(fSXNative, sflibsCheckFileStored).exists()) { terminate(1, "exportNativeLibraries: did not work"); } new File(fSXNative, sflibsCheckFileStored).renameTo(new File(fSXNative, sxLibsCheckName)); if (!new File(fSXNative, sxLibsCheckName).exists()) { terminate(1, "exportNativeLibraries: did not work"); } } for (String aFile : fSXNative.list()) { if (aFile.contains("opencv_java")) { sfLibOpencvJava = aFile; } else if (aFile.contains("JXGrabKey")) { sfLibJXGrabKey = aFile; } else if (aFile.contains("JIntellitype")) { sfLibJIntellitype = aFile; } else if (aFile.contains("WinUtil")) { sfLibWinUtil = aFile; } else if (aFile.contains("MacUtil")) { sfLibMacUtil = aFile; } else if (aFile.contains("MacHotkey")) { sfLibMacHotkey = aFile; } } areLibsExported = true; } public static enum NATIVES { OPENCV, TESSERACT, SYSUTIL, HOTKEY } static boolean loadNative(NATIVES type) { boolean success = true; if (libsLoaded.isEmpty()) { for (NATIVES nType : NATIVES.values()) { libsLoaded.put(nType, false); } exportNativeLibraries(); if (isWindows()) { addToWindowsSystemPath(getFile(getSXNATIVE())); if (!checkJavaUsrPath(getFile(getSXNATIVE()))) { error("exportNativeLibraries: JavaUserPath: see errors - might not work and crash later"); } String lib = "jawt.dll"; File fJawtDll = new File(getFile(getSXNATIVE()), lib); Content.deleteFileOrFolder(fJawtDll); Content.xcopy(new File(getJHOME() + "/bin/" + lib), fJawtDll); if (!fJawtDll.exists()) { terminate(1, "exportNativeLibraries: problem copying %s", fJawtDll); } } } if (OPENCV.equals(type) && !libsLoaded.get(OPENCV)) { loadNativeLibrary(sfLibOpencvJava); } else if (SYSUTIL.equals(type) && !libsLoaded.get(SYSUTIL)) { if (isWindows()) { loadNativeLibrary(sfLibWinUtil); } else if (isMac()) { loadNativeLibrary(sfLibMacUtil); } } else if (HOTKEY.equals(type) && !libsLoaded.get(HOTKEY)) { if (isWindows()) { loadNativeLibrary(sfLibJIntellitype); } else if (isMac()) { loadNativeLibrary(sfLibMacHotkey); } else if (isLinux()) { loadNativeLibrary(sfLibJXGrabKey); } } else { success = false; } if (success) { libsLoaded.put(type, true); } return success; } static void loadNativeLibrary(String aLib) { try { if (aLib.startsWith("_ext_")) { error("loadNativeLibrary: loading external library not implemented: %s", aLib); } else { String sf_aLib = new File(getSXNATIVE(), aLib).getAbsolutePath(); System.load(sf_aLib); debug("loadNativeLibrary: bundled: %s", aLib); } } catch (UnsatisfiedLinkError ex) { terminate(1, "loadNativeLibrary: loading library error: %s (%s)", aLib, ex.getMessage()); } } //</editor-fold> //<editor-fold desc="*** global helper methods"> /** * check wether the given object is in JSON format as ["ID", ...] * * @param json * @return true if object is in JSON format, false otherwise */ public static boolean isJSON(Object json) { if (json instanceof String) { return ((String) json).trim().startsWith("[\"") || ((String) json).trim().startsWith("{\""); } return false; } public static void dumpSysProps() { dumpSysProps(null); } public static void dumpSysProps(String filter) { filter = filter == null ? "" : filter; p("*** system properties dump " + filter); Properties sysProps = System.getProperties(); ArrayList<String> keysProp = new ArrayList<String>(); Integer nL = 0; String entry; for (Object e : sysProps.keySet()) { entry = (String) e; if (entry.length() > nL) { nL = entry.length(); } if (filter.isEmpty() || !filter.isEmpty() && entry.contains(filter)) { keysProp.add(entry); } } Collections.sort(keysProp); String form = "%-" + nL.toString() + "s = %s"; for (Object e : keysProp) { p(form, e, sysProps.get(e)); } p("*** system properties dump end" + filter); } public static void show() { if (hasOptions()) { dumpOptions(); } p("***** show environment (%s)", getSXVERSIONSHOW()); p("user.home: %s", getUSERHOME()); p("user.dir (work dir): %s", getUSERWORK()); p("java.io.tmpdir: %s", getSYSTEMP()); p("running on %s", getSYSTEM()); p(getJVERSION()); p("app data folder: %s", getSXAPP()); p("libs folder: %s", getSXNATIVE()); if (runningJar) { p("executing jar: %s", fSxBaseJar); } Content.dumpClassPath("sikulix"); if (isJythonReady) { JythonHelper.get().showSysPath(); } p("***** show environment end"); } private static File getFileMake(Object... args) { if (args.length < 1) { return null; } Object oPath = args[0]; Object oSub = ""; if (args.length > 1) { oSub = args[1]; } File fPath = null; if (isNotSet(oSub)) { fPath = new File(oPath.toString()); } else { fPath = new File(oPath.toString(), oSub.toString()); } try { fPath = fPath.getCanonicalFile(); } catch (IOException e) { error("getFile: %s %s error(%s)", oPath, oSub, e.getMessage()); } return fPath; } public static File getFile(Object... args) { return getFileMake(args); } public static File getFileExists(Object... args) { File fPath = getFileMake(args); if (!isNull(fPath) && !fPath.exists()) { error("getFile: %s error(not available)", fPath); return null; } return fPath; } public static File getFolder(Object... args) { File aFile = getFileMake(args); if (isNotSet(aFile)) { return null; } if (aFile.isDirectory()) { return aFile; } aFile.mkdirs(); if (aFile.isDirectory()) { return aFile; } error("getFolder: %s error(... does not exist)", aFile); return null; } public static URL getFileURL(Object... args) { File aFile = getFile(args); if (isNotSet(aFile)) { return null; } try { return new URL("file:" + aFile.toString()); } catch (MalformedURLException e) { error("getFileURL: %s error(%s)", aFile, e.getMessage()); return null; } } public static URL getJarURL(Object... args) { File aFile = getFile(args); if (isNotSet(aFile)) { return null; } String sSub = ""; if (args.length > 2) { sSub = args[2].toString(); } try { return new URL("jar:file:" + aFile.toString() + "!/" + sSub); } catch (MalformedURLException e) { error("getJarURL: %s %s error(%s)", aFile, sSub, e.getMessage()); return null; } } public static URL getNetURL(Object... args) { //TODO implment getNetURL() URL netURL = null; return netURL; } public static boolean existsFile(Object aPath) { if (aPath instanceof URL) { //TODO implement existsFile(URL) } return (getFile(aPath).exists()); } public static boolean isNull(Object obj) { return null == obj; } public static boolean isNotNull(Object obj) { return null != obj; } public static boolean isNotSet(Object obj) { if (null != obj && obj instanceof String) { if (((String) obj).isEmpty()) { return true; } else { return false; } } return null == obj; } public static boolean isSet(Object obj) { if (null != obj && obj instanceof String) { if (((String) obj).isEmpty()) { return false; } else { return true; } } return null != obj; } public static void pause(int time) { try { Thread.sleep(time * 1000); } catch (InterruptedException ex) { } } public static void pause(float time) { try { Thread.sleep((int) (time * 1000)); } catch (InterruptedException ex) { } } public static void pause(double time) { try { Thread.sleep((int) (time * 1000)); } catch (InterruptedException ex) { } } public static Location at() { PointerInfo mp = MouseInfo.getPointerInfo(); if (mp != null) { return new Location(MouseInfo.getPointerInfo().getLocation()); } else { error("not possible to get mouse position (PointerInfo == null)"); return null; } } //</editor-fold> //<editor-fold desc="*** candidates for Content"> public static String canonicalPath(File aFile) { try { return aFile.getCanonicalPath(); } catch (IOException e) { return aFile.getAbsolutePath(); } } public static URL makeURL(Object... args) { if (args.length < 1) { return null; } URL url = null; String proto = "file:"; String sURL = ""; String fpMain = ""; Object arg0 = args[0]; String fpSub = args.length > 1 ? (String) args[1] : ""; if (arg0 instanceof File) { fpMain = canonicalPath((File) arg0); } else if (arg0 instanceof String) { if (((String) arg0).startsWith("http")) { proto = "http:"; fpMain = (String) arg0; } else { fpMain = canonicalPath(getFile(arg0.toString())); } } if ("file:".equals(proto)) { if (fpMain.endsWith(".jar")) { if (!existsFile(fpMain)) { log.error("makeURL: not exists: %s", fpMain); } fpMain = "file:" + fpMain + "!/"; proto = "jar:"; } } if (isSet(fpSub)) { if ("file:".equals(proto)) { fpMain = canonicalPath(getFile(fpMain, fpSub)); } else { if (!fpSub.startsWith("/")) { fpSub = "/" + fpSub; } fpMain += fpSub; } } if (!"http:".equals(proto)) { if ("file:".equals(proto) && isNotSet(getFolder(fpMain))) { log.error("makeURL: not exists: %s", fpMain); } sURL = proto + fpMain; } else { sURL = fpMain; } try { url = new URL(sURL); } catch (MalformedURLException e) { log.error("makeURL: not valid: %s %s", arg0, (isNotSet(fpSub) ? "" : ", " + fpSub)); } return url; } public static String makePath(URL uPath) { String sPath = ""; String proto = ""; sPath = uPath.getPath(); proto = uPath.getProtocol(); if ("file".equals(proto) || "jar".equals(proto)) { if ("jar".equals(proto)) { sPath = sPath.replaceFirst("file:", ""); sPath = sPath.replaceFirst("!/", "/"); } sPath = getFile(sPath).getAbsolutePath(); } else { sPath = uPath.toExternalForm(); } return sPath; } //</editor-fold> /** * ***** Property SXROBOT ***** * * @return */ public static Robot getSXROBOT() { if (isNotSet(SXROBOT)) { try { SXROBOT = new Robot(); } catch (AWTException e) { terminate(1, "getSXROBOT: not possible: %s", e.getMessage()); } } return SXROBOT; } private static Robot SXROBOT = null; public static IRobot getLocalRobot() { if (isNotSet(SXLOCALROBOT)) { try { SXLOCALROBOT = new LocalRobot(); } catch (AWTException e) { terminate(1, "getLocalRobot: not possible: %s", e.getMessage()); } } return SXLOCALROBOT; } private static IRobot SXLOCALROBOT = null; }