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

net.automatalib.modelcheckers.ltsmin.LTSminUtil Maven / Gradle / Ivy

/* Copyright (C) 2013-2019 TU Dortmund
 * This file is part of AutomataLib, http://www.automatalib.net/.
 *
 * 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 net.automatalib.modelcheckers.ltsmin;

import java.io.IOException;
import java.io.StringWriter;
import java.nio.file.Paths;

import net.automatalib.AutomataLibProperty;
import net.automatalib.AutomataLibSettings;
import net.automatalib.commons.util.process.ProcessUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A utility class that encapsulates certain technical aspects of LTSmin (e.g. accessibility of the binary, etc.)
 *
 * @author Jeroen Meijer
 * @author frohme
 */
public final class LTSminUtil {

    /**
     * Path to the "etf2lts-mc" binary.
     */
    public static final String ETF2LTS_MC;

    /**
     * Path to the "ltsmin-convert" binary.
     */
    public static final String LTSMIN_CONVERT;

    private static final Logger LOGGER = LoggerFactory.getLogger(LTSminUtil.class);

    private static final String CHECK = "An exception occurred while checking if LTSmin is installed. " +
                                        "Could not run binary '%s', the following exception occurred: %s. " +
                                        "LTSmin can be obtained at https://ltsmin.utwente.nl. If you installed LTSmin " +
                                        "in a non standard location you can set the property: '" +
                                        AutomataLibProperty.LTSMIN_PATH.getPropertyKey() +
                                        "'. Setting the $PATH variable works too.";

    /**
     * The exit code for running an LTSmin binary with --version.
     */
    private static final int VERSION_EXIT = 255;

    /**
     * A flag for triggering verbose LTSmin output.
     */
    private static boolean verbose;

    private static LTSminVersion detectedVersion;

    static {
        AutomataLibSettings settings = AutomataLibSettings.getInstance();

        final String ltsMinPath = settings.getProperty(AutomataLibProperty.LTSMIN_PATH, "");

        ETF2LTS_MC = Paths.get(ltsMinPath, "etf2lts-mc").toString();
        LTSMIN_CONVERT = Paths.get(ltsMinPath, "ltsmin-convert").toString();

        verbose = !settings.getProperty(AutomataLibProperty.LTSMIN_VERBOSE, Boolean.toString(LOGGER.isDebugEnabled()))
                           .equalsIgnoreCase("false");

        detectLTSmin();
    }

    private LTSminUtil() {
        throw new AssertionError();
    }

    /**
     * Returns whether or not an LTSmin installation was detected.
     *
     * @return {@code true} if an LTSmin installation was detected, {@code false} otherwise.
     */
    public static boolean isInstalled() {
        return detectedVersion != null;
    }

    /**
     * Returns the detected version of the LTSmin installation. {@code null} if LTSmin is not installed.
     *
     * @return the detected version of the LTSmin installation. {@code null} if LTSmin is not installed.
     *
     * @see #isInstalled()
     */
    public static LTSminVersion getVersion() {
        return detectedVersion;
    }

    /**
     * Checks whether the currently detected LTSmin installation supports the queried version.
     *
     * @param requiredVersion
     *         the required version
     *
     * @return {@code true} if LTSmin is installed in the proper version, {@code false} otherwise.
     */
    public static boolean supports(LTSminVersion requiredVersion) {
        return isInstalled() && detectedVersion.supports(requiredVersion);
    }

    /**
     * Returns whether to make LTSmin's output more verbose.
     */
    public static boolean isVerbose() {
        return verbose;
    }

    /**
     * Programmitically set, whether to make LTSmin's output more verbose.
     */
    public static void setVerbose(boolean verbose) {
        LTSminUtil.verbose = verbose;
    }

    /**
     * (Re-)Checks whether the required binaries for the {@link AbstractLTSmin LTSmin modelchecker} can be executed, by
     * performing a version check. The results to these checks can be accessed by {@link #isInstalled()} and {@link
     * #getVersion()}.
     *
     * @see #ETF2LTS_MC
     * @see #LTSMIN_CONVERT
     */
    public static void detectLTSmin() {
        final LTSminVersion etf2ltsVersion = detectLTSmin(ETF2LTS_MC);
        final LTSminVersion ltsminConvertVersion = detectLTSmin(LTSMIN_CONVERT);

        if (etf2ltsVersion != null && ltsminConvertVersion != null) {
            if (!etf2ltsVersion.equals(ltsminConvertVersion)) {
                LOGGER.warn("Found differing etf2lts version '{}' and lstminConver version '{}'. Choosing the former",
                            etf2ltsVersion,
                            ltsminConvertVersion);
            }
            detectedVersion = etf2ltsVersion;
        }
    }

    private static LTSminVersion detectLTSmin(String bin) {

        // the command lines for the ProcessBuilder
        final String[] commandLine = new String[] {// add the binary
                                                   bin,
                                                   // just run a version check
                                                   "--version"};

        final StringWriter stringWriter = new StringWriter();

        try {
            final int exitValue = ProcessUtil.invokeProcess(commandLine, stringWriter::append);

            if (exitValue != VERSION_EXIT) {
                LOGGER.debug(String.format(CHECK,
                                           bin,
                                           String.format("Command '%s --version' did not exit with 255", bin)));
                return null;
            } else {
                return LTSminVersion.parse(stringWriter.toString());
            }
        } catch (IOException | InterruptedException e) {
            LOGGER.error(String.format(CHECK, bin, e.toString()), e);
            return null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy