//----------------------------------------------------------------------------// // // // M a i n // // // //----------------------------------------------------------------------------// // <editor-fold defaultstate="collapsed" desc="hdr"> // // Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. // // This software is released under the GNU General Public License. // // Goto http://kenai.com/projects/audiveris to report bugs or suggestions. // //----------------------------------------------------------------------------// // </editor-fold> package omr; import omr.constant.Constant; import omr.constant.ConstantManager; import omr.constant.ConstantSet; import omr.score.Score; import omr.script.ScriptManager; import omr.step.ProcessingCancellationException; import omr.step.Stepping; import omr.ui.MainGui; import omr.ui.symbol.MusicFont; import omr.util.ClassUtil; import omr.util.Clock; import omr.util.Dumping; import omr.util.OmrExecutors; import org.jdesktop.application.Application; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.nio.file.*; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Properties; import java.util.SortedSet; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * Class {@code Main} is the main class for OMR application. * It deals with the main routine and its command line parameters. * It launches the User Interface, unless a batch mode is selected. * * @see CLI * * @author Hervé Bitteur */ public class Main { //~ Static fields/initializers --------------------------------------------- static { /** Time stamp */ Clock.resetTime(); } /** Master View */ private static MainGui gui; /** Usual logger utility */ private static final Logger logger = LoggerFactory.getLogger(Main.class); /** Specific application parameters */ private static final Constants constants = new Constants(); /** Parameters read from CLI */ private static CLI.Parameters parameters; /** The application dumping service */ public static final Dumping dumping = new Dumping(Main.class.getPackage()); //~ Constructors ----------------------------------------------------------- //------// // Main // //------// private Main () { } //~ Methods ---------------------------------------------------------------- //--------// // doMain // //--------// /** * Specific starting method for the application. * * @param args command line parameters * @see omr.CLI the possible command line parameters */ public static void doMain (String[] args) { // Initialize tool parameters initialize(); // Process CLI arguments process(args); // Locale to be used in the whole application? checkLocale(); // Environment showEnvironment(); // Native libs loadNativeLibraries(); if (!parameters.batchMode) { // For interactive mode logger.debug("Main. Launching MainGui"); Application.launch(MainGui.class, args); } else { // For batch mode // Remember if at least one task failed boolean failure = false; // Check MusicFont is loaded MusicFont.checkMusicFont(); // Launch the required tasks, if any List<Callable<Void>> tasks = new ArrayList<Callable<Void>>(); tasks.addAll(getFilesTasks()); tasks.addAll(getScriptsTasks()); if (!tasks.isEmpty()) { try { logger.info("Submitting {} task(s)", tasks.size()); List<Future<Void>> futures = OmrExecutors.getCachedLowExecutor() .invokeAll( tasks, constants.processTimeOut.getValue(), TimeUnit.SECONDS); logger.info("Checking {} task(s)", tasks.size()); // Check for time-out for (Future<Void> future : futures) { try { future.get(); } catch (Exception ex) { logger.warn("Future exception", ex); failure = true; } } } catch (Exception ex) { logger.warn("Error in processing tasks", ex); failure = true; } } // At this point all tasks have completed (normally or not) // So shutdown immediately the executors OmrExecutors.shutdown(true); // Store latest constant values on disk? if (constants.persistBatchCliConstants.getValue()) { ConstantManager.getInstance() .storeResource(); } // Stop the JVM with failure status? if (failure) { logger.warn("Exit with failure status"); System.exit(-1); } } } //--------------// // getBenchPath // //--------------// /** * Report the bench path if present on the CLI * * @return the CLI bench path, or null */ public static String getBenchPath () { return parameters.benchPath; } //-----------------// // getCliConstants // //-----------------// /** * Report the properties set at the CLI level * * @return the CLI-defined constant values */ public static Properties getCliConstants () { if (parameters == null) { return null; } else { return parameters.options; } } //---------------// // getExportPath // //---------------// /** * Report the export path if present on the CLI * * @return the CLI export path, or null */ public static String getExportPath () { return parameters.exportPath; } //---------------// // getFilesTasks // //---------------// /** * Prepare the processing of image files listed on command line * * @return the collection of proper callables */ public static List<Callable<Void>> getFilesTasks () { List<Callable<Void>> tasks = new ArrayList<Callable<Void>>(); // Launch desired step on each score in parallel for (final String name : parameters.inputNames) { final File file = new File(name); tasks.add( new Callable<Void>() { @Override public Void call () throws Exception { if (!parameters.desiredSteps.isEmpty()) { logger.info( "Launching {} on {} {}", parameters.desiredSteps, name, (parameters.pages != null) ? ("pages " + parameters.pages) : ""); } // // to accomodate symplic links, we provide an option. The // problem may be if the link is broken, who knows what // will happen // if (file.exists() || Files.isSymbolicLink(Paths.get(name))) { final Score score = new Score(file); try { Stepping.processScore( parameters.desiredSteps, parameters.pages, score); } catch (ProcessingCancellationException pce) { logger.warn("Cancelled " + score, pce); score.getBench() .recordCancellation(); throw pce; } catch (Throwable ex) { logger.warn("Exception occurred", ex); throw ex; } finally { // Close (when in batch mode only) if (gui == null) { score.close(); } return null; } } else { String msg = "Could not find file " + file.getCanonicalPath(); logger.warn(msg); throw new RuntimeException(msg); } } }); } return tasks; } //--------// // getGui // //--------// /** * Points to the single instance of the User Interface, if any. * * @return MainGui instance, which may be null */ public static MainGui getGui () { return gui; } //-------------// // getMidiPath // //-------------// /** * Report the midi path if present on the CLI * * @return the CLI midi path, or null */ public static String getMidiPath () { return parameters.midiPath; } //-------------// // getPagesIds // //-------------// /** * Report the set of page ids if present on the CLI * * @return the CLI page ids, or null */ public static SortedSet<Integer> getPageIds () { return parameters.pages; } //--------------// // getPrintPath // //--------------// /** * Report the print path if present on the CLI * * @return the CLI print path, or null */ public static String getPrintPath () { return parameters.printPath; } //-----------------// // getScriptsTasks // //-----------------// /** * Prepare the processing of scripts listed on command line * * @return the collection of proper script callables */ public static List<Callable<Void>> getScriptsTasks () { List<Callable<Void>> tasks = new ArrayList<Callable<Void>>(); // Launch desired scripts in parallel for (String name : parameters.scriptNames) { final String scriptName = name; tasks.add( new Callable<Void>() { @Override public Void call () throws Exception { ScriptManager.getInstance() .loadAndRun(new File(scriptName)); return null; } }); } return tasks; } //--------// // setGui // //--------// /** * Register the GUI (done by the GUI itself when it is ready) * * @param gui the MainGui instance */ public static void setGui (MainGui gui) { Main.gui = gui; } //-------------// // checkLocale // //-------------// private static void checkLocale () { final String localeStr = constants.locale.getValue() .trim(); if (!localeStr.isEmpty()) { for (Locale locale : Locale.getAvailableLocales()) { if (locale.toString() .equalsIgnoreCase(localeStr)) { Locale.setDefault(locale); logger.debug("Locale set to {}", locale); return; } } logger.warn("Cannot set locale to {}", localeStr); } } //------------// // initialize // //------------// private static void initialize () { // (re) Open the executor services OmrExecutors.restart(); } //---------------------// // loadNativeLibraries // //---------------------// /** * Explicitly load all the needed native libraries. */ private static void loadNativeLibraries () { // Explicitly load all native libs resources and in proper order logger.info("Loading native libraries ..."); boolean success = true; if (WellKnowns.WINDOWS) { // For Windows, drop only the ".dll" suffix success &= ClassUtil.loadLibrary("jniTessBridge"); success &= ClassUtil.loadLibrary("libtesseract302"); success &= ClassUtil.loadLibrary("liblept168"); } else if (WellKnowns.LINUX) { // For Linux, drop both the "lib" prefix and the ".so" suffix success &= ClassUtil.loadLibrary("jniTessBridge"); } if (success) { logger.info("All libraries loaded."); } else { // Inform user of OCR installation problem String msg = "Tesseract OCR is not installed properly"; if (Main.getGui() != null) { Main.getGui() .displayError(msg); } else { logger.warn(msg); } } } //---------// // process // //---------// private static void process (String[] args) { // First get the provided arguments if any parameters = new CLI(WellKnowns.TOOL_NAME, args).getParameters(); if (parameters == null) { logger.warn("Exiting ..."); // Stop the JVM, with failure status (1) Runtime.getRuntime() .exit(1); } // Interactive or Batch mode ? if (parameters.batchMode) { logger.info("Running in batch mode"); ///System.setProperty("java.awt.headless", "true"); // // Check MIDI output is not asked for // Step midiStep = Steps.valueOf(Steps.MIDI); // // if ((midiStep != null) && // parameters.desiredSteps.contains(midiStep)) { // logger.warn( // "MIDI output is not compatible with -batch mode." + // " MIDI output is ignored."); // parameters.desiredSteps.remove(midiStep); // } } else { logger.debug("Running in interactive mode"); } } //-----------------// // showEnvironment // //-----------------// /** * Show the application environment to the user. */ private static void showEnvironment () { if (constants.showEnvironment.isSet()) { logger.info( "Environment:\n" + "- Audiveris: {}\n" + "- OS: {}\n" + "- Architecture: {}\n" + "- Java VM: {}", WellKnowns.TOOL_REF + ":" + WellKnowns.TOOL_BUILD, System.getProperty("os.name") + " " + System.getProperty("os.version"), System.getProperty("os.arch"), System.getProperty("java.vm.name") + " (build " + System.getProperty("java.vm.version") + ", " + System.getProperty("java.vm.info") + ")"); } } //~ Inner Classes ---------------------------------------------------------- //-----------// // Constants // //-----------// private static final class Constants extends ConstantSet { //~ Instance fields ---------------------------------------------------- private final Constant.Boolean showEnvironment = new Constant.Boolean( true, "Should we show environment?"); private final Constant.String locale = new Constant.String( "en", "Locale language to be used in the whole application (en, fr)"); private final Constant.Boolean persistBatchCliConstants = new Constant.Boolean( false, "Should we persist CLI-defined constants when running in batch?"); private final Constant.Integer processTimeOut = new Constant.Integer( "Seconds", 900, "Process time-out, specified in seconds"); } }