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

com.velasolaris.plugin.controller.matlab.matconsolectl.MatlabRuntimePluginController Maven / Gradle / Ivy

The newest version!
package com.velasolaris.plugin.controller.matlab.matconsolectl;

import static com.velasolaris.plugin.controller.spi.PluginControllerConfiguration.DEFAULT_TIMESTEP;
import static com.velasolaris.plugin.util.PluginUtils.*;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import com.velasolaris.plugin.controller.spi.PluginControllerConfiguration;
import com.velasolaris.plugin.controller.spi.PluginControllerConfiguration.ControlSignal;
import com.velasolaris.plugin.controller.spi.PluginControllerConfiguration.Log;
import com.velasolaris.plugin.controller.spi.PluginControllerConfiguration.Property;
import com.velasolaris.plugin.controller.spi.PluginControllerConfiguration.Sensor;
import com.velasolaris.plugin.controller.spi.PluginControllerException;
import com.velasolaris.plugin.painter.MCRPluginControllerPainter;

/**
 * Matlab Runtime (MCR) plugin controller.
 * This plugin controller allows Matlab control() that have been compiled to a JAR using Matlab's library compiler to be used with Polysun.
 * @author MAJ
 * @since Polysun 11.1
 */
public class MatlabRuntimePluginController extends AbstractMatlabPluginController {

    private static final int	CONTROL_SIGNALS_IDX = 0;
    private static final int	LOG_VALUES_IDX = 1;
    private static final int	TIME_POINTS_IDX = 2;
    private static ClassLoader 	sPluginClassLoader;
    private static Method		sControlMethod;
    private static Method		sGetFloatDataMethod;
    private static Method		sGetIntDataMethod;
    private static Object		sMcrPluginControllerInstance;
    private static Object		sMWNumericArrayInstance;
    private String 				mMcrJavaBuilder = "C:\\Program Files\\MATLAB\\MATLAB Runtime\\v95\\toolbox\\javabuilder\\jar\\javabuilder.jar";

    @Override
    public String getName() {
        return "Matlab MCR";
    }

    @Override
    public String getDescription() {
        return "Loads a JAR file 'McrPlugin.jar' generated by the Matlab Library Compiler for use without a Matlab installation. The plugin contains a class 'McrPluginController' "
            + "with the Matlab control() method used with the Matlab Plugin Controller. Requires the Matlab Compiler Runtime (MCR).";
    }

    @Override
    public void initialiseSimulation(Map parameters) throws PluginControllerException {
        super.initialiseSimulation(parameters);
        try {
            if (sPluginClassLoader == null) {
                URL pluginUrl = new File(pluginDataPath + System.getProperty("file.separator") + "McrPlugin.jar").toURI().toURL();
                JarFile jarFile = new JarFile(mMcrJavaBuilder);
                Enumeration e = jarFile.entries();

                URL[] urls = { new URL("jar:file:" + mMcrJavaBuilder + "!/"), pluginUrl };
                sPluginClassLoader = URLClassLoader.newInstance(urls);

                while (e.hasMoreElements()) {
                    JarEntry je = e.nextElement();
                    if(je.isDirectory() || !je.getName().endsWith(".class")){
                        continue;
                    }
                    // -6 because of .class
                    String className = je.getName().substring(0,je.getName().length()-6);
                    className = className.replace('/', '.');
                    className = className.replace("$1", "");
                    try {
                        sPluginClassLoader.loadClass(className);
                    } catch (ClassNotFoundException | NoClassDefFoundError ex) {
                        sLog.warning("Class not found: " + className);
                    }
                }
            }
            Class classToLoad = Class.forName("McrPlugin.McrPluginController", true, sPluginClassLoader);
            Class[] params = new Class[2];
            params[0] = int.class;
            params[1] = Object[].class;
            sControlMethod = classToLoad.getDeclaredMethod("control", params);
            sMcrPluginControllerInstance = classToLoad.newInstance();
            classToLoad = Class.forName("com.mathworks.toolbox.javabuilder.MWNumericArray", true, sPluginClassLoader);
            sGetFloatDataMethod = classToLoad.getDeclaredMethod("getFloatData");
            sGetIntDataMethod = classToLoad.getDeclaredMethod("getIntData");
            sMWNumericArrayInstance = classToLoad.newInstance();
        } catch (Throwable t) {
            cleanup();
            throw new PluginControllerException("Unable to load MCR plugin", t);
        }
        try {
            Object[] args = new Object[] {3, new Object[] { 0, false, new float[sensorsUsed.length], sensorsUsed, matlabPropertiesFloat, matlabPropertiesString, true, controlSignalsUsed, 0, FUNCTION_STAGE_INIT, fixedTimestep, verboseLevel, 0} };
            sControlMethod.invoke(sMcrPluginControllerInstance, args);
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            cleanup();
            throw new PluginControllerException(e);
        }
    }

    @Override
    public int[] control(int simulationTime, boolean status, float[] sensors, float[] controlSignals, float[] logValues,
            boolean preRun, Map parameters) throws PluginControllerException {
        Object[] result;
        try {
            Object[] args = new Object[] {3, new Object[] {simulationTime, status ? 1.0 : 0.0, sensors, sensorsUsed, matlabPropertiesFloat, matlabPropertiesString, preRun ? 1.0 : 0.0, controlSignalsUsed, logValues.length, FUNCTION_STAGE_SIMULATION, fixedTimestep, verboseLevel, 0 } };
            result = (Object[]) sControlMethod.invoke(sMcrPluginControllerInstance, args);
            cleanup();
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            throw new PluginControllerException(e);
        }
        try {
            controlSignals = getResultFloat(result[CONTROL_SIGNALS_IDX]);
            logValues = getResultFloat(result[LOG_VALUES_IDX]);
            return getResultInt(result[TIME_POINTS_IDX]);
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            cleanup();
            throw new PluginControllerException(e);
        }
    }

    @Override
    public void terminateSimulation(Map parameters) {
        super.terminateSimulation(parameters);
        try {
            if (verboseLevel > VERBOSE_LEVEL_STANDARD) {
                logPerfMeasure("Overall: ", parameters);
            }
            Object[] args = new Object[] {3, new Object[] { 0, false, new float[sensorsUsed.length], sensorsUsed, matlabPropertiesFloat, matlabPropertiesString, true, controlSignalsUsed, 0, FUNCTION_STAGE_TERMINATE, fixedTimestep, verboseLevel, 0} };
            sControlMethod.invoke(sMcrPluginControllerInstance, args);
        } catch (Throwable t) {
            cleanup();
            sLog.warning(getRootCauseStackTrace(t));
        }
        cleanup();
    }

    @Override
    public void cleanupOnSimulationException() {
        super.cleanupOnSimulationException();
        cleanup();
    }

    @Override
    public void cleanupOnSimulationAbort() {
        super.cleanupOnSimulationAbort();
        cleanup();
    }

    private void cleanup() {
        // Attempt to unload plugin JARs.
        sPluginClassLoader = null;
        System.gc();
    }

    private float[] getResultFloat(Object aResult) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        return (float[]) sGetFloatDataMethod.invoke(sMWNumericArrayInstance.getClass().cast(aResult));
    }

    private int[] getResultInt(Object aResult) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        return (int[]) sGetIntDataMethod.invoke(sMWNumericArrayInstance.getClass().cast(aResult));
    }

    @Override
    public PluginControllerConfiguration getConfiguration(Map parameters) throws PluginControllerException {
        setConfiguration(parameters);
        Properties config = new Properties();
        int defaultNumGenericSensors = 3;
        int defaultNumGenericControlSignals = 3;
        int defaultNumGenericProperties = 5;
        int defaultNumLogValues = 1;
        int defaultFixedTimestep = DEFAULT_TIMESTEP;
        Integer defaultVerboseLevel = 1;
        List printMessage = new ArrayList<>();
        File configFile = new File(pluginDataPath + File.separator + "config.properties");
        try {
            if (configFile.exists()) {
                try(FileReader fileReader = new FileReader(configFile);
                        BufferedReader reader = new BufferedReader(fileReader);) {
                    config.load(reader);
                    Object obj;
                    defaultNumGenericProperties = (obj = config.get("defaultNumGenericProperties")) != null && !"".equals(obj) ? Integer.parseInt(obj.toString()) : defaultNumGenericProperties;
                    defaultNumGenericSensors = (obj = config.get("defaultNumGenericSensors")) != null && !"".equals(obj) ? Integer.parseInt(obj.toString()) : defaultNumGenericSensors;
                    defaultNumGenericControlSignals = (obj = config.get("defaultNumGenericControlSignals")) != null && !"".equals(obj) ? Integer.parseInt(obj.toString()) : defaultNumGenericControlSignals;
                    defaultFixedTimestep = (obj = config.get("defaultFixedTimestep")) != null && !"".equals(obj) ? Integer.parseInt(obj.toString()) : defaultFixedTimestep;
                    defaultNumLogValues = (obj = config.get("defaultNumLogValues")) != null && !"".equals(obj) ? Integer.parseInt(obj.toString()) : defaultNumLogValues;
                    defaultVerboseLevel = (obj = config.get("defaultVerboseLevel")) != null && !"".equals(obj) ? Integer.parseInt(obj.toString()) : defaultVerboseLevel;
                    mMcrJavaBuilder = (obj = config.get("mcr.javabuilder.location")) != null && !"".equals(obj) ? obj.toString() : null;
                    sLog.info("Config.properties read: " + configFile);
                } catch (IOException e) {
                    sLog.warning(getRootCauseStackTrace(e));
                }
            } else {
                new File(pluginDataPath).mkdirs();
                try (FileWriter fileWriter = new FileWriter(configFile);
                        BufferedWriter writer = new BufferedWriter(fileWriter)) {
                    config.put("defaultNumGenericProperties", "" + defaultNumGenericProperties);
                    config.put("defaultNumGenericSensors", "" + defaultNumGenericSensors);
                    config.put("defaultNumGenericControlSignals", "" + defaultNumGenericControlSignals);
                    config.put("defaultNumLogValues", "" + defaultNumLogValues);
                    config.put("defaultFixedTimestep", "" + defaultFixedTimestep);
                    config.put("defaultVerboseLevel", "" + defaultVerboseLevel);
                    config.put("mcr.javabuilder.location", mMcrJavaBuilder != null ? mMcrJavaBuilder : "");
                    config.store(writer, "Properties of the Polysun MatlabPluginController + [" + getId() + "]");
                    sLog.info("Config file written: " + configFile);
                } catch(IOException e) {
                    sLog.warning(getRootCauseStackTrace(e));
                }
            }
        } catch (Exception e) {
            sLog.warning(getRootCauseStackTrace(e));
        }
        List properties = new ArrayList<>();
        properties.add(new Property(PROPERTY_FIXED_TIMESTEP, defaultFixedTimestep, 0f, 900, "s"));
        properties.add(new Property(PROPERTY_NUM_GENERIC_SENSORS, defaultNumGenericSensors, 0, 100));
        properties.add(new Property(PROPERTY_NUM_GENERIC_CONTROL_SIGNALS, defaultNumGenericControlSignals, 0, 100));
        properties.add(new Property(PROPERTY_NUM_GENERIC_LOGS, defaultNumLogValues, 0, 100));
        properties.add(new Property(PROPERTY_VERBOSE_LEVEL, new String[] { "Standard", "Verbose", "Debug" }, defaultVerboseLevel));

        numInternProperties = properties.size();

        List sensors = new ArrayList<>();

        List controlSignals = new ArrayList<>();

        List logs = new ArrayList<>();

        parameters.put("Plugin.PrintMessage", printMessage);

        PluginControllerConfiguration.Builder builder = new PluginControllerConfiguration.Builder();
        builder.setProperties(properties);
        builder.setSensors(sensors);
        builder.setControlSignals(controlSignals);
        builder.setLogs(logs);
        builder.setNumGenericProperties(defaultNumGenericProperties);
        builder.setNumGenericSensors(defaultNumGenericSensors);
        builder.setNumGenericControlSignals(defaultNumGenericControlSignals);
        builder.setPropertyNameNumGenericSensors(PROPERTY_NUM_GENERIC_SENSORS);
        builder.setPropertyNameNumGenericControlSignals(PROPERTY_NUM_GENERIC_CONTROL_SIGNALS);
        builder.setPropertyNameNumGenericLogs(PROPERTY_NUM_GENERIC_LOGS);
        builder.setImagePainter(new MCRPluginControllerPainter());
        return builder.build();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy