//------------------------------------------------------------------------------------------------// // // // W e l l K n o w n s // // // //------------------------------------------------------------------------------------------------// // <editor-fold defaultstate="collapsed" desc="hdr"> // // Copyright © Audiveris 2018. All rights reserved. // // This program is free software: you can redistribute it and/or modify it under the terms of the // GNU Affero General Public License as published by the Free Software Foundation, either version // 3 of the License, or (at your option) any later version. // // This program 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License along with this // program. If not, see <http://www.gnu.org/licenses/>. //------------------------------------------------------------------------------------------------// // </editor-fold> package org.audiveris.omr; import org.audiveris.omr.log.LogUtil; import static org.audiveris.omr.util.UriUtil.toURI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.lang.reflect.Field; import java.net.JarURLConnection; import java.net.URI; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Enumeration; import java.util.Locale; import java.util.jar.JarFile; import javax.swing.filechooser.FileSystemView; /** * Class {@code WellKnowns} gathers top public static final data to be shared within * Audiveris application. * <p> * Note that a few initial operations are performed here, because they need to take place before any * other class is loaded. * * @author Hervé Bitteur */ public abstract class WellKnowns { //----------// // IDENTITY // //----------// // /** Application company name: {@value}. */ public static final String COMPANY_NAME = ProgramId.COMPANY_NAME; /** Application company id: {@value}. */ public static final String COMPANY_ID = ProgramId.COMPANY_ID; /** Application name: {@value}. */ public static final String TOOL_NAME = ProgramId.PROGRAM_NAME; /** Application id: {@value}. */ public static final String TOOL_ID = ProgramId.PROGRAM_ID; /** Application reference: {@value}. */ public static final String TOOL_REF = ProgramId.PROGRAM_VERSION; /** Application build: {@value}. */ public static final String TOOL_BUILD = ProgramId.PROGRAM_BUILD; /** Specific prefix for application folders: {@value}. */ private static final String TOOL_PREFIX = "/" + COMPANY_ID + "/" + TOOL_ID; //----------// // PLATFORM // //----------// // /** Name of operating system. */ private static final String OS_NAME = System.getProperty("os.name").toLowerCase(Locale.ENGLISH); /** Are we using a Linux OS?. */ public static final boolean LINUX = OS_NAME.startsWith("linux"); /** Are we using a Mac OS?. */ public static final boolean MAC_OS_X = OS_NAME.startsWith("mac os x"); /** Are we using a Windows OS?. */ public static final boolean WINDOWS = OS_NAME.startsWith("windows"); /** Precise OS architecture. */ public static final String OS_ARCH = System.getProperty("os.arch"); /** Are we using Windows on 64 bit architecture?. */ public static final boolean WINDOWS_64 = WINDOWS && (System.getenv( "ProgramFiles(x86)") != null); /** File character encoding. */ public static final String FILE_ENCODING = getFileEncoding(); /** File separator for the current platform. */ public static final String FILE_SEPARATOR = System.getProperty("file.separator"); /** Line separator for the current platform. */ public static final String LINE_SEPARATOR = System.getProperty("line.separator"); /** Redirection, if any, of standard out and err streams. */ public static final String STD_OUT_ERR = System.getProperty("stdouterr"); //---------// // PROGRAM // This is a read-only area //---------// // /** The container from which the application classes were loaded. */ public static final URI CLASS_CONTAINER = getClassContainer(); /** * Running from normal jar archive rather than class files? . * When running directly from .class files, we are in development mode and * want to have very short cycles, data is retrieved from local files. * When running from .jar archive, we are in standard mode whereby most data * is meant to be retrieved from the .jar archive itself. */ public static final boolean RUNNING_FROM_JAR = runningFromJar(); /** The uri where read-only resources are stored. */ public static final URI RES_URI = RUNNING_FROM_JAR ? toURI( WellKnowns.class.getClassLoader().getResource("res")) : Paths.get("res").toUri(); //-------------// read-write area // USER CONFIG // Configuration files the user can edit on his own //-------------// // /** The folder where global configuration data is stored. */ public static final Path CONFIG_FOLDER = getFolder(FolderKind.CONFIG); //-----------// read-write area // USER DATA // User-specific data, except configuration stuff //-----------// // /** Base folder for data. */ public static final Path DATA_FOLDER = getFolder(FolderKind.DATA); /** * The folder where documentations files are installed. * Installation takes place when .jar is run for the first time */ public static final Path DOC_FOLDER = DATA_FOLDER.resolve("www"); /** * The folder where examples files are installed. * Installation takes place when .jar is run for the first time */ public static final Path EXAMPLES_FOLDER = DATA_FOLDER.resolve("examples"); /** The folder where training material is stored. */ public static final Path TRAIN_FOLDER = CONFIG_FOLDER.resolve("train"); /** The default base for output folders. */ public static final Path DEFAULT_BASE_FOLDER = DATA_FOLDER; // BHT: skip "output" //----------// // USER LOG // //----------// // /** The folder where log files are stored. */ public static final Path LOG_FOLDER = getFolder(FolderKind.LOG); /** The folder where temporary data can be stored. */ public static final Path TEMP_FOLDER = LOG_FOLDER.resolve("temp"); static { /** Logging configuration. */ LogUtil.initialize(CONFIG_FOLDER, RES_URI); /** Make sure LOG_FOLDER exists. */ createFolder(LOG_FOLDER); /** Log declared data (debug). */ logDeclaredData(); /** Make sure TEMP_FOLDER exists. */ createFolder(TEMP_FOLDER); } static { /** Disable DirectDraw by default. */ disableDirectDraw(); } static { /** Disable use of JAI native MediaLib, by default. */ disableMediaLib(); } private static enum FolderKind { DATA, CONFIG, LOG; } /** Not meant to be instantiated. */ private WellKnowns () { } //--------------// // ensureLoaded // //--------------// /** * Make sure this class is loaded. */ public static void ensureLoaded () { } //--------------// // createFolder // //--------------// /** * Make sure the provided folder exists. * * @param folder the folder to create if needed */ private static void createFolder (Path folder) { if (!Files.exists(folder)) { try { Files.createDirectories(folder); } catch (IOException ex) { final Logger logger = LoggerFactory.getLogger(WellKnowns.class); logger.warn("Error creating " + folder, ex); } } } //-------------------// // disableDirectDraw // //-------------------// private static void disableDirectDraw () { // See http://performance.netbeans.org/howto/jvmswitches/ // -Dsun.java2d.d3d=false // this switch disables DirectDraw and may solve performance problems // with some HW configurations. final String KEY = "sun.java2d.d3d"; // Respect user setting if any if (System.getProperty(KEY) == null) { System.setProperty(KEY, "false"); } } //-----------------// // disableMediaLib // //-----------------// private static void disableMediaLib () { // Avoid "Could not find mediaLib accelerator wrapper classes. Continuing in pure Java mode" final String KEY = "com.sun.media.jai.disableMediaLib"; // Respect user setting if any if (System.getProperty(KEY) == null) { System.setProperty(KEY, "true"); } } //-------------------// // getClassContainer // //-------------------// private static URI getClassContainer () { return toURI(WellKnowns.class.getProtectionDomain().getCodeSource().getLocation()); } //-----------------// // getFileEncoding // //-----------------// private static String getFileEncoding () { final String ENCODING_KEY = "file.encoding"; final String ENCODING_VALUE = "UTF-8"; System.setProperty(ENCODING_KEY, ENCODING_VALUE); return ENCODING_VALUE; } //-----------// // getFolder // //-----------// private static Path getFolder (FolderKind kind) { if (WINDOWS) { return getFolderForWindows(kind); } else if (MAC_OS_X) { return getFolderForMac(kind); } else if (LINUX) { return getFolderForLinux(kind); } else { printError("Platform unknown: " + kind); return null; } } //-------------------// // getFolderForLinux // //-------------------// private static Path getFolderForLinux (FolderKind kind) { // First try XDG specification final String xdg = System.getenv(xdgProperty(kind)); if (xdg != null) { final Path audiverisPath = Paths.get(xdg + TOOL_PREFIX); switch (kind) { case DATA: return audiverisPath; case CONFIG: return audiverisPath; default: case LOG: return audiverisPath.resolve("log"); } } // Fall back using home final String home = System.getenv("HOME"); if (home == null) { printError("HOME environment variable is not set"); return null; } switch (kind) { case DATA: return Paths.get(home + "/.local/share" + TOOL_PREFIX); case CONFIG: return Paths.get(home + "/.config" + TOOL_PREFIX); default: case LOG: return Paths.get(home + "/.cache" + TOOL_PREFIX + "/log"); } } //-----------------// // getFolderForMac // //-----------------// private static Path getFolderForMac (FolderKind kind) { final String home = System.getenv("HOME"); if (home == null) { printError("HOME environment variable is not set"); return null; } switch (kind) { case DATA: return Paths.get(home + "/Library/" + TOOL_PREFIX + "/data"); case CONFIG: return Paths.get(home + "/Library/Application Support/" + TOOL_PREFIX); default: case LOG: return Paths.get(home + "/Library/" + TOOL_PREFIX + "/log"); } } //---------------------// // getFolderForWindows // //---------------------// private static Path getFolderForWindows (FolderKind kind) { // User Application Data final String appdata = System.getenv("APPDATA"); if (appdata == null) { printError("APPDATA environment variable is not set"); return null; } final Path audiverisPath = Paths.get(appdata + TOOL_PREFIX); // User Documents final String userDocs = FileSystemView.getFileSystemView().getDefaultDirectory().getPath(); switch (kind) { case DATA: return Paths.get(userDocs + "/" + TOOL_NAME); case CONFIG: return audiverisPath.resolve("config"); default: case LOG: return audiverisPath.resolve("log"); } } //------------// // getJarFile // //------------// private static JarFile getJarFile () { try { String rn = WellKnowns.class.getName().replace('.', '/') + ".class"; Enumeration<URL> en = WellKnowns.class.getClassLoader().getResources(rn); if (en.hasMoreElements()) { URL url = en.nextElement(); // url = jar:http://audiveris.kenai.com/jnlp/audiveris.jar!/omr/WellKnowns.class JarURLConnection urlcon = (JarURLConnection) (url.openConnection()); JarFile jarFile = urlcon.getJarFile(); return jarFile; } } catch (IOException ex) { System.out.print("Error getting jar file " + ex); } return null; } //-----------------// // logDeclaredData // //-----------------// private static void logDeclaredData () { // Note: Logger initialization has been differed until now final Logger logger = LoggerFactory.getLogger(WellKnowns.class); if (logger.isTraceEnabled()) { for (Field field : WellKnowns.class.getDeclaredFields()) { try { logger.trace("{}= {}", field.getName(), field.get(null)); } catch (IllegalAccessException ex) { ex.printStackTrace(); } } } } //------------// // printError // //------------// /** * Fallback solution, since we cannot reliably use exception in static initializer. * * @param msg the error message */ private static void printError (String msg) { System.err.println("*** INIT_ERROR occurred in class WellKnowns: " + msg); } //----------------// // runningFromJar // //----------------// private static boolean runningFromJar () { return CLASS_CONTAINER.toString().toLowerCase().endsWith(".jar"); } //-------------// // xdgProperty // //-------------// private static String xdgProperty (FolderKind kind) { switch (kind) { case DATA: return "XDG_DATA_HOME"; case CONFIG: return "XDG_CONFIG_HOME"; default: case LOG: return "XDG_CACHE_HOME"; } } }