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

boofcv.gui.JavaRuntimeLauncher Maven / Gradle / Ivy

Go to download

BoofCV is an open source Java library for real-time computer vision and robotics applications.

The newest version!
/*
 * Copyright (c) 2011-2016, Peter Abeles. All Rights Reserved.
 *
 * This file is part of BoofCV (http://boofcv.org).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package boofcv.gui;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Date;
import java.util.List;

/**
 * Class for launching JVMs.  Monitors the status and kills frozen threads.  Keeps track of execution time and
 * sets up class path.
 *
 * @author Peter Abeles
 */
public class JavaRuntimeLauncher {

    String classPath;
    // amount of memory allocated to the JVM
    long memoryInMB = 200;
    // if the process doesn't finish in this number of milliesconds it's considered frozen and killed
    long frozenTime = 60*1000;

    // amount of time it actually took to execute in milliseconds
    long durationMilli;

    volatile boolean killRequested = false;

    // save for future debugging
    String[] jvmArgs;

    // Default to standard printOut and printErr
    PrintStream printOut = System.out;
    PrintStream printErr = System.err;

    /**
     * Constructor.  Configures which library it is to be launching a class from/related to
     * @param pathJars List of paths to all the jars
     */
    public JavaRuntimeLauncher( List pathJars ) {

        String sep = System.getProperty("path.separator");

        if( pathJars != null ) {
            classPath = "";

            for( String s : pathJars ) {
                classPath = classPath + sep + s;
            }
        }
    }

    /**
     * Specifies the amount of time the process has to complete.  After which it is considered frozen and
     * will be killed
     * @param frozenTime time in milliseconds
     */
    public void setFrozenTime(long frozenTime) {
        this.frozenTime = frozenTime;
    }

    /**
     * Specifies the amount of memory the process will be allocated in megabytes
     * @param memoryInMB megabytes
     */
    public void setMemoryInMB(long memoryInMB) {
        this.memoryInMB = memoryInMB;
    }

    /**
     * Returns how long the operation took to complete. In milliseconds
     */
    public long getDurationMilli() {
        return durationMilli;
    }

    /**
     * Launches the class with the provided arguments.  Blocks until the process stops.
     *
     * @param mainClass Class
     * @param args it's arguments
     * @return true if successful or false if it ended on error
     */
    public Exit launch( Class mainClass , String ...args ) {

        jvmArgs = configureArguments(mainClass,args);

        try {
            Runtime rt = Runtime.getRuntime();
            Process pr = rt.exec(jvmArgs);

            // If it exits too quickly it might not get any error messages if it crashes right away
            // so the work around is to sleep
            Thread.sleep(500);

            BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream()));
            BufferedReader error = new BufferedReader(new InputStreamReader(pr.getErrorStream()));

            // print the output from the slave
            if( !monitorSlave(pr, input, error) ) {
                if( killRequested )
                    return Exit.REQUESTED;
                else
                    return Exit.FROZEN;
            }

            if( pr.exitValue() != 0 ) {
                return Exit.RETURN_NOT_ZERO;
            } else {
                return Exit.NORMAL;
            }
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Prints printOut the standard printOut and error from the slave and checks its health.  Exits if
     * the slave has finished or is declared frozen.
     *
     * @return true if successful or false if it was forced to kill the slave because it was frozen
     */
    private boolean monitorSlave(Process pr,
                                 BufferedReader input, BufferedReader error)
            throws IOException, InterruptedException {

        // flush the input buffer
        System.in.skip(System.in.available());

        // If the total amount of time allocated to the slave exceeds the maximum number of trials multiplied
        // by the maximum runtime plus some fudge factor the slave is declared as frozen

        boolean frozen = false;

        long startTime = System.currentTimeMillis();
        long lastAliveMessage = startTime;
        for(;;) {
            while( System.in.available() > 0 ) {
                if( System.in.read() == 'q' ) {
                    System.out.println("User requested for the application to quit by pressing 'q'");
                    System.exit(0);
                }
            }

            printBuffer(error, printErr);

            if( input.ready() ) {
                printBuffer(input, printOut);
            } else {
                Thread.sleep(500);
            }

            try {
                // exit value throws an exception is the process has yet to stop
                pr.exitValue();
                break;
            } catch( IllegalThreadStateException e) {
                if( killRequested ) {
                    pr.destroy();
                    break;
                }
                // check to see if the process is frozen
                if(frozenTime > 0 && System.currentTimeMillis() - startTime > frozenTime ) {
                    pr.destroy(); // kill the process
                    frozen = true;
                    break;
                }

                // let everyone know its still alive
                if( System.currentTimeMillis() - lastAliveMessage > 60000 ) {
                    System.out.println("\nMaster is still alive: "+new Date()+"  Press 'q' and enter to quit.");
                    lastAliveMessage = System.currentTimeMillis();
                }
            }
        }

        printBuffer(error, printErr);
        printBuffer(input, printOut);

        durationMilli = System.currentTimeMillis()-startTime;
        return !frozen && !killRequested;
    }

    char buffInput[] = new char[1024];
    protected void printBuffer(BufferedReader input , PrintStream output ) throws IOException {
        int length = 0;
        while( input.ready() ) {
            int val = input.read();
            if( val < 0 ) break;
            buffInput[length++] = (char)val;

            if( length == buffInput.length ) {
                output.print(new String(buffInput,0,length));
                length = 0;
            }
        }
        output.print(new String(buffInput,0,length));
    }

    private String[] configureArguments( Class mainClass , String ...args ) {
        String out[] = new String[7+args.length];

        String app = System.getProperty("java.home")+"/bin/java";

        out[0] = app;
        out[1] = "-server";
        out[2] = "-Xms"+memoryInMB+"M";
        out[3] = "-Xmx"+memoryInMB+"M";
        out[4] = "-classpath";
        out[5] = classPath;
        out[6] = mainClass.getName();
        for (int i = 0; i < args.length; i++) {
            out[7+i] = args[i];
        }
        return out;
    }

    public String getClassPath() {
        return classPath;
    }

    public long getAllocatedMemoryInMB() {
        return memoryInMB;
    }

    public long getFrozenTime() {
        return frozenTime;
    }

    public String[] getArguments() {
        return jvmArgs;
    }

    public void requestKill() {
        killRequested = true;
    }

    public boolean isKillRequested() {
        return killRequested;
    }

    public PrintStream getPrintOut() {
        return printOut;
    }

    public void setPrintOut(PrintStream out) {
        this.printOut = out;
    }

    public PrintStream getPrintErr() {
        return printErr;
    }

    public void setPrintErr(PrintStream err) {
        this.printErr = err;
    }

    public enum Exit
    {
        /**
         * Exited normally.
         */
        NORMAL,
        /**
         * Did not finish in the required amount of time
         */
        FROZEN,
        /**
         * Killed by user
         */
        REQUESTED,
        /**
         * exited with a non zero return value
         */
        RETURN_NOT_ZERO,
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy